summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
authorTom Lane2011-03-20 00:29:08 +0000
committerTom Lane2011-03-20 00:30:08 +0000
commitb310b6e31ce5aa9e456c43c0e8e93248b0c84c02 (patch)
treee5168fcfdb231a9889e87e309f38a9e0f05a7896 /src/backend/optimizer/util
parent025f4c72f029242a6aaf3f14bb6d7da4ce070f72 (diff)
Revise collation derivation method and expression-tree representation.
All expression nodes now have an explicit output-collation field, unless they are known to only return a noncollatable data type (such as boolean or record). Also, nodes that can invoke collation-aware functions store a separate field that is the collation value to pass to the function. This avoids confusion that arises when a function has collatable inputs and noncollatable output type, or vice versa. Also, replace the parser's on-the-fly collation assignment method with a post-pass over the completed expression tree. This allows us to use a more complex (and hopefully more nearly spec-compliant) assignment rule without paying for it in extra storage in every expression node. Fix assorted bugs in the planner's handling of collations by making collation one of the defining properties of an EquivalenceClass and by converting CollateExprs into discardable RelabelType nodes during expression preprocessing.
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c176
-rw-r--r--src/backend/optimizer/util/predtest.c14
2 files changed, 115 insertions, 75 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 8503792df44..7b31b6b4fa6 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -100,7 +100,8 @@ static List *simplify_and_arguments(List *args,
bool *haveNull, bool *forceFalse);
static Node *simplify_boolean_equality(Oid opno, List *args);
static Expr *simplify_function(Oid funcid,
- Oid result_type, int32 result_typmod, Oid collid, List **args,
+ Oid result_type, int32 result_typmod,
+ Oid input_collid, List **args,
bool has_named_args,
bool allow_inline,
eval_const_expressions_context *context);
@@ -114,8 +115,8 @@ static List *fetch_function_defaults(HeapTuple func_tuple);
static void recheck_cast_function_args(List *args, Oid result_type,
HeapTuple func_tuple);
static Expr *evaluate_function(Oid funcid,
- Oid result_type, int32 result_typmod, Oid collid, List *args,
- HeapTuple func_tuple,
+ Oid result_type, int32 result_typmod,
+ Oid input_collid, List *args, HeapTuple func_tuple,
eval_const_expressions_context *context);
static Expr *inline_function(Oid funcid, Oid result_type, List *args,
HeapTuple func_tuple,
@@ -139,12 +140,14 @@ static bool tlist_matches_coltypelist(List *tlist, List *coltypelist);
/*
* make_opclause
- * Creates an operator clause given its operator info, left operand,
- * and right operand (pass NULL to create single-operand clause).
+ * Creates an operator clause given its operator info, left operand
+ * and right operand (pass NULL to create single-operand clause),
+ * and collation info.
*/
Expr *
make_opclause(Oid opno, Oid opresulttype, bool opretset,
- Expr *leftop, Expr *rightop)
+ Expr *leftop, Expr *rightop,
+ Oid opcollid, Oid inputcollid)
{
OpExpr *expr = makeNode(OpExpr);
@@ -152,11 +155,12 @@ make_opclause(Oid opno, Oid opresulttype, bool opretset,
expr->opfuncid = InvalidOid;
expr->opresulttype = opresulttype;
expr->opretset = opretset;
+ expr->opcollid = opcollid;
+ expr->inputcollid = inputcollid;
if (rightop)
expr->args = list_make2(leftop, rightop);
else
expr->args = list_make1(leftop);
- expr->collid = select_common_collation(NULL, expr->args, false);
expr->location = -1;
return (Expr *) expr;
}
@@ -709,6 +713,8 @@ expression_returns_set_rows_walker(Node *node, double *count)
return false;
if (IsA(node, DistinctExpr))
return false;
+ if (IsA(node, NullIfExpr))
+ return false;
if (IsA(node, ScalarArrayOpExpr))
return false;
if (IsA(node, BoolExpr))
@@ -731,8 +737,6 @@ expression_returns_set_rows_walker(Node *node, double *count)
return false;
if (IsA(node, XmlExpr))
return false;
- if (IsA(node, NullIfExpr))
- return false;
return expression_tree_walker(node, expression_returns_set_rows_walker,
(void *) count);
@@ -826,6 +830,15 @@ contain_mutable_functions_walker(Node *node, void *context)
return true;
/* else fall through to check args */
}
+ else if (IsA(node, NullIfExpr))
+ {
+ NullIfExpr *expr = (NullIfExpr *) node;
+
+ set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
+ if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)
+ return true;
+ /* else fall through to check args */
+ }
else if (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
@@ -863,15 +876,6 @@ contain_mutable_functions_walker(Node *node, void *context)
return true;
/* else fall through to check args */
}
- else if (IsA(node, NullIfExpr))
- {
- NullIfExpr *expr = (NullIfExpr *) node;
-
- set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
- if (func_volatile(expr->opfuncid) != PROVOLATILE_IMMUTABLE)
- return true;
- /* else fall through to check args */
- }
else if (IsA(node, RowCompareExpr))
{
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
@@ -941,6 +945,15 @@ contain_volatile_functions_walker(Node *node, void *context)
return true;
/* else fall through to check args */
}
+ else if (IsA(node, NullIfExpr))
+ {
+ NullIfExpr *expr = (NullIfExpr *) node;
+
+ set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
+ if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
+ return true;
+ /* else fall through to check args */
+ }
else if (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
@@ -978,15 +991,6 @@ contain_volatile_functions_walker(Node *node, void *context)
return true;
/* else fall through to check args */
}
- else if (IsA(node, NullIfExpr))
- {
- NullIfExpr *expr = (NullIfExpr *) node;
-
- set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
- if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
- return true;
- /* else fall through to check args */
- }
else if (IsA(node, RowCompareExpr))
{
/* RowCompare probably can't have volatile ops, but check anyway */
@@ -1071,6 +1075,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
/* IS DISTINCT FROM is inherently non-strict */
return true;
}
+ if (IsA(node, NullIfExpr))
+ return true;
if (IsA(node, ScalarArrayOpExpr))
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
@@ -1119,8 +1125,6 @@ contain_nonstrict_functions_walker(Node *node, void *context)
return true;
if (IsA(node, XmlExpr))
return true;
- if (IsA(node, NullIfExpr))
- return true;
if (IsA(node, NullTest))
return true;
if (IsA(node, BooleanTest))
@@ -1874,6 +1878,7 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
/*
* Note: we need not change the opfamilies list; we assume any btree
* opfamily containing an operator will also contain its commutator.
+ * Collations don't change either.
*/
temp = clause->largs;
@@ -1986,7 +1991,8 @@ set_coercionform_dontcare_walker(Node *node, void *context)
*/
static bool
rowtype_field_matches(Oid rowtypeid, int fieldnum,
- Oid expectedtype, int32 expectedtypmod, Oid expectedcollation)
+ Oid expectedtype, int32 expectedtypmod,
+ Oid expectedcollation)
{
TupleDesc tupdesc;
Form_pg_attribute attr;
@@ -2144,12 +2150,12 @@ eval_const_expressions_mutator(Node *node,
else
pval = datumCopy(prm->value, typByVal, typLen);
cnst = makeConst(param->paramtype,
- param->paramtypmod,
- (int) typLen,
- pval,
- prm->isnull,
- typByVal);
- cnst->constcollid = param->paramcollation;
+ param->paramtypmod,
+ (int) typLen,
+ pval,
+ prm->isnull,
+ typByVal);
+ cnst->constcollid = param->paramcollid;
return (Node *) cnst;
}
}
@@ -2190,7 +2196,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->funcid,
expr->funcresulttype, exprTypmod(node),
- expr->collid,
+ expr->inputcollid,
&args,
has_named_args, true, context);
if (simple) /* successfully simplified it */
@@ -2207,8 +2213,9 @@ eval_const_expressions_mutator(Node *node,
newexpr->funcresulttype = expr->funcresulttype;
newexpr->funcretset = expr->funcretset;
newexpr->funcformat = expr->funcformat;
+ newexpr->funccollid = expr->funccollid;
+ newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
- newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@@ -2240,7 +2247,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
- expr->collid,
+ expr->inputcollid,
&args,
false, true, context);
if (simple) /* successfully simplified it */
@@ -2269,8 +2276,9 @@ eval_const_expressions_mutator(Node *node,
newexpr->opfuncid = expr->opfuncid;
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
+ newexpr->opcollid = expr->opcollid;
+ newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
- newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@@ -2335,7 +2343,7 @@ eval_const_expressions_mutator(Node *node,
*/
simple = simplify_function(expr->opfuncid,
expr->opresulttype, -1,
- expr->collid,
+ expr->inputcollid,
&args,
false, false, context);
if (simple) /* successfully simplified it */
@@ -2363,8 +2371,9 @@ eval_const_expressions_mutator(Node *node,
newexpr->opfuncid = expr->opfuncid;
newexpr->opresulttype = expr->opresulttype;
newexpr->opretset = expr->opretset;
+ newexpr->opcollid = expr->opcollid;
+ newexpr->inputcollid = expr->inputcollid;
newexpr->args = args;
- newexpr->collid = expr->collid;
newexpr->location = expr->location;
return (Node *) newexpr;
}
@@ -2473,6 +2482,7 @@ eval_const_expressions_mutator(Node *node,
con->consttype = relabel->resulttype;
con->consttypmod = relabel->resulttypmod;
+ con->constcollid = relabel->resultcollid;
return (Node *) con;
}
else
@@ -2482,6 +2492,7 @@ eval_const_expressions_mutator(Node *node,
newrelabel->arg = (Expr *) arg;
newrelabel->resulttype = relabel->resulttype;
newrelabel->resulttypmod = relabel->resulttypmod;
+ newrelabel->resultcollid = relabel->resultcollid;
newrelabel->relabelformat = relabel->relabelformat;
newrelabel->location = relabel->location;
return (Node *) newrelabel;
@@ -2511,12 +2522,16 @@ eval_const_expressions_mutator(Node *node,
* then the result type's input function. So, try to simplify it as
* though it were a stack of two such function calls. First we need
* to know what the functions are.
+ *
+ * Note that the coercion functions are assumed not to care about
+ * input collation, so we just pass InvalidOid for that.
*/
getTypeOutputInfo(exprType((Node *) arg), &outfunc, &outtypisvarlena);
getTypeInputInfo(expr->resulttype, &infunc, &intypioparam);
simple = simplify_function(outfunc,
- CSTRINGOID, -1, InvalidOid,
+ CSTRINGOID, -1,
+ InvalidOid,
&args,
false, true, context);
if (simple) /* successfully simplified output fn */
@@ -2533,11 +2548,9 @@ eval_const_expressions_mutator(Node *node,
Int32GetDatum(-1),
false, true));
- /* preserve collation of input expression */
simple = simplify_function(infunc,
- expr->resulttype,
- -1,
- exprCollation((Node *) arg),
+ expr->resulttype, -1,
+ InvalidOid,
&args,
false, true, context);
if (simple) /* successfully simplified input fn */
@@ -2552,6 +2565,7 @@ eval_const_expressions_mutator(Node *node,
newexpr = makeNode(CoerceViaIO);
newexpr->arg = arg;
newexpr->resulttype = expr->resulttype;
+ newexpr->resultcollid = expr->resultcollid;
newexpr->coerceformat = expr->coerceformat;
newexpr->location = expr->location;
return (Node *) newexpr;
@@ -2574,6 +2588,7 @@ eval_const_expressions_mutator(Node *node,
newexpr->elemfuncid = expr->elemfuncid;
newexpr->resulttype = expr->resulttype;
newexpr->resulttypmod = expr->resulttypmod;
+ newexpr->resultcollid = expr->resultcollid;
newexpr->isExplicit = expr->isExplicit;
newexpr->coerceformat = expr->coerceformat;
newexpr->location = expr->location;
@@ -2596,8 +2611,10 @@ eval_const_expressions_mutator(Node *node,
{
/*
* If we can simplify the input to a constant, then we don't need the
- * CollateExpr node anymore: just change the constcollid field of the
- * Const node. Otherwise, must copy the CollateExpr node.
+ * CollateExpr node at all: just change the constcollid field of the
+ * Const node. Otherwise, replace the CollateExpr with a RelabelType.
+ * (We do that so as to improve uniformity of expression representation
+ * and thus simplify comparison of expressions.)
*/
CollateExpr *collate = (CollateExpr *) node;
Node *arg;
@@ -2605,12 +2622,6 @@ eval_const_expressions_mutator(Node *node,
arg = eval_const_expressions_mutator((Node *) collate->arg,
context);
- /*
- * If we find stacked CollateExprs, we can discard all but the top one.
- */
- while (arg && IsA(arg, CollateExpr))
- arg = (Node *) ((CollateExpr *) arg)->arg;
-
if (arg && IsA(arg, Const))
{
Const *con = (Const *) arg;
@@ -2618,14 +2629,27 @@ eval_const_expressions_mutator(Node *node,
con->constcollid = collate->collOid;
return (Node *) con;
}
+ else if (collate->collOid == exprCollation(arg))
+ {
+ /* Don't need a RelabelType either... */
+ return arg;
+ }
else
{
- CollateExpr *newcollate = makeNode(CollateExpr);
+ RelabelType *relabel = makeNode(RelabelType);
+
+ relabel->resulttype = exprType(arg);
+ relabel->resulttypmod = exprTypmod(arg);
+ relabel->resultcollid = collate->collOid;
+ relabel->relabelformat = COERCE_DONTCARE;
+ relabel->location = collate->location;
+
+ /* Don't create stacked RelabelTypes */
+ while (arg && IsA(arg, RelabelType))
+ arg = (Node *) ((RelabelType *) arg)->arg;
+ relabel->arg = (Expr *) arg;
- newcollate->arg = (Expr *) arg;
- newcollate->collOid = collate->collOid;
- newcollate->location = collate->location;
- return (Node *) newcollate;
+ return (Node *) relabel;
}
}
if (IsA(node, CaseExpr))
@@ -2752,7 +2776,7 @@ eval_const_expressions_mutator(Node *node,
/* Otherwise we need a new CASE node */
newcase = makeNode(CaseExpr);
newcase->casetype = caseexpr->casetype;
- newcase->casecollation = caseexpr->casecollation;
+ newcase->casecollid = caseexpr->casecollid;
newcase->arg = (Expr *) newarg;
newcase->args = newargs;
newcase->defresult = (Expr *) defresult;
@@ -2793,6 +2817,7 @@ eval_const_expressions_mutator(Node *node,
newarray = makeNode(ArrayExpr);
newarray->array_typeid = arrayexpr->array_typeid;
+ newarray->array_collid = arrayexpr->array_collid;
newarray->element_typeid = arrayexpr->element_typeid;
newarray->elements = newelems;
newarray->multidims = arrayexpr->multidims;
@@ -2845,7 +2870,7 @@ eval_const_expressions_mutator(Node *node,
newcoalesce = makeNode(CoalesceExpr);
newcoalesce->coalescetype = coalesceexpr->coalescetype;
- newcoalesce->coalescecollation = coalesceexpr->coalescecollation;
+ newcoalesce->coalescecollid = coalesceexpr->coalescecollid;
newcoalesce->args = newargs;
newcoalesce->location = coalesceexpr->location;
return (Node *) newcoalesce;
@@ -2876,12 +2901,12 @@ eval_const_expressions_mutator(Node *node,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
- fselect->resultcollation))
+ fselect->resultcollid))
return (Node *) makeVar(((Var *) arg)->varno,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
- fselect->resultcollation,
+ fselect->resultcollid,
((Var *) arg)->varlevelsup);
}
if (arg && IsA(arg, RowExpr))
@@ -2898,10 +2923,10 @@ eval_const_expressions_mutator(Node *node,
fselect->fieldnum,
fselect->resulttype,
fselect->resulttypmod,
- fselect->resultcollation) &&
+ fselect->resultcollid) &&
fselect->resulttype == exprType(fld) &&
fselect->resulttypmod == exprTypmod(fld) &&
- fselect->resultcollation == exprCollation(fld))
+ fselect->resultcollid == exprCollation(fld))
return fld;
}
}
@@ -2910,7 +2935,7 @@ eval_const_expressions_mutator(Node *node,
newfselect->fieldnum = fselect->fieldnum;
newfselect->resulttype = fselect->resulttype;
newfselect->resulttypmod = fselect->resulttypmod;
- newfselect->resultcollation = fselect->resultcollation;
+ newfselect->resultcollid = fselect->resultcollid;
return (Node *) newfselect;
}
if (IsA(node, NullTest))
@@ -3355,7 +3380,8 @@ simplify_boolean_equality(Oid opno, List *args)
* (which might originally have been an operator; we don't care)
*
* Inputs are the function OID, actual result type OID (which is needed for
- * polymorphic functions) and typmod, and the pre-simplified argument list;
+ * polymorphic functions) and typmod, input collation to use for the function,
+ * the pre-simplified argument list, and some flags;
* also the context data for eval_const_expressions.
*
* Returns a simplified expression if successful, or NULL if cannot
@@ -3368,7 +3394,8 @@ simplify_boolean_equality(Oid opno, List *args)
* pass-by-reference, and it may get modified even if simplification fails.
*/
static Expr *
-simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
+simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
+ Oid input_collid,
List **args,
bool has_named_args,
bool allow_inline,
@@ -3399,7 +3426,8 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
else if (((Form_pg_proc) GETSTRUCT(func_tuple))->pronargs > list_length(*args))
*args = add_function_defaults(*args, result_type, func_tuple, context);
- newexpr = evaluate_function(funcid, result_type, result_typmod, collid, *args,
+ newexpr = evaluate_function(funcid, result_type, result_typmod,
+ input_collid, *args,
func_tuple, context);
if (!newexpr && allow_inline)
@@ -3650,9 +3678,8 @@ recheck_cast_function_args(List *args, Oid result_type, HeapTuple func_tuple)
* simplify the function.
*/
static Expr *
-evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
- List *args,
- HeapTuple func_tuple,
+evaluate_function(Oid funcid, Oid result_type, int32 result_typmod,
+ Oid input_collid, List *args, HeapTuple func_tuple,
eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
@@ -3733,8 +3760,9 @@ evaluate_function(Oid funcid, Oid result_type, int32 result_typmod, Oid collid,
newexpr->funcresulttype = result_type;
newexpr->funcretset = false;
newexpr->funcformat = COERCE_DONTCARE; /* doesn't matter */
+ newexpr->funccollid = InvalidOid; /* doesn't matter */
+ newexpr->inputcollid = input_collid;
newexpr->args = args;
- newexpr->collid = collid;
newexpr->location = -1;
return evaluate_expr((Expr *) newexpr, result_type, result_typmod);
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 4561e8e92f1..6a1f7291ba5 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -1345,6 +1345,8 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
*clause_const;
bool pred_var_on_left,
clause_var_on_left;
+ Oid pred_collation,
+ clause_collation;
Oid pred_op,
clause_op,
test_op;
@@ -1421,6 +1423,14 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
return false;
/*
+ * They'd better have the same collation, too.
+ */
+ pred_collation = ((OpExpr *) predicate)->inputcollid;
+ clause_collation = ((OpExpr *) clause)->inputcollid;
+ if (pred_collation != clause_collation)
+ return false;
+
+ /*
* Okay, get the operators in the two clauses we're comparing. Commute
* them if needed so that we can assume the variables are on the left.
*/
@@ -1465,7 +1475,9 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
BOOLOID,
false,
(Expr *) pred_const,
- (Expr *) clause_const);
+ (Expr *) clause_const,
+ InvalidOid,
+ pred_collation);
/* Fill in opfuncids */
fix_opfuncids((Node *) test_expr);