1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-03 20:02:46 +03:00

Pass collations to functions in FunctionCallInfoData, not FmgrInfo.

Since collation is effectively an argument, not a property of the function,
FmgrInfo is really the wrong place for it; and this becomes critical in
cases where a cached FmgrInfo is used for varying purposes that might need
different collation settings.  Fix by passing it in FunctionCallInfoData
instead.  In particular this allows a clean fix for bug #5970 (record_cmp
not working).  This requires touching a bit more code than the original
method, but nobody ever thought that collations would not be an invasive
patch...
This commit is contained in:
Tom Lane
2011-04-12 19:19:24 -04:00
parent 88543ecfec
commit d64713df7e
49 changed files with 552 additions and 418 deletions

View File

@ -3,6 +3,10 @@
* execGrouping.c
* executor utility routines for grouping, hashing, and aggregation
*
* Note: we currently assume that equality and hashing functions are not
* collation-sensitive, so the code in this file has no support for passing
* collation settings through from callers. That may have to change someday.
*
* Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*

View File

@ -1202,12 +1202,12 @@ init_fcache(Oid foid, Oid input_collation, FuncExprState *fcache,
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(foid, &(fcache->func), fcacheCxt);
fmgr_info_set_collation(input_collation, &(fcache->func));
fmgr_info_set_expr((Node *) fcache->xprstate.expr, &(fcache->func));
/* Initialize the function call parameter struct as well */
InitFunctionCallInfoData(fcache->fcinfo_data, &(fcache->func),
list_length(fcache->args), NULL, NULL);
list_length(fcache->args),
input_collation, NULL, NULL);
/* If function returns set, prepare expected tuple descriptor */
if (fcache->func.fn_retset && needDescForSets)
@ -1980,6 +1980,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
returnsSet = fcache->func.fn_retset;
InitFunctionCallInfoData(fcinfo, &(fcache->func),
list_length(fcache->args),
fcache->fcinfo_data.fncollation,
NULL, (Node *) &rsinfo);
/*
@ -2017,7 +2018,7 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
{
/* Treat funcexpr as a generic expression */
direct_function_call = false;
InitFunctionCallInfoData(fcinfo, NULL, 0, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 0, InvalidOid, NULL, NULL);
}
/*
@ -3154,6 +3155,7 @@ ExecEvalRowCompare(RowCompareExprState *rstate,
FunctionCallInfoData locfcinfo;
InitFunctionCallInfoData(locfcinfo, &(rstate->funcs[i]), 2,
rstate->collations[i],
NULL, NULL);
locfcinfo.arg[0] = ExecEvalExpr(le, econtext,
&locfcinfo.argnull[0], NULL);
@ -3234,7 +3236,9 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone)
{
Datum result = (Datum) 0;
MinMaxOp op = ((MinMaxExpr *) minmaxExpr->xprstate.expr)->op;
MinMaxExpr *minmax = (MinMaxExpr *) minmaxExpr->xprstate.expr;
Oid collation = minmax->inputcollid;
MinMaxOp op = minmax->op;
FunctionCallInfoData locfcinfo;
ListCell *arg;
@ -3242,7 +3246,8 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
*isDone = ExprSingleResult;
*isNull = true; /* until we get a result */
InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2, NULL, NULL);
InitFunctionCallInfoData(locfcinfo, &minmaxExpr->cfunc, 2,
collation, NULL, NULL);
locfcinfo.argnull[0] = false;
locfcinfo.argnull[1] = false;
@ -4115,7 +4120,6 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
/* Set up the primary fmgr lookup information */
fmgr_info_cxt(acoerce->elemfuncid, &(astate->elemfunc),
econtext->ecxt_per_query_memory);
/* Note: coercion functions are assumed to not use collation */
fmgr_info_set_expr((Node *) acoerce, &(astate->elemfunc));
}
@ -4124,9 +4128,11 @@ ExecEvalArrayCoerceExpr(ArrayCoerceExprState *astate,
*
* We pass on the desttypmod and isExplicit flags whether or not the
* function wants them.
*
* Note: coercion functions are assumed to not use collation.
*/
InitFunctionCallInfoData(locfcinfo, &(astate->elemfunc), 3,
NULL, NULL);
InvalidOid, NULL, NULL);
locfcinfo.arg[0] = PointerGetDatum(array);
locfcinfo.arg[1] = Int32GetDatum(acoerce->resulttypmod);
locfcinfo.arg[2] = BoolGetDatum(acoerce->isExplicit);
@ -4699,6 +4705,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
rstate->rargs = outlist;
Assert(list_length(rcexpr->opfamilies) == nopers);
rstate->funcs = (FmgrInfo *) palloc(nopers * sizeof(FmgrInfo));
rstate->collations = (Oid *) palloc(nopers * sizeof(Oid));
i = 0;
forthree(l, rcexpr->opnos, l2, rcexpr->opfamilies, l3, rcexpr->inputcollids)
{
@ -4726,7 +4733,7 @@ ExecInitExpr(Expr *node, PlanState *parent)
* does this code.
*/
fmgr_info(proc, &(rstate->funcs[i]));
fmgr_info_set_collation(inputcollid, &(rstate->funcs[i]));
rstate->collations[i] = inputcollid;
i++;
}
state = (ExprState *) rstate;
@ -4786,8 +4793,6 @@ ExecInitExpr(Expr *node, PlanState *parent)
* code.
*/
fmgr_info(typentry->cmp_proc, &(mstate->cfunc));
fmgr_info_set_collation(minmaxexpr->inputcollid,
&(mstate->cfunc));
state = (ExprState *) mstate;
}
break;

View File

@ -1349,9 +1349,10 @@ index_recheck_constraint(Relation index, Oid *constr_procs,
if (existing_isnull[i])
return false;
if (!DatumGetBool(OidFunctionCall2(constr_procs[i],
existing_values[i],
new_values[i])))
if (!DatumGetBool(OidFunctionCall2Coll(constr_procs[i],
index->rd_indcollation[i],
existing_values[i],
new_values[i])))
return false;
}

View File

@ -127,7 +127,7 @@ static Node *sql_fn_param_ref(ParseState *pstate, ParamRef *pref);
static List *init_execution_state(List *queryTree_list,
SQLFunctionCachePtr fcache,
bool lazyEvalOK);
static void init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK);
static void init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK);
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
static void postquel_end(execution_state *es);
@ -363,7 +363,7 @@ init_execution_state(List *queryTree_list,
* Initialize the SQLFunctionCache for a SQL function
*/
static void
init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
init_sql_fcache(FmgrInfo *finfo, Oid collation, bool lazyEvalOK)
{
Oid foid = finfo->fn_oid;
Oid rettype;
@ -428,7 +428,7 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
*/
fcache->pinfo = prepare_sql_fn_parse_info(procedureTuple,
finfo->fn_expr,
finfo->fn_collation);
collation);
/*
* And of course we need the function body text.
@ -798,7 +798,7 @@ fmgr_sql(PG_FUNCTION_ARGS)
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
if (fcache == NULL)
{
init_sql_fcache(fcinfo->flinfo, lazyEvalOK);
init_sql_fcache(fcinfo->flinfo, PG_GET_COLLATION(), lazyEvalOK);
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
}
eslist = fcache->func_state;

View File

@ -130,6 +130,9 @@ typedef struct AggStatePerAggData
FmgrInfo transfn;
FmgrInfo finalfn;
/* Input collation derived for aggregate */
Oid aggCollation;
/* number of sorting columns */
int numSortCols;
@ -430,6 +433,7 @@ advance_transition_function(AggState *aggstate,
*/
InitFunctionCallInfoData(*fcinfo, &(peraggstate->transfn),
numArguments + 1,
peraggstate->aggCollation,
(void *) aggstate, NULL);
fcinfo->arg[0] = pergroupstate->transValue;
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
@ -597,6 +601,8 @@ process_ordered_aggregate_single(AggState *aggstate,
/*
* If DISTINCT mode, and not distinct from prior, skip it.
*
* Note: we assume equality functions don't care about collation.
*/
if (isDistinct &&
haveOldVal &&
@ -737,6 +743,7 @@ finalize_aggregate(AggState *aggstate,
FunctionCallInfoData fcinfo;
InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), 1,
peraggstate->aggCollation,
(void *) aggstate, NULL);
fcinfo.arg[0] = pergroupstate->transValue;
fcinfo.argnull[0] = pergroupstate->transValueIsNull;
@ -1676,16 +1683,16 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
&finalfnexpr);
fmgr_info(transfn_oid, &peraggstate->transfn);
fmgr_info_set_collation(aggref->inputcollid, &peraggstate->transfn);
fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
{
fmgr_info(finalfn_oid, &peraggstate->finalfn);
fmgr_info_set_collation(aggref->inputcollid, &peraggstate->finalfn);
fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
}
peraggstate->aggCollation = aggref->inputcollid;
get_typlenbyval(aggref->aggtype,
&peraggstate->resulttypeLen,
&peraggstate->resulttypeByVal);
@ -1833,8 +1840,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc);
fmgr_info(get_opcode(sortcl->eqop), &peraggstate->equalfns[i]);
fmgr_info_set_collation(aggref->inputcollid,
&peraggstate->equalfns[i]);
i++;
}
Assert(i == numDistinctCols);

View File

@ -973,7 +973,7 @@ ExecIndexBuildScanKeys(PlanState *planstate, Relation index, Index scanrelid,
this_scan_key->sk_flags = SK_ROW_HEADER;
this_scan_key->sk_attno = first_sub_key->sk_attno;
this_scan_key->sk_strategy = rc->rctype;
/* sk_subtype, sk_func not used in a header */
/* sk_subtype, sk_collation, sk_func not used in a header */
this_scan_key->sk_argument = PointerGetDatum(first_sub_key);
}
else if (IsA(clause, ScalarArrayOpExpr))

View File

@ -327,8 +327,9 @@ heap_compare_slots(MergeAppendState *node, SlotNumber slot1, SlotNumber slot2)
}
else
{
compare = DatumGetInt32(FunctionCall2(&scankey->sk_func,
datum1, datum2));
compare = DatumGetInt32(FunctionCall2Coll(&scankey->sk_func,
scankey->sk_collation,
datum1, datum2));
if (compare != 0)
{
if (scankey->sk_flags & SK_BT_DESC)

View File

@ -138,11 +138,12 @@ typedef struct MergeJoinClauseData
/*
* The comparison strategy in use, and the lookup info to let us call the
* btree comparison support function.
* btree comparison support function, and the collation to use.
*/
bool reverse; /* if true, negate the cmpfn's output */
bool nulls_first; /* if true, nulls sort low */
FmgrInfo cmpfinfo;
Oid collation;
} MergeJoinClauseData;
/* Result type for MJEvalOuterValues and MJEvalInnerValues */
@ -242,7 +243,6 @@ MJExamineQuals(List *mergeclauses,
/* Set up the fmgr lookup information */
fmgr_info(cmpproc, &(clause->cmpfinfo));
fmgr_info_set_collation(collation, &(clause->cmpfinfo));
/* Fill the additional comparison-strategy flags */
if (opstrategy == BTLessStrategyNumber)
@ -254,6 +254,9 @@ MJExamineQuals(List *mergeclauses,
clause->nulls_first = nulls_first;
/* ... and the collation too */
clause->collation = collation;
iClause++;
}
@ -429,7 +432,7 @@ MJCompare(MergeJoinState *mergestate)
* OK to call the comparison function.
*/
InitFunctionCallInfoData(fcinfo, &(clause->cmpfinfo), 2,
NULL, NULL);
clause->collation, NULL, NULL);
fcinfo.arg[0] = clause->ldatum;
fcinfo.arg[1] = clause->rdatum;
fcinfo.argnull[0] = false;

View File

@ -831,8 +831,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
/* Lookup the equality function (potentially cross-type) */
fmgr_info(opexpr->opfuncid, &sstate->cur_eq_funcs[i - 1]);
fmgr_info_set_collation(opexpr->inputcollid,
&sstate->cur_eq_funcs[i - 1]);
fmgr_info_set_expr((Node *) opexpr, &sstate->cur_eq_funcs[i - 1]);
/* Look up the equality function for the RHS type */
@ -841,8 +839,6 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent)
elog(ERROR, "could not find compatible hash operator for operator %u",
opexpr->opno);
fmgr_info(get_opcode(rhs_eq_oper), &sstate->tab_eq_funcs[i - 1]);
fmgr_info_set_collation(opexpr->inputcollid,
&sstate->tab_eq_funcs[i - 1]);
/* Lookup the associated hash functions */
if (!get_op_hash_functions(opexpr->opno,

View File

@ -81,6 +81,8 @@ typedef struct WindowStatePerFuncData
FmgrInfo flinfo; /* fmgr lookup data for window function */
Oid winCollation; /* collation derived for window function */
/*
* We need the len and byval info for the result of each function in order
* to know how to copy/delete values.
@ -289,6 +291,7 @@ advance_windowaggregate(WindowAggState *winstate,
*/
InitFunctionCallInfoData(*fcinfo, &(peraggstate->transfn),
numArguments + 1,
perfuncstate->winCollation,
(void *) winstate, NULL);
fcinfo->arg[0] = peraggstate->transValue;
fcinfo->argnull[0] = peraggstate->transValueIsNull;
@ -340,6 +343,7 @@ finalize_windowaggregate(WindowAggState *winstate,
FunctionCallInfoData fcinfo;
InitFunctionCallInfoData(fcinfo, &(peraggstate->finalfn), 1,
perfuncstate->winCollation,
(void *) winstate, NULL);
fcinfo.arg[0] = peraggstate->transValue;
fcinfo.argnull[0] = peraggstate->transValueIsNull;
@ -627,6 +631,7 @@ eval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate,
*/
InitFunctionCallInfoData(fcinfo, &(perfuncstate->flinfo),
perfuncstate->numArguments,
perfuncstate->winCollation,
(void *) perfuncstate->winobj, NULL);
/* Just in case, make all the regular argument slots be null */
memset(fcinfo.argnull, true, perfuncstate->numArguments);
@ -1561,9 +1566,10 @@ ExecInitWindowAgg(WindowAgg *node, EState *estate, int eflags)
fmgr_info_cxt(wfunc->winfnoid, &perfuncstate->flinfo,
econtext->ecxt_per_query_memory);
fmgr_info_set_collation(wfunc->inputcollid, &perfuncstate->flinfo);
fmgr_info_set_expr((Node *) wfunc, &perfuncstate->flinfo);
perfuncstate->winCollation = wfunc->inputcollid;
get_typlenbyval(wfunc->wintype,
&perfuncstate->resulttypeLen,
&perfuncstate->resulttypeByVal);
@ -1801,13 +1807,11 @@ initialize_peragg(WindowAggState *winstate, WindowFunc *wfunc,
&finalfnexpr);
fmgr_info(transfn_oid, &peraggstate->transfn);
fmgr_info_set_collation(wfunc->inputcollid, &peraggstate->transfn);
fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
if (OidIsValid(finalfn_oid))
{
fmgr_info(finalfn_oid, &peraggstate->finalfn);
fmgr_info_set_collation(wfunc->inputcollid, &peraggstate->finalfn);
fmgr_info_set_expr((Node *) finalfnexpr, &peraggstate->finalfn);
}