diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 1999-11-15 02:00:15 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 1999-11-15 02:00:15 +0000 |
commit | f68e11f373de8b7b1d19203b8edac1a13a8d406d (patch) | |
tree | c4e61de2b9bd9b8dd7c70545dc861de3547294d4 /src/backend/executor/nodeSubplan.c | |
parent | 1ecb129d206f30f5813b01e1f1efe75c06febe49 (diff) | |
download | postgresql-f68e11f373de8b7b1d19203b8edac1a13a8d406d.tar.gz postgresql-f68e11f373de8b7b1d19203b8edac1a13a8d406d.zip |
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.
Diffstat (limited to 'src/backend/executor/nodeSubplan.c')
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 70 |
1 files changed, 45 insertions, 25 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 452e3414b3c..dbb824fe64c 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -3,6 +3,11 @@ * nodeSubplan.c * routines to support subselects * + * Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/executor/nodeSubplan.c,v 1.16 1999/11/15 02:00:01 tgl Exp $ + * *------------------------------------------------------------------------- */ /* @@ -68,19 +73,17 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) * within a tuple (if there are multiple columns) using OR semantics * if "useor" is true, AND semantics if not. We then combine results * across tuples (if the subplan produces more than one) using OR - * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. NULL - * results from the combining operators are handled according to the - * usual SQL semantics for OR and AND. The result for no input - * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK. + * semantics for ANY_SUBLINK or AND semantics for ALL_SUBLINK. + * (MULTIEXPR_SUBLINK doesn't allow multiple tuples from the subplan.) + * NULL results from the combining operators are handled according to + * the usual SQL semantics for OR and AND. The result for no input + * tuples is FALSE for ANY_SUBLINK, TRUE for ALL_SUBLINK, NULL for + * MULTIEXPR_SUBLINK. * * For EXPR_SUBLINK we require the subplan to produce no more than one * tuple, else an error is raised. If zero tuples are produced, we - * return NULL. (XXX it would probably be more correct to evaluate - * the combining operator with a NULL input?) Assuming we get a tuple: - * if there is only one column then we just return its result as-is, NULL - * or otherwise. If there is more than one column we combine the results - * per "useor" --- this only makes sense if the combining operators yield - * boolean, and we assume the parser has checked that. + * return NULL. Assuming we get a tuple, we just return its first + * column (there can be only one non-junk column in this case). */ result = (Datum) (subLinkType == ALL_SUBLINK ? true : false); *isNull = false; @@ -98,13 +101,29 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) if (subLinkType == EXISTS_SUBLINK) return (Datum) true; - /* cannot allow multiple input tuples for EXPR sublink */ - if (subLinkType == EXPR_SUBLINK && found) + if (subLinkType == EXPR_SUBLINK) + { + /* cannot allow multiple input tuples for EXPR sublink */ + if (found) + elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect"); + found = true; + /* XXX need to copy tuple in case pass by ref */ + /* XXX need to ref-count the tuple to avoid mem leak! */ + tup = heap_copytuple(tup); + result = heap_getattr(tup, col, tdesc, isNull); + /* keep scanning subplan to make sure there's only one tuple */ + continue; + } + + /* cannot allow multiple input tuples for MULTIEXPR sublink either */ + if (subLinkType == MULTIEXPR_SUBLINK && found) elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect"); found = true; - /* iterate over combining operators for columns of tuple */ + /* For ALL, ANY, and MULTIEXPR sublinks, iterate over combining + * operators for columns of tuple. + */ foreach(lst, sublink->oper) { Expr *expr = (Expr *) lfirst(lst); @@ -193,7 +212,7 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) } else { - /* must be EXPR_SUBLINK */ + /* must be MULTIEXPR_SUBLINK */ result = rowresult; *isNull = rownull; } @@ -202,9 +221,10 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext, bool *isNull) if (!found) { /* deal with empty subplan result. result/isNull were previously - * initialized correctly for all sublink types except EXPR. + * initialized correctly for all sublink types except EXPR and + * MULTIEXPR; for those, return NULL. */ - if (subLinkType == EXPR_SUBLINK) + if (subLinkType == EXPR_SUBLINK || subLinkType == MULTIEXPR_SUBLINK) { result = (Datum) false; *isNull = true; @@ -242,7 +262,7 @@ ExecInitSubPlan(SubPlan *node, EState *estate, Plan *parent) * If this plan is un-correlated or undirect correlated one and want * to set params for parent plan then prepare parameters. */ - if (node->setParam != NULL) + if (node->setParam != NIL) { List *lst; @@ -293,14 +313,6 @@ ExecSetParamPlan(SubPlan *node) TupleDesc tdesc = slot->ttc_tupleDescriptor; int i = 1; - if (sublink->subLinkType == EXPR_SUBLINK && found) - { - elog(ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect"); - return; - } - - found = true; - if (sublink->subLinkType == EXISTS_SUBLINK) { ParamExecData *prm = &(plan->state->es_param_exec_vals[lfirsti(node->setParam)]); @@ -308,9 +320,17 @@ ExecSetParamPlan(SubPlan *node) prm->execPlan = NULL; prm->value = (Datum) true; prm->isnull = false; + found = true; break; } + if (found && + (sublink->subLinkType == EXPR_SUBLINK || + sublink->subLinkType == MULTIEXPR_SUBLINK)) + elog(ERROR, "ExecSetParamPlan: more than one tuple returned by expression subselect"); + + found = true; + /* * If this is uncorrelated subquery then its plan will be closed * (see below) and this tuple will be free-ed - bad for not byval |