mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
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().
This commit is contained in:
@ -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
|
||||
@ -878,6 +881,80 @@ ExecEvalOper(Expr *opClause,
|
||||
isNull, isDone);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* 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,
|
||||
|
Reference in New Issue
Block a user