+/*
+ * 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;
+}
+