Fix checking for expressions containing an EXISTS subquery (#71)
EXISTS subquery is currently allowed only directly under WHERE clause or in AND expression that is directly under WHERE. However, the check was insufficient previously so that views using expressions other than AND containing an EXISTS subquery could be created without an error and it caused incorrect maintenance results. To fix this check, add a new boolean member allow_context into check_ivm_restriction_context. This member means whether EXISTS subquery is allowed in the current node being examined in check_ivm_restriction_walker. This should be set to true just before calling check_ivm_restriction_walker for nodes directly under WHERE or operands of AND expression direct under WHERE, and is reset to false on every call of the function. In passing, move the check for OR and NOT expression from rewrite_exists_subquery_walker to check_ivm_restriction_context, with some code cleaning. --------- Co-authored-by: Yugo Nagata <nagata@sraoss.co.jp>
This commit is contained in:
parent
980c4be338
commit
fc2339e16c
4 changed files with 121 additions and 69 deletions
120
createas.c
120
createas.c
|
|
@ -65,12 +65,11 @@ typedef struct
|
|||
|
||||
typedef struct
|
||||
{
|
||||
bool has_agg;
|
||||
bool has_subquery;
|
||||
bool in_exists_subquery; /* true, if it is in a exists subquery */
|
||||
bool in_jointree; /* true, if it is in a join tree */
|
||||
List *exists_qual_vars;
|
||||
int sublevels_up;
|
||||
bool has_agg; /* the query has an aggregate */
|
||||
bool allow_exists; /* EXISTS subquery is allowed in the current node */
|
||||
bool in_exists_subquery; /* true, if under an EXISTS subquery */
|
||||
List *exists_qual_vars; /* Vars used in EXISTS subqueries */
|
||||
int sublevels_up; /* (current) nesting depth */
|
||||
} check_ivm_restriction_context;
|
||||
|
||||
static void CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
||||
|
|
@ -466,7 +465,7 @@ makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *
|
|||
|
||||
/* Make a Func with a dummy arg, and then override this by the original agg's args. */
|
||||
node = ParseFuncOrColumn(pstate, fn->funcname, list_make1(dmy_arg), NULL, fn, false, -1);
|
||||
((Aggref *)node)->args = aggref->args;
|
||||
((Aggref *) node)->args = aggref->args;
|
||||
|
||||
tle_count = makeTargetEntry((Expr *) node,
|
||||
*next_resno,
|
||||
|
|
@ -502,7 +501,7 @@ makeIvmAggColumn(ParseState *pstate, Aggref *aggref, char *resname, AttrNumber *
|
|||
|
||||
/* Make a Func with dummy args, and then override this by the original agg's args. */
|
||||
node = ParseFuncOrColumn(pstate, fn->funcname, dmy_args, NULL, fn, false, -1);
|
||||
((Aggref *)node)->args = aggref->args;
|
||||
((Aggref *) node)->args = aggref->args;
|
||||
|
||||
tle_count = makeTargetEntry((Expr *) node,
|
||||
*next_resno,
|
||||
|
|
@ -573,7 +572,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
Query *query = (Query *) node;
|
||||
ListCell *lc;
|
||||
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *)query->jointree, matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(qry, (Node *) query->jointree, matviewOid, relids, ex_lock);
|
||||
foreach(lc, query->cteList)
|
||||
{
|
||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||
|
|
@ -605,7 +604,7 @@ CreateIvmTriggersOnBaseTablesRecurse(Query *qry, Node *node, Oid matviewOid,
|
|||
{
|
||||
Query *subquery = rte->subquery;
|
||||
Assert(rte->subquery != NULL);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *)subquery, matviewOid, relids, ex_lock);
|
||||
CreateIvmTriggersOnBaseTablesRecurse(subquery, (Node *) subquery, matviewOid, relids, ex_lock);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -740,7 +739,13 @@ CreateIvmTrigger(Oid relOid, Oid viewOid, int16 type, int16 timing, bool ex_lock
|
|||
static void
|
||||
check_ivm_restriction(Node *node)
|
||||
{
|
||||
check_ivm_restriction_context context = {false, false, false, false, NIL, 0};
|
||||
check_ivm_restriction_context context;
|
||||
|
||||
context.has_agg = false;
|
||||
context.allow_exists = false;
|
||||
context.in_exists_subquery = false;
|
||||
context.exists_qual_vars = NIL;
|
||||
context.sublevels_up = 0;
|
||||
|
||||
check_ivm_restriction_walker(node, &context);
|
||||
}
|
||||
|
|
@ -748,6 +753,10 @@ check_ivm_restriction(Node *node)
|
|||
static bool
|
||||
check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||
{
|
||||
/* EXISTS is allowed only in this node */
|
||||
bool allow_exists = context->allow_exists;
|
||||
context->allow_exists = false;
|
||||
|
||||
if (node == NULL)
|
||||
return false;
|
||||
|
||||
|
|
@ -758,7 +767,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
{
|
||||
case T_Query:
|
||||
{
|
||||
Query *qry = (Query *)node;
|
||||
Query *qry = (Query *) node;
|
||||
ListCell *lc;
|
||||
List *vars;
|
||||
|
||||
|
|
@ -814,7 +823,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
if (IsA(lfirst(lc), Var))
|
||||
{
|
||||
Var *var = (Var *) lfirst(lc);
|
||||
/* if system column, return error */
|
||||
/* if the view has a system column, raise an error */
|
||||
if (var->varattno < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
|
|
@ -822,7 +831,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
}
|
||||
}
|
||||
|
||||
/* check if type in the top target list had an equality operator */
|
||||
/* check that each type in the target list has an equality operator */
|
||||
if (context->sublevels_up == 0)
|
||||
{
|
||||
foreach(lc, qry->targetList)
|
||||
|
|
@ -893,6 +902,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("VALUES is not supported on incrementally maintainable materialized view")));
|
||||
|
||||
if (rte->relkind == RELKIND_RELATION && isImmv(rte->relid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
|
|
@ -900,10 +910,8 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
|
||||
if (rte->rtekind == RTE_SUBQUERY)
|
||||
{
|
||||
context->has_subquery = true;
|
||||
|
||||
context->sublevels_up++;
|
||||
check_ivm_restriction_walker((Node *)rte->subquery, context);
|
||||
check_ivm_restriction_walker((Node *) rte->subquery, context);
|
||||
context->sublevels_up--;
|
||||
}
|
||||
}
|
||||
|
|
@ -913,9 +921,11 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
/*
|
||||
* additional restriction checks for exists subquery
|
||||
*
|
||||
* If the query has any EXISTS clauses and columns in them refer to
|
||||
* columns in tables in the output query, those columns must be
|
||||
* included in the target list.
|
||||
* If the query has an EXISTS subquery and columns of a table in
|
||||
* the outer query are used in the EXISTS subquery, those columns
|
||||
* must be included in the target list. These columns are required
|
||||
* to identify tuples in the view to be affected by modification
|
||||
* of tables in the EXISTS subquery.
|
||||
*/
|
||||
if (context->exists_qual_vars != NIL && context->sublevels_up == 0)
|
||||
{
|
||||
|
|
@ -958,7 +968,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("WITH query name %s is not supported on incrementally maintainable materialized view", cte->ctename)));
|
||||
|
||||
/*
|
||||
/*
|
||||
* When a table in a unreferenced CTE is TRUNCATEd, the contents of the
|
||||
* IMMV is not affected so it must not be truncated. For confirming it
|
||||
* at the maintenance time, we have to check if the modified table used
|
||||
|
|
@ -979,12 +989,13 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
}
|
||||
case T_TargetEntry:
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *)node;
|
||||
TargetEntry *tle = (TargetEntry *) node;
|
||||
|
||||
if (isIvmName(tle->resname))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("column name %s is not supported on incrementally maintainable materialized view", tle->resname)));
|
||||
|
||||
if (context->has_agg && !IsA(tle->expr, Aggref) && contain_aggs_of_level((Node *) tle->expr, 0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
|
|
@ -993,19 +1004,22 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
expression_tree_walker(node, check_ivm_restriction_walker, (void *) context);
|
||||
break;
|
||||
}
|
||||
case T_FromExpr:
|
||||
{
|
||||
FromExpr *from = (FromExpr *) node;
|
||||
case T_FromExpr:
|
||||
{
|
||||
FromExpr *from = (FromExpr *) node;
|
||||
|
||||
check_ivm_restriction_walker((Node *)from->fromlist, context);
|
||||
context->in_jointree = true;
|
||||
check_ivm_restriction_walker((Node *) from->fromlist, context);
|
||||
|
||||
/*
|
||||
* EXIEST is allowed directly under FROM clause
|
||||
*/
|
||||
context->allow_exists = true;
|
||||
check_ivm_restriction_walker(from->quals, context);
|
||||
context->in_jointree = false;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case T_JoinExpr:
|
||||
{
|
||||
JoinExpr *joinexpr = (JoinExpr *)node;
|
||||
JoinExpr *joinexpr = (JoinExpr *) node;
|
||||
|
||||
if (joinexpr->jointype > JOIN_INNER)
|
||||
ereport(ERROR,
|
||||
|
|
@ -1055,22 +1069,60 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
|||
context->exists_qual_vars = lappend(context->exists_qual_vars, node);
|
||||
break;
|
||||
}
|
||||
case T_BoolExpr:
|
||||
{
|
||||
BoolExpr *expr = (BoolExpr *) node;
|
||||
BoolExprType type = ((BoolExpr *) node)->boolop;
|
||||
ListCell *lc;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AND_EXPR:
|
||||
foreach(lc, expr->args)
|
||||
{
|
||||
Node *opnode = (Node *) lfirst(lc);
|
||||
|
||||
/*
|
||||
* EXIEST is allowed under AND expression only if it is
|
||||
* directly under WHERE.
|
||||
*/
|
||||
if (allow_exists)
|
||||
context->allow_exists = true;
|
||||
check_ivm_restriction_walker(opnode, context);
|
||||
}
|
||||
break;
|
||||
case OR_EXPR:
|
||||
case NOT_EXPR:
|
||||
if (checkExprHasSubLink(node))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("this query is not allowed on incrementally maintainable materialized view"),
|
||||
errhint("OR or NOT conditions and EXISTS condition can not be used together")));
|
||||
|
||||
expression_tree_walker((Node *) expr->args, check_ivm_restriction_walker, (void *) context);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case T_SubLink:
|
||||
{
|
||||
/* Currently, EXISTS clause is supported only */
|
||||
Query *subselect;
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
if (!context->in_jointree || sublink->subLinkType != EXISTS_SUBLINK)
|
||||
|
||||
/* Only EXISTS clause is supported if it is directly under WHERE */
|
||||
if (!allow_exists || sublink->subLinkType != EXISTS_SUBLINK)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("this query is not allowed on incrementally maintainable materialized view"),
|
||||
errhint("sublink only supports subquery with EXISTS clause in WHERE clause")));
|
||||
|
||||
if (context->sublevels_up > 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("nested sublink is not supported on incrementally maintainable materialized view")));
|
||||
|
||||
subselect = (Query *)sublink->subselect;
|
||||
subselect = (Query *) sublink->subselect;
|
||||
|
||||
/* raise ERROR if the sublink has CTE */
|
||||
if (subselect->cteList)
|
||||
ereport(ERROR,
|
||||
|
|
@ -1600,7 +1652,7 @@ get_primary_key_attnos_from_query(Query *query, List **constraintList)
|
|||
i = 1;
|
||||
foreach(lc, key_attnos_list)
|
||||
{
|
||||
Bitmapset *bms = (Bitmapset *)lfirst(lc);
|
||||
Bitmapset *bms = (Bitmapset *) lfirst(lc);
|
||||
if (!bms_is_empty(bms) && bms_is_member(i, rels_in_from))
|
||||
return NULL;
|
||||
i++;
|
||||
|
|
|
|||
|
|
@ -906,7 +906,7 @@ ERROR: this query is not allowed on incrementally maintainable materialized vie
|
|||
HINT: targetlist must contain vars that are referred to in EXISTS subquery
|
||||
SELECT create_immv('mv_ivm_subquery', 'SELECT a.i,a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a.i = b.i) OR a.i > 2');
|
||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||
HINT: OR or NOT conditions and EXISTS condition are not used together
|
||||
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
||||
SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(SELECT 1 FROM mv_base_a a2 WHERE EXISTS(SELECT 1 FROM mv_base_b b WHERE a2.i = b.i))');
|
||||
ERROR: nested sublink is not supported on incrementally maintainable materialized view
|
||||
SELECT create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
||||
|
|
@ -914,10 +914,16 @@ ERROR: this query is not allowed on incrementally maintainable materialized vie
|
|||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||
SELECT create_immv('mv_ivm_subquery', 'SELECT false OR EXISTS(SELECT 1 FROM mv_base_a) FROM mv_base_b');
|
||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||
HINT: OR or NOT conditions and EXISTS condition can not be used together
|
||||
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');
|
||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||
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');
|
||||
ERROR: this query is not allowed on incrementally maintainable materialized view
|
||||
HINT: sublink only supports subquery 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: this query is not allowed on incrementally maintainable materialized view
|
||||
HINT: sublink only supports subquery with EXISTS clause in WHERE clause
|
||||
-- support join subquery in FROM clause
|
||||
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');
|
||||
|
|
|
|||
57
matview.c
57
matview.c
|
|
@ -1606,7 +1606,8 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
|||
if (fromexpr->quals != NULL)
|
||||
{
|
||||
query = rewrite_exists_subquery_walker(query, fromexpr->quals, count);
|
||||
/* drop subquery in WHERE clause */
|
||||
|
||||
/* drop WHERE clause when it has only one EXISTS */
|
||||
if (IsA(fromexpr->quals, SubLink))
|
||||
fromexpr->quals = NULL;
|
||||
}
|
||||
|
|
@ -1614,35 +1615,25 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
|||
}
|
||||
case T_BoolExpr:
|
||||
{
|
||||
BoolExprType type;
|
||||
BoolExprType type = ((BoolExpr *) node)->boolop;
|
||||
|
||||
type = ((BoolExpr *) node)->boolop;
|
||||
switch (type)
|
||||
if (type == AND_EXPR)
|
||||
{
|
||||
ListCell *lc;
|
||||
case AND_EXPR:
|
||||
foreach(lc, ((BoolExpr *)node)->args)
|
||||
{
|
||||
/* If simple EXISTS subquery is used, rewrite LATERAL subquery */
|
||||
Node *opnode = (Node *)lfirst(lc);
|
||||
query = rewrite_exists_subquery_walker(query, opnode, count);
|
||||
/*
|
||||
* overwrite SubLink node to true condition if it is contained in AND_EXPR.
|
||||
* EXISTS clause have already overwritten to LATERAL, so original EXISTS clause
|
||||
* is not necessory.
|
||||
*/
|
||||
if (IsA(opnode, SubLink))
|
||||
lfirst(lc) = makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
|
||||
}
|
||||
break;
|
||||
case OR_EXPR:
|
||||
case NOT_EXPR:
|
||||
if (checkExprHasSubLink(node))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("this query is not allowed on incrementally maintainable materialized view"),
|
||||
errhint("OR or NOT conditions and EXISTS condition are not used together")));
|
||||
break;
|
||||
foreach(lc, ((BoolExpr *) node)->args)
|
||||
{
|
||||
/* If simple EXISTS subquery is used, rewrite LATERAL subquery */
|
||||
Node *opnode = (Node *) lfirst(lc);
|
||||
query = rewrite_exists_subquery_walker(query, opnode, count);
|
||||
|
||||
/*
|
||||
* overwrite SubLink node to true condition if it is contained in AND_EXPR.
|
||||
* EXISTS clause have already overwritten to LATERAL, so original EXISTS clause
|
||||
* is not necessory.
|
||||
*/
|
||||
if (IsA(opnode, SubLink))
|
||||
lfirst(lc) = makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -1701,7 +1692,7 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
|||
/* assume the new RTE is at the end */
|
||||
rtr = makeNode(RangeTblRef);
|
||||
rtr->rtindex = list_length(query->rtable);
|
||||
((FromExpr *)query->jointree)->fromlist = lappend(((FromExpr *)query->jointree)->fromlist, rtr);
|
||||
((FromExpr *) query->jointree)->fromlist = lappend(((FromExpr *) query->jointree)->fromlist, rtr);
|
||||
|
||||
/*
|
||||
* EXISTS condition is converted to HAVING count(*) > 0.
|
||||
|
|
@ -1709,13 +1700,13 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
|||
*/
|
||||
opId = OpernameGetOprid(list_make2(makeString("pg_catalog"), makeString(">")), INT8OID, INT4OID);
|
||||
opexpr = make_opclause(opId, BOOLOID, false,
|
||||
(Expr *)fn_node,
|
||||
(Expr *)makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(0), false, true),
|
||||
(Expr *) fn_node,
|
||||
(Expr *) makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(0), false, true),
|
||||
InvalidOid, InvalidOid);
|
||||
fix_opfuncids((Node *) opexpr);
|
||||
query->hasSubLinks = false;
|
||||
|
||||
subselect->havingQual = (Node *)opexpr;
|
||||
subselect->havingQual = (Node *) opexpr;
|
||||
(*count)++;
|
||||
break;
|
||||
}
|
||||
|
|
@ -1738,7 +1729,7 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
|||
* SELECT 1, COUNT(*) AS __ivm_exists_count_0__
|
||||
* FROM t2
|
||||
* WHERE t1.key = t2.key
|
||||
* HAVING __ivm_exists_count_0__ > 0) AS ex
|
||||
* HAVING COUNT(*) > 0) AS ex
|
||||
*/
|
||||
Query *
|
||||
rewrite_query_for_exists_subquery(Query *query)
|
||||
|
|
@ -1750,7 +1741,7 @@ rewrite_query_for_exists_subquery(Query *query)
|
|||
errmsg("this query is not allowed on incrementally maintainable materialized view"),
|
||||
errhint("aggregate function and EXISTS condition are not supported at the same time")));
|
||||
|
||||
return rewrite_exists_subquery_walker(query, (Node *)query, &count);
|
||||
return rewrite_exists_subquery_walker(query, (Node *) query, &count);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -298,6 +298,9 @@ SELECT create_immv('mv_ivm_subquery', 'SELECT a.j FROM mv_base_a a WHERE EXISTS(
|
|||
SELECT create_immv('mv_ivm_subquery', 'SELECT EXISTS(SELECT 1 from mv_base_b) FROM mv_base_a a');
|
||||
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 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
|
||||
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');
|
||||
|
|
|
|||
Loading…
Reference in a new issue