mirror of
https://github.com/postgres/postgres.git
synced 2025-07-26 01:22:12 +03:00
Extend CTE patch to support recursive UNION (ie, without ALL). The
implementation uses an in-memory hash table, so it will poop out for very large recursive results ... but the performance characteristics of a sort-based implementation would be pretty unpleasant too.
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.249 2008/10/04 21:56:53 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.250 2008/10/07 19:27:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -2545,10 +2545,13 @@ RecursiveUnion *
|
||||
make_recursive_union(List *tlist,
|
||||
Plan *lefttree,
|
||||
Plan *righttree,
|
||||
int wtParam)
|
||||
int wtParam,
|
||||
List *distinctList,
|
||||
long numGroups)
|
||||
{
|
||||
RecursiveUnion *node = makeNode(RecursiveUnion);
|
||||
Plan *plan = &node->plan;
|
||||
int numCols = list_length(distinctList);
|
||||
|
||||
cost_recursive_union(plan, lefttree, righttree);
|
||||
|
||||
@ -2558,6 +2561,37 @@ make_recursive_union(List *tlist,
|
||||
plan->righttree = righttree;
|
||||
node->wtParam = wtParam;
|
||||
|
||||
/*
|
||||
* convert SortGroupClause list into arrays of attr indexes and equality
|
||||
* operators, as wanted by executor
|
||||
*/
|
||||
node->numCols = numCols;
|
||||
if (numCols > 0)
|
||||
{
|
||||
int keyno = 0;
|
||||
AttrNumber *dupColIdx;
|
||||
Oid *dupOperators;
|
||||
ListCell *slitem;
|
||||
|
||||
dupColIdx = (AttrNumber *) palloc(sizeof(AttrNumber) * numCols);
|
||||
dupOperators = (Oid *) palloc(sizeof(Oid) * numCols);
|
||||
|
||||
foreach(slitem, distinctList)
|
||||
{
|
||||
SortGroupClause *sortcl = (SortGroupClause *) lfirst(slitem);
|
||||
TargetEntry *tle = get_sortgroupclause_tle(sortcl,
|
||||
plan->targetlist);
|
||||
|
||||
dupColIdx[keyno] = tle->resno;
|
||||
dupOperators[keyno] = sortcl->eqop;
|
||||
Assert(OidIsValid(dupOperators[keyno]));
|
||||
keyno++;
|
||||
}
|
||||
node->dupColIdx = dupColIdx;
|
||||
node->dupOperators = dupOperators;
|
||||
}
|
||||
node->numGroups = numGroups;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.157 2008/10/06 17:39:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.158 2008/10/07 19:27:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -318,10 +318,12 @@ generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
|
||||
Plan *lplan;
|
||||
Plan *rplan;
|
||||
List *tlist;
|
||||
List *groupList;
|
||||
long numGroups;
|
||||
|
||||
/* Parser should have rejected other cases */
|
||||
if (setOp->op != SETOP_UNION || !setOp->all)
|
||||
elog(ERROR, "only UNION ALL queries can be recursive");
|
||||
if (setOp->op != SETOP_UNION)
|
||||
elog(ERROR, "only UNION queries can be recursive");
|
||||
/* Worktable ID should be assigned */
|
||||
Assert(root->wt_param_id >= 0);
|
||||
|
||||
@ -346,13 +348,46 @@ generate_recursion_plan(SetOperationStmt *setOp, PlannerInfo *root,
|
||||
list_make2(lplan, rplan),
|
||||
refnames_tlist);
|
||||
|
||||
/*
|
||||
* If UNION, identify the grouping operators
|
||||
*/
|
||||
if (setOp->all)
|
||||
{
|
||||
groupList = NIL;
|
||||
numGroups = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double dNumGroups;
|
||||
|
||||
/* Identify the grouping semantics */
|
||||
groupList = generate_setop_grouplist(setOp, tlist);
|
||||
|
||||
/* We only support hashing here */
|
||||
if (!grouping_is_hashable(groupList))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not implement recursive UNION"),
|
||||
errdetail("All column datatypes must be hashable.")));
|
||||
|
||||
/*
|
||||
* For the moment, take the number of distinct groups as equal to
|
||||
* the total input size, ie, the worst case.
|
||||
*/
|
||||
dNumGroups = lplan->plan_rows + rplan->plan_rows * 10;
|
||||
|
||||
/* Also convert to long int --- but 'ware overflow! */
|
||||
numGroups = (long) Min(dNumGroups, (double) LONG_MAX);
|
||||
}
|
||||
|
||||
/*
|
||||
* And make the plan node.
|
||||
*/
|
||||
plan = (Plan *) make_recursive_union(tlist, lplan, rplan,
|
||||
root->wt_param_id);
|
||||
root->wt_param_id,
|
||||
groupList, numGroups);
|
||||
|
||||
*sortClauses = NIL; /* result of UNION ALL is always unsorted */
|
||||
*sortClauses = NIL; /* RecursiveUnion result is always unsorted */
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
Reference in New Issue
Block a user