+
+/* ----------------------------------------------------------------
+ * 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 *fcache, ExprContext *econtext,
+ bool *isNull)
+{
+ Datum result;
+ FunctionCallInfoData fcinfo;
+ ExprDoneCond argDone;
+ List *argList;
+
+ /*
+ * Initialize function cache if first time through
+ */
+ if (fcache->func.fn_oid == InvalidOid)
+ {
+ NullIfExpr *op = (NullIfExpr *) fcache->xprstate.expr;
+
+ init_fcache(op->opfuncid, fcache, econtext->ecxt_per_query_memory);
+ Assert(!fcache->func.fn_retset);
+ }
+
+ /*
+ * extract info from fcache
+ */
+ argList = fcache->args;
+
+ /* Need to prep callinfo structure */
+ MemSet(&fcinfo, 0, sizeof(fcinfo));
+ fcinfo.flinfo = &(fcache->func);
+ 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];
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalNullTest
+ *
+ * Evaluate a NullTest node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalNullTest(GenericExprState *nstate,
+ ExprContext *econtext,
+ bool *isNull,
+ ExprDoneCond *isDone)
+{
+ NullTest *ntest = (NullTest *) nstate->xprstate.expr;
+ Datum result;
+
+ result = ExecEvalExpr(nstate->arg, econtext, isNull, isDone);
+
+ if (isDone && *isDone == ExprEndResult)
+ return result; /* nothing to check */
+
+ switch (ntest->nulltesttype)
+ {
+ case IS_NULL:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(true);
+ }
+ else
+ return BoolGetDatum(false);
+ case IS_NOT_NULL:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(false);
+ }
+ else
+ return BoolGetDatum(true);
+ default:
+ elog(ERROR, "unrecognized nulltesttype: %d",
+ (int) ntest->nulltesttype);
+ return (Datum) 0; /* keep compiler quiet */
+ }
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalBooleanTest
+ *
+ * Evaluate a BooleanTest node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalBooleanTest(GenericExprState *bstate,
+ ExprContext *econtext,
+ bool *isNull,
+ ExprDoneCond *isDone)
+{
+ BooleanTest *btest = (BooleanTest *) bstate->xprstate.expr;
+ Datum result;
+
+ result = ExecEvalExpr(bstate->arg, econtext, isNull, isDone);
+
+ if (isDone && *isDone == ExprEndResult)
+ return result; /* nothing to check */
+
+ switch (btest->booltesttype)
+ {
+ case IS_TRUE:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(false);
+ }
+ else if (DatumGetBool(result))
+ return BoolGetDatum(true);
+ else
+ return BoolGetDatum(false);
+ case IS_NOT_TRUE:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(true);
+ }
+ else if (DatumGetBool(result))
+ return BoolGetDatum(false);
+ else
+ return BoolGetDatum(true);
+ case IS_FALSE:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(false);
+ }
+ else if (DatumGetBool(result))
+ return BoolGetDatum(false);
+ else
+ return BoolGetDatum(true);
+ case IS_NOT_FALSE:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(true);
+ }
+ else if (DatumGetBool(result))
+ return BoolGetDatum(true);
+ else
+ return BoolGetDatum(false);
+ case IS_UNKNOWN:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(true);
+ }
+ else
+ return BoolGetDatum(false);
+ case IS_NOT_UNKNOWN:
+ if (*isNull)
+ {
+ *isNull = false;
+ return BoolGetDatum(false);
+ }
+ else
+ return BoolGetDatum(true);
+ default:
+ elog(ERROR, "unrecognized booltesttype: %d",
+ (int) btest->booltesttype);
+ return (Datum) 0; /* keep compiler quiet */
+ }
+}
+
+/*
+ * ExecEvalCoerceToDomain
+ *
+ * Test the provided data against the domain constraint(s). If the data
+ * passes the constraint specifications, pass it through (return the
+ * datum) otherwise throw an error.
+ */
+static Datum
+ExecEvalCoerceToDomain(CoerceToDomainState *cstate, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ CoerceToDomain *ctest = (CoerceToDomain *) cstate->xprstate.expr;
+ Datum result;
+ List *l;
+
+ result = ExecEvalExpr(cstate->arg, econtext, isNull, isDone);
+
+ if (isDone && *isDone == ExprEndResult)
+ return result; /* nothing to check */
+
+ foreach(l, cstate->constraints)
+ {
+ DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
+
+ switch (con->constrainttype)
+ {
+ case DOM_CONSTRAINT_NOTNULL:
+ if (*isNull)
+ 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:
+ {
+ Datum conResult;
+ bool conIsNull;
+ Datum save_datum;
+ bool save_isNull;
+
+ /*
+ * Set up value to be returned by CoerceToDomainValue nodes.
+ * We must save and restore prior setting of econtext's
+ * domainValue fields, in case this node is itself within
+ * a check expression for another domain.
+ */
+ save_datum = econtext->domainValue_datum;
+ save_isNull = econtext->domainValue_isNull;
+
+ econtext->domainValue_datum = result;
+ econtext->domainValue_isNull = *isNull;
+
+ conResult = ExecEvalExpr(con->check_expr,
+ econtext, &conIsNull, NULL);
+
+ if (!conIsNull &&
+ !DatumGetBool(conResult))
+ 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, "unrecognized constraint type: %d",
+ (int) con->constrainttype);
+ break;
+ }
+ }
+
+ /* If all has gone well (constraints did not fail) return the datum */
+ return result;
+}
+
+/*
+ * ExecEvalCoerceToDomainValue
+ *
+ * Return the value stored by CoerceToDomain.
+ */
+static Datum
+ExecEvalCoerceToDomainValue(CoerceToDomainValue *conVal,
+ ExprContext *econtext, bool *isNull)
+{
+ *isNull = econtext->domainValue_isNull;
+ return econtext->domainValue_datum;
+}
+
+/* ----------------------------------------------------------------
+ * ExecEvalFieldSelect
+ *
+ * Evaluate a FieldSelect node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalFieldSelect(GenericExprState *fstate,
+ ExprContext *econtext,
+ bool *isNull,
+ ExprDoneCond *isDone)
+{
+ FieldSelect *fselect = (FieldSelect *) fstate->xprstate.expr;
+ Datum result;
+ TupleTableSlot *resSlot;
+
+ result = ExecEvalExpr(fstate->arg, econtext, isNull, isDone);
+
+ /* this test covers the isDone exception too: */
+ if (*isNull)
+ return result;
+
+ resSlot = (TupleTableSlot *) DatumGetPointer(result);
+ Assert(resSlot != NULL && IsA(resSlot, TupleTableSlot));
+ result = heap_getattr(resSlot->val,
+ fselect->fieldnum,
+ resSlot->ttc_tupleDescriptor,
+ isNull);
+ return result;
+}