Simple CTEs which does not contain aggregates or DISTINCT are now supported similarly to simple sub-queries. Before a view is maintained, all CTEs are converted to corresponding subqueries to enable to treat CTEs as same as subqueries. For this end, codes of the static function inline_cte in the core (optimizer/plan/subselect.c) was imported. Prohibit Unreferenced CTE is prohibited. 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 in a CTE is actually referenced. Although it would possible, we just disallow to create such IMMVs for now since such unreferenced CTE is useless unless it doesn't contain modifying commands, that is already prohibited.
112 lines
2.9 KiB
C
112 lines
2.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* subselect.c
|
|
* incremental view maintenance extension
|
|
* Routines for CTE support.
|
|
*
|
|
* Portions Copyright (c) 2023, IVM Development Group
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
#include "nodes/nodeFuncs.h"
|
|
#include "rewrite/rewriteManip.h"
|
|
|
|
#include "pg_ivm.h"
|
|
|
|
typedef struct inline_cte_walker_context
|
|
{
|
|
const char *ctename; /* name and relative level of target CTE */
|
|
int levelsup;
|
|
Query *ctequery; /* query to substitute */
|
|
} inline_cte_walker_context;
|
|
|
|
static bool inline_cte_walker(Node *node, inline_cte_walker_context *context);
|
|
|
|
/*
|
|
* inline_cte: convert RTE_CTE references to given CTE into RTE_SUBQUERYs
|
|
*/
|
|
void
|
|
inline_cte(PlannerInfo *root, CommonTableExpr *cte)
|
|
{
|
|
struct inline_cte_walker_context context;
|
|
|
|
context.ctename = cte->ctename;
|
|
/* Start at levelsup = -1 because we'll immediately increment it */
|
|
context.levelsup = -1;
|
|
context.ctequery = castNode(Query, cte->ctequery);
|
|
|
|
(void) inline_cte_walker((Node *) root->parse, &context);
|
|
}
|
|
|
|
static bool
|
|
inline_cte_walker(Node *node, inline_cte_walker_context *context)
|
|
{
|
|
if (node == NULL)
|
|
return false;
|
|
if (IsA(node, Query))
|
|
{
|
|
Query *query = (Query *) node;
|
|
|
|
context->levelsup++;
|
|
|
|
/*
|
|
* Visit the query's RTE nodes after their contents; otherwise
|
|
* query_tree_walker would descend into the newly inlined CTE query,
|
|
* which we don't want.
|
|
*/
|
|
(void) query_tree_walker(query, inline_cte_walker, context,
|
|
QTW_EXAMINE_RTES_AFTER);
|
|
|
|
context->levelsup--;
|
|
|
|
return false;
|
|
}
|
|
else if (IsA(node, RangeTblEntry))
|
|
{
|
|
RangeTblEntry *rte = (RangeTblEntry *) node;
|
|
|
|
if (rte->rtekind == RTE_CTE &&
|
|
strcmp(rte->ctename, context->ctename) == 0 &&
|
|
rte->ctelevelsup == context->levelsup)
|
|
{
|
|
/*
|
|
* Found a reference to replace. Generate a copy of the CTE query
|
|
* with appropriate level adjustment for outer references (e.g.,
|
|
* to other CTEs).
|
|
*/
|
|
Query *newquery = copyObject(context->ctequery);
|
|
|
|
if (context->levelsup > 0)
|
|
IncrementVarSublevelsUp((Node *) newquery, context->levelsup, 1);
|
|
|
|
/*
|
|
* Convert the RTE_CTE RTE into a RTE_SUBQUERY.
|
|
*
|
|
* Historically, a FOR UPDATE clause has been treated as extending
|
|
* into views and subqueries, but not into CTEs. We preserve this
|
|
* distinction by not trying to push rowmarks into the new
|
|
* subquery.
|
|
*/
|
|
rte->rtekind = RTE_SUBQUERY;
|
|
rte->subquery = newquery;
|
|
rte->security_barrier = false;
|
|
|
|
/* Zero out CTE-specific fields */
|
|
rte->ctename = NULL;
|
|
rte->ctelevelsup = 0;
|
|
rte->self_reference = false;
|
|
rte->coltypes = NIL;
|
|
rte->coltypmods = NIL;
|
|
rte->colcollations = NIL;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
return expression_tree_walker(node, inline_cte_walker, context);
|
|
}
|