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

Commit814a570

Browse files
committed
Suppress unnecessary RelabelType nodes in yet more cases.
Commita477bfc fixed eval_const_expressions() to ensure that itdidn't generate unnecessary RelabelType nodes, but I failed to noticethat some other places in the planner had the same issue. Reallynoplace in the planner should be using plain makeRelabelType(), forfear of generating expressions that should be equal() to semanticallyequivalent trees, but aren't.An example is that because canonicalize_ec_expression() failedto be careful about this, we could end up with an equivalence classcontaining both a plain Const, and a Const-with-RelabelTyperepresenting exactly the same value. So far as I can tell this led tono visible misbehavior, but we did waste a bunch of cycles generatingand evaluating "Const = Const-with-RelabelType" to prove such entriesare redundant.Hence, move the support function added bya477bfc to where it canbe more generally useful, and use it in the places where planner codepreviously used makeRelabelType.Back-patch to v12, like the previous patch. While I have no concreteevidence of any real misbehavior here, it's certainly possible thatI overlooked a case where equivalent expressions that aren't equal()could cause a user-visible problem. In any case carrying extraRelabelType nodes through planning to execution isn't very desirable.Discussion:https://postgr.es/m/1311836.1597781384@sss.pgh.pa.us
1 parentaecefff commit814a570

File tree

5 files changed

+106
-119
lines changed

5 files changed

+106
-119
lines changed

‎src/backend/nodes/nodeFuncs.c

Lines changed: 62 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -576,27 +576,76 @@ exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
576576
return false;
577577
}
578578

579+
/*
580+
* applyRelabelType
581+
*Add a RelabelType node if needed to make the expression expose
582+
*the specified type, typmod, and collation.
583+
*
584+
* This is primarily intended to be used during planning. Therefore, it must
585+
* maintain the post-eval_const_expressions invariants that there are not
586+
* adjacent RelabelTypes, and that the tree is fully const-folded (hence,
587+
* we mustn't return a RelabelType atop a Const). If we do find a Const,
588+
* we'll modify it in-place if "overwrite_ok" is true; that should only be
589+
* passed as true if caller knows the Const is newly generated.
590+
*/
591+
Node*
592+
applyRelabelType(Node*arg,Oidrtype,int32rtypmod,Oidrcollid,
593+
CoercionFormrformat,intrlocation,booloverwrite_ok)
594+
{
595+
/*
596+
* If we find stacked RelabelTypes (eg, from foo::int::oid) we can discard
597+
* all but the top one, and must do so to ensure that semantically
598+
* equivalent expressions are equal().
599+
*/
600+
while (arg&&IsA(arg,RelabelType))
601+
arg= (Node*) ((RelabelType*)arg)->arg;
602+
603+
if (arg&&IsA(arg,Const))
604+
{
605+
/* Modify the Const directly to preserve const-flatness. */
606+
Const*con= (Const*)arg;
607+
608+
if (!overwrite_ok)
609+
con=copyObject(con);
610+
con->consttype=rtype;
611+
con->consttypmod=rtypmod;
612+
con->constcollid=rcollid;
613+
/* We keep the Const's original location. */
614+
return (Node*)con;
615+
}
616+
elseif (exprType(arg)==rtype&&
617+
exprTypmod(arg)==rtypmod&&
618+
exprCollation(arg)==rcollid)
619+
{
620+
/* Sometimes we find a nest of relabels that net out to nothing. */
621+
returnarg;
622+
}
623+
else
624+
{
625+
/* Nope, gotta have a RelabelType. */
626+
RelabelType*newrelabel=makeNode(RelabelType);
627+
628+
newrelabel->arg= (Expr*)arg;
629+
newrelabel->resulttype=rtype;
630+
newrelabel->resulttypmod=rtypmod;
631+
newrelabel->resultcollid=rcollid;
632+
newrelabel->relabelformat=rformat;
633+
newrelabel->location=rlocation;
634+
return (Node*)newrelabel;
635+
}
636+
}
637+
579638
/*
580639
* relabel_to_typmod
581640
*Add a RelabelType node that changes just the typmod of the expression.
582641
*
583-
* This is primarily intended to be used during planning. Therefore, it
584-
* strips any existing RelabelType nodes to maintain the planner's invariant
585-
* that there are not adjacent RelabelTypes.
642+
* Convenience function for a common usage of applyRelabelType.
586643
*/
587644
Node*
588645
relabel_to_typmod(Node*expr,int32typmod)
589646
{
590-
Oidtype=exprType(expr);
591-
Oidcoll=exprCollation(expr);
592-
593-
/* Strip any existing RelabelType node(s) */
594-
while (expr&&IsA(expr,RelabelType))
595-
expr= (Node*) ((RelabelType*)expr)->arg;
596-
597-
/* Apply new typmod, preserving the previous exposed type and collation */
598-
return (Node*)makeRelabelType((Expr*)expr,type,typmod,coll,
599-
COERCE_EXPLICIT_CAST);
647+
returnapplyRelabelType(expr,exprType(expr),typmod,exprCollation(expr),
648+
COERCE_EXPLICIT_CAST,-1, false);
600649
}
601650

602651
/*

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

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -485,10 +485,6 @@ process_equivalence(PlannerInfo *root,
485485
* work to not label the collation at all in EC members, but this is risky
486486
* since some parts of the system expect exprCollation() to deliver the
487487
* right answer for a sort key.)
488-
*
489-
* Note this code assumes that the expression has already been through
490-
* eval_const_expressions, so there are no CollateExprs and no redundant
491-
* RelabelTypes.
492488
*/
493489
Expr*
494490
canonicalize_ec_expression(Expr*expr,Oidreq_type,Oidreq_collation)
@@ -509,29 +505,24 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
509505
exprCollation((Node*)expr)!=req_collation)
510506
{
511507
/*
512-
* Strip any existing RelabelType, then add a new one if needed. This
513-
* is to preserve the invariant of no redundant RelabelTypes.
514-
*
515-
* If we have to change the exposed type of the stripped expression,
516-
* set typmod to -1 (since the new type may not have the same typmod
517-
* interpretation). If we only have to change collation, preserve the
518-
* exposed typmod.
508+
* If we have to change the type of the expression, set typmod to -1,
509+
* since the new type may not have the same typmod interpretation.
510+
* When we only have to change collation, preserve the exposed typmod.
511+
*/
512+
int32req_typmod;
513+
514+
if (expr_type!=req_type)
515+
req_typmod=-1;
516+
else
517+
req_typmod=exprTypmod((Node*)expr);
518+
519+
/*
520+
* Use applyRelabelType so that we preserve const-flatness. This is
521+
* important since eval_const_expressions has already been applied.
519522
*/
520-
while (expr&&IsA(expr,RelabelType))
521-
expr= (Expr*) ((RelabelType*)expr)->arg;
522-
523-
if (exprType((Node*)expr)!=req_type)
524-
expr= (Expr*)makeRelabelType(expr,
525-
req_type,
526-
-1,
527-
req_collation,
528-
COERCE_IMPLICIT_CAST);
529-
elseif (exprCollation((Node*)expr)!=req_collation)
530-
expr= (Expr*)makeRelabelType(expr,
531-
req_type,
532-
exprTypmod((Node*)expr),
533-
req_collation,
534-
COERCE_IMPLICIT_CAST);
523+
expr= (Expr*)applyRelabelType((Node*)expr,
524+
req_type,req_typmod,req_collation,
525+
COERCE_IMPLICIT_CAST,-1, false);
535526
}
536527

537528
returnexpr;

‎src/backend/optimizer/prep/prepunion.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,13 +1195,9 @@ generate_setop_tlist(List *colTypes, List *colCollations,
11951195
* will reach the executor without any further processing.
11961196
*/
11971197
if (exprCollation(expr)!=colColl)
1198-
{
1199-
expr= (Node*)makeRelabelType((Expr*)expr,
1200-
exprType(expr),
1201-
exprTypmod(expr),
1202-
colColl,
1203-
COERCE_IMPLICIT_CAST);
1204-
}
1198+
expr=applyRelabelType(expr,
1199+
exprType(expr),exprTypmod(expr),colColl,
1200+
COERCE_IMPLICIT_CAST,-1, false);
12051201

12061202
tle=makeTargetEntry((Expr*)expr,
12071203
(AttrNumber)resno++,

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

Lines changed: 21 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,6 @@ static Node *eval_const_expressions_mutator(Node *node,
120120
staticboolcontain_non_const_walker(Node*node,void*context);
121121
staticboolece_function_is_safe(Oidfuncid,
122122
eval_const_expressions_context*context);
123-
staticNode*apply_const_relabel(Node*arg,Oidrtype,
124-
int32rtypmod,Oidrcollid,
125-
CoercionFormrformat,intrlocation);
126123
staticList*simplify_or_arguments(List*args,
127124
eval_const_expressions_context*context,
128125
bool*haveNull,bool*forceTrue);
@@ -2821,12 +2818,13 @@ eval_const_expressions_mutator(Node *node,
28212818
arg=eval_const_expressions_mutator((Node*)relabel->arg,
28222819
context);
28232820
/* ... and attach a new RelabelType node, if needed */
2824-
returnapply_const_relabel(arg,
2825-
relabel->resulttype,
2826-
relabel->resulttypmod,
2827-
relabel->resultcollid,
2828-
relabel->relabelformat,
2829-
relabel->location);
2821+
returnapplyRelabelType(arg,
2822+
relabel->resulttype,
2823+
relabel->resulttypmod,
2824+
relabel->resultcollid,
2825+
relabel->relabelformat,
2826+
relabel->location,
2827+
true);
28302828
}
28312829
caseT_CoerceViaIO:
28322830
{
@@ -2973,12 +2971,13 @@ eval_const_expressions_mutator(Node *node,
29732971
arg=eval_const_expressions_mutator((Node*)collate->arg,
29742972
context);
29752973
/* ... and attach a new RelabelType node, if needed */
2976-
returnapply_const_relabel(arg,
2977-
exprType(arg),
2978-
exprTypmod(arg),
2979-
collate->collOid,
2980-
COERCE_IMPLICIT_CAST,
2981-
collate->location);
2974+
returnapplyRelabelType(arg,
2975+
exprType(arg),
2976+
exprTypmod(arg),
2977+
collate->collOid,
2978+
COERCE_IMPLICIT_CAST,
2979+
collate->location,
2980+
true);
29822981
}
29832982
caseT_CaseExpr:
29842983
{
@@ -3480,12 +3479,13 @@ eval_const_expressions_mutator(Node *node,
34803479
cdomain->resulttype);
34813480

34823481
/* Generate RelabelType to substitute for CoerceToDomain */
3483-
returnapply_const_relabel(arg,
3484-
cdomain->resulttype,
3485-
cdomain->resulttypmod,
3486-
cdomain->resultcollid,
3487-
cdomain->coercionformat,
3488-
cdomain->location);
3482+
returnapplyRelabelType(arg,
3483+
cdomain->resulttype,
3484+
cdomain->resulttypmod,
3485+
cdomain->resultcollid,
3486+
cdomain->coercionformat,
3487+
cdomain->location,
3488+
true);
34893489
}
34903490

34913491
newcdomain=makeNode(CoerceToDomain);
@@ -3618,58 +3618,6 @@ ece_function_is_safe(Oid funcid, eval_const_expressions_context *context)
36183618
return false;
36193619
}
36203620

3621-
/*
3622-
* Subroutine for eval_const_expressions: apply RelabelType if needed
3623-
*/
3624-
staticNode*
3625-
apply_const_relabel(Node*arg,Oidrtype,int32rtypmod,Oidrcollid,
3626-
CoercionFormrformat,intrlocation)
3627-
{
3628-
/*
3629-
* If we find stacked RelabelTypes (eg, from foo::int::oid) we can discard
3630-
* all but the top one, and must do so to ensure that semantically
3631-
* equivalent expressions are equal().
3632-
*/
3633-
while (arg&&IsA(arg,RelabelType))
3634-
arg= (Node*) ((RelabelType*)arg)->arg;
3635-
3636-
if (arg&&IsA(arg,Const))
3637-
{
3638-
/*
3639-
* If it's a Const, just modify it in-place; since this is part of
3640-
* eval_const_expressions, we want to end up with a simple Const not
3641-
* an expression tree. We assume the Const is newly generated and
3642-
* hence safe to modify.
3643-
*/
3644-
Const*con= (Const*)arg;
3645-
3646-
con->consttype=rtype;
3647-
con->consttypmod=rtypmod;
3648-
con->constcollid=rcollid;
3649-
return (Node*)con;
3650-
}
3651-
elseif (exprType(arg)==rtype&&
3652-
exprTypmod(arg)==rtypmod&&
3653-
exprCollation(arg)==rcollid)
3654-
{
3655-
/* Sometimes we find a nest of relabels that net out to nothing. */
3656-
returnarg;
3657-
}
3658-
else
3659-
{
3660-
/* Nope, gotta have a RelabelType. */
3661-
RelabelType*newrelabel=makeNode(RelabelType);
3662-
3663-
newrelabel->arg= (Expr*)arg;
3664-
newrelabel->resulttype=rtype;
3665-
newrelabel->resulttypmod=rtypmod;
3666-
newrelabel->resultcollid=rcollid;
3667-
newrelabel->relabelformat=rformat;
3668-
newrelabel->location=rlocation;
3669-
return (Node*)newrelabel;
3670-
}
3671-
}
3672-
36733621
/*
36743622
* Subroutine for eval_const_expressions: process arguments of an OR clause
36753623
*

‎src/include/nodes/nodeFuncs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ typedef bool (*check_function_callback) (Oid func_id, void *context);
3636
externOidexprType(constNode*expr);
3737
externint32exprTypmod(constNode*expr);
3838
externboolexprIsLengthCoercion(constNode*expr,int32*coercedTypmod);
39+
externNode*applyRelabelType(Node*arg,Oidrtype,int32rtypmod,Oidrcollid,
40+
CoercionFormrformat,intrlocation,
41+
booloverwrite_ok);
3942
externNode*relabel_to_typmod(Node*expr,int32typmod);
4043
externNode*strip_implicit_coercions(Node*node);
4144
externboolexpression_returns_set(Node*clause);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp