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

Commitf213131

Browse files
committed
Fix IS NULL and IS NOT NULL tests on row-valued expressions to conform to
the SQL spec, viz IS NULL is true if all the row's fields are null, IS NOTNULL is true if all the row's fields are not null. The former coding gotthis right for a limited number of cases with IS NULL (ie, those where itcould disassemble a ROW constructor at parse time), but was entirely wrongfor IS NOT NULL. Per report from Teodor.I desisted from changing the behavior for arrays, since on closer inspectionit's not clear that there's any support for that in the SQL spec. Thisprobably needs more consideration.
1 parentd3aa4a8 commitf213131

File tree

10 files changed

+253
-130
lines changed

10 files changed

+253
-130
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.340 2006/09/22 16:20:00 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.341 2006/09/2820:51:41 tgl Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -338,6 +338,19 @@
338338
</para>
339339
</tip>
340340

341+
<note>
342+
<para>
343+
If the <replaceable>expression</replaceable> is row-valued, then
344+
<literal>IS NULL</> is true when the row expression itself is null
345+
or when all the row's fields are null, while
346+
<literal>IS NOT NULL</> is true when the row expression itself is non-null
347+
and all the row's fields are non-null.
348+
This definition conforms to the SQL standard, and is a change from the
349+
inconsistent behavior exhibited by <productname>PostgreSQL</productname>
350+
versions prior to 8.2.
351+
</para>
352+
</note>
353+
341354
<para>
342355
<indexterm>
343356
<primary>IS DISTINCT FROM</primary>

‎src/backend/executor/execQual.c

Lines changed: 75 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.193 2006/07/27 19:52:05 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.194 2006/09/28 20:51:41 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -119,7 +119,7 @@ static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
119119
staticDatumExecEvalNullIf(FuncExprState*nullIfExpr,
120120
ExprContext*econtext,
121121
bool*isNull,ExprDoneCond*isDone);
122-
staticDatumExecEvalNullTest(GenericExprState*nstate,
122+
staticDatumExecEvalNullTest(NullTestState*nstate,
123123
ExprContext*econtext,
124124
bool*isNull,ExprDoneCond*isDone);
125125
staticDatumExecEvalBooleanTest(GenericExprState*bstate,
@@ -1247,8 +1247,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
12471247

12481248
funcrettype=exprType((Node*)funcexpr->expr);
12491249

1250-
returnsTuple= (funcrettype==RECORDOID||
1251-
get_typtype(funcrettype)=='c');
1250+
returnsTuple=type_is_rowtype(funcrettype);
12521251

12531252
/*
12541253
* Prepare a resultinfo node for communication. We always do this even if
@@ -2683,7 +2682,7 @@ ExecEvalNullIf(FuncExprState *nullIfExpr,
26832682
* ----------------------------------------------------------------
26842683
*/
26852684
staticDatum
2686-
ExecEvalNullTest(GenericExprState*nstate,
2685+
ExecEvalNullTest(NullTestState*nstate,
26872686
ExprContext*econtext,
26882687
bool*isNull,
26892688
ExprDoneCond*isDone)
@@ -2696,28 +2695,77 @@ ExecEvalNullTest(GenericExprState *nstate,
26962695
if (isDone&&*isDone==ExprEndResult)
26972696
returnresult;/* nothing to check */
26982697

2699-
switch (ntest->nulltesttype)
2698+
if (nstate->argisrow&& !(*isNull))
27002699
{
2701-
caseIS_NULL:
2702-
if (*isNull)
2700+
HeapTupleHeadertuple;
2701+
OidtupType;
2702+
int32tupTypmod;
2703+
TupleDesctupDesc;
2704+
HeapTupleDatatmptup;
2705+
intatt;
2706+
2707+
tuple=DatumGetHeapTupleHeader(result);
2708+
2709+
tupType=HeapTupleHeaderGetTypeId(tuple);
2710+
tupTypmod=HeapTupleHeaderGetTypMod(tuple);
2711+
2712+
/* Lookup tupdesc if first time through or if type changes */
2713+
tupDesc=get_cached_rowtype(tupType,tupTypmod,
2714+
&nstate->argdesc,econtext);
2715+
2716+
/*
2717+
* heap_attisnull needs a HeapTuple not a bare HeapTupleHeader.
2718+
*/
2719+
tmptup.t_len=HeapTupleHeaderGetDatumLength(tuple);
2720+
tmptup.t_data=tuple;
2721+
2722+
for (att=1;att <=tupDesc->natts;att++)
2723+
{
2724+
/* ignore dropped columns */
2725+
if (tupDesc->attrs[att-1]->attisdropped)
2726+
continue;
2727+
if (heap_attisnull(&tmptup,att))
27032728
{
2704-
*isNull= false;
2705-
returnBoolGetDatum(true);
2729+
/* null field disproves IS NOT NULL */
2730+
if (ntest->nulltesttype==IS_NOT_NULL)
2731+
returnBoolGetDatum(false);
27062732
}
27072733
else
2708-
returnBoolGetDatum(false);
2709-
caseIS_NOT_NULL:
2710-
if (*isNull)
27112734
{
2712-
*isNull= false;
2713-
returnBoolGetDatum(false);
2735+
/* non-null field disproves IS NULL */
2736+
if (ntest->nulltesttype==IS_NULL)
2737+
returnBoolGetDatum(false);
27142738
}
2715-
else
2716-
returnBoolGetDatum(true);
2717-
default:
2718-
elog(ERROR,"unrecognized nulltesttype: %d",
2719-
(int)ntest->nulltesttype);
2720-
return (Datum)0;/* keep compiler quiet */
2739+
}
2740+
2741+
returnBoolGetDatum(true);
2742+
}
2743+
else
2744+
{
2745+
/* Simple scalar-argument case, or a null rowtype datum */
2746+
switch (ntest->nulltesttype)
2747+
{
2748+
caseIS_NULL:
2749+
if (*isNull)
2750+
{
2751+
*isNull= false;
2752+
returnBoolGetDatum(true);
2753+
}
2754+
else
2755+
returnBoolGetDatum(false);
2756+
caseIS_NOT_NULL:
2757+
if (*isNull)
2758+
{
2759+
*isNull= false;
2760+
returnBoolGetDatum(false);
2761+
}
2762+
else
2763+
returnBoolGetDatum(true);
2764+
default:
2765+
elog(ERROR,"unrecognized nulltesttype: %d",
2766+
(int)ntest->nulltesttype);
2767+
return (Datum)0;/* keep compiler quiet */
2768+
}
27212769
}
27222770
}
27232771

@@ -3609,11 +3657,13 @@ ExecInitExpr(Expr *node, PlanState *parent)
36093657
caseT_NullTest:
36103658
{
36113659
NullTest*ntest= (NullTest*)node;
3612-
GenericExprState*gstate=makeNode(GenericExprState);
3660+
NullTestState*nstate=makeNode(NullTestState);
36133661

3614-
gstate->xprstate.evalfunc= (ExprStateEvalFunc)ExecEvalNullTest;
3615-
gstate->arg=ExecInitExpr(ntest->arg,parent);
3616-
state= (ExprState*)gstate;
3662+
nstate->xprstate.evalfunc= (ExprStateEvalFunc)ExecEvalNullTest;
3663+
nstate->arg=ExecInitExpr(ntest->arg,parent);
3664+
nstate->argisrow=type_is_rowtype(exprType((Node*)ntest->arg));
3665+
nstate->argdesc=NULL;
3666+
state= (ExprState*)nstate;
36173667
}
36183668
break;
36193669
caseT_BooleanTest:

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

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.220 2006/09/06 20:40:47 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.221 2006/09/28 20:51:41 tgl Exp $
1212
*
1313
* HISTORY
1414
* AUTHORDATEMAJOR EVENT
@@ -2099,6 +2099,85 @@ eval_const_expressions_mutator(Node *node,
20992099
newfselect->resulttypmod=fselect->resulttypmod;
21002100
return (Node*)newfselect;
21012101
}
2102+
if (IsA(node,NullTest))
2103+
{
2104+
NullTest*ntest= (NullTest*)node;
2105+
NullTest*newntest;
2106+
Node*arg;
2107+
2108+
arg=eval_const_expressions_mutator((Node*)ntest->arg,
2109+
context);
2110+
if (arg&&IsA(arg,RowExpr))
2111+
{
2112+
RowExpr*rarg= (RowExpr*)arg;
2113+
List*newargs=NIL;
2114+
ListCell*l;
2115+
2116+
/*
2117+
* We break ROW(...) IS [NOT] NULL into separate tests on its
2118+
* component fields. This form is usually more efficient to
2119+
* evaluate, as well as being more amenable to optimization.
2120+
*/
2121+
foreach(l,rarg->args)
2122+
{
2123+
Node*relem= (Node*)lfirst(l);
2124+
2125+
/*
2126+
* A constant field refutes the whole NullTest if it's of
2127+
* the wrong nullness; else we can discard it.
2128+
*/
2129+
if (relem&&IsA(relem,Const))
2130+
{
2131+
Const*carg= (Const*)relem;
2132+
2133+
if (carg->constisnull ?
2134+
(ntest->nulltesttype==IS_NOT_NULL) :
2135+
(ntest->nulltesttype==IS_NULL))
2136+
returnmakeBoolConst(false, false);
2137+
continue;
2138+
}
2139+
newntest=makeNode(NullTest);
2140+
newntest->arg= (Expr*)relem;
2141+
newntest->nulltesttype=ntest->nulltesttype;
2142+
newargs=lappend(newargs,newntest);
2143+
}
2144+
/* If all the inputs were constants, result is TRUE */
2145+
if (newargs==NIL)
2146+
returnmakeBoolConst(true, false);
2147+
/* If only one nonconst input, it's the result */
2148+
if (list_length(newargs)==1)
2149+
return (Node*)linitial(newargs);
2150+
/* Else we need an AND node */
2151+
return (Node*)make_andclause(newargs);
2152+
}
2153+
if (arg&&IsA(arg,Const))
2154+
{
2155+
Const*carg= (Const*)arg;
2156+
boolresult;
2157+
2158+
switch (ntest->nulltesttype)
2159+
{
2160+
caseIS_NULL:
2161+
result=carg->constisnull;
2162+
break;
2163+
caseIS_NOT_NULL:
2164+
result= !carg->constisnull;
2165+
break;
2166+
default:
2167+
elog(ERROR,"unrecognized nulltesttype: %d",
2168+
(int)ntest->nulltesttype);
2169+
result= false;/* keep compiler quiet */
2170+
break;
2171+
}
2172+
2173+
returnmakeBoolConst(result, false);
2174+
}
2175+
2176+
newntest=makeNode(NullTest);
2177+
newntest->arg= (Expr*)arg;
2178+
newntest->nulltesttype=ntest->nulltesttype;
2179+
return (Node*)newntest;
2180+
}
21022181
if (IsA(node,BooleanTest))
21032182
{
21042183
BooleanTest*btest= (BooleanTest*)node;

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

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.8 2006/08/05 00:21:14 tgl Exp $
12+
* $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.9 2006/09/28 20:51:42 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -21,6 +21,7 @@
2121
#include"executor/executor.h"
2222
#include"optimizer/clauses.h"
2323
#include"optimizer/predtest.h"
24+
#include"parser/parse_expr.h"
2425
#include"utils/array.h"
2526
#include"utils/lsyscache.h"
2627
#include"utils/syscache.h"
@@ -931,14 +932,18 @@ predicate_implied_by_simple_clause(Expr *predicate, Node *clause)
931932
{
932933
Expr*nonnullarg= ((NullTest*)predicate)->arg;
933934

934-
if (is_opclause(clause)&&
935-
list_member(((OpExpr*)clause)->args,nonnullarg)&&
936-
op_strict(((OpExpr*)clause)->opno))
937-
return true;
938-
if (is_funcclause(clause)&&
939-
list_member(((FuncExpr*)clause)->args,nonnullarg)&&
940-
func_strict(((FuncExpr*)clause)->funcid))
941-
return true;
935+
/* row IS NOT NULL does not act in the simple way we have in mind */
936+
if (!type_is_rowtype(exprType((Node*)nonnullarg)))
937+
{
938+
if (is_opclause(clause)&&
939+
list_member(((OpExpr*)clause)->args,nonnullarg)&&
940+
op_strict(((OpExpr*)clause)->opno))
941+
return true;
942+
if (is_funcclause(clause)&&
943+
list_member(((FuncExpr*)clause)->args,nonnullarg)&&
944+
func_strict(((FuncExpr*)clause)->funcid))
945+
return true;
946+
}
942947
return false;/* we can't succeed below... */
943948
}
944949

@@ -978,14 +983,18 @@ predicate_refuted_by_simple_clause(Expr *predicate, Node *clause)
978983
{
979984
Expr*isnullarg= ((NullTest*)predicate)->arg;
980985

981-
if (is_opclause(clause)&&
982-
list_member(((OpExpr*)clause)->args,isnullarg)&&
983-
op_strict(((OpExpr*)clause)->opno))
984-
return true;
985-
if (is_funcclause(clause)&&
986-
list_member(((FuncExpr*)clause)->args,isnullarg)&&
987-
func_strict(((FuncExpr*)clause)->funcid))
988-
return true;
986+
/* row IS NULL does not act in the simple way we have in mind */
987+
if (!type_is_rowtype(exprType((Node*)isnullarg)))
988+
{
989+
if (is_opclause(clause)&&
990+
list_member(((OpExpr*)clause)->args,isnullarg)&&
991+
op_strict(((OpExpr*)clause)->opno))
992+
return true;
993+
if (is_funcclause(clause)&&
994+
list_member(((FuncExpr*)clause)->args,isnullarg)&&
995+
func_strict(((FuncExpr*)clause)->funcid))
996+
return true;
997+
}
989998
return false;/* we can't succeed below... */
990999
}
9911000

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp