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/parser/parse_expr.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/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 47 |
1 files changed, 35 insertions, 12 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index ee9d3077283..76e5f91f1a8 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.58 1999/09/13 04:14:56 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.59 1999/11/15 02:00:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -220,8 +220,30 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) sublink->lefthand = NIL; sublink->oper = NIL; } + else if (sublink->subLinkType == EXPR_SUBLINK) + { + List *tlist = qtree->targetList; + + /* Make sure the subselect delivers a single column + * (ignoring resjunk targets). + */ + if (tlist == NIL || + ((TargetEntry *) lfirst(tlist))->resdom->resjunk) + elog(ERROR, "parser: subselect must have a field"); + while ((tlist = lnext(tlist)) != NIL) + { + if (! ((TargetEntry *) lfirst(tlist))->resdom->resjunk) + elog(ERROR, "parser: subselect must have only one field"); + } + /* EXPR needs no lefthand or combining operator. + * These fields should be NIL already, but make sure. + */ + sublink->lefthand = NIL; + sublink->oper = NIL; + } else { + /* ALL, ANY, or MULTIEXPR: generate operator list */ char *op = lfirst(sublink->oper); List *left_list = sublink->lefthand; List *right_list = qtree->targetList; @@ -231,9 +253,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) lfirst(elist) = transformExpr(pstate, lfirst(elist), precedence); - if (length(left_list) > 1 && + /* Combining operators other than =/<> is dubious... */ + if (length(left_list) != 1 && strcmp(op, "=") != 0 && strcmp(op, "<>") != 0) - elog(ERROR, "parser: '%s' is not relational operator", + elog(ERROR, "parser: '%s' is not usable for row comparison", op); sublink->oper = NIL; @@ -266,8 +289,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) FALSE); opform = (Form_pg_operator) GETSTRUCT(optup); - if (opform->oprresult != BOOLOID && - sublink->subLinkType != EXPR_SUBLINK) + if (opform->oprresult != BOOLOID) elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op); newop = makeOper(oprid(optup),/* opno */ @@ -589,13 +611,14 @@ exprType(Node *expr) if (sublink->subLinkType == EXPR_SUBLINK) { - /* return the result type of the combining operator; - * should only be one... - */ - Oper *op = (Oper *) lfirst(sublink->oper); - - Assert(IsA(op, Oper)); - type = op->opresulttype; + /* get the type of the subselect's first target column */ + Query *qtree = (Query *) sublink->subselect; + TargetEntry *tent; + + if (! qtree || ! IsA(qtree, Query)) + elog(ERROR, "exprType: can't get type for untransformed sublink"); + tent = (TargetEntry *) lfirst(qtree->targetList); + type = tent->resdom->restype; } else { |