+/*
+ * ExecEvalCaseTestExpr
+ *
+ * Return the value stored by CASE.
+ */
+static Datum
+ExecEvalCaseTestExpr(ExprState *exprstate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = econtext->caseValue_isNull;
+ return econtext->caseValue_datum;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalArray - ARRAY[] expressions
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalArray(ArrayExprState *astate, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ ArrayExpr *arrayExpr = (ArrayExpr *) astate->xprstate.expr;
+ ArrayType *result;
+ ListCell *element;
+ Oid element_type = arrayExpr->element_typeid;
+ int ndims = 0;
+ int dims[MAXDIM];
+ int lbs[MAXDIM];
+
+ /* Set default values for result flags: non-null, not a set result */
+ *isNull = false;
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ if (!arrayExpr->multidims)
+ {
+ /* Elements are presumably of scalar type */
+ int nelems;
+ Datum *dvalues;
+ bool *dnulls;
+ int i = 0;
+
+ ndims = 1;
+ nelems = list_length(astate->elements);
+
+ /* Shouldn't happen here, but if length is 0, return empty array */
+ if (nelems == 0)
+ return PointerGetDatum(construct_empty_array(element_type));
+
+ dvalues = (Datum *) palloc(nelems * sizeof(Datum));
+ dnulls = (bool *) palloc(nelems * sizeof(bool));
+
+ /* loop through and build array of datums */
+ foreach(element, astate->elements)
+ {
+ ExprState *e = (ExprState *) lfirst(element);
+
+ dvalues[i] = ExecEvalExpr(e, econtext, &dnulls[i], NULL);
+ i++;
+ }
+
+ /* setup for 1-D array of the given length */
+ dims[0] = nelems;
+ lbs[0] = 1;
+
+ result = construct_md_array(dvalues, dnulls, ndims, dims, lbs,
+ element_type,
+ astate->elemlength,
+ astate->elembyval,
+ astate->elemalign);
+ }
+ else
+ {
+ /* Must be nested array expressions */
+ int nbytes = 0;
+ int nitems = 0;
+ int outer_nelems = 0;
+ int elem_ndims = 0;
+ int *elem_dims = NULL;
+ int *elem_lbs = NULL;
+ bool firstone = true;
+ bool havenulls = false;
+ bool haveempty = false;
+ char **subdata;
+ bits8 **subbitmaps;
+ int *subbytes;
+ int *subnitems;
+ int i;
+ int32 dataoffset;
+ char *dat;
+ int iitem;
+
+ i = list_length(astate->elements);
+ subdata = (char **) palloc(i * sizeof(char *));
+ subbitmaps = (bits8 **) palloc(i * sizeof(bits8 *));
+ subbytes = (int *) palloc(i * sizeof(int));
+ subnitems = (int *) palloc(i * sizeof(int));
+
+ /* loop through and get data area from each element */
+ foreach(element, astate->elements)
+ {
+ ExprState *e = (ExprState *) lfirst(element);
+ bool eisnull;
+ Datum arraydatum;
+ ArrayType *array;
+ int this_ndims;
+
+ arraydatum = ExecEvalExpr(e, econtext, &eisnull, NULL);
+ /* temporarily ignore null subarrays */
+ if (eisnull)
+ {
+ haveempty = true;
+ continue;
+ }
+
+ array = DatumGetArrayTypeP(arraydatum);
+
+ /* run-time double-check on element type */
+ if (element_type != ARR_ELEMTYPE(array))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot merge incompatible arrays"),
+ errdetail("Array with element type %s cannot be "
+ "included in ARRAY construct with element type %s.",
+ format_type_be(ARR_ELEMTYPE(array)),
+ format_type_be(element_type))));
+
+ this_ndims = ARR_NDIM(array);
+ /* temporarily ignore zero-dimensional subarrays */
+ if (this_ndims <= 0)
+ {
+ haveempty = true;
+ continue;
+ }
+
+ if (firstone)
+ {
+ /* Get sub-array details from first member */
+ elem_ndims = this_ndims;
+ ndims = elem_ndims + 1;
+ if (ndims <= 0 || ndims > MAXDIM)
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("number of array dimensions (%d) exceeds " \
+ "the maximum allowed (%d)", ndims, MAXDIM)));
+
+ elem_dims = (int *) palloc(elem_ndims * sizeof(int));
+ memcpy(elem_dims, ARR_DIMS(array), elem_ndims * sizeof(int));
+ elem_lbs = (int *) palloc(elem_ndims * sizeof(int));
+ memcpy(elem_lbs, ARR_LBOUND(array), elem_ndims * sizeof(int));
+
+ firstone = false;
+ }
+ else
+ {
+ /* Check other sub-arrays are compatible */
+ if (elem_ndims != this_ndims ||
+ memcmp(elem_dims, ARR_DIMS(array),
+ elem_ndims * sizeof(int)) != 0 ||
+ memcmp(elem_lbs, ARR_LBOUND(array),
+ elem_ndims * sizeof(int)) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("multidimensional arrays must have array "
+ "expressions with matching dimensions")));
+ }
+
+ subdata[outer_nelems] = ARR_DATA_PTR(array);
+ subbitmaps[outer_nelems] = ARR_NULLBITMAP(array);
+ subbytes[outer_nelems] = ARR_SIZE(array) - ARR_DATA_OFFSET(array);
+ nbytes += subbytes[outer_nelems];
+ subnitems[outer_nelems] = ArrayGetNItems(this_ndims,
+ ARR_DIMS(array));
+ nitems += subnitems[outer_nelems];
+ havenulls |= ARR_HASNULL(array);
+ outer_nelems++;
+ }
+
+ /*
+ * If all items were null or empty arrays, return an empty array;
+ * otherwise, if some were and some weren't, raise error. (Note:
+ * we must special-case this somehow to avoid trying to generate
+ * a 1-D array formed from empty arrays. It's not ideal...)
+ */
+ if (haveempty)
+ {
+ if (ndims == 0) /* didn't find any nonempty array */
+ return PointerGetDatum(construct_empty_array(element_type));
+ ereport(ERROR,
+ (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
+ errmsg("multidimensional arrays must have array "
+ "expressions with matching dimensions")));
+ }
+
+ /* setup for multi-D array */
+ dims[0] = outer_nelems;
+ lbs[0] = 1;
+ for (i = 1; i < ndims; i++)
+ {
+ dims[i] = elem_dims[i - 1];
+ lbs[i] = elem_lbs[i - 1];
+ }
+
+ if (havenulls)
+ {
+ dataoffset = ARR_OVERHEAD_WITHNULLS(ndims, nitems);
+ nbytes += dataoffset;
+ }
+ else
+ {
+ dataoffset = 0; /* marker for no null bitmap */
+ nbytes += ARR_OVERHEAD_NONULLS(ndims);
+ }
+
+ result = (ArrayType *) palloc(nbytes);
+ result->size = nbytes;
+ result->ndim = ndims;
+ result->dataoffset = dataoffset;
+ result->elemtype = element_type;
+ memcpy(ARR_DIMS(result), dims, ndims * sizeof(int));
+ memcpy(ARR_LBOUND(result), lbs, ndims * sizeof(int));
+
+ dat = ARR_DATA_PTR(result);
+ iitem = 0;
+ for (i = 0; i < outer_nelems; i++)
+ {
+ memcpy(dat, subdata[i], subbytes[i]);
+ dat += subbytes[i];
+ if (havenulls)
+ array_bitmap_copy(ARR_NULLBITMAP(result), iitem,
+ subbitmaps[i], 0,
+ subnitems[i]);
+ iitem += subnitems[i];
+ }
+ }
+
+ return PointerGetDatum(result);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalRow - ROW() expressions
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalRow(RowExprState *rstate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ HeapTuple tuple;
+ Datum *values;
+ bool *isnull;
+ int natts;
+ ListCell *arg;
+ int i;
+
+ /* Set default values for result flags: non-null, not a set result */
+ *isNull = false;
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ /* Allocate workspace */
+ natts = rstate->tupdesc->natts;
+ values = (Datum *) palloc0(natts * sizeof(Datum));
+ isnull = (bool *) palloc(natts * sizeof(bool));
+
+ /* preset to nulls in case rowtype has some later-added columns */
+ memset(isnull, true, natts * sizeof(bool));
+
+ /* Evaluate field values */
+ i = 0;
+ foreach(arg, rstate->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+
+ values[i] = ExecEvalExpr(e, econtext, &isnull[i], NULL);
+ i++;
+ }
+
+ tuple = heap_form_tuple(rstate->tupdesc, values, isnull);
+
+ pfree(values);
+ pfree(isnull);
+
+ return HeapTupleGetDatum(tuple);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalRowCompare - ROW() comparison-op ROW()
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalRowCompare(RowCompareExprState *rstate,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ bool result;
+ RowCompareType rctype = ((RowCompareExpr *) rstate->xprstate.expr)->rctype;
+ int32 cmpresult = 0;
+ ListCell *l;
+ ListCell *r;
+ int i;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = true; /* until we get a result */
+
+ i = 0;
+ forboth(l, rstate->largs, r, rstate->rargs)
+ {
+ ExprState *le = (ExprState *) lfirst(l);
+ ExprState *re = (ExprState *) lfirst(r);
+ FunctionCallInfoData locfcinfo;
+
+ InitFunctionCallInfoData(locfcinfo, &(rstate->funcs[i]), 2,
+ NULL, NULL);
+ locfcinfo.arg[0] = ExecEvalExpr(le, econtext,
+ &locfcinfo.argnull[0], NULL);
+ locfcinfo.arg[1] = ExecEvalExpr(re, econtext,
+ &locfcinfo.argnull[1], NULL);
+ if (rstate->funcs[i].fn_strict &&
+ (locfcinfo.argnull[0] || locfcinfo.argnull[1]))
+ return (Datum) 0; /* force NULL result */
+ locfcinfo.isnull = false;
+ cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+ if (locfcinfo.isnull)
+ return (Datum) 0; /* force NULL result */
+ if (cmpresult != 0)
+ break; /* no need to compare remaining columns */
+ i++;
+ }
+
+ switch (rctype)
+ {
+ /* EQ and NE cases aren't allowed here */
+ case ROWCOMPARE_LT:
+ result = (cmpresult < 0);
+ break;
+ case ROWCOMPARE_LE:
+ result = (cmpresult <= 0);
+ break;
+ case ROWCOMPARE_GE:
+ result = (cmpresult >= 0);
+ break;
+ case ROWCOMPARE_GT:
+ result = (cmpresult > 0);
+ break;
+ default:
+ elog(ERROR, "unrecognized RowCompareType: %d", (int) rctype);
+ result = 0; /* keep compiler quiet */
+ break;
+ }
+
+ *isNull = false;
+ return BoolGetDatum(result);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalCoalesce
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ ListCell *arg;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ /* Simply loop through until something NOT NULL is found */
+ foreach(arg, coalesceExpr->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+ Datum value;
+
+ value = ExecEvalExpr(e, econtext, isNull, NULL);
+ if (!*isNull)
+ return value;
+ }
+
+ /* Else return NULL */
+ *isNull = true;
+ return (Datum) 0;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalMinMax
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ Datum result = (Datum) 0;
+ MinMaxOp op = ((MinMaxExpr *) minmaxExpr->xprstate.expr)->op;
+ FunctionCallInfoData locfcinfo;
+ ListCell *arg;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = true; /* until we get a result */
+
+ InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2, NULL, NULL);
+ locfcinfo.argnull[0] = false;
+ locfcinfo.argnull[1] = false;
+
+ foreach(arg, minmaxExpr->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+ Datum value;
+ bool valueIsNull;
+ int32 cmpresult;
+
+ value = ExecEvalExpr(e, econtext, &valueIsNull, NULL);
+ if (valueIsNull)
+ continue; /* ignore NULL inputs */
+
+ if (*isNull)
+ {
+ /* first nonnull input, adopt value */
+ result = value;
+ *isNull = false;
+ }
+ else
+ {
+ /* apply comparison function */
+ locfcinfo.arg[0] = result;
+ locfcinfo.arg[1] = value;
+ locfcinfo.isnull = false;
+ cmpresult = DatumGetInt32(FunctionCallInvoke(&locfcinfo));
+ if (locfcinfo.isnull) /* probably should not happen */
+ continue;
+ if (cmpresult > 0 && op == IS_LEAST)
+ result = value;
+ else if (cmpresult < 0 && op == IS_GREATEST)
+ result = value;
+ }
+ }
+
+ return result;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
+ text *result;
+ StringInfoData buf;
+ Datum value;
+ bool isnull;
+ ListCell *arg;
+ ListCell *narg;
+ int i;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = true; /* until we get a result */
+
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ {
+ List *values = NIL;
+
+ foreach(arg, xmlExpr->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ values = lappend(values, DatumGetPointer(value));
+ }
+
+ if (list_length(values) > 0)
+ {
+ *isNull = false;
+ return PointerGetDatum(xmlconcat(values));
+ }
+ }
+ break;
+
+ case IS_XMLFOREST:
+ initStringInfo(&buf);
+ i = 0;
+ forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ {
+ appendStringInfo(&buf, "<%s>%s</%s>",
+ argname,
+ map_sql_value_to_xml_value(value, exprType((Node *) e->expr)),
+ argname);
+ *isNull = false;
+ }
+ i++;
+ }
+ break;
+
+ /* The remaining cases don't need to set up buf */
+ case IS_XMLELEMENT:
+ *isNull = false;
+ return PointerGetDatum(xmlelement(xmlExpr, econtext));
+ break;
+
+ case IS_XMLPARSE:
+ {
+ ExprState *e;
+ text *data;
+ bool preserve_whitespace;
+
+ /* arguments are known to be text, bool */
+ Assert(list_length(xmlExpr->args) == 2);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ data = DatumGetTextP(value);
+
+ e = (ExprState *) lsecond(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull) /* probably can't happen */
+ return (Datum) 0;
+ preserve_whitespace = DatumGetBool(value);
+
+ *isNull = false;
+
+ return PointerGetDatum(xmlparse(data,
+ xexpr->xmloption,
+ preserve_whitespace));
+ }
+ break;
+
+ case IS_XMLPI:
+ {
+ ExprState *e;
+ text *arg;
+
+ /* optional argument is known to be text */
+ Assert(list_length(xmlExpr->args) <= 1);
+
+ if (xmlExpr->args)
+ {
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ arg = NULL;
+ else
+ arg = DatumGetTextP(value);
+ }
+ else
+ {
+ arg = NULL;
+ isnull = false;
+ }
+
+ return PointerGetDatum(xmlpi(xexpr->name, arg, isnull, isNull));
+ }
+ break;
+
+ case IS_XMLROOT:
+ {
+ ExprState *e;
+ xmltype *data;
+ text *version;
+ int standalone;
+
+ /* arguments are known to be xml, text, int */
+ Assert(list_length(xmlExpr->args) == 3);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ data = DatumGetXmlP(value);
+
+ e = (ExprState *) lsecond(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ version = NULL;
+ else
+ version = DatumGetTextP(value);
+
+ e = (ExprState *) lthird(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ standalone = DatumGetInt32(value);
+
+ *isNull = false;
+
+ return PointerGetDatum(xmlroot(data,
+ version,
+ standalone));
+ }
+ break;
+
+ case IS_XMLSERIALIZE:
+ {
+ ExprState *e;
+
+ /* argument type is known to be xml */
+ Assert(list_length(xmlExpr->args) == 1);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+
+ *isNull = false;
+
+ return PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value), xexpr->xmloption));
+ }
+ break;
+
+ case IS_DOCUMENT:
+ {
+ ExprState *e;
+
+ /* optional argument is known to be xml */
+ Assert(list_length(xmlExpr->args) == 1);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ else
+ {
+ *isNull = false;
+ return BoolGetDatum(xml_is_document(DatumGetXmlP(value)));
+ }
+ }
+ break;
+ }
+
+ if (*isNull)
+ result = NULL;
+ else
+ {
+ int len = buf.len + VARHDRSZ;
+
+ result = palloc(len);
+ VARATT_SIZEP(result) = len;
+ memcpy(VARDATA(result), buf.data, buf.len);
+ }
+
+ pfree(buf.data);
+ return PointerGetDatum(result);
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalNullIf
+ *
+ * Note that this is *always* derived from the equals operator,
+ * but since we need special processing of the arguments
+ * we can not simply reuse ExecEvalOper() or ExecEvalFunc().
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalNullIf(FuncExprState *nullIfExpr,
+ ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ Datum result;
+ FunctionCallInfoData fcinfo;
+ ExprDoneCond argDone;
+ List *argList;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+
+ /*
+ * Initialize function cache if first time through
+ */
+ if (nullIfExpr->func.fn_oid == InvalidOid)
+ {
+ NullIfExpr *op = (NullIfExpr *) nullIfExpr->xprstate.expr;
+
+ init_fcache(op->opfuncid, nullIfExpr, econtext->ecxt_per_query_memory);
+ Assert(!nullIfExpr->func.fn_retset);
+ }
+
+ /*
+ * extract info from nullIfExpr
+ */
+ argList = nullIfExpr->args;
+
+ /* Need to prep callinfo structure */
+ InitFunctionCallInfoData(fcinfo, &(nullIfExpr->func), 0, NULL, NULL);
+ argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext);
+ if (argDone != ExprSingleResult)
+ 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 */
+ if (!fcinfo.argnull[0] && !fcinfo.argnull[1])
+ {
+ fcinfo.isnull = false;
+ result = FunctionCallInvoke(&fcinfo);
+ /* if the arguments are equal return null */
+ if (!fcinfo.isnull && DatumGetBool(result))
+ {
+ *isNull = true;
+ return (Datum) 0;
+ }
+ }
+
+ /* else return first argument */
+ *isNull = fcinfo.argnull[0];
+ return fcinfo.arg[0];
+}
+