fix a expression including EXISTS condition under AND condition

Previously, queries could not be searched correctlywhen the
EXISTS clause was included in a CASE statement.
This commit is contained in:
thoshiai 2024-01-15 03:28:29 +09:00
parent 6f5ae0ee22
commit 7eb8a1da38
3 changed files with 25 additions and 2 deletions

View file

@ -70,6 +70,7 @@ typedef struct
bool has_subquery; bool has_subquery;
bool in_exists_subquery; /* true, if it is in a exists subquery */ bool in_exists_subquery; /* true, if it is in a exists subquery */
bool in_jointree; /* true, if it is in a join tree */ bool in_jointree; /* true, if it is in a join tree */
bool is_simple_jointree; /* true, if it is in a simple join tree or boolexpr directly under jointree */
List *exists_qual_vars; List *exists_qual_vars;
int sublevels_up; int sublevels_up;
} check_ivm_restriction_context; } check_ivm_restriction_context;
@ -741,7 +742,7 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock
static void static void
check_ivm_restriction(Node *node) check_ivm_restriction(Node *node)
{ {
check_ivm_restriction_context context = {false, false, false, false, false, NIL, 0}; check_ivm_restriction_context context = {false, false, false, false, false, false, NIL, 0};
check_ivm_restriction_walker(node, &context); check_ivm_restriction_walker(node, &context);
} }
@ -996,6 +997,15 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
expression_tree_walker(node, check_ivm_restriction_walker, (void *) context); expression_tree_walker(node, check_ivm_restriction_walker, (void *) context);
break; break;
} }
case T_List:
{
ListCell *temp;
foreach(temp, (List *) node)
{
check_ivm_restriction_walker(lfirst(temp), context);
}
break;
}
case T_FromExpr: case T_FromExpr:
{ {
FromExpr *from = (FromExpr *) node; FromExpr *from = (FromExpr *) node;
@ -1015,7 +1025,9 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
errhint("sublink only supports simple conditions with EXISTS clause in WHERE clause"))); errhint("sublink only supports simple conditions with EXISTS clause in WHERE clause")));
context->in_jointree = true; context->in_jointree = true;
context->is_simple_jointree = true;
check_ivm_restriction_walker(from->quals, context); check_ivm_restriction_walker(from->quals, context);
context->is_simple_jointree = false;
context->in_jointree = false; context->in_jointree = false;
break; break;
} }
@ -1071,6 +1083,12 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
context->exists_qual_vars = lappend(context->exists_qual_vars, node); context->exists_qual_vars = lappend(context->exists_qual_vars, node);
break; break;
} }
case T_BoolExpr:
{
BoolExpr *expr = (BoolExpr *) node;
expression_tree_walker((Node *) expr->args, check_ivm_restriction_walker, (void *) context);
break;
}
case T_SubLink: case T_SubLink:
{ {
/* Currently, EXISTS clause is supported only */ /* Currently, EXISTS clause is supported only */
@ -1081,7 +1099,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("this query is not allowed on incrementally maintainable materialized view"), errmsg("this query is not allowed on incrementally maintainable materialized view"),
errhint("sublink only supports subquery with EXISTS clause in WHERE clause"))); errhint("sublink only supports subquery with EXISTS clause in WHERE clause")));
if (context->sublevels_up > 0) if (context->sublevels_up > 0 || (context->in_jointree && !context->is_simple_jointree))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("nested sublink is not supported on incrementally maintainable materialized view"))); errmsg("nested sublink is not supported on incrementally maintainable materialized view")));
@ -1101,6 +1119,8 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
break; break;
} }
default: default:
// not a simple query, if a condition don't match these
context->is_simple_jointree = false;
expression_tree_walker(node, check_ivm_restriction_walker, (void *) context); expression_tree_walker(node, check_ivm_restriction_walker, (void *) context);
break; break;
} }

View file

@ -891,6 +891,8 @@ HINT: sublink only supports subquery with EXISTS clause in WHERE clause
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END'); SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
ERROR: this query is not allowed on incrementally maintainable materialized view ERROR: this query is not allowed on incrementally maintainable materialized view
HINT: sublink only supports simple conditions with EXISTS clause in WHERE clause HINT: sublink only supports simple conditions with EXISTS clause in WHERE clause
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
ERROR: nested sublink is not supported on incrementally maintainable materialized view
-- support join subquery in FROM clause -- support join subquery in FROM clause
BEGIN; BEGIN;
SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp'); SELECT create_immv('mv_ivm_join_subquery', 'SELECT i, j, k FROM ( SELECT i, a.j, b.k FROM mv_base_b b INNER JOIN mv_base_a a USING(i)) tmp');

View file

@ -293,6 +293,7 @@ SELECT create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FR
SELECT create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b'); SELECT create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b'); SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM generate_series(1, CASE EXISTS(SELECT 1 FROM mv_base_a) WHEN true THEN 100 ELSE 10 END), mv_base_b');
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END'); SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
SELECT create_immv('mv_ivm_subquery', 'SELECT * FROM mv_base_a a WHERE true and CASE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) WHEN true THEN false ELSE true END');
-- support join subquery in FROM clause -- support join subquery in FROM clause
BEGIN; BEGIN;