OSDN Git Service

Fix problems seen when result of a subselect was used in an
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Apr 1999 04:17:11 +0000 (04:17 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 19 Apr 1999 04:17:11 +0000 (04:17 +0000)
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;

src/backend/executor/nodeSubplan.c
src/backend/parser/parse_expr.c

index 9f872c6..2eebbf1 100644 (file)
@@ -29,10 +29,11 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
 {
        Plan       *plan = node->plan;
        SubLink    *sublink = node->sublink;
+       SubLinkType subLinkType = sublink->subLinkType;
        TupleTableSlot *slot;
        List       *lst;
-       bool            result = false;
-       bool            found = false;
+       Datum           result = (Datum) false;
+       bool            found = false;  /* TRUE if got at least one subplan tuple */
 
        if (node->setParam != NULL)
                elog(ERROR, "ExecSubPlan: can't set parent params from subquery");
@@ -56,6 +57,18 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
 
        ExecReScan(plan, (ExprContext *) NULL, plan);
 
+       /*
+        * For all sublink types except EXPR_SUBLINK, the result type is boolean,
+        * and we have a fairly clear idea of how to combine multiple subitems
+        * and deal with NULL values or an empty subplan result.
+        *
+        * For EXPR_SUBLINK, the result type is whatever the combining operator
+        * returns.  We have no way to deal with more than one column in the
+        * subplan result --- hopefully the parser forbids that.  More seriously,
+        * it's unclear what to do with NULL values or an empty subplan result.
+        * For now, we error out, but should something else happen?
+        */
+
        for (slot = ExecProcNode(plan, plan);
                 !TupIsNull(slot);
                 slot = ExecProcNode(plan, plan))
@@ -64,13 +77,13 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
                TupleDesc       tdesc = slot->ttc_tupleDescriptor;
                int                     i = 1;
 
-               if (sublink->subLinkType == EXPR_SUBLINK && found)
+               if (subLinkType == EXPR_SUBLINK && found)
                {
                        elog(ERROR, "ExecSubPlan: more than one tuple returned by expression subselect");
                        return (Datum) false;
                }
 
-               if (sublink->subLinkType == EXISTS_SUBLINK)
+               if (subLinkType == EXISTS_SUBLINK)
                        return (Datum) true;
 
                found = true;
@@ -82,23 +95,39 @@ ExecSubPlan(SubPlan *node, List *pvar, ExprContext *econtext)
                        bool            isnull;
 
                        con->constvalue = heap_getattr(tup, i, tdesc, &(con->constisnull));
-                       result = (bool) ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
+                       result = ExecEvalExpr((Node *) expr, econtext, &isnull, (bool *) NULL);
                        if (isnull)
-                               result = false;
-                       if ((!result && !(sublink->useor)) || (result && sublink->useor))
-                               break;
+                       {
+                               if (subLinkType == EXPR_SUBLINK)
+                                       elog(ERROR, "ExecSubPlan: null value returned by expression subselect");
+                               else
+                                       result = (Datum) false;
+                       }
+                       if (subLinkType != EXPR_SUBLINK)
+                       {
+                               if ((! (bool) result && !(sublink->useor)) ||
+                                       ((bool) result && sublink->useor))
+                                       break;
+                       }
                        i++;
                }
 
-               if ((!result && sublink->subLinkType == ALL_SUBLINK) ||
-                       (result && sublink->subLinkType == ANY_SUBLINK))
+               if (subLinkType == ALL_SUBLINK && ! (bool) result)
+                       break;
+               if (subLinkType == ANY_SUBLINK && (bool) result)
                        break;
        }
 
-       if (!found && sublink->subLinkType == ALL_SUBLINK)
-               return (Datum) true;
+       if (!found)
+       {
+               /* deal with empty subplan result.  Note default result is 'false' */
+               if (subLinkType == ALL_SUBLINK)
+                       result = (Datum) true;
+               else if (subLinkType == EXPR_SUBLINK)
+                       elog(ERROR, "ExecSubPlan: no tuples returned by expression subselect");
+       }
 
-       return (Datum) result;
+       return result;
 }
 
 /* ----------------------------------------------------------------
index d23d721..f18fbd4 100644 (file)
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.41 1999/04/18 17:35:51 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.42 1999/04/19 04:17:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -312,14 +312,6 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
 
                                                op_expr = make_op(op, lexpr, tent->expr);
 
-                                               /*
-                                                * HACK! Second IF is more valid but currently we
-                                                * don't support EXPR subqueries inside
-                                                * expressions generally, only in WHERE clauses.
-                                                * After fixing this, first IF must be removed.
-                                                */
-                                               if (op_expr->typeOid != BOOLOID)
-                                                       elog(ERROR, "parser: '%s' must return 'bool' to be used with subquery", op);
                                                if (op_expr->typeOid != BOOLOID &&
                                                        sublink->subLinkType != EXPR_SUBLINK)
                                                        elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
@@ -598,7 +590,20 @@ exprType(Node *expr)
                        type = ((Param *) expr)->paramtype;
                        break;
                case T_SubLink:
-                       type = BOOLOID;
+                       {
+                               SubLink *sublink = (SubLink *) expr;
+                               if (sublink->subLinkType == EXPR_SUBLINK)
+                               {
+                                       /* return the result type of the combining operator */
+                                       Expr *op_expr = (Expr *) lfirst(sublink->oper);
+                                       type = op_expr->typeOid;
+                               }
+                               else
+                               {
+                                       /* for all other sublink types, result is boolean */
+                                       type = BOOLOID;
+                               }
+                       }
                        break;
                case T_CaseExpr:
                        type = ((CaseExpr *) expr)->casetype;