summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2020-08-19 14:07:49 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2020-08-19 14:07:49 -0400
commit814a57065ec97e44de58db61a16957ddd09938e8 (patch)
tree9d2ceeca7660d552fd141202c4f3a9a0cc74d2dd /src/backend/optimizer/util/clauses.c
parentaecefffc3f8041c883ab4fb035cf0d5519b5a7ed (diff)
Suppress unnecessary RelabelType nodes in yet more cases.
Commit a477bfc1d fixed eval_const_expressions() to ensure that it didn't generate unnecessary RelabelType nodes, but I failed to notice that some other places in the planner had the same issue. Really noplace in the planner should be using plain makeRelabelType(), for fear of generating expressions that should be equal() to semantically equivalent trees, but aren't. An example is that because canonicalize_ec_expression() failed to be careful about this, we could end up with an equivalence class containing both a plain Const, and a Const-with-RelabelType representing exactly the same value. So far as I can tell this led to no visible misbehavior, but we did waste a bunch of cycles generating and evaluating "Const = Const-with-RelabelType" to prove such entries are redundant. Hence, move the support function added by a477bfc1d to where it can be more generally useful, and use it in the places where planner code previously used makeRelabelType. Back-patch to v12, like the previous patch. While I have no concrete evidence of any real misbehavior here, it's certainly possible that I overlooked a case where equivalent expressions that aren't equal() could cause a user-visible problem. In any case carrying extra RelabelType nodes through planning to execution isn't very desirable. Discussion: https://postgr.es/m/1311836.1597781384@sss.pgh.pa.us
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c94
1 files changed, 21 insertions, 73 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 928752e6a9e..56435e76934 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -120,9 +120,6 @@ static Node *eval_const_expressions_mutator(Node *node,
static bool contain_non_const_walker(Node *node, void *context);
static bool ece_function_is_safe(Oid funcid,
eval_const_expressions_context *context);
-static Node *apply_const_relabel(Node *arg, Oid rtype,
- int32 rtypmod, Oid rcollid,
- CoercionForm rformat, int rlocation);
static List *simplify_or_arguments(List *args,
eval_const_expressions_context *context,
bool *haveNull, bool *forceTrue);
@@ -2821,12 +2818,13 @@ eval_const_expressions_mutator(Node *node,
arg = eval_const_expressions_mutator((Node *) relabel->arg,
context);
/* ... and attach a new RelabelType node, if needed */
- return apply_const_relabel(arg,
- relabel->resulttype,
- relabel->resulttypmod,
- relabel->resultcollid,
- relabel->relabelformat,
- relabel->location);
+ return applyRelabelType(arg,
+ relabel->resulttype,
+ relabel->resulttypmod,
+ relabel->resultcollid,
+ relabel->relabelformat,
+ relabel->location,
+ true);
}
case T_CoerceViaIO:
{
@@ -2973,12 +2971,13 @@ eval_const_expressions_mutator(Node *node,
arg = eval_const_expressions_mutator((Node *) collate->arg,
context);
/* ... and attach a new RelabelType node, if needed */
- return apply_const_relabel(arg,
- exprType(arg),
- exprTypmod(arg),
- collate->collOid,
- COERCE_IMPLICIT_CAST,
- collate->location);
+ return applyRelabelType(arg,
+ exprType(arg),
+ exprTypmod(arg),
+ collate->collOid,
+ COERCE_IMPLICIT_CAST,
+ collate->location,
+ true);
}
case T_CaseExpr:
{
@@ -3480,12 +3479,13 @@ eval_const_expressions_mutator(Node *node,
cdomain->resulttype);
/* Generate RelabelType to substitute for CoerceToDomain */
- return apply_const_relabel(arg,
- cdomain->resulttype,
- cdomain->resulttypmod,
- cdomain->resultcollid,
- cdomain->coercionformat,
- cdomain->location);
+ return applyRelabelType(arg,
+ cdomain->resulttype,
+ cdomain->resulttypmod,
+ cdomain->resultcollid,
+ cdomain->coercionformat,
+ cdomain->location,
+ true);
}
newcdomain = makeNode(CoerceToDomain);
@@ -3619,58 +3619,6 @@ ece_function_is_safe(Oid funcid, eval_const_expressions_context *context)
}
/*
- * Subroutine for eval_const_expressions: apply RelabelType if needed
- */
-static Node *
-apply_const_relabel(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid,
- CoercionForm rformat, int rlocation)
-{
- /*
- * If we find stacked RelabelTypes (eg, from foo::int::oid) we can discard
- * all but the top one, and must do so to ensure that semantically
- * equivalent expressions are equal().
- */
- while (arg && IsA(arg, RelabelType))
- arg = (Node *) ((RelabelType *) arg)->arg;
-
- if (arg && IsA(arg, Const))
- {
- /*
- * If it's a Const, just modify it in-place; since this is part of
- * eval_const_expressions, we want to end up with a simple Const not
- * an expression tree. We assume the Const is newly generated and
- * hence safe to modify.
- */
- Const *con = (Const *) arg;
-
- con->consttype = rtype;
- con->consttypmod = rtypmod;
- con->constcollid = rcollid;
- return (Node *) con;
- }
- else if (exprType(arg) == rtype &&
- exprTypmod(arg) == rtypmod &&
- exprCollation(arg) == rcollid)
- {
- /* Sometimes we find a nest of relabels that net out to nothing. */
- return arg;
- }
- else
- {
- /* Nope, gotta have a RelabelType. */
- RelabelType *newrelabel = makeNode(RelabelType);
-
- newrelabel->arg = (Expr *) arg;
- newrelabel->resulttype = rtype;
- newrelabel->resulttypmod = rtypmod;
- newrelabel->resultcollid = rcollid;
- newrelabel->relabelformat = rformat;
- newrelabel->location = rlocation;
- return (Node *) newrelabel;
- }
-}
-
-/*
* Subroutine for eval_const_expressions: process arguments of an OR clause
*
* This includes flattening of nested ORs as well as recursion to