Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a58843b

Browse files
committed
Fix problems seen when result of a subselect was used in an
expression context (ie, not at the top level of a WHERE clause). Examples like this one work now: SELECT name, value FROM t1 as touter WHERE (value/(SELECT AVG(value) FROM t1 WHERE name = touter.name)) > 0.75;
1 parent 4438b70 commit a58843b

File tree

2 files changed

+57
-23
lines changed

2 files changed

+57
-23
lines changed

src/backend/executor/nodeSubplan.c

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
2929
{
3030
Plan *plan = node->plan;
3131
SubLink *sublink = node->sublink;
32+
SubLinkType subLinkType = sublink->subLinkType;
3233
TupleTableSlot *slot;
3334
List *lst;
34-
bool result = false;
35-
bool found = false;
35+
Datum result = (Datum) false;
36+
bool found = false; /* TRUE if got at least one subplan tuple */
3637

3738
if (node->setParam != NULL)
3839
elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
@@ -56,6 +57,18 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
5657

5758
ExecReScan(plan, (ExprContext *) NULL, plan);
5859

60+
/*
61+
* For all sublink types except EXPR_SUBLINK, the result type is boolean,
62+
* and we have a fairly clear idea of how to combine multiple subitems
63+
* and deal with NULL values or an empty subplan result.
64+
*
65+
* For EXPR_SUBLINK, the result type is whatever the combining operator
66+
* returns. We have no way to deal with more than one column in the
67+
* subplan result --- hopefully the parser forbids that. More seriously,
68+
* it's unclear what to do with NULL values or an empty subplan result.
69+
* For now, we error out, but should something else happen?
70+
*/
71+
5972
for (slot = ExecProcNode(plan, plan);
6073
!TupIsNull(slot);
6174
slot = ExecProcNode(plan, plan))
@@ -64,13 +77,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
6477
TupleDesc tdesc = slot->ttc_tupleDescriptor;
6578
int i = 1;
6679

67-
if (sublink->subLinkType == EXPR_SUBLINK && found)
80+
if (subLinkType == EXPR_SUBLINK && found)
6881
{
6982
elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
7083
return (Datum) false;
7184
}
7285

73-
if (sublink->subLinkType == EXISTS_SUBLINK)
86+
if (subLinkType == EXISTS_SUBLINK)
7487
return (Datum) true;
7588

7689
found = true;
@@ -82,23 +95,39 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
8295
bool isnull;
8396

8497
con->constvalue = heap_getattr(tup, i, tdesc, &(con->constisnull));
85-
result = (bool) ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
98+
result = ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
8699
if (isnull)
87-
result = false;
88-
if ((!result && !(sublink->useor)) || (result && sublink->useor))
89-
break;
100+
{
101+
if (subLinkType == EXPR_SUBLINK)
102+
elog(ERROR, "ExecSubPlan: null value returned by expression subselect");
103+
else
104+
result = (Datum) false;
105+
}
106+
if (subLinkType != EXPR_SUBLINK)
107+
{
108+
if ((! (bool) result && !(sublink->useor)) ||
109+
((bool) result && sublink->useor))
110+
break;
111+
}
90112
i++;
91113
}
92114

93-
if ((!result && sublink->subLinkType == ALL_SUBLINK) ||
94-
(result && sublink->subLinkType == ANY_SUBLINK))
115+
if (subLinkType == ALL_SUBLINK && ! (bool) result)
116+
break;
117+
if (subLinkType == ANY_SUBLINK && (bool) result)
95118
break;
96119
}
97120

98-
if (!found && sublink->subLinkType == ALL_SUBLINK)
99-
return (Datum) true;
121+
if (!found)
122+
{
123+
/* deal with empty subplan result. Note default result is 'false' */
124+
if (subLinkType == ALL_SUBLINK)
125+
result = (Datum) true;
126+
else if (subLinkType == EXPR_SUBLINK)
127+
elog(ERROR, "ExecSubPlan: no tuples returned by expression subselect");
128+
}
100129

101-
return (Datum) result;
130+
return result;
102131
}
103132

104133
/* ----------------------------------------------------------------

src/backend/parser/parse_expr.c

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.41 1999/04/18 17:35:51 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.42 1999/04/19 04:17:11 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -312,14 +312,6 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
312312

313313
op_expr = make_op(op, lexpr, tent->expr);
314314

315-
/*
316-
* HACK! Second IF is more valid but currently we
317-
* don't support EXPR subqueries inside
318-
* expressions generally, only in WHERE clauses.
319-
* After fixing this, first IF must be removed.
320-
*/
321-
if (op_expr->typeOid != BOOLOID)
322-
elog(ERROR, "parser: '%s' must return 'bool' to be used with subquery", op);
323315
if (op_expr->typeOid != BOOLOID &&
324316
sublink->subLinkType != EXPR_SUBLINK)
325317
elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
@@ -598,7 +590,20 @@ exprType(Node *expr)
598590
type = ((Param *) expr)->paramtype;
599591
break;
600592
case T_SubLink:
601-
type = BOOLOID;
593+
{
594+
SubLink *sublink = (SubLink *) expr;
595+
if (sublink->subLinkType == EXPR_SUBLINK)
596+
{
597+
/* return the result type of the combining operator */
598+
Expr *op_expr = (Expr *) lfirst(sublink->oper);
599+
type = op_expr->typeOid;
600+
}
601+
else
602+
{
603+
/* for all other sublink types, result is boolean */
604+
type = BOOLOID;
605+
}
606+
}
602607
break;
603608
case T_CaseExpr:
604609
type = ((CaseExpr *) expr)->casetype;

0 commit comments

Comments
 (0)