aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/nodes/nodeFuncs.c75
-rw-r--r--src/backend/optimizer/path/equivclass.c43
-rw-r--r--src/backend/optimizer/prep/prepunion.c10
-rw-r--r--src/backend/optimizer/util/clauses.c94
-rw-r--r--src/include/nodes/nodeFuncs.h3
5 files changed, 106 insertions, 119 deletions
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index d85ca9f7c50..9ce8f43385e 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -576,26 +576,75 @@ exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
}
/*
+ * applyRelabelType
+ * Add a RelabelType node if needed to make the expression expose
+ * the specified type, typmod, and collation.
+ *
+ * This is primarily intended to be used during planning. Therefore, it must
+ * maintain the post-eval_const_expressions invariants that there are not
+ * adjacent RelabelTypes, and that the tree is fully const-folded (hence,
+ * we mustn't return a RelabelType atop a Const). If we do find a Const,
+ * we'll modify it in-place if "overwrite_ok" is true; that should only be
+ * passed as true if caller knows the Const is newly generated.
+ */
+Node *
+applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid,
+ CoercionForm rformat, int rlocation, bool overwrite_ok)
+{
+ /*
+ * 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))
+ {
+ /* Modify the Const directly to preserve const-flatness. */
+ Const *con = (Const *) arg;
+
+ if (!overwrite_ok)
+ con = copyObject(con);
+ con->consttype = rtype;
+ con->consttypmod = rtypmod;
+ con->constcollid = rcollid;
+ /* We keep the Const's original location. */
+ 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;
+ }
+}
+
+/*
* relabel_to_typmod
* Add a RelabelType node that changes just the typmod of the expression.
*
- * This is primarily intended to be used during planning. Therefore, it
- * strips any existing RelabelType nodes to maintain the planner's invariant
- * that there are not adjacent RelabelTypes.
+ * Convenience function for a common usage of applyRelabelType.
*/
Node *
relabel_to_typmod(Node *expr, int32 typmod)
{
- Oid type = exprType(expr);
- Oid coll = exprCollation(expr);
-
- /* Strip any existing RelabelType node(s) */
- while (expr && IsA(expr, RelabelType))
- expr = (Node *) ((RelabelType *) expr)->arg;
-
- /* Apply new typmod, preserving the previous exposed type and collation */
- return (Node *) makeRelabelType((Expr *) expr, type, typmod, coll,
- COERCE_EXPLICIT_CAST);
+ return applyRelabelType(expr, exprType(expr), typmod, exprCollation(expr),
+ COERCE_EXPLICIT_CAST, -1, false);
}
/*
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index b99cec00cb7..b68a5a0ec71 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -490,10 +490,6 @@ process_equivalence(PlannerInfo *root,
* work to not label the collation at all in EC members, but this is risky
* since some parts of the system expect exprCollation() to deliver the
* right answer for a sort key.)
- *
- * Note this code assumes that the expression has already been through
- * eval_const_expressions, so there are no CollateExprs and no redundant
- * RelabelTypes.
*/
Expr *
canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
@@ -514,29 +510,24 @@ canonicalize_ec_expression(Expr *expr, Oid req_type, Oid req_collation)
exprCollation((Node *) expr) != req_collation)
{
/*
- * Strip any existing RelabelType, then add a new one if needed. This
- * is to preserve the invariant of no redundant RelabelTypes.
- *
- * If we have to change the exposed type of the stripped expression,
- * set typmod to -1 (since the new type may not have the same typmod
- * interpretation). If we only have to change collation, preserve the
- * exposed typmod.
+ * If we have to change the type of the expression, set typmod to -1,
+ * since the new type may not have the same typmod interpretation.
+ * When we only have to change collation, preserve the exposed typmod.
+ */
+ int32 req_typmod;
+
+ if (expr_type != req_type)
+ req_typmod = -1;
+ else
+ req_typmod = exprTypmod((Node *) expr);
+
+ /*
+ * Use applyRelabelType so that we preserve const-flatness. This is
+ * important since eval_const_expressions has already been applied.
*/
- while (expr && IsA(expr, RelabelType))
- expr = (Expr *) ((RelabelType *) expr)->arg;
-
- if (exprType((Node *) expr) != req_type)
- expr = (Expr *) makeRelabelType(expr,
- req_type,
- -1,
- req_collation,
- COERCE_IMPLICIT_CAST);
- else if (exprCollation((Node *) expr) != req_collation)
- expr = (Expr *) makeRelabelType(expr,
- req_type,
- exprTypmod((Node *) expr),
- req_collation,
- COERCE_IMPLICIT_CAST);
+ expr = (Expr *) applyRelabelType((Node *) expr,
+ req_type, req_typmod, req_collation,
+ COERCE_IMPLICIT_CAST, -1, false);
}
return expr;
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 2ebd4ea3320..745f443e5c2 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1200,13 +1200,9 @@ generate_setop_tlist(List *colTypes, List *colCollations,
* will reach the executor without any further processing.
*/
if (exprCollation(expr) != colColl)
- {
- expr = (Node *) makeRelabelType((Expr *) expr,
- exprType(expr),
- exprTypmod(expr),
- colColl,
- COERCE_IMPLICIT_CAST);
- }
+ expr = applyRelabelType(expr,
+ exprType(expr), exprTypmod(expr), colColl,
+ COERCE_IMPLICIT_CAST, -1, false);
tle = makeTargetEntry((Expr *) expr,
(AttrNumber) resno++,
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index e0b5580c207..95c051c4fee 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);
@@ -2819,12 +2816,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:
{
@@ -2971,12 +2969,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:
{
@@ -3478,12 +3477,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);
@@ -3617,58 +3617,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
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index 779906b9b77..9cc56eecaa3 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -36,6 +36,9 @@ typedef bool (*check_function_callback) (Oid func_id, void *context);
extern Oid exprType(const Node *expr);
extern int32 exprTypmod(const Node *expr);
extern bool exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod);
+extern Node *applyRelabelType(Node *arg, Oid rtype, int32 rtypmod, Oid rcollid,
+ CoercionForm rformat, int rlocation,
+ bool overwrite_ok);
extern Node *relabel_to_typmod(Node *expr, int32 typmod);
extern Node *strip_implicit_coercions(Node *node);
extern bool expression_returns_set(Node *clause);