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:
@ -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
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user