Fix and cleanup source code
And add some comments and documents.
This commit is contained in:
parent
f29aa802b8
commit
c0f8a22fa1
4 changed files with 37 additions and 25 deletions
|
|
@ -188,7 +188,7 @@ Time: 3224.741 ms (00:03.225)
|
||||||
|
|
||||||
## Supported View Definitions and Restriction
|
## Supported View Definitions and Restriction
|
||||||
|
|
||||||
Currently, IMMV's view definition can contain inner joins, DISTINCT clause, some built-in aggregate functions, simple sub-queries in `FROM` clause, and simple CTE (`WITH` query). Inner joins including self-join are supported, but outer joins are not supported. Supported aggregate functions are count, sum, avg, min and max. Other aggregates, sub-queries which contain an aggregate or `DISTINCT` clause, sub-queries in other than `FROM` clause, window functions, `HAVING`, `ORDER BY`, `LIMIT`/`OFFSET`, `UNION`/`INTERSECT`/`EXCEPT`, `DISTINCT ON`, `TABLESAMPLE`, `VALUES`, and `FOR UPDATE`/`SHARE` can not be used in view definition.
|
Currently, IMMV's view definition can contain inner joins, DISTINCT clause, some built-in aggregate functions, simple sub-queries in `FROM` clause, EXISTS sub-queries, and simple CTE (`WITH` query). Inner joins including self-join are supported, but outer joins are not supported. Supported aggregate functions are count, sum, avg, min and max. Other aggregates, sub-queries which contain an aggregate or `DISTINCT` clause, sub-queries in other than `FROM` clause, window functions, `HAVING`, `ORDER BY`, `LIMIT`/`OFFSET`, `UNION`/`INTERSECT`/`EXCEPT`, `DISTINCT ON`, `TABLESAMPLE`, `VALUES`, and `FOR UPDATE`/`SHARE` can not be used in view definition.
|
||||||
|
|
||||||
The base tables must be simple tables. Views, materialized views, inheritance parent tables, partitioned tables, partitions, and foreign tables can not be used.
|
The base tables must be simple tables. Views, materialized views, inheritance parent tables, partitioned tables, partitions, and foreign tables can not be used.
|
||||||
|
|
||||||
|
|
@ -216,11 +216,11 @@ Targetlist cannot contain expressions which contain an aggregate in it.
|
||||||
|
|
||||||
### Subqueries
|
### Subqueries
|
||||||
|
|
||||||
Simple subqueries in `FROM` clause are supported.
|
Simple subqueries in `FROM` clause and EXISTS subqueries in 'WHERE' clause are supported.
|
||||||
|
|
||||||
#### Restrictions on Subqueries
|
#### Restrictions on Subqueries
|
||||||
|
|
||||||
Subqueries can be used only in `FROM` clause. Subqueries in target list or `WHERE` clause are not supported.
|
Subqueries using EXISTS and simple subqueries in FROM clause are supported. EXISTS subqueries with condition other than 'AND' and Subqueries in targetlist are not supported.
|
||||||
|
|
||||||
Subqueries containing an aggregate function or `DISTINCT` are not supported.
|
Subqueries containing an aggregate function or `DISTINCT` are not supported.
|
||||||
|
|
||||||
|
|
|
||||||
22
createas.c
22
createas.c
|
|
@ -166,7 +166,7 @@ ExecCreateImmv(ParseState *pstate, CreateTableAsStmt *stmt,
|
||||||
check_ivm_restriction((Node *) query);
|
check_ivm_restriction((Node *) query);
|
||||||
|
|
||||||
/* For IMMV, we need to rewrite matview query */
|
/* For IMMV, we need to rewrite matview query */
|
||||||
query = rewriteQueryForIMMV(query, into->colNames);
|
query = rewriteQueryForIMMV(viewQuery, into->colNames);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,7 +340,6 @@ rewriteQueryForIMMV(Query *query, List *colNames)
|
||||||
countCol = (Node *) makeVar(varno, attnum,
|
countCol = (Node *) makeVar(varno, attnum,
|
||||||
INT8OID, -1, InvalidOid, 0);
|
INT8OID, -1, InvalidOid, 0);
|
||||||
|
|
||||||
|
|
||||||
if (countCol != NULL)
|
if (countCol != NULL)
|
||||||
{
|
{
|
||||||
tle = makeTargetEntry((Expr *) countCol,
|
tle = makeTargetEntry((Expr *) countCol,
|
||||||
|
|
@ -893,7 +892,12 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
|
|
||||||
query_tree_walker(qry, check_ivm_restriction_walker, (void *) context, QTW_IGNORE_RT_SUBQUERIES);
|
query_tree_walker(qry, check_ivm_restriction_walker, (void *) context, QTW_IGNORE_RT_SUBQUERIES);
|
||||||
|
|
||||||
/* additional restriction checks for exists subquery */
|
/*
|
||||||
|
* additional restriction checks for exists subquery
|
||||||
|
*
|
||||||
|
* When contain EXISTS clauses, and it has a column refernces
|
||||||
|
* a table outside, its column must be included by target list.
|
||||||
|
*/
|
||||||
if (context->exists_qual_vars != NIL && context->sublevels_up == 0)
|
if (context->exists_qual_vars != NIL && context->sublevels_up == 0)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
@ -1015,7 +1019,9 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
case T_Var:
|
case T_Var:
|
||||||
{
|
{
|
||||||
Var *variable = (Var *) node;
|
Var *variable = (Var *) node;
|
||||||
/* If EXISTS subquery refers to vars of the upper query, collect these vars */
|
/* Currently, only EXISTS clause is allowed here.
|
||||||
|
* If EXISTS subquery refers to vars of the upper query, collect these vars.
|
||||||
|
*/
|
||||||
if (variable->varlevelsup > 0 && context->in_exists_subquery)
|
if (variable->varlevelsup > 0 && context->in_exists_subquery)
|
||||||
context->exists_qual_vars = lappend(context->exists_qual_vars, node);
|
context->exists_qual_vars = lappend(context->exists_qual_vars, node);
|
||||||
break;
|
break;
|
||||||
|
|
@ -1023,6 +1029,7 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
case T_SubLink:
|
case T_SubLink:
|
||||||
{
|
{
|
||||||
/* Now, EXISTS clause is supported only */
|
/* Now, EXISTS clause is supported only */
|
||||||
|
Query *subselect;
|
||||||
SubLink *sublink = (SubLink *) node;
|
SubLink *sublink = (SubLink *) node;
|
||||||
if (sublink->subLinkType != EXISTS_SUBLINK)
|
if (sublink->subLinkType != EXISTS_SUBLINK)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
|
@ -1034,6 +1041,13 @@ check_ivm_restriction_walker(Node *node, check_ivm_restriction_context *context)
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("nested subquery is not supported on incrementally maintainable materialized view")));
|
errmsg("nested subquery is not supported on incrementally maintainable materialized view")));
|
||||||
|
|
||||||
|
subselect = (Query *)sublink->subselect;
|
||||||
|
/* raise ERROR if the sublink has CTE */
|
||||||
|
if (subselect->cteList)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("CTE in EXIST clause is not supported on incrementally maintainable materialized view")));
|
||||||
|
|
||||||
context->in_exists_subquery = true;
|
context->in_exists_subquery = true;
|
||||||
context->sublevels_up++;
|
context->sublevels_up++;
|
||||||
check_ivm_restriction_walker(sublink->subselect, context);
|
check_ivm_restriction_walker(sublink->subselect, context);
|
||||||
|
|
|
||||||
|
|
@ -1160,6 +1160,8 @@ SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT i, COUNT(*) FROM mv_base_b
|
||||||
ERROR: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
ERROR: aggregate functions in nested query are not supported on incrementally maintainable materialized view
|
||||||
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT DISTINCT i FROM mv_base_b) SELECT a.i,a.j FROM mv_base_a a, b WHERE a.i = b.i');
|
||||||
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
ERROR: DISTINCT clause in nested query are not supported on incrementally maintainable materialized view
|
||||||
|
SELECT create_immv('mv_cte_fail', 'WITH a AS (SELECT i, j FROM mv_base_a) SELECT a.i,a.j FROM a WHERE EXISTS(WITH b AS (SELECT i FROM mv_base_b) SELECT 1 FROM b WHERE a.i = b.i)');
|
||||||
|
ERROR: CTE in EXIST clause is not supported on incrementally maintainable materialized view
|
||||||
-- unreferenced CTE
|
-- unreferenced CTE
|
||||||
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
SELECT create_immv('mv_cte_fail', 'WITH b AS (SELECT * FROM mv_base_b) SELECT * FROM mv_base_a a');
|
||||||
ERROR: Ureferenced WITH query is not supported on incrementally maintainable materialized view
|
ERROR: Ureferenced WITH query is not supported on incrementally maintainable materialized view
|
||||||
|
|
|
||||||
28
matview.c
28
matview.c
|
|
@ -1623,9 +1623,14 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
||||||
case AND_EXPR:
|
case AND_EXPR:
|
||||||
foreach(lc, ((BoolExpr *)node)->args)
|
foreach(lc, ((BoolExpr *)node)->args)
|
||||||
{
|
{
|
||||||
|
/* If simple EXISTS subquery is used, rewrite LATERAL subquery */
|
||||||
Node *opnode = (Node *)lfirst(lc);
|
Node *opnode = (Node *)lfirst(lc);
|
||||||
query = rewrite_exists_subquery_walker(query, opnode, count);
|
query = rewrite_exists_subquery_walker(query, opnode, count);
|
||||||
/* overwrite SubLink node if it is contained in AND_EXPR */
|
/*
|
||||||
|
* 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))
|
if (IsA(opnode, SubLink))
|
||||||
lfirst(lc) = makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
|
lfirst(lc) = makeConst(BOOLOID, -1, InvalidOid, sizeof(bool), BoolGetDatum(true), false, true);
|
||||||
}
|
}
|
||||||
|
|
@ -1659,21 +1664,8 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
||||||
Expr *opexpr;
|
Expr *opexpr;
|
||||||
|
|
||||||
SubLink *sublink = (SubLink *)node;
|
SubLink *sublink = (SubLink *)node;
|
||||||
/* raise ERROR if there is non-EXISTS sublink */
|
|
||||||
if (sublink->subLinkType != EXISTS_SUBLINK)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("this query is not allowed on incrementally maintainable materialized view"),
|
|
||||||
errhint("subquery in WHERE clause only supports subquery with EXISTS clause")));
|
|
||||||
|
|
||||||
subselect = (Query *)sublink->subselect;
|
subselect = (Query *)sublink->subselect;
|
||||||
|
|
||||||
/* raise ERROR if the sublink has CTE */
|
|
||||||
if (subselect->cteList)
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("CTE is not supported on incrementally maintainable materialized view")));
|
|
||||||
|
|
||||||
pstate = make_parsestate(NULL);
|
pstate = make_parsestate(NULL);
|
||||||
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
|
||||||
|
|
||||||
|
|
@ -1685,7 +1677,11 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
||||||
snprintf(columnName, sizeof(columnName), "__ivm_exists_count_%d__", *count);
|
snprintf(columnName, sizeof(columnName), "__ivm_exists_count_%d__", *count);
|
||||||
|
|
||||||
/* add COUNT(*) for counting rows that meet exists condition */
|
/* add COUNT(*) for counting rows that meet exists condition */
|
||||||
fn = makeFuncCall(list_make1(makeString("count")), NIL, COERCE_EXPLICIT_CALL, -1);
|
#if defined(PG_VERSION_NUM) && (PG_VERSION_NUM >= 140000)
|
||||||
|
fn = makeFuncCall(SystemFuncName("count"), NIL, COERCE_EXPLICIT_CALL, -1);
|
||||||
|
#else
|
||||||
|
fn = makeFuncCall(SystemFuncName("count"), NIL, -1);
|
||||||
|
#endif
|
||||||
fn->agg_star = true;
|
fn->agg_star = true;
|
||||||
fn_node = ParseFuncOrColumn(pstate, fn->funcname, NIL, NULL, fn, false, -1);
|
fn_node = ParseFuncOrColumn(pstate, fn->funcname, NIL, NULL, fn, false, -1);
|
||||||
tle_count = makeTargetEntry((Expr *) fn_node,
|
tle_count = makeTargetEntry((Expr *) fn_node,
|
||||||
|
|
@ -1711,7 +1707,7 @@ rewrite_exists_subquery_walker(Query *query, Node *node, int *count)
|
||||||
* EXISTS condition is converted to HAVING count(*) > 0.
|
* EXISTS condition is converted to HAVING count(*) > 0.
|
||||||
* We use make_opcllause() to get int84gt( '>' operator). We might be able to use make_op().
|
* We use make_opcllause() to get int84gt( '>' operator). We might be able to use make_op().
|
||||||
*/
|
*/
|
||||||
opId = OpernameGetOprid(list_make1(makeString(">")), INT8OID, INT4OID);
|
opId = OpernameGetOprid(list_make2(makeString("pg_catalog"), makeString(">")), INT8OID, INT4OID);
|
||||||
opexpr = make_opclause(opId, BOOLOID, false,
|
opexpr = make_opclause(opId, BOOLOID, false,
|
||||||
(Expr *)fn_node,
|
(Expr *)fn_node,
|
||||||
(Expr *)makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(0), false, true),
|
(Expr *)makeConst(INT4OID, -1, InvalidOid, sizeof(int32), Int32GetDatum(0), false, true),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue