diff options
author | Thomas G. Lockhart <lockhart@fourpalms.org> | 2002-07-04 15:24:11 +0000 |
---|---|---|
committer | Thomas G. Lockhart <lockhart@fourpalms.org> | 2002-07-04 15:24:11 +0000 |
commit | 68d9fbeb5511d846ce3a6f66b8955d3ca55a4b76 (patch) | |
tree | 2c916fdd1c617a90fdd143e6f68ea9c48d19f296 /src/backend/executor | |
parent | c7eea66c392cd3f5c914ed135d01a2e20ecb1f92 (diff) | |
download | postgresql-68d9fbeb5511d846ce3a6f66b8955d3ca55a4b76.tar.gz postgresql-68d9fbeb5511d846ce3a6f66b8955d3ca55a4b76.zip |
Implement the IS DISTINCT FROM operator per SQL99.
Reused the Expr node to hold DISTINCT which strongly resembles
the existing OP info. Define DISTINCT_EXPR which strongly resembles
the existing OPER_EXPR opType, but with handling for NULLs required
by SQL99.
We have explicit support for single-element DISTINCT comparisons
all the way through to the executor. But, multi-element DISTINCTs
are handled by expanding into a comparison tree in gram.y as is done for
other row comparisons. Per discussions, it might be desirable to move
this into one or more purpose-built nodes to be handled in the backend.
Define the optional ROW keyword and token per SQL99.
This allows single-element row constructs, which were formerly disallowed
due to shift/reduce conflicts with parenthesized a_expr clauses.
Define the SQL99 TREAT() function. Currently, use as a synonym for CAST().
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execQual.c | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 0b2f24d917a..2a7c45ef136 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.94 2002/06/20 20:29:27 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.95 2002/07/04 15:23:29 thomas Exp $ * *------------------------------------------------------------------------- */ @@ -51,6 +51,8 @@ static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext, static Datum ExecEvalVar(Var *variable, ExprContext *econtext, bool *isNull); static Datum ExecEvalOper(Expr *opClause, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); +static Datum ExecEvalDistinct(Expr *opClause, ExprContext *econtext, + bool *isNull, ExprDoneCond *isDone); static Datum ExecEvalFunc(Expr *funcClause, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone); static ExprDoneCond ExecEvalFuncArgs(FunctionCallInfo fcinfo, @@ -832,6 +834,7 @@ ExecMakeFunctionResult(FunctionCachePtr fcache, /* ---------------------------------------------------------------- * ExecEvalOper + * ExecEvalDistinct * ExecEvalFunc * * Evaluate the functional result of a list of arguments by calling the @@ -879,6 +882,80 @@ ExecEvalOper(Expr *opClause, } /* ---------------------------------------------------------------- + * ExecEvalDistinct + * + * IS DISTINCT FROM must evaluate arguments to determine whether + * they are NULL; if either is NULL then the result is already + * known. If neither is NULL, then proceed to evaluate the + * function. Note that this is *always* derived from the equals + * operator, but since we've already evaluated the arguments + * we can not simply reuse ExecEvalOper() or ExecEvalFunc(). + * ---------------------------------------------------------------- + */ +static Datum +ExecEvalDistinct(Expr *opClause, + ExprContext *econtext, + bool *isNull, + ExprDoneCond *isDone) +{ + bool result; + FunctionCachePtr fcache; + FunctionCallInfoData fcinfo; + ExprDoneCond argDone; + Oper *op; + List *argList; + + /* + * we extract the oid of the function associated with the op and then + * pass the work onto ExecMakeFunctionResult which evaluates the + * arguments and returns the result of calling the function on the + * evaluated arguments. + */ + op = (Oper *) opClause->oper; + argList = opClause->args; + + /* + * get the fcache from the Oper node. If it is NULL, then initialize + * it + */ + fcache = op->op_fcache; + if (fcache == NULL) + { + fcache = init_fcache(op->opid, length(argList), + econtext->ecxt_per_query_memory); + op->op_fcache = fcache; + } + Assert(fcache->func.fn_retset == FALSE); + + /* Need to prep callinfo structure */ + MemSet(&fcinfo, 0, sizeof(fcinfo)); + fcinfo.flinfo = &(fcache->func); + argDone = ExecEvalFuncArgs(&fcinfo, argList, econtext); + Assert(fcinfo->nargs == 2); + + if (fcinfo.argnull[0] && fcinfo.argnull[1]) + { + /* Both NULL? Then is not distinct... */ + result = FALSE; + } + else if (fcinfo.argnull[0] || fcinfo.argnull[1]) + { + /* One is NULL? Then is distinct... */ + result = TRUE; + } + else + { + fcinfo.isnull = false; + result = FunctionCallInvoke(&fcinfo); + *isNull = fcinfo.isnull; + + result = (!DatumGetBool(result)); + } + + return BoolGetDatum(result); +} + +/* ---------------------------------------------------------------- * ExecEvalFunc * ---------------------------------------------------------------- */ @@ -1367,6 +1444,10 @@ ExecEvalExpr(Node *expression, case NOT_EXPR: retDatum = ExecEvalNot(expr, econtext, isNull); break; + case DISTINCT_EXPR: + retDatum = ExecEvalDistinct(expr, econtext, + isNull, isDone); + break; case SUBPLAN_EXPR: retDatum = ExecSubPlan((SubPlan *) expr->oper, expr->args, econtext, |