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

Commit8d19d0e

Browse files
committed
Teach parser to transform "x IS [NOT] DISTINCT FROM NULL" to a NullTest.
Now that we've nailed down the principle that NullTest with !argisrowis fully equivalent to SQL's IS [NOT] DISTINCT FROM NULL, let's teachthe parser about it. This produces a slightly more compact parse treeand is much more amenable to optimization than a DistinctExpr, sincethe planner knows a good deal about NullTest and next to nothing aboutDistinctExpr.I'm not sure that there are all that many queries in the wild that couldbe improved by this, but at least one source of such cases is the patchjust made to postgres_fdw to emit IS [NOT] DISTINCT FROM NULL whenIS [NOT] NULL isn't semantically correct.No back-patch, since to the extent that this does affect planning results,it might be considered undesirable plan destabilization.
1 parentef5d4a3 commit8d19d0e

File tree

4 files changed

+65
-16
lines changed

4 files changed

+65
-16
lines changed

‎src/backend/nodes/outfuncs.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2903,6 +2903,10 @@ _outAExpr(StringInfo str, const A_Expr *node)
29032903
appendStringInfoString(str," DISTINCT ");
29042904
WRITE_NODE_FIELD(name);
29052905
break;
2906+
caseAEXPR_NOT_DISTINCT:
2907+
appendStringInfoString(str," NOT_DISTINCT ");
2908+
WRITE_NODE_FIELD(name);
2909+
break;
29062910
caseAEXPR_NULLIF:
29072911
appendStringInfoString(str," NULLIF ");
29082912
WRITE_NODE_FIELD(name);

‎src/backend/parser/gram.y

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11839,9 +11839,7 @@ a_expr:c_expr{ $$ = $1; }
1183911839
}
1184011840
|a_exprISNOTDISTINCTFROMa_expr%precIS
1184111841
{
11842-
$$ = makeNotExpr((Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
11843-
"=",$1,$6,@2),
11844-
@2);
11842+
$$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT,"=",$1,$6,@2);
1184511843
}
1184611844
|a_exprISOF'('type_list')'%precIS
1184711845
{
@@ -12025,9 +12023,7 @@ b_expr:c_expr
1202512023
}
1202612024
|b_exprISNOTDISTINCTFROMb_expr%precIS
1202712025
{
12028-
$$ = makeNotExpr((Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
12029-
"=",$1,$6,@2),
12030-
@2);
12026+
$$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT,"=",$1,$6,@2);
1203112027
}
1203212028
|b_exprISOF'('type_list')'%precIS
1203312029
{

‎src/backend/parser/parse_expr.c

Lines changed: 58 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ static Node *make_row_distinct_op(ParseState *pstate, List *opname,
124124
RowExpr*lrow,RowExpr*rrow,intlocation);
125125
staticExpr*make_distinct_op(ParseState*pstate,List*opname,
126126
Node*ltree,Node*rtree,intlocation);
127+
staticNode*make_nulltest_from_distinct(ParseState*pstate,
128+
A_Expr*distincta,Node*arg);
127129
staticintoperator_precedence_group(Node*node,constchar**nodename);
128130
staticvoidemit_precedence_warnings(ParseState*pstate,
129131
intopgroup,constchar*opname,
@@ -224,6 +226,7 @@ transformExprRecurse(ParseState *pstate, Node *expr)
224226
result=transformAExprOpAll(pstate,a);
225227
break;
226228
caseAEXPR_DISTINCT:
229+
caseAEXPR_NOT_DISTINCT:
227230
result=transformAExprDistinct(pstate,a);
228231
break;
229232
caseAEXPR_NULLIF:
@@ -991,33 +994,55 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
991994
{
992995
Node*lexpr=a->lexpr;
993996
Node*rexpr=a->rexpr;
997+
Node*result;
994998

995999
if (operator_precedence_warning)
9961000
emit_precedence_warnings(pstate,PREC_GROUP_INFIX_IS,"IS",
9971001
lexpr,rexpr,
9981002
a->location);
9991003

1004+
/*
1005+
* If either input is an undecorated NULL literal, transform to a NullTest
1006+
* on the other input. That's simpler to process than a full DistinctExpr,
1007+
* and it avoids needing to require that the datatype have an = operator.
1008+
*/
1009+
if (exprIsNullConstant(rexpr))
1010+
returnmake_nulltest_from_distinct(pstate,a,lexpr);
1011+
if (exprIsNullConstant(lexpr))
1012+
returnmake_nulltest_from_distinct(pstate,a,rexpr);
1013+
10001014
lexpr=transformExprRecurse(pstate,lexpr);
10011015
rexpr=transformExprRecurse(pstate,rexpr);
10021016

10031017
if (lexpr&&IsA(lexpr,RowExpr)&&
10041018
rexpr&&IsA(rexpr,RowExpr))
10051019
{
10061020
/* ROW() op ROW() is handled specially */
1007-
returnmake_row_distinct_op(pstate,a->name,
1008-
(RowExpr*)lexpr,
1009-
(RowExpr*)rexpr,
1010-
a->location);
1021+
result=make_row_distinct_op(pstate,a->name,
1022+
(RowExpr*)lexpr,
1023+
(RowExpr*)rexpr,
1024+
a->location);
10111025
}
10121026
else
10131027
{
10141028
/* Ordinary scalar operator */
1015-
return (Node*)make_distinct_op(pstate,
1016-
a->name,
1017-
lexpr,
1018-
rexpr,
1019-
a->location);
1029+
result= (Node*)make_distinct_op(pstate,
1030+
a->name,
1031+
lexpr,
1032+
rexpr,
1033+
a->location);
10201034
}
1035+
1036+
/*
1037+
* If it's NOT DISTINCT, we first build a DistinctExpr and then stick a
1038+
* NOT on top.
1039+
*/
1040+
if (a->kind==AEXPR_NOT_DISTINCT)
1041+
result= (Node*)makeBoolExpr(NOT_EXPR,
1042+
list_make1(result),
1043+
a->location);
1044+
1045+
returnresult;
10211046
}
10221047

10231048
staticNode*
@@ -2869,6 +2894,28 @@ make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
28692894
returnresult;
28702895
}
28712896

2897+
/*
2898+
* Produce a NullTest node from an IS [NOT] DISTINCT FROM NULL construct
2899+
*
2900+
* "arg" is the untransformed other argument
2901+
*/
2902+
staticNode*
2903+
make_nulltest_from_distinct(ParseState*pstate,A_Expr*distincta,Node*arg)
2904+
{
2905+
NullTest*nt=makeNode(NullTest);
2906+
2907+
nt->arg= (Expr*)transformExprRecurse(pstate,arg);
2908+
/* the argument can be any type, so don't coerce it */
2909+
if (distincta->kind==AEXPR_NOT_DISTINCT)
2910+
nt->nulltesttype=IS_NULL;
2911+
else
2912+
nt->nulltesttype=IS_NOT_NULL;
2913+
/* argisrow = false is correct whether or not arg is composite */
2914+
nt->argisrow= false;
2915+
nt->location=distincta->location;
2916+
return (Node*)nt;
2917+
}
2918+
28722919
/*
28732920
* Identify node's group for operator precedence warnings
28742921
*
@@ -2971,7 +3018,8 @@ operator_precedence_group(Node *node, const char **nodename)
29713018
*nodename=strVal(llast(aexpr->name));
29723019
group=PREC_GROUP_POSTFIX_OP;
29733020
}
2974-
elseif (aexpr->kind==AEXPR_DISTINCT)
3021+
elseif (aexpr->kind==AEXPR_DISTINCT||
3022+
aexpr->kind==AEXPR_NOT_DISTINCT)
29753023
{
29763024
*nodename="IS";
29773025
group=PREC_GROUP_INFIX_IS;

‎src/include/nodes/parsenodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,7 @@ typedef enum A_Expr_Kind
237237
AEXPR_OP_ANY,/* scalar op ANY (array) */
238238
AEXPR_OP_ALL,/* scalar op ALL (array) */
239239
AEXPR_DISTINCT,/* IS DISTINCT FROM - name must be "=" */
240+
AEXPR_NOT_DISTINCT,/* IS NOT DISTINCT FROM - name must be "=" */
240241
AEXPR_NULLIF,/* NULLIF - name must be "=" */
241242
AEXPR_OF,/* IS [NOT] OF - name must be "=" or "<>" */
242243
AEXPR_IN,/* [NOT] IN - name must be "=" or "<>" */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp