1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-05 07:21:24 +03:00

Make equal() ignore CoercionForm fields for better planning with casts.

This change ensures that the planner will see implicit and explicit casts
as equivalent for all purposes, except in the minority of cases where
there's actually a semantic difference (as reflected by having a 3-argument
cast function).  In particular, this fixes cases where the EquivalenceClass
machinery failed to consider two references to a varchar column as
equivalent if one was implicitly cast to text but the other was explicitly
cast to text, as seen in bug #7598 from Vaclav Juza.  We have had similar
bugs before in other parts of the planner, so I think it's time to fix this
problem at the core instead of continuing to band-aid around it.

Remove set_coercionform_dontcare(), which represents the band-aid
previously in use for allowing matching of index and constraint expressions
with inconsistent cast labeling.  (We can probably get rid of
COERCE_DONTCARE altogether, but I don't think removing that enum value in
back branches would be wise; it's possible there's third party code
referring to it.)

Back-patch to 9.2.  We could go back further, and might want to once this
has been tested more; but for the moment I won't risk destabilizing plan
choices in long-since-stable branches.
This commit is contained in:
Tom Lane
2012-10-12 12:10:49 -04:00
parent e583ffe947
commit 71e58dcfb9
6 changed files with 17 additions and 132 deletions

View File

@ -98,7 +98,6 @@ static bool contain_leaky_functions_walker(Node *node, void *context);
static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
static List *find_nonnullable_vars_walker(Node *node, bool top_level);
static bool is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK);
static bool set_coercionform_dontcare_walker(Node *node, void *context);
static Node *eval_const_expressions_mutator(Node *node,
eval_const_expressions_context *context);
static List *simplify_or_arguments(List *args,
@ -2114,47 +2113,6 @@ strip_implicit_coercions(Node *node)
return node;
}
/*
* set_coercionform_dontcare: set all CoercionForm fields to COERCE_DONTCARE
*
* This is used to make index expressions and index predicates more easily
* comparable to clauses of queries. CoercionForm is not semantically
* significant (for cases where it does matter, the significant info is
* coded into the coercion function arguments) so we can ignore it during
* comparisons. Thus, for example, an index on "foo::int4" can match an
* implicit coercion to int4.
*
* Caution: the passed expression tree is modified in-place.
*/
void
set_coercionform_dontcare(Node *node)
{
(void) set_coercionform_dontcare_walker(node, NULL);
}
static bool
set_coercionform_dontcare_walker(Node *node, void *context)
{
if (node == NULL)
return false;
if (IsA(node, FuncExpr))
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
else if (IsA(node, RelabelType))
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
else if (IsA(node, CoerceViaIO))
((CoerceViaIO *) node)->coerceformat = COERCE_DONTCARE;
else if (IsA(node, ArrayCoerceExpr))
((ArrayCoerceExpr *) node)->coerceformat = COERCE_DONTCARE;
else if (IsA(node, ConvertRowtypeExpr))
((ConvertRowtypeExpr *) node)->convertformat = COERCE_DONTCARE;
else if (IsA(node, RowExpr))
((RowExpr *) node)->row_format = COERCE_DONTCARE;
else if (IsA(node, CoerceToDomain))
((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
return expression_tree_walker(node, set_coercionform_dontcare_walker,
context);
}
/*
* Helper for eval_const_expressions: check that datatype of an attribute
* is still what it was when the expression was parsed. This is needed to

View File

@ -665,12 +665,6 @@ get_relation_constraints(PlannerInfo *root,
cexpr = (Node *) canonicalize_qual((Expr *) cexpr);
/*
* Also mark any coercion format fields as "don't care", so that
* we can match to both explicit and implicit coercions.
*/
set_coercionform_dontcare(cexpr);
/* Fix Vars to have the desired varno */
if (varno != 1)
ChangeVarNodes(cexpr, 1, varno, 0);