Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit68d9fbe

Browse files
author
Thomas G. Lockhart
committed
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().
1 parentc7eea66 commit68d9fbe

File tree

10 files changed

+438
-100
lines changed

10 files changed

+438
-100
lines changed

‎src/backend/executor/execQual.c

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.94 2002/06/20 20:29:27 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.95 2002/07/04 15:23:29 thomas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -51,6 +51,8 @@ static Datum ExecEvalArrayRef(ArrayRef *arrayRef, ExprContext *econtext,
5151
staticDatumExecEvalVar(Var*variable,ExprContext*econtext,bool*isNull);
5252
staticDatumExecEvalOper(Expr*opClause,ExprContext*econtext,
5353
bool*isNull,ExprDoneCond*isDone);
54+
staticDatumExecEvalDistinct(Expr*opClause,ExprContext*econtext,
55+
bool*isNull,ExprDoneCond*isDone);
5456
staticDatumExecEvalFunc(Expr*funcClause,ExprContext*econtext,
5557
bool*isNull,ExprDoneCond*isDone);
5658
staticExprDoneCondExecEvalFuncArgs(FunctionCallInfofcinfo,
@@ -832,6 +834,7 @@ ExecMakeFunctionResult(FunctionCachePtr fcache,
832834

833835
/* ----------------------------------------------------------------
834836
*ExecEvalOper
837+
*ExecEvalDistinct
835838
*ExecEvalFunc
836839
*
837840
*Evaluate the functional result of a list of arguments by calling the
@@ -878,6 +881,80 @@ ExecEvalOper(Expr *opClause,
878881
isNull,isDone);
879882
}
880883

884+
/* ----------------------------------------------------------------
885+
*ExecEvalDistinct
886+
*
887+
* IS DISTINCT FROM must evaluate arguments to determine whether
888+
* they are NULL; if either is NULL then the result is already
889+
* known. If neither is NULL, then proceed to evaluate the
890+
* function. Note that this is *always* derived from the equals
891+
* operator, but since we've already evaluated the arguments
892+
* we can not simply reuse ExecEvalOper() or ExecEvalFunc().
893+
* ----------------------------------------------------------------
894+
*/
895+
staticDatum
896+
ExecEvalDistinct(Expr*opClause,
897+
ExprContext*econtext,
898+
bool*isNull,
899+
ExprDoneCond*isDone)
900+
{
901+
boolresult;
902+
FunctionCachePtrfcache;
903+
FunctionCallInfoDatafcinfo;
904+
ExprDoneCondargDone;
905+
Oper*op;
906+
List*argList;
907+
908+
/*
909+
* we extract the oid of the function associated with the op and then
910+
* pass the work onto ExecMakeFunctionResult which evaluates the
911+
* arguments and returns the result of calling the function on the
912+
* evaluated arguments.
913+
*/
914+
op= (Oper*)opClause->oper;
915+
argList=opClause->args;
916+
917+
/*
918+
* get the fcache from the Oper node. If it is NULL, then initialize
919+
* it
920+
*/
921+
fcache=op->op_fcache;
922+
if (fcache==NULL)
923+
{
924+
fcache=init_fcache(op->opid,length(argList),
925+
econtext->ecxt_per_query_memory);
926+
op->op_fcache=fcache;
927+
}
928+
Assert(fcache->func.fn_retset== FALSE);
929+
930+
/* Need to prep callinfo structure */
931+
MemSet(&fcinfo,0,sizeof(fcinfo));
932+
fcinfo.flinfo=&(fcache->func);
933+
argDone=ExecEvalFuncArgs(&fcinfo,argList,econtext);
934+
Assert(fcinfo->nargs==2);
935+
936+
if (fcinfo.argnull[0]&&fcinfo.argnull[1])
937+
{
938+
/* Both NULL? Then is not distinct... */
939+
result= FALSE;
940+
}
941+
elseif (fcinfo.argnull[0]||fcinfo.argnull[1])
942+
{
943+
/* One is NULL? Then is distinct... */
944+
result= TRUE;
945+
}
946+
else
947+
{
948+
fcinfo.isnull= false;
949+
result=FunctionCallInvoke(&fcinfo);
950+
*isNull=fcinfo.isnull;
951+
952+
result= (!DatumGetBool(result));
953+
}
954+
955+
returnBoolGetDatum(result);
956+
}
957+
881958
/* ----------------------------------------------------------------
882959
*ExecEvalFunc
883960
* ----------------------------------------------------------------
@@ -1367,6 +1444,10 @@ ExecEvalExpr(Node *expression,
13671444
caseNOT_EXPR:
13681445
retDatum=ExecEvalNot(expr,econtext,isNull);
13691446
break;
1447+
caseDISTINCT_EXPR:
1448+
retDatum=ExecEvalDistinct(expr,econtext,
1449+
isNull,isDone);
1450+
break;
13701451
caseSUBPLAN_EXPR:
13711452
retDatum=ExecSubPlan((SubPlan*)expr->oper,
13721453
expr->args,econtext,

‎src/backend/nodes/outfuncs.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
66
* Portions Copyright (c) 1994, Regents of the University of California
77
*
8-
*$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.160 2002/06/20 20:29:29 momjian Exp $
8+
*$Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.161 2002/07/04 15:23:53 thomas Exp $
99
*
1010
* NOTES
1111
* Every (plan) node in POSTGRES has an associated "out" routine which
@@ -719,6 +719,9 @@ _outExpr(StringInfo str, Expr *node)
719719
caseOP_EXPR:
720720
opstr="op";
721721
break;
722+
caseDISTINCT_EXPR:
723+
opstr="distinct";
724+
break;
722725
caseFUNC_EXPR:
723726
opstr="func";
724727
break;

‎src/backend/nodes/readfuncs.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.123 2002/06/20 20:29:29 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.124 2002/07/04 15:23:54 thomas Exp $
1212
*
1313
* NOTES
1414
* Most of the read functions for plan nodes are tested. (In fact, they
@@ -804,6 +804,8 @@ _readExpr(void)
804804
token=pg_strtok(&length);/* get opType */
805805
if (strncmp(token,"op",2)==0)
806806
local_node->opType=OP_EXPR;
807+
elseif (strncmp(token,"distinct",8)==0)
808+
local_node->opType=DISTINCT_EXPR;
807809
elseif (strncmp(token,"func",4)==0)
808810
local_node->opType=FUNC_EXPR;
809811
elseif (strncmp(token,"or",2)==0)

‎src/backend/optimizer/path/costsize.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
* Portions Copyright (c) 1994, Regents of the University of California
4343
*
4444
* IDENTIFICATION
45-
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.88 2002/06/26 21:58:56momjian Exp $
45+
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.89 2002/07/04 15:23:56thomas Exp $
4646
*
4747
*-------------------------------------------------------------------------
4848
*/
@@ -1092,6 +1092,7 @@ cost_qual_eval_walker(Node *node, Cost *total)
10921092
switch (expr->opType)
10931093
{
10941094
caseOP_EXPR:
1095+
caseDISTINCT_EXPR:
10951096
caseFUNC_EXPR:
10961097
*total+=cpu_operator_cost;
10971098
break;

‎src/backend/optimizer/util/clauses.c

Lines changed: 100 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.101 2002/06/20 20:29:31 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.102 2002/07/04 15:23:58 thomas Exp $
1212
*
1313
* HISTORY
1414
* AUTHORDATEMAJOR EVENT
@@ -71,6 +71,7 @@ make_clause(int type, Node *oper, List *args)
7171
expr->typeOid=BOOLOID;
7272
break;
7373
caseOP_EXPR:
74+
caseDISTINCT_EXPR:
7475
expr->typeOid= ((Oper*)oper)->opresulttype;
7576
break;
7677
caseFUNC_EXPR:
@@ -107,7 +108,8 @@ is_opclause(Node *clause)
107108
{
108109
return (clause!=NULL&&
109110
IsA(clause,Expr)&&
110-
((Expr*)clause)->opType==OP_EXPR);
111+
((((Expr*)clause)->opType==OP_EXPR)||
112+
((Expr*)clause)->opType==DISTINCT_EXPR));
111113
}
112114

113115
/*
@@ -458,7 +460,7 @@ pull_agg_clause_walker(Node *node, List **listptr)
458460

459461
/*
460462
* expression_returns_set
461-
* Testwhethe an expression returns a set result.
463+
* Testwhether an expression returns a set result.
462464
*
463465
* Because we use expression_tree_walker(), this can also be applied to
464466
* whole targetlists; it'll produce TRUE if any one of the tlist items
@@ -482,6 +484,7 @@ expression_returns_set_walker(Node *node, void *context)
482484
switch (expr->opType)
483485
{
484486
caseOP_EXPR:
487+
caseDISTINCT_EXPR:
485488
if (((Oper*)expr->oper)->opretset)
486489
return true;
487490
/* else fall through to check args */
@@ -757,6 +760,7 @@ contain_mutable_functions_walker(Node *node, void *context)
757760
switch (expr->opType)
758761
{
759762
caseOP_EXPR:
763+
caseDISTINCT_EXPR:
760764
if (op_volatile(((Oper*)expr->oper)->opno)!=PROVOLATILE_IMMUTABLE)
761765
return true;
762766
break;
@@ -806,6 +810,7 @@ contain_volatile_functions_walker(Node *node, void *context)
806810
switch (expr->opType)
807811
{
808812
caseOP_EXPR:
813+
caseDISTINCT_EXPR:
809814
if (op_volatile(((Oper*)expr->oper)->opno)==PROVOLATILE_VOLATILE)
810815
return true;
811816
break;
@@ -1138,7 +1143,7 @@ eval_const_expressions_mutator(Node *node, void *context)
11381143
* expression_tree_mutator directly rather than recursing to self.
11391144
*/
11401145
args= (List*)expression_tree_mutator((Node*)expr->args,
1141-
eval_const_expressions_mutator,
1146+
eval_const_expressions_mutator,
11421147
(void*)context);
11431148

11441149
switch (expr->opType)
@@ -1159,6 +1164,97 @@ eval_const_expressions_mutator(Node *node, void *context)
11591164
* args
11601165
*/
11611166
break;
1167+
caseDISTINCT_EXPR:
1168+
{
1169+
List*arg;
1170+
boolhas_null_input= false;
1171+
boolall_null_input= true;
1172+
boolhas_nonconst_input= false;
1173+
1174+
/*
1175+
* Check for constant inputs and especially constant-NULL inputs.
1176+
*/
1177+
Assert(length(args)==2);
1178+
foreach(arg,args)
1179+
{
1180+
if (IsA(lfirst(arg),Const))
1181+
{
1182+
has_null_input |= ((Const*)lfirst(arg))->constisnull;
1183+
all_null_input &= ((Const*)lfirst(arg))->constisnull;
1184+
}
1185+
else
1186+
{
1187+
has_nonconst_input= true;
1188+
}
1189+
}
1190+
/* all nulls? then not distinct */
1191+
if (all_null_input)
1192+
returnMAKEBOOLCONST(false, false);
1193+
1194+
/* one null? then distinct */
1195+
if (has_null_input)
1196+
returnMAKEBOOLCONST(true, false);
1197+
1198+
/* all constants? then optimize this out */
1199+
if (!has_nonconst_input)
1200+
{
1201+
Oidresult_typeid;
1202+
int16resultTypLen;
1203+
boolresultTypByVal;
1204+
ExprContext*econtext;
1205+
Datumconst_val;
1206+
boolconst_is_null;
1207+
1208+
Oper*oper= (Oper*)expr->oper;
1209+
replace_opid(oper);/* OK to scribble on input to this extent */
1210+
result_typeid=oper->opresulttype;
1211+
1212+
/*
1213+
* OK, looks like we can simplify this operator/function.
1214+
*
1215+
* We use the executor's routine ExecEvalExpr() to avoid duplication of
1216+
* code and ensure we get the same result as the executor would get.
1217+
*
1218+
* Build a new Expr node containing the already-simplified arguments. The
1219+
* only other setup needed here is the replace_opid() that we already
1220+
* did for the OP_EXPR case.
1221+
*/
1222+
newexpr=makeNode(Expr);
1223+
newexpr->typeOid=expr->typeOid;
1224+
newexpr->opType=expr->opType;
1225+
newexpr->oper=expr->oper;
1226+
newexpr->args=args;
1227+
1228+
/* Get info needed about result datatype */
1229+
get_typlenbyval(result_typeid,&resultTypLen,&resultTypByVal);
1230+
1231+
/*
1232+
* It is OK to pass a dummy econtext because none of the
1233+
* ExecEvalExpr() code used in this situation will use econtext. That
1234+
* might seem fortuitous, but it's not so unreasonable --- a constant
1235+
* expression does not depend on context, by definition, n'est ce pas?
1236+
*/
1237+
econtext=MakeExprContext(NULL,CurrentMemoryContext);
1238+
1239+
const_val=ExecEvalExprSwitchContext((Node*)newexpr,econtext,
1240+
&const_is_null,NULL);
1241+
1242+
/* Must copy result out of sub-context used by expression eval */
1243+
if (!const_is_null)
1244+
const_val=datumCopy(const_val,resultTypByVal,resultTypLen);
1245+
1246+
FreeExprContext(econtext);
1247+
pfree(newexpr);
1248+
1249+
/*
1250+
* Make the constant result node.
1251+
*/
1252+
return (Node*)makeConst(result_typeid,resultTypLen,
1253+
const_val,const_is_null,
1254+
resultTypByVal, false, false);
1255+
}
1256+
break;
1257+
}
11621258
caseOR_EXPR:
11631259
{
11641260

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp