diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 176 |
1 files changed, 102 insertions, 74 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); |