diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-03-19 20:29:08 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-03-19 20:30:08 -0400 |
commit | b310b6e31ce5aa9e456c43c0e8e93248b0c84c02 (patch) | |
tree | e5168fcfdb231a9889e87e309f38a9e0f05a7896 /src/backend/utils | |
parent | 025f4c72f029242a6aaf3f14bb6d7da4ce070f72 (diff) | |
download | postgresql-b310b6e31ce5aa9e456c43c0e8e93248b0c84c02.tar.gz postgresql-b310b6e31ce5aa9e456c43c0e8e93248b0c84c02.zip |
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/utils')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 25 | ||||
-rw-r--r-- | src/backend/utils/adt/selfuncs.c | 19 | ||||
-rw-r--r-- | src/backend/utils/fmgr/README | 13 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 36 | ||||
-rw-r--r-- | src/backend/utils/fmgr/funcapi.c | 25 | ||||
-rw-r--r-- | src/backend/utils/sort/tuplesort.c | 2 |
6 files changed, 68 insertions, 52 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index ac0c53a7f32..573c8dd4104 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -4869,6 +4869,16 @@ get_rule_expr(Node *node, deparse_context *context, } break; + case T_NullIfExpr: + { + NullIfExpr *nullifexpr = (NullIfExpr *) node; + + appendStringInfo(buf, "NULLIF("); + get_rule_expr((Node *) nullifexpr->args, context, true); + appendStringInfoChar(buf, ')'); + } + break; + case T_ScalarArrayOpExpr: { ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; @@ -5529,8 +5539,9 @@ get_rule_expr(Node *node, deparse_context *context, } if (xexpr->op == IS_XMLSERIALIZE) - appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type, - xexpr->typmod)); + appendStringInfo(buf, " AS %s", + format_type_with_typemod(xexpr->type, + xexpr->typmod)); if (xexpr->op == IS_DOCUMENT) appendStringInfoString(buf, " IS DOCUMENT"); else @@ -5538,16 +5549,6 @@ get_rule_expr(Node *node, deparse_context *context, } break; - case T_NullIfExpr: - { - NullIfExpr *nullifexpr = (NullIfExpr *) node; - - appendStringInfo(buf, "NULLIF("); - get_rule_expr((Node *) nullifexpr->args, context, true); - appendStringInfoChar(buf, ')'); - } - break; - case T_NullTest: { NullTest *ntest = (NullTest *) node; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index 5cad1b88ad5..33f300bfea2 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -285,7 +285,7 @@ var_eq_const(VariableStatData *vardata, Oid operator, FmgrInfo eqproc; fmgr_info(get_opcode(operator), &eqproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &eqproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc); for (i = 0; i < nvalues; i++) { @@ -515,7 +515,7 @@ scalarineqsel(PlannerInfo *root, Oid operator, bool isgt, stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple); fmgr_info(get_opcode(operator), &opproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &opproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc); /* * If we have most-common-values info, add up the fractions of the MCV @@ -1252,7 +1252,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype, bool negate) /* Try to use the histogram entries to get selectivity */ fmgr_info(get_opcode(operator), &opproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &opproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc); selec = histogram_selectivity(&vardata, &opproc, constval, true, 10, 1, &hist_size); @@ -1701,7 +1701,7 @@ scalararraysel(PlannerInfo *root, if (!oprsel) return (Selectivity) 0.5; fmgr_info(oprsel, &oprselproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &oprselproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &oprselproc); /* deconstruct the expression */ Assert(list_length(clause->args) == 2); @@ -1839,6 +1839,7 @@ scalararraysel(PlannerInfo *root, dummyexpr = makeNode(CaseTestExpr); dummyexpr->typeId = nominal_element_type; dummyexpr->typeMod = -1; + dummyexpr->collation = clause->inputcollid; args = list_make2(leftop, dummyexpr); if (is_join_clause) s2 = DatumGetFloat8(FunctionCall5(&oprselproc, @@ -2118,7 +2119,7 @@ eqjoinsel_inner(Oid operator, nmatches; fmgr_info(get_opcode(operator), &eqproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &eqproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc); hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool)); hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool)); @@ -2341,7 +2342,7 @@ eqjoinsel_semi(Oid operator, nmatches; fmgr_info(get_opcode(operator), &eqproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &eqproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc); hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool)); hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool)); @@ -4484,7 +4485,7 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop, FmgrInfo opproc; fmgr_info(get_opcode(sortop), &opproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &opproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc); for (i = 0; i < nvalues; i++) { @@ -5111,7 +5112,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata, if (cmpopr == InvalidOid) elog(ERROR, "no >= operator for opfamily %u", opfamily); fmgr_info(get_opcode(cmpopr), &opproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &opproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc); prefixsel = ineq_histogram_selectivity(root, vardata, &opproc, true, prefixcon->constvalue, @@ -5133,7 +5134,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata, if (cmpopr == InvalidOid) elog(ERROR, "no < operator for opfamily %u", opfamily); fmgr_info(get_opcode(cmpopr), &opproc); - fmgr_info_collation(DEFAULT_COLLATION_OID, &opproc); + fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc); greaterstrcon = make_greater_string(prefixcon, &opproc); if (greaterstrcon) diff --git a/src/backend/utils/fmgr/README b/src/backend/utils/fmgr/README index 72695fe197d..6647fe95f72 100644 --- a/src/backend/utils/fmgr/README +++ b/src/backend/utils/fmgr/README @@ -71,6 +71,7 @@ typedef struct bool fn_strict; /* function is "strict" (NULL in => NULL out) */ bool fn_retset; /* function returns a set (over multiple calls) */ unsigned char fn_stats; /* collect stats if track_functions > this */ + Oid fn_collation; /* collation that function should use */ void *fn_extra; /* extra space for use by handler */ MemoryContext fn_mcxt; /* memory context to store fn_extra in */ Node *fn_expr; /* expression parse tree for call, or NULL */ @@ -89,12 +90,16 @@ is the number of arguments expected by the function, fn_strict is its strictness flag, and fn_retset shows whether it returns a set; all of these values come from the function's pg_proc entry. fn_stats is also set up to control whether or not to track runtime statistics for calling -this function. If the function is being called as part of a SQL expression, +this function. + +fn_collation supplies the collation to use for collation-sensitive +functions. If the function is being called as part of a SQL expression, fn_expr will point to the expression parse tree for the function call; this can be used to extract parse-time knowledge about the actual arguments. - -FmgrInfo already exists in the current code, but has fewer fields. This -change should be transparent at the source-code level. +Note that these two fields really are information about the arguments +rather than information about the function, but it's proven to be more +convenient to keep them in FmgrInfo than in FunctionCallInfoData where +they might more logically go. During a call of a function, the following data structure is created diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index a115a29da4c..e193e560eab 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -192,7 +192,7 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt, * elogs. */ finfo->fn_oid = InvalidOid; - finfo->fn_collation = InvalidOid; + finfo->fn_collation = InvalidOid; /* caller may set this later */ finfo->fn_extra = NULL; finfo->fn_mcxt = mcxt; finfo->fn_expr = NULL; /* caller may set this later */ @@ -421,25 +421,6 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple) } /* - * Initialize the fn_collation field - */ -void -fmgr_info_collation(Oid collationId, FmgrInfo *finfo) -{ - finfo->fn_collation = collationId; -} - -/* - * Initialize the fn_expr field and set the collation based on it - */ -void -fmgr_info_expr(Node *expr, FmgrInfo *finfo) -{ - finfo->fn_expr = expr; - finfo->fn_collation = exprCollation(expr); -} - -/* * Fetch and validate the information record for the given external function. * The function is specified by a handle for the containing library * (obtained from load_external_function) as well as the function name. @@ -920,6 +901,7 @@ fmgr_security_definer(PG_FUNCTION_ARGS) fmgr_info_cxt_security(fcinfo->flinfo->fn_oid, &fcache->flinfo, fcinfo->flinfo->fn_mcxt, true); + fcache->flinfo.fn_collation = fcinfo->flinfo->fn_collation; fcache->flinfo.fn_expr = fcinfo->flinfo->fn_expr; tuple = SearchSysCache1(PROCOID, @@ -1293,6 +1275,11 @@ DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2, return result; } + +/* + * These are the same as DirectFunctionCallN except that a nonzero + * collation can be specified. No other fields of FmgrInfo are made valid. + */ Datum DirectFunctionCall1WithCollation(PGFunction func, Oid collation, Datum arg1) { @@ -1300,8 +1287,9 @@ DirectFunctionCall1WithCollation(PGFunction func, Oid collation, Datum arg1) FmgrInfo flinfo; Datum result; + MemSet(&flinfo, 0, sizeof(flinfo)); + flinfo.fn_collation = collation; InitFunctionCallInfoData(fcinfo, &flinfo, 1, NULL, NULL); - fcinfo.flinfo->fn_collation = collation; fcinfo.arg[0] = arg1; fcinfo.argnull[0] = false; @@ -1316,14 +1304,16 @@ DirectFunctionCall1WithCollation(PGFunction func, Oid collation, Datum arg1) } Datum -DirectFunctionCall2WithCollation(PGFunction func, Oid collation, Datum arg1, Datum arg2) +DirectFunctionCall2WithCollation(PGFunction func, Oid collation, + Datum arg1, Datum arg2) { FunctionCallInfoData fcinfo; FmgrInfo flinfo; Datum result; + MemSet(&flinfo, 0, sizeof(flinfo)); + flinfo.fn_collation = collation; InitFunctionCallInfoData(fcinfo, &flinfo, 2, NULL, NULL); - fcinfo.flinfo->fn_collation = collation; fcinfo.arg[0] = arg1; fcinfo.arg[1] = arg2; diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c index 321b4e7f8ff..cad4a371b7d 100644 --- a/src/backend/utils/fmgr/funcapi.c +++ b/src/backend/utils/fmgr/funcapi.c @@ -411,6 +411,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, bool have_anyenum = false; Oid anyelement_type = InvalidOid; Oid anyarray_type = InvalidOid; + Oid anycollation; int i; /* See if there are any polymorphic outputs; quick out if not */ @@ -468,6 +469,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, /* If nothing found, parser messed up */ if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type)) return false; + /* If needed, deduce one polymorphic type from the other */ if (have_anyelement_result && !OidIsValid(anyelement_type)) anyelement_type = resolve_generic_type(ANYELEMENTOID, @@ -486,6 +488,24 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, if (have_anyenum && !type_is_enum(anyelement_type)) return false; + /* + * Identify the collation to use for polymorphic OUT parameters. + * (It'll necessarily be the same for both anyelement and anyarray.) + */ + anycollation = get_typcollation(OidIsValid(anyelement_type) ? anyelement_type : anyarray_type); + if (OidIsValid(anycollation)) + { + /* + * The types are collatable, so consider whether to use a nondefault + * collation. We do so if we can identify the input collation used + * for the function. + */ + Oid inputcollation = exprInputCollation(call_expr); + + if (OidIsValid(inputcollation)) + anycollation = inputcollation; + } + /* And finally replace the tuple column types as needed */ for (i = 0; i < natts; i++) { @@ -499,6 +519,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, anyelement_type, -1, 0); + TupleDescInitEntryCollation(tupdesc, i + 1, anycollation); break; case ANYARRAYOID: TupleDescInitEntry(tupdesc, i + 1, @@ -506,13 +527,11 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args, anyarray_type, -1, 0); + TupleDescInitEntryCollation(tupdesc, i + 1, anycollation); break; default: break; } - /* Set collation based on actual argument types */ - TupleDescInitEntryCollation(tupdesc, i + 1, - exprCollation(call_expr)); } return true; diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index f2449ea6b13..56185fcabc7 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -836,7 +836,7 @@ tuplesort_begin_datum(Oid datumType, elog(ERROR, "operator %u is not a valid ordering operator", sortOperator); fmgr_info(sortFunction, &state->sortOpFn); - fmgr_info_collation(sortCollation, &state->sortOpFn); + fmgr_info_set_collation(sortCollation, &state->sortOpFn); /* set ordering flags */ state->sortFnFlags = reverse ? SK_BT_DESC : 0; |