1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +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/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);
/* get the type of the subselect's first target column */
Query *qtree = (Query *) sublink->subselect;
TargetEntry *tent;
Assert(IsA(op, Oper));
type = op->opresulttype;
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
{