mirror of https://github.com/citusdata/citus.git
Add CteNameExists function and improve CTE unification logic in PrepareInsertSelectForCitusPlanner
parent
b1a38e0bca
commit
7dd4c18935
|
@ -128,6 +128,9 @@ DecrementInsertLevelReferences(Query *subquery,
|
||||||
int offset, /* typically -1 */
|
int offset, /* typically -1 */
|
||||||
List *topLevelCteList);
|
List *topLevelCteList);
|
||||||
|
|
||||||
|
static bool
|
||||||
|
CteNameExists(List *cteList, const char *ctename);
|
||||||
|
|
||||||
|
|
||||||
/* depth of current insert/select planner. */
|
/* depth of current insert/select planner. */
|
||||||
static int insertSelectPlannerLevel = 0;
|
static int insertSelectPlannerLevel = 0;
|
||||||
|
@ -554,27 +557,47 @@ PrepareInsertSelectForCitusPlanner(Query *insertSelectQuery)
|
||||||
|
|
||||||
if (list_length(insertSelectQuery->cteList) > 0)
|
if (list_length(insertSelectQuery->cteList) > 0)
|
||||||
{
|
{
|
||||||
/* we physically unify ctes from top-level into subquery,
|
List *topCopy = copyObject(insertSelectQuery->cteList);
|
||||||
* then want references in the subquery from ctelevelsup=1 => 0
|
ListCell *lc;
|
||||||
*/
|
|
||||||
elog(DEBUG1, "Unifying top-level cteList with subquery cteList");
|
elog(DEBUG1, "Unifying top‑level CTEs into subquery");
|
||||||
|
|
||||||
|
/* append only the *new* ones */
|
||||||
|
foreach(lc, topCopy)
|
||||||
|
{
|
||||||
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||||
|
if (!CteNameExists(selectRte->subquery->cteList, cte->ctename))
|
||||||
|
selectRte->subquery->cteList =
|
||||||
|
lappend(selectRte->subquery->cteList, cte);
|
||||||
|
}
|
||||||
|
|
||||||
List *topLevelCteListCopy = copyObject(insertSelectQuery->cteList);
|
|
||||||
|
|
||||||
selectRte->subquery->cteList =
|
|
||||||
list_concat(selectRte->subquery->cteList,
|
|
||||||
copyObject(insertSelectQuery->cteList));
|
|
||||||
insertSelectQuery->cteList = NIL;
|
insertSelectQuery->cteList = NIL;
|
||||||
|
|
||||||
/* Suppose we physically appended the top-level cteList into the subquery,
|
/* Suppose we physically appended the top-level cteList into the subquery,
|
||||||
so references are at ctelevelsup=1, 2, etc. We want them all to shift by -1. */
|
so references are at ctelevelsup=1, 2, etc. We want them all to shift by -1. */
|
||||||
|
|
||||||
DecrementInsertLevelReferences(selectRte->subquery, -1, topLevelCteListCopy /* for ctename check */);
|
DecrementInsertLevelReferences(selectRte->subquery, -1, topCopy /* for ctename check */);
|
||||||
|
|
||||||
elog(DEBUG1, "Done shifting ctelevelsup X->X-1 for subquery references");
|
elog(DEBUG1, "Done shifting ctelevelsup X->X-1 for subquery references");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
CteNameExists(List *cteList, const char *ctename)
|
||||||
|
{
|
||||||
|
ListCell *lc;
|
||||||
|
foreach(lc, cteList)
|
||||||
|
{
|
||||||
|
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
||||||
|
if (strcmp(cte->ctename, ctename) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* inline_cte_walker
|
* inline_cte_walker
|
||||||
*
|
*
|
||||||
|
@ -630,32 +653,13 @@ inline_cte_walker(Node *node, ShiftReferencesWalkerContext *context)
|
||||||
*/
|
*/
|
||||||
if (rte->ctelevelsup == (context->levelsup + 1))
|
if (rte->ctelevelsup == (context->levelsup + 1))
|
||||||
{
|
{
|
||||||
/* optionally verify ctename is in topLevelCteList */
|
if (context->topLevelCteList == NULL ||
|
||||||
bool foundName = false;
|
CteNameExists(context->topLevelCteList, rte->ctename))
|
||||||
if (context->topLevelCteList != NULL)
|
|
||||||
{
|
{
|
||||||
ListCell *lc = NULL;
|
int old = rte->ctelevelsup;
|
||||||
foreach(lc, context->topLevelCteList)
|
rte->ctelevelsup += context->offset; /* usually ‑1 */
|
||||||
{
|
elog(DEBUG2, "Shifted ctelevelsup for %s from %d to %d",
|
||||||
CommonTableExpr *cte = (CommonTableExpr *) lfirst(lc);
|
rte->ctename, old, rte->ctelevelsup);
|
||||||
if (strcmp(cte->ctename, rte->ctename) == 0)
|
|
||||||
{
|
|
||||||
foundName = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foundName = true; /* if we don't need a name check */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foundName)
|
|
||||||
{
|
|
||||||
int oldSup = rte->ctelevelsup;
|
|
||||||
rte->ctelevelsup += context->offset; /* e.g. -1 => (k+1) → k */
|
|
||||||
elog(DEBUG2, "Shifting ctelevelsup for ctename=%s from %d to %d",
|
|
||||||
rte->ctename, oldSup, rte->ctelevelsup);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -665,6 +669,10 @@ inline_cte_walker(Node *node, ShiftReferencesWalkerContext *context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* look into sub‑queries held inside an RTE */
|
||||||
|
if (rte->rtekind == RTE_SUBQUERY && rte->subquery)
|
||||||
|
inline_cte_walker((Node *) rte->subquery, context);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue