diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-16 02:30:39 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2003-02-16 02:30:39 +0000 |
commit | 51972a9d5d068dd34b24ff4923981ffb90e5cc2d (patch) | |
tree | c68fddbb3eaafbd332e84afbafe3c171f6372d4e /src/backend/executor | |
parent | de25638d2fbe9e56ecfc60a7dda8a0c56028317a (diff) | |
download | postgresql-51972a9d5d068dd34b24ff4923981ffb90e5cc2d.tar.gz postgresql-51972a9d5d068dd34b24ff4923981ffb90e5cc2d.zip |
COALESCE() and NULLIF() are now first-class expressions, not macros
that turn into CASE expressions. They evaluate their arguments at most
once. Patch by Kris Jurka, review and (very light) editorializing by me.
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 140 |
1 files changed, 135 insertions, 5 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index a2583fcc4c9..968617c39a9 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.124 2003/02/03 21:15:43 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.125 2003/02/16 02:30:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,7 +64,7 @@ static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext, static Datum ExecEvalOper(FuncExprState *fcache, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, ExprDoneCond *isDone); + bool *isNull); static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, List *argList, ExprContext *econtext); static Datum ExecEvalNot(BoolExprState *notclause, ExprContext *econtext, @@ -75,6 +75,11 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull); static Datum ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr, + ExprContext *econtext, + bool *isNull); +static Datum ExecEvalNullIf(FuncExprState *nullIfExpr, ExprContext *econtext, + bool *isNull); static Datum ExecEvalNullTest(GenericExprState *nstate, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); @@ -1187,8 +1192,7 @@ ExecEvalOper(FuncExprState *fcache, static Datum ExecEvalDistinct(FuncExprState *fcache, ExprContext *econtext, - bool *isNull, - ExprDoneCond *isDone) + bool *isNull) { Datum result; FunctionCallInfoData fcinfo; @@ -1370,6 +1374,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull) return BoolGetDatum(!AnyNull); } + /* ---------------------------------------------------------------- * ExecEvalCase * @@ -1430,6 +1435,91 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext, } /* ---------------------------------------------------------------- + * ExecEvalCoalesce + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalCoalesce(CoalesceExprState *coalesceExpr, ExprContext *econtext, + bool *isNull) +{ + List *arg; + + /* 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; +} + +/* ---------------------------------------------------------------- + * 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) + elog(ERROR, "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. @@ -1778,7 +1868,7 @@ ExecEvalExpr(ExprState *expression, break; case T_DistinctExpr: retDatum = ExecEvalDistinct((FuncExprState *) expression, econtext, - isNull, isDone); + isNull); break; case T_BoolExpr: { @@ -1826,6 +1916,16 @@ ExecEvalExpr(ExprState *expression, isNull, isDone); break; + case T_CoalesceExpr: + retDatum = ExecEvalCoalesce((CoalesceExprState *) expression, + econtext, + isNull); + break; + case T_NullIfExpr: + retDatum = ExecEvalNullIf((FuncExprState *) expression, + econtext, + isNull); + break; case T_NullTest: retDatum = ExecEvalNullTest((GenericExprState *) expression, econtext, @@ -2082,6 +2182,36 @@ ExecInitExpr(Expr *node, PlanState *parent) state = (ExprState *) cstate; } break; + case T_CoalesceExpr: + { + CoalesceExpr *coalesceexpr = (CoalesceExpr *) node; + CoalesceExprState *cstate = makeNode(CoalesceExprState); + List *outlist = NIL; + List *inlist; + + foreach(inlist, coalesceexpr->args) + { + Expr *e = (Expr *) lfirst(inlist); + ExprState *estate; + + estate = ExecInitExpr(e, parent); + outlist = lappend(outlist, estate); + } + cstate->args = outlist; + state = (ExprState *) cstate; + } + break; + case T_NullIfExpr: + { + NullIfExpr *nullifexpr = (NullIfExpr *) node; + FuncExprState *fstate = makeNode(FuncExprState); + + fstate->args = (List *) + ExecInitExpr((Expr *) nullifexpr->args, parent); + fstate->func.fn_oid = InvalidOid; /* not initialized */ + state = (ExprState *) fstate; + } + break; case T_NullTest: { NullTest *ntest = (NullTest *) node; |