mirror of https://github.com/citusdata/citus.git
Refactor CTE inlining logic to improve clarity and remove unused functions
parent
1c6167f18e
commit
e02d49c220
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 3376bd6845f0614908ed304f5033bd644c82d3bf
|
|
@ -16,7 +16,6 @@
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "optimizer/optimizer.h"
|
#include "optimizer/optimizer.h"
|
||||||
#include "rewrite/rewriteManip.h"
|
#include "rewrite/rewriteManip.h"
|
||||||
#include "distributed/citus_ruleutils.h" /* Ensure this header declares contain_nextval_expression_walker */
|
|
||||||
|
|
||||||
#include "pg_version_compat.h"
|
#include "pg_version_compat.h"
|
||||||
#include "pg_version_constants.h"
|
#include "pg_version_constants.h"
|
||||||
|
@ -49,9 +48,6 @@ static bool RecursivelyInlineCteWalker(Node *node, void *context);
|
||||||
static void InlineCTEsInQueryTree(Query *query);
|
static void InlineCTEsInQueryTree(Query *query);
|
||||||
static bool QueryTreeContainsInlinableCteWalker(Node *node, void *context);
|
static bool QueryTreeContainsInlinableCteWalker(Node *node, void *context);
|
||||||
|
|
||||||
static bool
|
|
||||||
QueryContainsNextval2(Query *q);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RecursivelyInlineCtesInQueryTree gets a query and recursively traverses the
|
* RecursivelyInlineCtesInQueryTree gets a query and recursively traverses the
|
||||||
|
@ -97,77 +93,44 @@ RecursivelyInlineCteWalker(Node *node, void *context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* InlineCTEsInQueryTree gets a query tree and tries to inline CTEs as subqueries
|
||||||
|
* in the query tree.
|
||||||
|
*
|
||||||
|
* Most of the code is coming from PostgreSQL's CTE inlining logic, there are very
|
||||||
|
* few additions that Citus added, which are already commented in the code.
|
||||||
|
*/
|
||||||
void
|
void
|
||||||
InlineCTEsInQueryTree(Query *query)
|
InlineCTEsInQueryTree(Query *query)
|
||||||
{
|
{
|
||||||
ListCell *cteCell = NULL;
|
ListCell *cteCell = NULL;
|
||||||
List *copyOfCteList = list_copy(query->cteList);
|
|
||||||
|
|
||||||
foreach(cteCell, copyOfCteList)
|
/* iterate on the copy of the list because we'll be modifying query->cteList */
|
||||||
{
|
List *copyOfCteList = list_copy(query->cteList);
|
||||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(cteCell);
|
foreach(cteCell, copyOfCteList)
|
||||||
|
{
|
||||||
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(cteCell);
|
||||||
|
|
||||||
/* Extra check: if the CTE query contains nextval, do not inline it */
|
/*
|
||||||
if (QueryContainsNextval2((Query *) cte->ctequery))
|
* First, make sure that Postgres is OK to inline the CTE. Later, check for
|
||||||
{
|
* distributed query planning constraints that might prevent inlining.
|
||||||
elog(DEBUG1, "CTE \"%s\" contains nextval; materializing it instead of inlining", cte->ctename);
|
*/
|
||||||
continue;
|
if (PostgreSQLCTEInlineCondition(cte, query->commandType))
|
||||||
}
|
{
|
||||||
|
elog(DEBUG1, "CTE %s is going to be inlined via "
|
||||||
|
"distributed planning", cte->ctename);
|
||||||
|
|
||||||
/* Standard PostgreSQL inline condition */
|
/* do the hard work of cte inlining */
|
||||||
if (PostgreSQLCTEInlineCondition(cte, query->commandType))
|
inline_cte(query, cte);
|
||||||
{
|
|
||||||
elog(DEBUG1, "CTE \"%s\" is going to be inlined via distributed planning", cte->ctename);
|
|
||||||
inline_cte(query, cte);
|
|
||||||
|
|
||||||
/* Reset reference count and remove from cteList */
|
/* clean-up the necessary fields for distributed planning */
|
||||||
cte->cterefcount = 0;
|
cte->cterefcount = 0;
|
||||||
query->cteList = list_delete_ptr(query->cteList, cte);
|
query->cteList = list_delete_ptr(query->cteList, cte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
QueryContainsNextval2(Query *q)
|
|
||||||
{
|
|
||||||
ListCell *lc = NULL;
|
|
||||||
|
|
||||||
/* Check the target list */
|
|
||||||
foreach(lc, q->targetList)
|
|
||||||
{
|
|
||||||
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
|
||||||
if (contain_nextval_expression_walker((Node *) tle->expr, NULL))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check the WHERE clause (jointree quals) */
|
|
||||||
if (q->jointree && q->jointree->quals &&
|
|
||||||
contain_nextval_expression_walker((Node *) q->jointree->quals, NULL))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* Recursively check subqueries in the range table */
|
|
||||||
foreach(lc, q->rtable)
|
|
||||||
{
|
|
||||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
|
|
||||||
if (rte->rtekind == RTE_SUBQUERY && rte->subquery != NULL)
|
|
||||||
{
|
|
||||||
if (QueryContainsNextval2(rte->subquery))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Optionally, check havingQual if needed */
|
|
||||||
if (q->havingQual &&
|
|
||||||
contain_nextval_expression_walker((Node *) q->havingQual, NULL))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* QueryTreeContainsInlinableCTE recursively traverses the queryTree, and returns true
|
* QueryTreeContainsInlinableCTE recursively traverses the queryTree, and returns true
|
||||||
* if any of the (sub)queries in the queryTree contains at least one CTE.
|
* if any of the (sub)queries in the queryTree contains at least one CTE.
|
||||||
|
|
|
@ -3888,8 +3888,6 @@ QueryContainsNextval(Query *query)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 5) Possibly check setOperations, windowClause offsets, etc. in a more robust approach. */
|
|
||||||
|
|
||||||
/* If none found, return false */
|
/* If none found, return false */
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -251,7 +251,6 @@ extern PlannedStmt * FinalizePlan(PlannedStmt *localPlan,
|
||||||
struct DistributedPlan *distributedPlan);
|
struct DistributedPlan *distributedPlan);
|
||||||
extern bool ContainsSingleShardTable(Query *query);
|
extern bool ContainsSingleShardTable(Query *query);
|
||||||
extern RTEListProperties * GetRTEListPropertiesForQuery(Query *query);
|
extern RTEListProperties * GetRTEListPropertiesForQuery(Query *query);
|
||||||
extern List *ExtractRangeTableEntryList(Query *query);
|
|
||||||
extern bool ListContainsDistributedTableRTE(List *rangeTableList, bool *maybeHasForeignDistributedTable);
|
extern bool ListContainsDistributedTableRTE(List *rangeTableList, bool *maybeHasForeignDistributedTable);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue