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

Commit30d5c6b

Browse files
committed
Suppress unnecessary RelabelType nodes in more cases.
eval_const_expressions sometimes produced RelabelType nodes thatwere useless because they just relabeled an expression to the sameexposed type it already had. This is worth avoiding because it cancause two equivalent expressions to not be equal(), preventingrecognition of useful optimizations. In the test case added here,an unpatched planner fails to notice that the "sqli = constant" clauserenders a sort step unnecessary, because one code path produces anextra RelabelType and another doesn't.Fix by ensuring that eval_const_expressions_mutator's T_RelabelTypecase will not add in an unnecessary RelabelType. Also save somecode by sharing a subroutine with the effectively-equivalent casesfor CollateExpr and CoerceToDomain. (CollateExpr had no bug, andI think that the case couldn't arise with CoerceToDomain, butit seems prudent to do the same check for all three cases.)Back-patch to v12. In principle this has been wrong all along,but I haven't seen a case where it causes visible misbehaviorbefore v12, so refrain from changing stable branches unnecessarily.Per investigation of a report from Eric Gillum.Discussion:https://postgr.es/m/CAMmjdmvAZsUEskHYj=KT9sTukVVCiCSoe_PBKOXsncFeAUDPCQ@mail.gmail.com
1 parent902f40d commit30d5c6b

File tree

3 files changed

+101
-97
lines changed

3 files changed

+101
-97
lines changed

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

Lines changed: 82 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ static Node *eval_const_expressions_mutator(Node *node,
119119
staticboolcontain_non_const_walker(Node*node,void*context);
120120
staticboolece_function_is_safe(Oidfuncid,
121121
eval_const_expressions_context*context);
122+
staticNode*apply_const_relabel(Node*arg,Oidrtype,
123+
int32rtypmod,Oidrcollid,
124+
CoercionFormrformat,intrlocation);
122125
staticList*simplify_or_arguments(List*args,
123126
eval_const_expressions_context*context,
124127
bool*haveNull,bool*forceTrue);
@@ -2776,46 +2779,19 @@ eval_const_expressions_mutator(Node *node,
27762779
returnnode;
27772780
caseT_RelabelType:
27782781
{
2779-
/*
2780-
* If we can simplify the input to a constant, then we don't
2781-
* need the RelabelType node anymore: just change the type
2782-
* field of the Const node. Otherwise, must copy the
2783-
* RelabelType node.
2784-
*/
27852782
RelabelType*relabel= (RelabelType*)node;
27862783
Node*arg;
27872784

2785+
/* Simplify the input ... */
27882786
arg=eval_const_expressions_mutator((Node*)relabel->arg,
27892787
context);
2790-
2791-
/*
2792-
* If we find stacked RelabelTypes (eg, from foo :: int ::
2793-
* oid) we can discard all but the top one.
2794-
*/
2795-
while (arg&&IsA(arg,RelabelType))
2796-
arg= (Node*) ((RelabelType*)arg)->arg;
2797-
2798-
if (arg&&IsA(arg,Const))
2799-
{
2800-
Const*con= (Const*)arg;
2801-
2802-
con->consttype=relabel->resulttype;
2803-
con->consttypmod=relabel->resulttypmod;
2804-
con->constcollid=relabel->resultcollid;
2805-
return (Node*)con;
2806-
}
2807-
else
2808-
{
2809-
RelabelType*newrelabel=makeNode(RelabelType);
2810-
2811-
newrelabel->arg= (Expr*)arg;
2812-
newrelabel->resulttype=relabel->resulttype;
2813-
newrelabel->resulttypmod=relabel->resulttypmod;
2814-
newrelabel->resultcollid=relabel->resultcollid;
2815-
newrelabel->relabelformat=relabel->relabelformat;
2816-
newrelabel->location=relabel->location;
2817-
return (Node*)newrelabel;
2818-
}
2788+
/* ... and attach a new RelabelType node, if needed */
2789+
returnapply_const_relabel(arg,
2790+
relabel->resulttype,
2791+
relabel->resulttypmod,
2792+
relabel->resultcollid,
2793+
relabel->relabelformat,
2794+
relabel->location);
28192795
}
28202796
caseT_CoerceViaIO:
28212797
{
@@ -2949,48 +2925,25 @@ eval_const_expressions_mutator(Node *node,
29492925
caseT_CollateExpr:
29502926
{
29512927
/*
2952-
* If we can simplify the input to a constant, then we don't
2953-
* need the CollateExpr node at all: just change the
2954-
* constcollid field of the Const node. Otherwise, replace
2955-
* the CollateExpr with a RelabelType. (We do that so as to
2956-
* improve uniformity of expression representation and thus
2957-
* simplify comparison of expressions.)
2928+
* We replace CollateExpr with RelabelType, so as to improve
2929+
* uniformity of expression representation and thus simplify
2930+
* comparison of expressions. Hence this looks very nearly
2931+
* the same as the RelabelType case, and we can apply the same
2932+
* optimizations to avoid unnecessary RelabelTypes.
29582933
*/
29592934
CollateExpr*collate= (CollateExpr*)node;
29602935
Node*arg;
29612936

2937+
/* Simplify the input ... */
29622938
arg=eval_const_expressions_mutator((Node*)collate->arg,
29632939
context);
2964-
2965-
if (arg&&IsA(arg,Const))
2966-
{
2967-
Const*con= (Const*)arg;
2968-
2969-
con->constcollid=collate->collOid;
2970-
return (Node*)con;
2971-
}
2972-
elseif (collate->collOid==exprCollation(arg))
2973-
{
2974-
/* Don't need a RelabelType either... */
2975-
returnarg;
2976-
}
2977-
else
2978-
{
2979-
RelabelType*relabel=makeNode(RelabelType);
2980-
2981-
relabel->resulttype=exprType(arg);
2982-
relabel->resulttypmod=exprTypmod(arg);
2983-
relabel->resultcollid=collate->collOid;
2984-
relabel->relabelformat=COERCE_IMPLICIT_CAST;
2985-
relabel->location=collate->location;
2986-
2987-
/* Don't create stacked RelabelTypes */
2988-
while (arg&&IsA(arg,RelabelType))
2989-
arg= (Node*) ((RelabelType*)arg)->arg;
2990-
relabel->arg= (Expr*)arg;
2991-
2992-
return (Node*)relabel;
2993-
}
2940+
/* ... and attach a new RelabelType node, if needed */
2941+
returnapply_const_relabel(arg,
2942+
exprType(arg),
2943+
exprTypmod(arg),
2944+
collate->collOid,
2945+
COERCE_IMPLICIT_CAST,
2946+
collate->location);
29942947
}
29952948
caseT_CaseExpr:
29962949
{
@@ -3492,32 +3445,12 @@ eval_const_expressions_mutator(Node *node,
34923445
cdomain->resulttype);
34933446

34943447
/* Generate RelabelType to substitute for CoerceToDomain */
3495-
/* This should match the RelabelType logic above */
3496-
3497-
while (arg&&IsA(arg,RelabelType))
3498-
arg= (Node*) ((RelabelType*)arg)->arg;
3499-
3500-
if (arg&&IsA(arg,Const))
3501-
{
3502-
Const*con= (Const*)arg;
3503-
3504-
con->consttype=cdomain->resulttype;
3505-
con->consttypmod=cdomain->resulttypmod;
3506-
con->constcollid=cdomain->resultcollid;
3507-
return (Node*)con;
3508-
}
3509-
else
3510-
{
3511-
RelabelType*newrelabel=makeNode(RelabelType);
3512-
3513-
newrelabel->arg= (Expr*)arg;
3514-
newrelabel->resulttype=cdomain->resulttype;
3515-
newrelabel->resulttypmod=cdomain->resulttypmod;
3516-
newrelabel->resultcollid=cdomain->resultcollid;
3517-
newrelabel->relabelformat=cdomain->coercionformat;
3518-
newrelabel->location=cdomain->location;
3519-
return (Node*)newrelabel;
3520-
}
3448+
returnapply_const_relabel(arg,
3449+
cdomain->resulttype,
3450+
cdomain->resulttypmod,
3451+
cdomain->resultcollid,
3452+
cdomain->coercionformat,
3453+
cdomain->location);
35213454
}
35223455

35233456
newcdomain=makeNode(CoerceToDomain);
@@ -3650,6 +3583,58 @@ ece_function_is_safe(Oid funcid, eval_const_expressions_context *context)
36503583
return false;
36513584
}
36523585

3586+
/*
3587+
* Subroutine for eval_const_expressions: apply RelabelType if needed
3588+
*/
3589+
staticNode*
3590+
apply_const_relabel(Node*arg,Oidrtype,int32rtypmod,Oidrcollid,
3591+
CoercionFormrformat,intrlocation)
3592+
{
3593+
/*
3594+
* If we find stacked RelabelTypes (eg, from foo::int::oid) we can discard
3595+
* all but the top one, and must do so to ensure that semantically
3596+
* equivalent expressions are equal().
3597+
*/
3598+
while (arg&&IsA(arg,RelabelType))
3599+
arg= (Node*) ((RelabelType*)arg)->arg;
3600+
3601+
if (arg&&IsA(arg,Const))
3602+
{
3603+
/*
3604+
* If it's a Const, just modify it in-place; since this is part of
3605+
* eval_const_expressions, we want to end up with a simple Const not
3606+
* an expression tree. We assume the Const is newly generated and
3607+
* hence safe to modify.
3608+
*/
3609+
Const*con= (Const*)arg;
3610+
3611+
con->consttype=rtype;
3612+
con->consttypmod=rtypmod;
3613+
con->constcollid=rcollid;
3614+
return (Node*)con;
3615+
}
3616+
elseif (exprType(arg)==rtype&&
3617+
exprTypmod(arg)==rtypmod&&
3618+
exprCollation(arg)==rcollid)
3619+
{
3620+
/* Sometimes we find a nest of relabels that net out to nothing. */
3621+
returnarg;
3622+
}
3623+
else
3624+
{
3625+
/* Nope, gotta have a RelabelType. */
3626+
RelabelType*newrelabel=makeNode(RelabelType);
3627+
3628+
newrelabel->arg= (Expr*)arg;
3629+
newrelabel->resulttype=rtype;
3630+
newrelabel->resulttypmod=rtypmod;
3631+
newrelabel->resultcollid=rcollid;
3632+
newrelabel->relabelformat=rformat;
3633+
newrelabel->location=rlocation;
3634+
return (Node*)newrelabel;
3635+
}
3636+
}
3637+
36533638
/*
36543639
* Subroutine for eval_const_expressions: process arguments of an OR clause
36553640
*

‎src/test/regress/expected/equivclass.out

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,15 @@ explain (costs off)
439439
Filter: ((unique1 = unique1) OR (unique2 = unique2))
440440
(2 rows)
441441

442+
-- check that we recognize equivalence with dummy domains in the way
443+
create temp table undername (f1 name, f2 int);
444+
create temp view overview as
445+
select f1::information_schema.sql_identifier as sqli, f2 from undername;
446+
explain (costs off) -- this should not require a sort
447+
select * from overview where sqli = 'foo' order by sqli;
448+
QUERY PLAN
449+
------------------------------
450+
Seq Scan on undername
451+
Filter: (f1 = 'foo'::name)
452+
(2 rows)
453+

‎src/test/regress/sql/equivclass.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,10 @@ explain (costs off)
262262
-- this could be converted, but isn't at present
263263
explain (costs off)
264264
select*from tenk1where unique1= unique1or unique2= unique2;
265+
266+
-- check that we recognize equivalence with dummy domains in the way
267+
create temp table undername (f1 name, f2int);
268+
create temp view overviewas
269+
select f1::information_schema.sql_identifieras sqli, f2from undername;
270+
explain (costs off)-- this should not require a sort
271+
select*from overviewwhere sqli='foo'order by sqli;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp