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

Commit51972a9

Browse files
committed
COALESCE() and NULLIF() are now first-class expressions, not macros
that turn into CASE expressions. They evaluate their arguments at mostonce. Patch by Kris Jurka, review and (very light) editorializing by me.
1 parentde25638 commit51972a9

File tree

22 files changed

+645
-108
lines changed

22 files changed

+645
-108
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!--
2-
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.139 2003/02/13 05:24:01 momjian Exp $
2+
$Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.140 2003/02/16 02:30:36 tgl Exp $
33
PostgreSQL documentation
44
-->
55

@@ -6295,17 +6295,6 @@ SELECT NULLIF(value, '(none)') ...
62956295
</programlisting>
62966296
</para>
62976297

6298-
<tip>
6299-
<para>
6300-
<function>COALESCE</function> and <function>NULLIF</function> are
6301-
just shorthand for <token>CASE</token> expressions. They are actually
6302-
converted into <token>CASE</token> expressions at a very early stage
6303-
of processing, and subsequent processing thinks it is dealing with
6304-
<token>CASE</token>. Thus an incorrect <function>COALESCE</function> or
6305-
<function>NULLIF</function> usage may draw an error message that
6306-
refers to <token>CASE</token>.
6307-
</para>
6308-
</tip>
63096298
</sect2>
63106299

63116300
</sect1>

‎src/backend/catalog/dependency.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.21 2003/02/09 06:56:26 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.22 2003/02/16 02:30:37 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -933,6 +933,14 @@ find_expr_references_walker(Node *node,
933933
&context->addrs);
934934
/* fall through to examine arguments */
935935
}
936+
if (IsA(node,NullIfExpr))
937+
{
938+
NullIfExpr*nullifexpr= (NullIfExpr*)node;
939+
940+
add_object_address(OCLASS_OPERATOR,nullifexpr->opno,0,
941+
&context->addrs);
942+
/* fall through to examine arguments */
943+
}
936944
if (IsA(node,Aggref))
937945
{
938946
Aggref*aggref= (Aggref*)node;

‎src/backend/executor/execQual.c

Lines changed: 135 additions & 5 deletions
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.124 2003/02/03 21:15:43 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.125 2003/02/16 02:30:37 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -64,7 +64,7 @@ static Datum ExecEvalFunc(FuncExprState *fcache, ExprContext *econtext,
6464
staticDatumExecEvalOper(FuncExprState*fcache,ExprContext*econtext,
6565
bool*isNull,ExprDoneCond*isDone);
6666
staticDatumExecEvalDistinct(FuncExprState*fcache,ExprContext*econtext,
67-
bool*isNull,ExprDoneCond*isDone);
67+
bool*isNull);
6868
staticExprDoneCondExecEvalFuncArgs(FunctionCallInfofcinfo,
6969
List*argList,ExprContext*econtext);
7070
staticDatumExecEvalNot(BoolExprState*notclause,ExprContext*econtext,
@@ -75,6 +75,11 @@ static Datum ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext,
7575
bool*isNull);
7676
staticDatumExecEvalCase(CaseExprState*caseExpr,ExprContext*econtext,
7777
bool*isNull,ExprDoneCond*isDone);
78+
staticDatumExecEvalCoalesce(CoalesceExprState*coalesceExpr,
79+
ExprContext*econtext,
80+
bool*isNull);
81+
staticDatumExecEvalNullIf(FuncExprState*nullIfExpr,ExprContext*econtext,
82+
bool*isNull);
7883
staticDatumExecEvalNullTest(GenericExprState*nstate,
7984
ExprContext*econtext,
8085
bool*isNull,ExprDoneCond*isDone);
@@ -1187,8 +1192,7 @@ ExecEvalOper(FuncExprState *fcache,
11871192
staticDatum
11881193
ExecEvalDistinct(FuncExprState*fcache,
11891194
ExprContext*econtext,
1190-
bool*isNull,
1191-
ExprDoneCond*isDone)
1195+
bool*isNull)
11921196
{
11931197
Datumresult;
11941198
FunctionCallInfoDatafcinfo;
@@ -1370,6 +1374,7 @@ ExecEvalAnd(BoolExprState *andExpr, ExprContext *econtext, bool *isNull)
13701374
returnBoolGetDatum(!AnyNull);
13711375
}
13721376

1377+
13731378
/* ----------------------------------------------------------------
13741379
*ExecEvalCase
13751380
*
@@ -1429,6 +1434,91 @@ ExecEvalCase(CaseExprState *caseExpr, ExprContext *econtext,
14291434
return (Datum)0;
14301435
}
14311436

1437+
/* ----------------------------------------------------------------
1438+
*ExecEvalCoalesce
1439+
* ----------------------------------------------------------------
1440+
*/
1441+
staticDatum
1442+
ExecEvalCoalesce(CoalesceExprState*coalesceExpr,ExprContext*econtext,
1443+
bool*isNull)
1444+
{
1445+
List*arg;
1446+
1447+
/* Simply loop through until something NOT NULL is found */
1448+
foreach(arg,coalesceExpr->args)
1449+
{
1450+
ExprState*e= (ExprState*)lfirst(arg);
1451+
Datumvalue;
1452+
1453+
value=ExecEvalExpr(e,econtext,isNull,NULL);
1454+
if (!*isNull)
1455+
returnvalue;
1456+
}
1457+
1458+
/* Else return NULL */
1459+
*isNull= true;
1460+
return (Datum)0;
1461+
}
1462+
1463+
/* ----------------------------------------------------------------
1464+
*ExecEvalNullIf
1465+
*
1466+
* Note that this is *always* derived from the equals operator,
1467+
* but since we need special processing of the arguments
1468+
* we can not simply reuse ExecEvalOper() or ExecEvalFunc().
1469+
* ----------------------------------------------------------------
1470+
*/
1471+
staticDatum
1472+
ExecEvalNullIf(FuncExprState*fcache,ExprContext*econtext,
1473+
bool*isNull)
1474+
{
1475+
Datumresult;
1476+
FunctionCallInfoDatafcinfo;
1477+
ExprDoneCondargDone;
1478+
List*argList;
1479+
1480+
/*
1481+
* Initialize function cache if first time through
1482+
*/
1483+
if (fcache->func.fn_oid==InvalidOid)
1484+
{
1485+
NullIfExpr*op= (NullIfExpr*)fcache->xprstate.expr;
1486+
1487+
init_fcache(op->opfuncid,fcache,econtext->ecxt_per_query_memory);
1488+
Assert(!fcache->func.fn_retset);
1489+
}
1490+
1491+
/*
1492+
* extract info from fcache
1493+
*/
1494+
argList=fcache->args;
1495+
1496+
/* Need to prep callinfo structure */
1497+
MemSet(&fcinfo,0,sizeof(fcinfo));
1498+
fcinfo.flinfo=&(fcache->func);
1499+
argDone=ExecEvalFuncArgs(&fcinfo,argList,econtext);
1500+
if (argDone!=ExprSingleResult)
1501+
elog(ERROR,"NULLIF does not support set arguments");
1502+
Assert(fcinfo.nargs==2);
1503+
1504+
/* if either argument is NULL they can't be equal */
1505+
if (!fcinfo.argnull[0]&& !fcinfo.argnull[1])
1506+
{
1507+
fcinfo.isnull= false;
1508+
result=FunctionCallInvoke(&fcinfo);
1509+
/* if the arguments are equal return null */
1510+
if (!fcinfo.isnull&&DatumGetBool(result))
1511+
{
1512+
*isNull= true;
1513+
return (Datum)0;
1514+
}
1515+
}
1516+
1517+
/* else return first argument */
1518+
*isNull=fcinfo.argnull[0];
1519+
returnfcinfo.arg[0];
1520+
}
1521+
14321522
/* ----------------------------------------------------------------
14331523
*ExecEvalNullTest
14341524
*
@@ -1778,7 +1868,7 @@ ExecEvalExpr(ExprState *expression,
17781868
break;
17791869
caseT_DistinctExpr:
17801870
retDatum=ExecEvalDistinct((FuncExprState*)expression,econtext,
1781-
isNull,isDone);
1871+
isNull);
17821872
break;
17831873
caseT_BoolExpr:
17841874
{
@@ -1826,6 +1916,16 @@ ExecEvalExpr(ExprState *expression,
18261916
isNull,
18271917
isDone);
18281918
break;
1919+
caseT_CoalesceExpr:
1920+
retDatum=ExecEvalCoalesce((CoalesceExprState*)expression,
1921+
econtext,
1922+
isNull);
1923+
break;
1924+
caseT_NullIfExpr:
1925+
retDatum=ExecEvalNullIf((FuncExprState*)expression,
1926+
econtext,
1927+
isNull);
1928+
break;
18291929
caseT_NullTest:
18301930
retDatum=ExecEvalNullTest((GenericExprState*)expression,
18311931
econtext,
@@ -2082,6 +2182,36 @@ ExecInitExpr(Expr *node, PlanState *parent)
20822182
state= (ExprState*)cstate;
20832183
}
20842184
break;
2185+
caseT_CoalesceExpr:
2186+
{
2187+
CoalesceExpr*coalesceexpr= (CoalesceExpr*)node;
2188+
CoalesceExprState*cstate=makeNode(CoalesceExprState);
2189+
List*outlist=NIL;
2190+
List*inlist;
2191+
2192+
foreach(inlist,coalesceexpr->args)
2193+
{
2194+
Expr*e= (Expr*)lfirst(inlist);
2195+
ExprState*estate;
2196+
2197+
estate=ExecInitExpr(e,parent);
2198+
outlist=lappend(outlist,estate);
2199+
}
2200+
cstate->args=outlist;
2201+
state= (ExprState*)cstate;
2202+
}
2203+
break;
2204+
caseT_NullIfExpr:
2205+
{
2206+
NullIfExpr*nullifexpr= (NullIfExpr*)node;
2207+
FuncExprState*fstate=makeNode(FuncExprState);
2208+
2209+
fstate->args= (List*)
2210+
ExecInitExpr((Expr*)nullifexpr->args,parent);
2211+
fstate->func.fn_oid=InvalidOid;/* not initialized */
2212+
state= (ExprState*)fstate;
2213+
}
2214+
break;
20852215
caseT_NullTest:
20862216
{
20872217
NullTest*ntest= (NullTest*)node;

‎src/backend/nodes/copyfuncs.c

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* Portions Copyright (c) 1994, Regents of the University of California
1616
*
1717
* IDENTIFICATION
18-
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.243 2003/02/10 04:44:44 tgl Exp $
18+
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.244 2003/02/16 02:30:37 tgl Exp $
1919
*
2020
*-------------------------------------------------------------------------
2121
*/
@@ -785,7 +785,7 @@ _copyOpExpr(OpExpr *from)
785785
}
786786

787787
/*
788-
* _copyDistinctExpr
788+
* _copyDistinctExpr (same as OpExpr)
789789
*/
790790
staticDistinctExpr*
791791
_copyDistinctExpr(DistinctExpr*from)
@@ -919,6 +919,37 @@ _copyCaseWhen(CaseWhen *from)
919919
returnnewnode;
920920
}
921921

922+
/*
923+
* _copyCoalesceExpr
924+
*/
925+
staticCoalesceExpr*
926+
_copyCoalesceExpr(CoalesceExpr*from)
927+
{
928+
CoalesceExpr*newnode=makeNode(CoalesceExpr);
929+
930+
COPY_SCALAR_FIELD(coalescetype);
931+
COPY_NODE_FIELD(args);
932+
933+
returnnewnode;
934+
}
935+
936+
/*
937+
* _copyNullIfExpr (same as OpExpr)
938+
*/
939+
staticNullIfExpr*
940+
_copyNullIfExpr(NullIfExpr*from)
941+
{
942+
NullIfExpr*newnode=makeNode(NullIfExpr);
943+
944+
COPY_SCALAR_FIELD(opno);
945+
COPY_SCALAR_FIELD(opfuncid);
946+
COPY_SCALAR_FIELD(opresulttype);
947+
COPY_SCALAR_FIELD(opretset);
948+
COPY_NODE_FIELD(args);
949+
950+
returnnewnode;
951+
}
952+
922953
/*
923954
* _copyNullTest
924955
*/
@@ -2484,6 +2515,12 @@ copyObject(void *from)
24842515
caseT_CaseWhen:
24852516
retval=_copyCaseWhen(from);
24862517
break;
2518+
caseT_CoalesceExpr:
2519+
retval=_copyCoalesceExpr(from);
2520+
break;
2521+
caseT_NullIfExpr:
2522+
retval=_copyNullIfExpr(from);
2523+
break;
24872524
caseT_NullTest:
24882525
retval=_copyNullTest(from);
24892526
break;

‎src/backend/nodes/equalfuncs.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
2020
* IDENTIFICATION
21-
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.186 2003/02/10 04:44:45 tgl Exp $
21+
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.187 2003/02/16 02:30:37 tgl Exp $
2222
*
2323
*-------------------------------------------------------------------------
2424
*/
@@ -378,6 +378,37 @@ _equalCaseWhen(CaseWhen *a, CaseWhen *b)
378378
return true;
379379
}
380380

381+
staticbool
382+
_equalCoalesceExpr(CoalesceExpr*a,CoalesceExpr*b)
383+
{
384+
COMPARE_SCALAR_FIELD(coalescetype);
385+
COMPARE_NODE_FIELD(args);
386+
387+
return true;
388+
}
389+
390+
staticbool
391+
_equalNullIfExpr(NullIfExpr*a,NullIfExpr*b)
392+
{
393+
COMPARE_SCALAR_FIELD(opno);
394+
/*
395+
* Special-case opfuncid: it is allowable for it to differ if one
396+
* node contains zero and the other doesn't. This just means that the
397+
* one node isn't as far along in the parse/plan pipeline and hasn't
398+
* had the opfuncid cache filled yet.
399+
*/
400+
if (a->opfuncid!=b->opfuncid&&
401+
a->opfuncid!=0&&
402+
b->opfuncid!=0)
403+
return false;
404+
405+
COMPARE_SCALAR_FIELD(opresulttype);
406+
COMPARE_SCALAR_FIELD(opretset);
407+
COMPARE_NODE_FIELD(args);
408+
409+
return true;
410+
}
411+
381412
staticbool
382413
_equalNullTest(NullTest*a,NullTest*b)
383414
{
@@ -1613,6 +1644,12 @@ equal(void *a, void *b)
16131644
caseT_CaseWhen:
16141645
retval=_equalCaseWhen(a,b);
16151646
break;
1647+
caseT_CoalesceExpr:
1648+
retval=_equalCoalesceExpr(a,b);
1649+
break;
1650+
caseT_NullIfExpr:
1651+
retval=_equalNullIfExpr(a,b);
1652+
break;
16161653
caseT_NullTest:
16171654
retval=_equalNullTest(a,b);
16181655
break;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp