1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-07 19:06:32 +03:00

Implement subselects in target lists. Also, relax requirement that

subselects can only appear on the righthand side of a binary operator.
That's still true for quantified predicates like x = ANY (SELECT ...),
but a subselect that delivers a single result can now appear anywhere
in an expression.  This is implemented by changing EXPR_SUBLINK sublinks
to represent just the (SELECT ...) expression, without any 'left hand
side' or combining operator --- so they're now more like EXISTS_SUBLINK.
To handle the case of '(x, y, z) = (SELECT ...)', I added a new sublink
type MULTIEXPR_SUBLINK, which acts just like EXPR_SUBLINK used to.
But the grammar will only generate one for a multiple-left-hand-side
row expression.
This commit is contained in:
Tom Lane
1999-11-15 02:00:15 +00:00
parent 1ecb129d20
commit f68e11f373
12 changed files with 364 additions and 566 deletions

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.46 1999/10/07 04:23:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.47 1999/11/15 02:00:07 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -87,9 +87,25 @@ query_planner(Query *root,
tlist = (List *) SS_replace_correlation_vars((Node *) tlist);
qual = (List *) SS_replace_correlation_vars((Node *) qual);
}
/* Expand SubLinks to SubPlans */
if (root->hasSubLinks)
{
tlist = (List *) SS_process_sublinks((Node *) tlist);
qual = (List *) SS_process_sublinks((Node *) qual);
if (root->groupClause != NIL)
{
/*
* Check for ungrouped variables passed to subplans.
* Note we do NOT do this for subplans in WHERE; it's legal
* there because WHERE is evaluated pre-GROUP.
*/
if (check_subplans_for_ungrouped_vars((Node *) tlist,
root->groupClause,
tlist))
elog(ERROR, "Sub-SELECT must use only GROUPed attributes from outer SELECT");
}
}
/*
* If the query contains no relation references at all, it must be

View File

@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.70 1999/10/07 04:23:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.71 1999/11/15 02:00:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -343,17 +343,11 @@ union_planner(Query *parse)
{
/* Expand SubLinks to SubPlans */
parse->havingQual = SS_process_sublinks(parse->havingQual);
/*
* Check for ungrouped variables passed to subplans. (Probably
* this should be done for the targetlist as well??? But we
* should NOT do it for the WHERE qual, since WHERE is
* evaluated pre-GROUP.)
*/
/* Check for ungrouped variables passed to subplans */
if (check_subplans_for_ungrouped_vars(parse->havingQual,
parse->groupClause,
parse->targetList))
elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
elog(ERROR, "Sub-SELECT must use only GROUPed attributes from outer SELECT");
}
}

View File

@@ -6,7 +6,7 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.24 1999/08/25 23:21:39 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.25 1999/11/15 02:00:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -173,10 +173,43 @@ make_subplan(SubLink *slink)
}
/*
* Un-correlated or undirect correlated plans of EXISTS or EXPR types
* can be used as initPlans...
* Un-correlated or undirect correlated plans of EXISTS, EXPR, or
* MULTIEXPR types can be used as initPlans. For EXISTS or EXPR,
* we just produce a Param referring to the result of evaluating the
* initPlan. For MULTIEXPR, we must build an AND or OR-clause of the
* individual comparison operators, using the appropriate lefthand
* side expressions and Params for the initPlan's target items.
*/
if (node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK)
if (node->parParam == NIL && slink->subLinkType == EXISTS_SUBLINK)
{
Var *var = makeVar(0, 0, BOOLOID, -1, 0);
Param *prm = makeNode(Param);
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
node->setParam = lappendi(node->setParam, prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
}
else if (node->parParam == NIL && slink->subLinkType == EXPR_SUBLINK)
{
TargetEntry *te = lfirst(plan->targetlist);
/* need a var node just to pass to new_param()... */
Var *var = makeVar(0, 0, te->resdom->restype,
te->resdom->restypmod, 0);
Param *prm = makeNode(Param);
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
node->setParam = lappendi(node->setParam, prm->paramid);
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
}
else if (node->parParam == NIL && slink->subLinkType == MULTIEXPR_SUBLINK)
{
List *newoper = NIL;
int i = 0;
@@ -202,6 +235,7 @@ make_subplan(SubLink *slink)
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
pfree(var); /* var is only needed for new_param */
Assert(IsA(oper, Oper));
tup = get_operator_tuple(oper->opno);
@@ -219,7 +253,6 @@ make_subplan(SubLink *slink)
(Var *) left,
(Var *) right));
node->setParam = lappendi(node->setParam, prm->paramid);
pfree(var);
i++;
}
slink->oper = newoper;
@@ -231,19 +264,6 @@ make_subplan(SubLink *slink)
else
result = (Node *) lfirst(newoper);
}
else if (node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK)
{
Var *var = makeVar(0, 0, BOOLOID, -1, 0);
Param *prm = makeNode(Param);
prm->paramkind = PARAM_EXEC;
prm->paramid = (AttrNumber) new_param(var, PlannerQueryLevel);
prm->paramtype = var->vartype;
node->setParam = lappendi(node->setParam, prm->paramid);
pfree(var);
PlannerInitPlan = lappend(PlannerInitPlan, node);
result = (Node *) prm;
}
else
{
/* make expression of SUBPLAN type */
@@ -333,7 +353,8 @@ set_unioni(List *l1, List *l2)
/*
* finalize_primnode: build lists of subplans and params appearing
* in the given expression tree.
* in the given expression tree. NOTE: items are added to lists passed in,
* so caller must initialize lists to NIL before first call!
*/
typedef struct finalize_primnode_results {
@@ -341,20 +362,8 @@ typedef struct finalize_primnode_results {
List *paramids; /* List of PARAM_EXEC paramids found */
} finalize_primnode_results;
static bool finalize_primnode_walker(Node *node,
finalize_primnode_results *results);
static void
finalize_primnode(Node *expr, finalize_primnode_results *results)
{
results->subplans = NIL; /* initialize */
results->paramids = NIL;
(void) finalize_primnode_walker(expr, results);
}
static bool
finalize_primnode_walker(Node *node,
finalize_primnode_results *results)
finalize_primnode(Node *node, finalize_primnode_results *results)
{
if (node == NULL)
return false;
@@ -389,7 +398,7 @@ finalize_primnode_walker(Node *node,
}
/* fall through to recurse into subplan args */
}
return expression_tree_walker(node, finalize_primnode_walker,
return expression_tree_walker(node, finalize_primnode,
(void *) results);
}
@@ -443,7 +452,7 @@ process_sublinks_mutator(Node *node, void *context)
{
SubLink *sublink = (SubLink *) node;
/* First, scan the lefthand-side expressions.
/* First, scan the lefthand-side expressions, if any.
* This is a tad klugy since we modify the input SubLink node,
* but that should be OK (make_subplan does it too!)
*/
@@ -475,23 +484,28 @@ SS_finalize_plan(Plan *plan)
List *lst;
if (plan == NULL)
return NULL;
return NIL;
/* Find params in targetlist, make sure there are no subplans there */
finalize_primnode((Node *) plan->targetlist, &results);
Assert(results.subplans == NIL);
/* From here on, we invoke finalize_primnode_walker not finalize_primnode,
* so that results.paramids lists are automatically merged together and
* we don't have to do it the hard way. But when recursing to self,
* we do have to merge the lists. Oh well.
results.subplans = NIL; /* initialize lists to NIL */
results.paramids = NIL;
/*
* When we call finalize_primnode, results.paramids lists are
* automatically merged together. But when recursing to self,
* we have to do it the hard way. We want the paramids list
* to include params in subplans as well as at this level.
* (We don't care about finding subplans of subplans, though.)
*/
/* Find params and subplans in targetlist and qual */
finalize_primnode((Node *) plan->targetlist, &results);
finalize_primnode((Node *) plan->qual, &results);
/* Check additional node-type-specific fields */
switch (nodeTag(plan))
{
case T_Result:
finalize_primnode_walker(((Result *) plan)->resconstantqual,
&results);
/* results.subplans is NOT necessarily empty here ... */
finalize_primnode(((Result *) plan)->resconstantqual,
&results);
break;
case T_Append:
@@ -501,33 +515,26 @@ SS_finalize_plan(Plan *plan)
break;
case T_IndexScan:
finalize_primnode_walker((Node *) ((IndexScan *) plan)->indxqual,
&results);
Assert(results.subplans == NIL);
finalize_primnode((Node *) ((IndexScan *) plan)->indxqual,
&results);
break;
case T_MergeJoin:
finalize_primnode_walker((Node *) ((MergeJoin *) plan)->mergeclauses,
&results);
Assert(results.subplans == NIL);
finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses,
&results);
break;
case T_HashJoin:
finalize_primnode_walker((Node *) ((HashJoin *) plan)->hashclauses,
&results);
Assert(results.subplans == NIL);
finalize_primnode((Node *) ((HashJoin *) plan)->hashclauses,
&results);
break;
case T_Hash:
finalize_primnode_walker((Node *) ((Hash *) plan)->hashkey,
&results);
Assert(results.subplans == NIL);
finalize_primnode((Node *) ((Hash *) plan)->hashkey,
&results);
break;
case T_Agg:
/* XXX Code used to reject subplans in Aggref args; needed?? */
break;
case T_SeqScan:
case T_NestLoop:
case T_Material:
@@ -539,12 +546,9 @@ SS_finalize_plan(Plan *plan)
default:
elog(ERROR, "SS_finalize_plan: node %d unsupported",
nodeTag(plan));
return NULL;
}
finalize_primnode_walker((Node *) plan->qual, &results);
/* subplans are OK in the qual... */
/* Process left and right subplans, if any */
results.paramids = set_unioni(results.paramids,
SS_finalize_plan(plan->lefttree));
results.paramids = set_unioni(results.paramids,