]> granicus.if.org Git - postgresql/blobdiff - src/backend/executor/execQual.c
Cause ARRAY[] construct to return a NULL array, rather than raising an
[postgresql] / src / backend / executor / execQual.c
index 8dac4b2e44049a74eeddd1d2184fc87503b5164b..d2efab0e36fa459b5991387cf0d2fda832604d3a 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.130 2003/05/28 22:32:49 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.137 2003/07/30 19:02:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,6 +65,8 @@ static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext,
                         bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext,
                                 bool *isNull);
+static Datum ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
+                                                                  ExprContext *econtext, bool *isNull);
 static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo,
                                 List *argList, ExprContext *econtext);
 static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext,
@@ -173,8 +175,10 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
        foreach(elt, astate->refupperindexpr)
        {
                if (i >= MAXDIM)
-                       elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
-                                MAXDIM);
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                        errmsg("number of array dimensions exceeds the maximum allowed, %d",
+                                                       MAXDIM)));
 
                upper.indx[i++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),
                                                                                                         econtext,
@@ -195,8 +199,10 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
                foreach(elt, astate->reflowerindexpr)
                {
                        if (j >= MAXDIM)
-                               elog(ERROR, "ExecEvalArrayRef: can only handle %d dimensions",
-                                        MAXDIM);
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                                errmsg("number of array dimensions exceeds the maximum allowed, %d",
+                                                               MAXDIM)));
 
                        lower.indx[j++] = DatumGetInt32(ExecEvalExpr((ExprState *) lfirst(elt),
                                                                                                                 econtext,
@@ -215,9 +221,9 @@ ExecEvalArrayRef(ArrayRefExprState *astate,
                                return PointerGetDatum(array_source);
                        }
                }
+               /* this can't happen unless parser messed up */
                if (i != j)
-                       elog(ERROR,
-                                "ExecEvalArrayRef: upper and lower indices mismatch");
+                       elog(ERROR, "upper and lower index lists are not same length");
                lIndex = lower.indx;
        }
        else
@@ -298,7 +304,7 @@ static Datum
 ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext, bool *isNull)
 {
        if (econtext->ecxt_aggvalues == NULL)           /* safety check */
-               elog(ERROR, "ExecEvalAggref: no aggregates in this expression context");
+               elog(ERROR, "no aggregates in this expression context");
 
        *isNull = econtext->ecxt_aggnulls[aggref->aggno];
        return econtext->ecxt_aggvalues[aggref->aggno];
@@ -476,7 +482,7 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
                                                                matchFound = true;
                                                        break;
                                                default:
-                                                       elog(ERROR, "ExecEvalParam: invalid paramkind %d",
+                                                       elog(ERROR, "unrecognized paramkind: %d",
                                                                 thisParamKind);
                                        }
                                }
@@ -488,11 +494,15 @@ ExecEvalParam(Param *expression, ExprContext *econtext, bool *isNull)
                if (!matchFound)
                {
                        if (thisParamKind == PARAM_NAMED)
-                               elog(ERROR, "ExecEvalParam: Unknown value for parameter %s",
-                                        thisParamName);
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                errmsg("no value found for parameter \"%s\"",
+                                                               thisParamName)));
                        else
-                               elog(ERROR, "ExecEvalParam: Unknown value for parameter %d",
-                                        thisParamId);
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_UNDEFINED_OBJECT),
+                                                errmsg("no value found for parameter %d",
+                                                               thisParamId)));
                }
 
                *isNull = paramList->isnull;
@@ -523,13 +533,10 @@ GetAttributeByNum(TupleTableSlot *slot,
        Datum           retval;
 
        if (!AttributeNumberIsValid(attrno))
-               elog(ERROR, "GetAttributeByNum: Invalid attribute number");
-
-       if (!AttrNumberIsForUserDefinedAttr(attrno))
-               elog(ERROR, "GetAttributeByNum: cannot access system attributes here");
+               elog(ERROR, "invalid attribute number %d", attrno);
 
        if (isNull == (bool *) NULL)
-               elog(ERROR, "GetAttributeByNum: a NULL isNull flag was passed");
+               elog(ERROR, "a NULL isNull pointer was passed");
 
        if (TupIsNull(slot))
        {
@@ -557,10 +564,10 @@ GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull)
        int                     i;
 
        if (attname == NULL)
-               elog(ERROR, "GetAttributeByName: Invalid attribute name");
+               elog(ERROR, "invalid attribute name");
 
        if (isNull == (bool *) NULL)
-               elog(ERROR, "GetAttributeByName: a NULL isNull flag was passed");
+               elog(ERROR, "a NULL isNull pointer was passed");
 
        if (TupIsNull(slot))
        {
@@ -582,7 +589,7 @@ GetAttributeByName(TupleTableSlot *slot, char *attname, bool *isNull)
        }
 
        if (attrno == InvalidAttrNumber)
-               elog(ERROR, "GetAttributeByName: attribute %s not found", attname);
+               elog(ERROR, "attribute \"%s\" does not exist", attname);
 
        retval = heap_getattr(slot->val,
                                                  attrno,
@@ -609,7 +616,7 @@ init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt)
 
        /* Safety check (should never fail, as parser should check sooner) */
        if (length(fcache->args) > FUNC_MAX_ARGS)
-               elog(ERROR, "init_fcache: too many arguments");
+               elog(ERROR, "too many arguments");
 
        /* Set up the primary fmgr lookup information */
        fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
@@ -652,7 +659,9 @@ ExecEvalFuncArgs(FunctionCallInfo fcinfo,
                         * it.
                         */
                        if (argIsDone != ExprSingleResult)
-                               elog(ERROR, "Functions and operators can take only one set argument");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("functions and operators can take at most one set argument")));
                        argIsDone = thisArgIsDone;
                }
                i++;
@@ -702,7 +711,9 @@ ExecMakeFunctionResult(FuncExprState *fcache,
                        if (isDone)
                                *isDone = ExprEndResult;
                        else
-                               elog(ERROR, "Set-valued function called in context that cannot accept a set");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("set-valued function called in context that cannot accept a set")));
                        return (Datum) 0;
                }
                hasSetArg = (argDone != ExprSingleResult);
@@ -744,7 +755,9 @@ ExecMakeFunctionResult(FuncExprState *fcache,
                 * to accept one.
                 */
                if (isDone == NULL)
-                       elog(ERROR, "Set-valued function called in context that cannot accept a set");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("set-valued function called in context that cannot accept a set")));
 
                /*
                 * This loop handles the situation where we have both a set
@@ -929,7 +942,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                argDone = ExecEvalFuncArgs(&fcinfo, fcache->args, econtext);
                /* We don't allow sets in the arguments of the table function */
                if (argDone != ExprSingleResult)
-                       elog(ERROR, "Set-valued function called in context that cannot accept a set");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("set-valued function called in context that cannot accept a set")));
 
                /*
                 * If function is strict, and there are any NULL arguments, skip
@@ -1036,11 +1051,15 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                                         * TupleTableSlot; use its descriptor
                                         */
                                        slot = (TupleTableSlot *) DatumGetPointer(result);
-                                       if (fcinfo.isnull ||
-                                               !slot ||
-                                               !IsA(slot, TupleTableSlot) ||
+                                       if (fcinfo.isnull || !slot)
+                                               ereport(ERROR,
+                                                               (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+                                                                errmsg("function returning tuple cannot return NULL")));
+                                       if (!IsA(slot, TupleTableSlot) ||
                                                !slot->ttc_tupleDescriptor)
-                                               elog(ERROR, "ExecMakeTableFunctionResult: Invalid result from function returning tuple");
+                                               ereport(ERROR,
+                                                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                                                errmsg("function returning tuple did not return a valid tuple slot")));
                                        tupdesc = CreateTupleDescCopy(slot->ttc_tupleDescriptor);
                                        returnsTuple = true;
                                }
@@ -1074,7 +1093,9 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                                        !slot ||
                                        !IsA(slot, TupleTableSlot) ||
                                        TupIsNull(slot))
-                                       elog(ERROR, "ExecMakeTableFunctionResult: Invalid result from function returning tuple");
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+                                                        errmsg("function returning tuple cannot return NULL")));
                                tuple = slot->val;
                        }
                        else
@@ -1099,13 +1120,17 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
                {
                        /* check we're on the same page as the function author */
                        if (!first_time || rsinfo.isDone != ExprSingleResult)
-                               elog(ERROR, "ExecMakeTableFunctionResult: Materialize-mode protocol not followed");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+                                                errmsg("table-function protocol for materialize mode was not followed")));
                        /* Done evaluating the set result */
                        break;
                }
                else
-                       elog(ERROR, "ExecMakeTableFunctionResult: unknown returnMode %d",
-                                (int) rsinfo.returnMode);
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_E_R_I_E_SRF_PROTOCOL_VIOLATED),
+                                        errmsg("unrecognized table-function returnMode: %d",
+                                                       (int) rsinfo.returnMode)));
 
                first_time = false;
        }
@@ -1121,7 +1146,6 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
 /* ----------------------------------------------------------------
  *             ExecEvalFunc
  *             ExecEvalOper
- *             ExecEvalDistinct
  *
  *             Evaluate the functional result of a list of arguments by calling the
  *             function manager.
@@ -1216,7 +1240,9 @@ ExecEvalDistinct(FuncExprState *fcache,
        fcinfo.flinfo = &(fcache->func);
        argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
        if (argDone != ExprSingleResult)
-               elog(ERROR, "IS DISTINCT FROM does not support set arguments");
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                errmsg("IS DISTINCT FROM does not support set arguments")));
        Assert(fcinfo.nargs == 2);
 
        if (fcinfo.argnull[0] && fcinfo.argnull[1])
@@ -1241,6 +1267,151 @@ ExecEvalDistinct(FuncExprState *fcache,
        return result;
 }
 
+/*
+ * ExecEvalScalarArrayOp
+ *
+ * Evaluate "scalar op ANY/ALL (array)".  The operator always yields boolean,
+ * and we combine the results across all array elements using OR and AND
+ * (for ANY and ALL respectively).  Of course we short-circuit as soon as
+ * the result is known.
+ */
+static Datum
+ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate,
+                                         ExprContext *econtext, bool *isNull)
+{
+       ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) sstate->fxprstate.xprstate.expr;
+       bool            useOr = opexpr->useOr;
+       ArrayType  *arr;
+       int                     nitems;
+       Datum           result;
+       bool            resultnull;
+       FunctionCallInfoData fcinfo;
+       ExprDoneCond argDone;
+       int                     i;
+       int16           typlen;
+       bool            typbyval;
+       char            typalign;
+       char       *s;
+
+       /*
+        * Initialize function cache if first time through
+        */
+       if (sstate->fxprstate.func.fn_oid == InvalidOid)
+       {
+               init_fcache(opexpr->opfuncid, &sstate->fxprstate,
+                                       econtext->ecxt_per_query_memory);
+               Assert(!sstate->fxprstate.func.fn_retset);
+       }
+
+       /* Need to prep callinfo structure */
+       MemSet(&fcinfo, 0, sizeof(fcinfo));
+       fcinfo.flinfo = &(sstate->fxprstate.func);
+       argDone = ExecEvalFuncArgs(&fcinfo, sstate->fxprstate.args, econtext);
+       if (argDone != ExprSingleResult)
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                errmsg("op ANY/ALL (array) does not support set arguments")));
+       Assert(fcinfo.nargs == 2);
+
+       /*
+        * If the array is NULL then we return NULL --- it's not very meaningful
+        * to do anything else, even if the operator isn't strict.
+        */
+       if (fcinfo.argnull[1])
+       {
+               *isNull = true;
+               return (Datum) 0;
+       }
+       /* Else okay to fetch and detoast the array */
+       arr = DatumGetArrayTypeP(fcinfo.arg[1]);
+
+       /*
+        * If the array is empty, we return either FALSE or TRUE per the useOr
+        * flag.  This is correct even if the scalar is NULL; since we would
+        * evaluate the operator zero times, it matters not whether it would
+        * want to return NULL.
+        */
+       nitems = ArrayGetNItems(ARR_NDIM(arr), ARR_DIMS(arr));
+       if (nitems <= 0)
+               return BoolGetDatum(!useOr);
+       /*
+        * If the scalar is NULL, and the function is strict, return NULL.
+        * This is just to avoid having to test for strictness inside the
+        * loop.  (XXX but if arrays could have null elements, we'd need a
+        * test anyway.)
+        */
+       if (fcinfo.argnull[0] && sstate->fxprstate.func.fn_strict)
+       {
+               *isNull = true;
+               return (Datum) 0;
+       }
+
+       /*
+        * We arrange to look up info about the element type only
+        * once per series of calls, assuming the element type doesn't change
+        * underneath us.
+        */
+       if (sstate->element_type != ARR_ELEMTYPE(arr))
+       {
+               get_typlenbyvalalign(ARR_ELEMTYPE(arr),
+                                                        &sstate->typlen,
+                                                        &sstate->typbyval,
+                                                        &sstate->typalign);
+               sstate->element_type = ARR_ELEMTYPE(arr);
+       }
+       typlen = sstate->typlen;
+       typbyval = sstate->typbyval;
+       typalign = sstate->typalign;
+
+       result = BoolGetDatum(!useOr);
+       resultnull = false;
+
+       /* Loop over the array elements */
+       s = (char *) ARR_DATA_PTR(arr);
+       for (i = 0; i < nitems; i++)
+       {
+               Datum   elt;
+               Datum   thisresult;
+
+               /* Get array element */
+               elt = fetch_att(s, typbyval, typlen);
+
+               s = att_addlength(s, typlen, PointerGetDatum(s));
+               s = (char *) att_align(s, typalign);
+
+               /* Call comparison function */
+               fcinfo.arg[1] = elt;
+               fcinfo.argnull[1] = false;
+               fcinfo.isnull = false;
+               thisresult = FunctionCallInvoke(&fcinfo);
+
+               /* Combine results per OR or AND semantics */
+               if (fcinfo.isnull)
+                       resultnull = true;
+               else if (useOr)
+               {
+                       if (DatumGetBool(thisresult))
+                       {
+                               result = BoolGetDatum(true);
+                               resultnull = false;
+                               break;          /* needn't look at any more elements */
+                       }
+               }
+               else
+               {
+                       if (!DatumGetBool(thisresult))
+                       {
+                               result = BoolGetDatum(false);
+                               resultnull = false;
+                               break;          /* needn't look at any more elements */
+                       }
+               }
+       }
+
+       *isNull = resultnull;
+       return result;
+}
+
 /* ----------------------------------------------------------------
  *             ExecEvalNot
  *             ExecEvalOr
@@ -1432,6 +1603,10 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
 
 /* ----------------------------------------------------------------
  *             ExecEvalArray - ARRAY[] expressions
+ *
+ * NOTE: currently, if any input value is NULL then we return a NULL array,
+ * so the ARRAY[] construct can be considered strict.  Eventually this will
+ * change; when it does, be sure to fix contain_nonstrict_functions().
  * ----------------------------------------------------------------
  */
 static Datum
@@ -1471,7 +1646,10 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 
                        dvalues[i++] = ExecEvalExpr(e, econtext, &eisnull, NULL);
                        if (eisnull)
-                               elog(ERROR, "Arrays cannot have NULL elements");
+                       {
+                               *isNull = true;
+                               return (Datum) 0;
+                       }
                }
 
                /* setup for 1-D array of the given length */
@@ -1497,7 +1675,10 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
                int                     i;
 
                if (ndims <= 0 || ndims > MAXDIM)
-                       elog(ERROR, "Arrays cannot have more than %d dimensions", MAXDIM);
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+                                        errmsg("number of array dimensions exceeds the maximum allowed, %d",
+                                                       MAXDIM)));
 
                /* loop through and get data area from each element */
                foreach(element, astate->elements)
@@ -1510,7 +1691,10 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
 
                        arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
                        if (eisnull)
-                               elog(ERROR, "Arrays cannot have NULL elements");
+                       {
+                               *isNull = true;
+                               return (Datum) 0;
+                       }
 
                        array = DatumGetArrayTypeP(arraydatum);
 
@@ -1527,19 +1711,15 @@ ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
                        else
                        {
                                /* Check other sub-arrays are compatible */
-                               if (elem_ndims != ARR_NDIM(array))
-                                       elog(ERROR, "Multiple dimension arrays must have array "
-                                                "expressions with matching number of dimensions");
-
-                               if (memcmp(elem_dims, ARR_DIMS(array),
-                                                  elem_ndims * sizeof(int)) != 0)
-                                       elog(ERROR, "Multiple dimension arrays must have array "
-                                                "expressions with matching dimensions");
-
-                               if (memcmp(elem_lbs, ARR_LBOUND(array),
+                               if (elem_ndims != ARR_NDIM(array) ||
+                                       memcmp(elem_dims, ARR_DIMS(array),
+                                                  elem_ndims * sizeof(int)) != 0 ||
+                                       memcmp(elem_lbs, ARR_LBOUND(array),
                                                   elem_ndims * sizeof(int)) != 0)
-                                       elog(ERROR, "Multiple dimension arrays must have array "
-                                                "expressions with matching dimensions");
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+                                                        errmsg("multidimensional arrays must have array "
+                                                                       "expressions with matching dimensions")));
                        }
 
                        elem_ndatabytes = ARR_SIZE(array) - ARR_OVERHEAD(elem_ndims);
@@ -1646,7 +1826,9 @@ ExecEvalNullIf(FuncExprState *fcache, ExprContext *econtext,
        fcinfo.flinfo = &(fcache->func);
        argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
        if (argDone != ExprSingleResult)
-               elog(ERROR, "NULLIF does not support set arguments");
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+                                errmsg("NULLIF does not support set arguments")));
        Assert(fcinfo.nargs == 2);
 
        /* if either argument is NULL they can't be equal */
@@ -1706,7 +1888,7 @@ ExecEvalNullTest(GenericExprState *nstate,
                        else
                                return BoolGetDatum(true);
                default:
-                       elog(ERROR, "ExecEvalNullTest: unexpected nulltesttype %d",
+                       elog(ERROR, "unrecognized nulltesttype: %d",
                                 (int) ntest->nulltesttype);
                        return (Datum) 0;       /* keep compiler quiet */
        }
@@ -1791,7 +1973,7 @@ ExecEvalBooleanTest(GenericExprState *bstate,
                        else
                                return BoolGetDatum(true);
                default:
-                       elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d",
+                       elog(ERROR, "unrecognized booltesttype: %d",
                                 (int) btest->booltesttype);
                        return (Datum) 0;       /* keep compiler quiet */
        }
@@ -1825,8 +2007,10 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
                {
                        case DOM_CONSTRAINT_NOTNULL:
                                if (*isNull)
-                                       elog(ERROR, "Domain %s does not allow NULL values",
-                                                format_type_be(ctest->resulttype));
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_NOT_NULL_VIOLATION),
+                                                        errmsg("domain %s does not allow NULL values",
+                                                                       format_type_be(ctest->resulttype))));
                                break;
                        case DOM_CONSTRAINT_CHECK:
                        {
@@ -1852,16 +2036,19 @@ ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
 
                                if (!conIsNull &&
                                        !DatumGetBool(conResult))
-                                       elog(ERROR, "ExecEvalCoerceToDomain: Domain %s constraint %s failed",
-                                                format_type_be(ctest->resulttype), con->name);
-
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_CHECK_VIOLATION),
+                                                        errmsg("value for domain %s violates CHECK constraint \"%s\"",
+                                                                       format_type_be(ctest->resulttype),
+                                                                       con->name)));
                                econtext->domainValue_datum = save_datum;
                                econtext->domainValue_isNull = save_isNull;
 
                                break;
                        }
                        default:
-                               elog(ERROR, "ExecEvalCoerceToDomain: Constraint type unknown");
+                               elog(ERROR, "unrecognized constraint type: %d",
+                                        (int) con->constrainttype);
                                break;
                }
        }
@@ -1930,9 +2117,9 @@ ExecEvalFieldSelect(GenericExprState *fstate,
  *             *isDone: set to indicator of set-result status
  *
  * A caller that can only accept a singleton (non-set) result should pass
- * NULL for isDone; if the expression computes a set result then an elog()
- * error will be reported.     If the caller does pass an isDone pointer then
- * *isDone is set to one of these three states:
+ * NULL for isDone; if the expression computes a set result then an error
+ * will be reported via ereport.  If the caller does pass an isDone pointer
+ * then *isDone is set to one of these three states:
  *             ExprSingleResult                singleton result (not a set)
  *             ExprMultipleResult              return value is one element of a set
  *             ExprEndResult                   there are no more elements in the set
@@ -2018,6 +2205,10 @@ ExecEvalExpr(ExprState *expression,
                        retDatum = ExecEvalDistinct((FuncExprState *) expression, econtext,
                                                                                isNull);
                        break;
+               case T_ScalarArrayOpExpr:
+                       retDatum = ExecEvalScalarArrayOp((ScalarArrayOpExprState *) expression,
+                                                                                        econtext, isNull);
+                       break;
                case T_BoolExpr:
                        {
                                BoolExprState *state = (BoolExprState *) expression;
@@ -2034,8 +2225,8 @@ ExecEvalExpr(ExprState *expression,
                                                retDatum = ExecEvalNot(state, econtext, isNull);
                                                break;
                                        default:
-                                               elog(ERROR, "ExecEvalExpr: unknown boolop %d",
-                                                        ((BoolExpr *) expr)->boolop);
+                                               elog(ERROR, "unrecognized boolop: %d",
+                                                        (int) ((BoolExpr *) expr)->boolop);
                                                retDatum = 0;   /* keep compiler quiet */
                                                break;
                                }
@@ -2103,8 +2294,8 @@ ExecEvalExpr(ExprState *expression,
                                                                                                   isNull);
                        break;
                default:
-                       elog(ERROR, "ExecEvalExpr: unknown expression type %d",
-                                nodeTag(expression));
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(expression));
                        retDatum = 0;           /* keep compiler quiet */
                        break;
        }
@@ -2198,14 +2389,19 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                        /*
                                         * Complain if the aggregate's argument contains any
                                         * aggregates; nested agg functions are semantically
-                                        * nonsensical.  (This probably was caught earlier,
+                                        * nonsensical.  (This should have been caught earlier,
                                         * but we defend against it here anyway.)
                                         */
                                        if (naggs != aggstate->numaggs)
-                                               elog(ERROR, "Aggregate function calls may not be nested");
+                                               ereport(ERROR,
+                                                               (errcode(ERRCODE_GROUPING_ERROR),
+                                                                errmsg("aggregate function calls may not be nested")));
                                }
                                else
-                                       elog(ERROR, "ExecInitExpr: Aggref not expected here");
+                               {
+                                       /* planner messed up */
+                                       elog(ERROR, "aggref found in non-Agg plan node");
+                               }
                                state = (ExprState *) astate;
                        }
                        break;
@@ -2263,6 +2459,18 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                state = (ExprState *) fstate;
                        }
                        break;
+               case T_ScalarArrayOpExpr:
+                       {
+                               ScalarArrayOpExpr   *opexpr = (ScalarArrayOpExpr *) node;
+                               ScalarArrayOpExprState *sstate = makeNode(ScalarArrayOpExprState);
+
+                               sstate->fxprstate.args = (List *)
+                                       ExecInitExpr((Expr *) opexpr->args, parent);
+                               sstate->fxprstate.func.fn_oid = InvalidOid; /* not initialized */
+                               sstate->element_type = InvalidOid; /* ditto */
+                               state = (ExprState *) sstate;
+                       }
+                       break;
                case T_BoolExpr:
                        {
                                BoolExpr   *boolexpr = (BoolExpr *) node;
@@ -2280,7 +2488,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                SubPlanState *sstate = makeNode(SubPlanState);
 
                                if (!parent)
-                                       elog(ERROR, "ExecInitExpr: SubPlan not expected here");
+                                       elog(ERROR, "SubPlan found with no parent plan");
 
                                /*
                                 * Here we just add the SubPlanState nodes to
@@ -2451,8 +2659,8 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                return (ExprState *) FastListValue(&outlist);
                        }
                default:
-                       elog(ERROR, "ExecInitExpr: unknown expression type %d",
-                                nodeTag(node));
+                       elog(ERROR, "unrecognized node type: %d",
+                                (int) nodeTag(node));
                        state = NULL;           /* keep compiler quiet */
                        break;
        }
@@ -2475,7 +2683,7 @@ ExecInitExprInitPlan(SubPlan *node, PlanState *parent)
        SubPlanState *sstate = makeNode(SubPlanState);
 
        if (!parent)
-               elog(ERROR, "ExecInitExpr: SubPlan not expected here");
+               elog(ERROR, "SubPlan found with no parent plan");
 
        /* The subplan's state will be initialized later */
        sstate->sub_estate = NULL;
@@ -2726,7 +2934,9 @@ ExecTargetList(List *targetlist,
                {
                        /* We have a set-valued expression in the tlist */
                        if (isDone == NULL)
-                               elog(ERROR, "Set-valued function called in context that cannot accept a set");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("set-valued function called in context that cannot accept a set")));
                        if (itemIsDone[resind] == ExprMultipleResult)
                        {
                                /* we have undone sets in the tlist, set flag */