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

@ -121,7 +121,7 @@ gin_compare_prefix_##type(PG_FUNCTION_ARGS) \
int32 res, \
cmp; \
\
cmp = DatumGetInt32(DirectFunctionCall2WithCollation( \
cmp = DatumGetInt32(DirectFunctionCall2Coll( \
TypeInfo_##type.typecmp, \
DEFAULT_COLLATION_OID, \
(data->strategy == BTLessStrategyNumber || \

View File

@ -33,37 +33,55 @@ Datum gbt_text_same(PG_FUNCTION_ARGS);
static bool
gbt_textgt(const void *a, const void *b)
{
return (DatumGetBool(DirectFunctionCall2WithCollation(text_gt, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b))));
return DatumGetBool(DirectFunctionCall2Coll(text_gt,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static bool
gbt_textge(const void *a, const void *b)
{
return (DatumGetBool(DirectFunctionCall2WithCollation(text_ge, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b))));
return DatumGetBool(DirectFunctionCall2Coll(text_ge,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static bool
gbt_texteq(const void *a, const void *b)
{
return (DatumGetBool(DirectFunctionCall2WithCollation(texteq, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b))));
return DatumGetBool(DirectFunctionCall2Coll(texteq,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static bool
gbt_textle(const void *a, const void *b)
{
return (DatumGetBool(DirectFunctionCall2WithCollation(text_le, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b))));
return DatumGetBool(DirectFunctionCall2Coll(text_le,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static bool
gbt_textlt(const void *a, const void *b)
{
return (DatumGetBool(DirectFunctionCall2WithCollation(text_lt, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b))));
return DatumGetBool(DirectFunctionCall2Coll(text_lt,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static int32
gbt_textcmp(const bytea *a, const bytea *b)
{
return DatumGetInt32(DirectFunctionCall2WithCollation(bttextcmp, DEFAULT_COLLATION_OID, PointerGetDatum(a), PointerGetDatum(b)));
return DatumGetInt32(DirectFunctionCall2Coll(bttextcmp,
DEFAULT_COLLATION_OID,
PointerGetDatum(a),
PointerGetDatum(b)));
}
static gbtree_vinfo tinfo =

View File

@ -1206,7 +1206,7 @@ index_reloptions(RegProcedure amoptions, Datum reloptions, bool validate)
/* Can't use OidFunctionCallN because we might get a NULL result */
fmgr_info(amoptions, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 2, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 2, InvalidOid, NULL, NULL);
fcinfo.arg[0] = reloptions;
fcinfo.arg[1] = BoolGetDatum(validate);

View File

@ -42,11 +42,11 @@ ScanKeyEntryInitialize(ScanKey entry,
entry->sk_attno = attributeNumber;
entry->sk_strategy = strategy;
entry->sk_subtype = subtype;
entry->sk_collation = collation;
entry->sk_argument = argument;
if (RegProcedureIsValid(procedure))
{
fmgr_info(procedure, &entry->sk_func);
entry->sk_func.fn_collation = collation;
}
else
{
@ -83,9 +83,9 @@ ScanKeyInit(ScanKey entry,
entry->sk_attno = attributeNumber;
entry->sk_strategy = strategy;
entry->sk_subtype = InvalidOid;
entry->sk_collation = DEFAULT_COLLATION_OID;
entry->sk_argument = argument;
fmgr_info(procedure, &entry->sk_func);
entry->sk_func.fn_collation = DEFAULT_COLLATION_OID;
}
/*
@ -111,7 +111,7 @@ ScanKeyEntryInitializeWithInfo(ScanKey entry,
entry->sk_attno = attributeNumber;
entry->sk_strategy = strategy;
entry->sk_subtype = subtype;
entry->sk_collation = collation;
entry->sk_argument = argument;
fmgr_info_copy(&entry->sk_func, finfo, CurrentMemoryContext);
entry->sk_func.fn_collation = collation;
}

View File

@ -55,15 +55,16 @@ callConsistentFn(GinState *ginstate, GinScanKey key)
*/
key->recheckCurItem = true;
return DatumGetBool(FunctionCall8(&ginstate->consistentFn[key->attnum - 1],
PointerGetDatum(key->entryRes),
UInt16GetDatum(key->strategy),
key->query,
UInt32GetDatum(key->nuserentries),
PointerGetDatum(key->extra_data),
PointerGetDatum(&key->recheckCurItem),
PointerGetDatum(key->queryValues),
PointerGetDatum(key->queryCategories)));
return DatumGetBool(FunctionCall8Coll(&ginstate->consistentFn[key->attnum - 1],
ginstate->compareCollation[key->attnum - 1],
PointerGetDatum(key->entryRes),
UInt16GetDatum(key->strategy),
key->query,
UInt32GetDatum(key->nuserentries),
PointerGetDatum(key->extra_data),
PointerGetDatum(&key->recheckCurItem),
PointerGetDatum(key->queryValues),
PointerGetDatum(key->queryCategories)));
}
/*
@ -250,9 +251,10 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack,
* case cmp < 0 => not match and continue scan
*----------
*/
cmp = DatumGetInt32(FunctionCall4(&btree->ginstate->comparePartialFn[attnum - 1],
scanEntry->queryKey,
idatum,
cmp = DatumGetInt32(FunctionCall4Coll(&btree->ginstate->comparePartialFn[attnum - 1],
btree->ginstate->compareCollation[attnum - 1],
scanEntry->queryKey,
idatum,
UInt16GetDatum(scanEntry->strategy),
PointerGetDatum(scanEntry->extra_data)));
@ -1175,9 +1177,10 @@ matchPartialInPendingList(GinState *ginstate, Page page,
* case cmp < 0 => not match and continue scan
*----------
*/
cmp = DatumGetInt32(FunctionCall4(&ginstate->comparePartialFn[entry->attnum - 1],
entry->queryKey,
datum[off - 1],
cmp = DatumGetInt32(FunctionCall4Coll(&ginstate->comparePartialFn[entry->attnum - 1],
ginstate->compareCollation[entry->attnum - 1],
entry->queryKey,
datum[off - 1],
UInt16GetDatum(entry->strategy),
PointerGetDatum(entry->extra_data)));
if (cmp == 0)

View File

@ -63,23 +63,6 @@ initGinState(GinState *state, Relation index)
fmgr_info_copy(&(state->compareFn[i]),
index_getprocinfo(index, i + 1, GIN_COMPARE_PROC),
CurrentMemoryContext);
/*
* If the index column has a specified collation, index_getprocinfo
* will have installed it into the fmgr info, and we should honor it.
* However, we may have a collatable storage type for a noncollatable
* indexed data type (for instance, hstore uses text index entries).
* If there's no index collation then specify default collation in
* case the comparison function needs one. This is harmless if the
* comparison function doesn't care about collation, so we just do it
* unconditionally. (We could alternatively call get_typcollation,
* but that seems like expensive overkill --- there aren't going to be
* any cases where a GIN storage type has a nondefault collation.)
*/
if (!OidIsValid(state->compareFn[i].fn_collation))
fmgr_info_set_collation(DEFAULT_COLLATION_OID,
&(state->compareFn[i]));
fmgr_info_copy(&(state->extractValueFn[i]),
index_getprocinfo(index, i + 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext);
@ -98,18 +81,29 @@ initGinState(GinState *state, Relation index)
fmgr_info_copy(&(state->comparePartialFn[i]),
index_getprocinfo(index, i + 1, GIN_COMPARE_PARTIAL_PROC),
CurrentMemoryContext);
/* As above, install collation spec in case compare fn needs it */
if (!OidIsValid(state->comparePartialFn[i].fn_collation))
fmgr_info_set_collation(DEFAULT_COLLATION_OID,
&(state->comparePartialFn[i]));
state->canPartialMatch[i] = true;
}
else
{
state->canPartialMatch[i] = false;
}
/*
* If the index column has a specified collation, we should honor that
* while doing comparisons. However, we may have a collatable storage
* type for a noncollatable indexed data type (for instance, hstore
* uses text index entries). If there's no index collation then
* specify default collation in case the comparison function needs
* collation. This is harmless if the comparison function doesn't
* care about collation, so we just do it unconditionally. (We could
* alternatively call get_typcollation, but that seems like expensive
* overkill --- there aren't going to be any cases where a GIN storage
* type has a nondefault collation.)
*/
if (OidIsValid(index->rd_indcollation[i]))
state->compareCollation[i] = index->rd_indcollation[i];
else
state->compareCollation[i] = DEFAULT_COLLATION_OID;
}
}
@ -298,8 +292,9 @@ ginCompareEntries(GinState *ginstate, OffsetNumber attnum,
return 0;
/* both not null, so safe to call the compareFn */
return DatumGetInt32(FunctionCall2(&ginstate->compareFn[attnum - 1],
a, b));
return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1],
ginstate->compareCollation[attnum - 1],
a, b));
}
/*
@ -334,6 +329,7 @@ typedef struct
typedef struct
{
FmgrInfo *cmpDatumFunc;
Oid collation;
bool haveDups;
} cmpEntriesArg;
@ -355,8 +351,9 @@ cmpEntries(const void *a, const void *b, void *arg)
else if (bb->isnull)
res = -1; /* not-NULL "<" NULL */
else
res = DatumGetInt32(FunctionCall2(data->cmpDatumFunc,
aa->datum, bb->datum));
res = DatumGetInt32(FunctionCall2Coll(data->cmpDatumFunc,
data->collation,
aa->datum, bb->datum));
/*
* Detect if we have any duplicates. If there are equal keys, qsort must
@ -456,6 +453,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum,
}
arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1];
arg.collation = ginstate->compareCollation[attnum - 1];
arg.haveDups = false;
qsort_arg(keydata, *nentries, sizeof(keyEntryData),
cmpEntries, (void *) &arg);

View File

@ -137,12 +137,13 @@ gistindex_keytest(IndexScanDesc scan,
*/
recheck = true;
test = FunctionCall5(&key->sk_func,
PointerGetDatum(&de),
key->sk_argument,
Int32GetDatum(key->sk_strategy),
ObjectIdGetDatum(key->sk_subtype),
PointerGetDatum(&recheck));
test = FunctionCall5Coll(&key->sk_func,
key->sk_collation,
PointerGetDatum(&de),
key->sk_argument,
Int32GetDatum(key->sk_strategy),
ObjectIdGetDatum(key->sk_subtype),
PointerGetDatum(&recheck));
if (!DatumGetBool(test))
return false;
@ -195,11 +196,12 @@ gistindex_keytest(IndexScanDesc scan,
* can't tolerate lossy distance calculations on leaf tuples;
* there is no opportunity to re-sort the tuples afterwards.
*/
dist = FunctionCall4(&key->sk_func,
PointerGetDatum(&de),
key->sk_argument,
Int32GetDatum(key->sk_strategy),
ObjectIdGetDatum(key->sk_subtype));
dist = FunctionCall4Coll(&key->sk_func,
key->sk_collation,
PointerGetDatum(&de),
key->sk_argument,
Int32GetDatum(key->sk_strategy),
ObjectIdGetDatum(key->sk_subtype));
*distance_p = DatumGetFloat8(dist);
}

View File

@ -169,8 +169,7 @@ gistrescan(PG_FUNCTION_ARGS)
* comparisons. The original operator is passed to the Consistent
* function in the form of its strategy number, which is available
* from the sk_strategy field, and its subtype from the sk_subtype
* field. Also, preserve sk_func.fn_collation which is the input
* collation for the operator.
* field.
*
* Next, if any of keys is a NULL and that key is not marked with
* SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie, we
@ -181,10 +180,8 @@ gistrescan(PG_FUNCTION_ARGS)
for (i = 0; i < scan->numberOfKeys; i++)
{
ScanKey skey = scan->keyData + i;
Oid collation = skey->sk_func.fn_collation;
skey->sk_func = so->giststate->consistentFn[skey->sk_attno - 1];
skey->sk_func.fn_collation = collation;
if (skey->sk_flags & SK_ISNULL)
{
@ -205,16 +202,13 @@ gistrescan(PG_FUNCTION_ARGS)
* all comparisons. The original operator is passed to the Distance
* function in the form of its strategy number, which is available
* from the sk_strategy field, and its subtype from the sk_subtype
* field. Also, preserve sk_func.fn_collation which is the input
* collation for the operator.
* field.
*/
for (i = 0; i < scan->numberOfOrderBys; i++)
{
ScanKey skey = scan->orderByData + i;
Oid collation = skey->sk_func.fn_collation;
skey->sk_func = so->giststate->distanceFn[skey->sk_attno - 1];
skey->sk_func.fn_collation = collation;
/* Check we actually have a distance function ... */
if (!OidIsValid(skey->sk_func.fn_oid))

View File

@ -56,7 +56,8 @@ _hash_checkqual(IndexScanDesc scan, IndexTuple itup)
if (key->sk_flags & SK_ISNULL)
return false;
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
test = FunctionCall2Coll(&key->sk_func, key->sk_collation,
datum, key->sk_argument);
if (!DatumGetBool(test))
return false;

View File

@ -872,7 +872,6 @@ index_getprocinfo(Relation irel,
procnum, attnum, RelationGetRelationName(irel));
fmgr_info_cxt(procId, locinfo, irel->rd_indexcxt);
fmgr_info_set_collation(irel->rd_indcollation[attnum - 1], locinfo);
}
return locinfo;

View File

@ -2043,9 +2043,10 @@ _bt_isequal(TupleDesc itupdesc, Page page, OffsetNumber offnum,
if (isNull || (scankey->sk_flags & SK_ISNULL))
return false;
result = DatumGetInt32(FunctionCall2(&scankey->sk_func,
datum,
scankey->sk_argument));
result = DatumGetInt32(FunctionCall2Coll(&scankey->sk_func,
scankey->sk_collation,
datum,
scankey->sk_argument));
if (result != 0)
return false;

View File

@ -410,9 +410,10 @@ _bt_compare(Relation rel,
* to flip the sign of the comparison result. (Unless it's a DESC
* column, in which case we *don't* flip the sign.)
*/
result = DatumGetInt32(FunctionCall2(&scankey->sk_func,
datum,
scankey->sk_argument));
result = DatumGetInt32(FunctionCall2Coll(&scankey->sk_func,
scankey->sk_collation,
datum,
scankey->sk_argument));
if (!(scankey->sk_flags & SK_BT_DESC))
result = -result;
@ -721,7 +722,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
cur->sk_attno,
InvalidStrategy,
cur->sk_subtype,
cur->sk_func.fn_collation,
cur->sk_collation,
procinfo,
cur->sk_argument);
}
@ -742,7 +743,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
cur->sk_attno,
InvalidStrategy,
cur->sk_subtype,
cur->sk_func.fn_collation,
cur->sk_collation,
cmp_proc,
cur->sk_argument);
}

View File

@ -736,9 +736,11 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
}
else
{
compare = DatumGetInt32(FunctionCall2(&entry->sk_func,
attrDatum1,
attrDatum2));
compare =
DatumGetInt32(FunctionCall2Coll(&entry->sk_func,
entry->sk_collation,
attrDatum1,
attrDatum2));
if (entry->sk_flags & SK_BT_DESC)
compare = -compare;

View File

@ -70,8 +70,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
/*
* We can use the cached (default) support procs since no cross-type
* comparison can be needed. The cached support proc entries have the
* right collation for the index, too.
* comparison can be needed.
*/
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
arg = index_getattr(itup, i + 1, itupdesc, &null);
@ -81,7 +80,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
(AttrNumber) (i + 1),
InvalidStrategy,
InvalidOid,
procinfo->fn_collation,
rel->rd_indcollation[i],
procinfo,
arg);
}
@ -120,8 +119,7 @@ _bt_mkscankey_nodata(Relation rel)
/*
* We can use the cached (default) support procs since no cross-type
* comparison can be needed. The cached support proc entries have the
* right collation for the index, too.
* comparison can be needed.
*/
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
flags = SK_ISNULL | (indoption[i] << SK_BT_INDOPTION_SHIFT);
@ -130,7 +128,7 @@ _bt_mkscankey_nodata(Relation rel)
(AttrNumber) (i + 1),
InvalidStrategy,
InvalidOid,
procinfo->fn_collation,
rel->rd_indcollation[i],
procinfo,
(Datum) 0);
}
@ -604,9 +602,10 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
*/
if (lefttype == opcintype && righttype == optype)
{
*result = DatumGetBool(FunctionCall2(&op->sk_func,
leftarg->sk_argument,
rightarg->sk_argument));
*result = DatumGetBool(FunctionCall2Coll(&op->sk_func,
op->sk_collation,
leftarg->sk_argument,
rightarg->sk_argument));
return true;
}
@ -633,9 +632,10 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
if (RegProcedureIsValid(cmp_proc))
{
*result = DatumGetBool(OidFunctionCall2(cmp_proc,
leftarg->sk_argument,
rightarg->sk_argument));
*result = DatumGetBool(OidFunctionCall2Coll(cmp_proc,
op->sk_collation,
leftarg->sk_argument,
rightarg->sk_argument));
return true;
}
}
@ -689,6 +689,10 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
* Likewise, "x IS NOT NULL" is supported. We treat that as either "less
* than NULL" in a NULLS LAST index, or "greater than NULL" in a NULLS
* FIRST index.
*
* Note: someday we might have to fill in sk_collation from the index
* column's collation. At the moment this is a non-issue because we'll
* never actually call the comparison operator on a NULL.
*/
if (skey->sk_flags & SK_ISNULL)
{
@ -703,6 +707,7 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
{
skey->sk_strategy = BTEqualStrategyNumber;
skey->sk_subtype = InvalidOid;
skey->sk_collation = InvalidOid;
}
else if (skey->sk_flags & SK_SEARCHNOTNULL)
{
@ -711,6 +716,7 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
else
skey->sk_strategy = BTLessStrategyNumber;
skey->sk_subtype = InvalidOid;
skey->sk_collation = InvalidOid;
}
else
{
@ -976,7 +982,8 @@ _bt_checkkeys(IndexScanDesc scan,
return false;
}
test = FunctionCall2(&key->sk_func, datum, key->sk_argument);
test = FunctionCall2Coll(&key->sk_func, key->sk_collation,
datum, key->sk_argument);
if (!DatumGetBool(test))
{
@ -1099,9 +1106,10 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, TupleDesc tupdesc,
}
/* Perform the test --- three-way comparison not bool operator */
cmpresult = DatumGetInt32(FunctionCall2(&subkey->sk_func,
datum,
subkey->sk_argument));
cmpresult = DatumGetInt32(FunctionCall2Coll(&subkey->sk_func,
subkey->sk_collation,
datum,
subkey->sk_argument));
if (subkey->sk_flags & SK_BT_DESC)
cmpresult = -cmpresult;

View File

@ -1930,8 +1930,6 @@ compute_minimal_stats(VacAttrStatsP stats,
track_cnt = 0;
fmgr_info(mystats->eqfunc, &f_cmpeq);
/* We always use the default collation for statistics */
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &f_cmpeq);
for (i = 0; i < samplerows; i++)
{
@ -1990,7 +1988,10 @@ compute_minimal_stats(VacAttrStatsP stats,
firstcount1 = track_cnt;
for (j = 0; j < track_cnt; j++)
{
if (DatumGetBool(FunctionCall2(&f_cmpeq, value, track[j].value)))
/* We always use the default collation for statistics */
if (DatumGetBool(FunctionCall2Coll(&f_cmpeq,
DEFAULT_COLLATION_OID,
value, track[j].value)))
{
match = true;
break;
@ -2253,8 +2254,6 @@ compute_scalar_stats(VacAttrStatsP stats,
SelectSortFunction(mystats->ltopr, false, &cmpFn, &cmpFlags);
fmgr_info(cmpFn, &f_cmpfn);
/* We always use the default collation for statistics */
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &f_cmpfn);
/* Initial scan to find sortable values */
for (i = 0; i < samplerows; i++)
@ -2729,7 +2728,9 @@ compare_scalars(const void *a, const void *b, void *arg)
CompareScalarsContext *cxt = (CompareScalarsContext *) arg;
int32 compare;
/* We always use the default collation for statistics */
compare = ApplySortFunction(cxt->cmpFn, cxt->cmpFlags,
DEFAULT_COLLATION_OID,
da, false, db, false);
if (compare != 0)
return compare;

View File

@ -1822,7 +1822,8 @@ ExecCallTriggerFunc(TriggerData *trigdata,
/*
* Call the function, passing no arguments but setting a context.
*/
InitFunctionCallInfoData(fcinfo, finfo, 0, (Node *) trigdata, NULL);
InitFunctionCallInfoData(fcinfo, finfo, 0,
InvalidOid, (Node *) trigdata, NULL);
pgstat_init_function_usage(&fcinfo, &fcusage);

View File

@ -96,6 +96,11 @@ get_ts_parser_func(DefElem *defel, int attnum)
break;
case Anum_pg_ts_parser_prslextype:
nargs = 1;
/*
* Note: because the lextype method returns type internal, it must
* have an internal-type argument for security reasons. The
* argument is not actually used, but is just passed as a zero.
*/
break;
default:
/* should not be here */
@ -1947,7 +1952,7 @@ getTokenTypes(Oid prsId, List *tokennames)
elog(ERROR, "method lextype isn't defined for text search parser %u",
prsId);
/* OidFunctionCall0 is absent */
/* lextype takes one dummy argument */
list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
(Datum) 0));

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);
}

View File

@ -3189,8 +3189,7 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
if (oproid == InvalidOid)
elog(ERROR, "no < operator for opfamily %u", opfamily);
fmgr_info(get_opcode(oproid), &ltproc);
fmgr_info_set_collation(collation, &ltproc);
greaterstr = make_greater_string(prefix_const, &ltproc);
greaterstr = make_greater_string(prefix_const, &ltproc, collation);
if (greaterstr)
{
expr = make_opclause(oproid, BOOLOID, false,

View File

@ -349,8 +349,12 @@ HandleFunctionRequest(StringInfo msgBuf)
/*
* Prepare function call info block and insert arguments.
*
* Note: for now we pass collation = InvalidOid, so collation-sensitive
* functions can't be called this way. Perhaps we should pass
* DEFAULT_COLLATION_OID, instead?
*/
InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, InvalidOid, NULL, NULL);
if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);

View File

@ -54,7 +54,7 @@ tt_setup_firstcall(FuncCallContext *funcctx, Oid prsid)
st = (TSTokenTypeStorage *) palloc(sizeof(TSTokenTypeStorage));
st->cur = 0;
/* OidFunctionCall0 is absent */
/* lextype takes one dummy argument */
st->list = (LexDescr *) DatumGetPointer(OidFunctionCall1(prs->lextypeOid,
(Datum) 0));
funcctx->user_fctx = (void *) st;

View File

@ -3127,6 +3127,7 @@ array_eq(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
Oid collation = PG_GET_COLLATION();
int ndims1 = ARR_NDIM(array1);
int ndims2 = ARR_NDIM(array2);
int *dims1 = ARR_DIMS(array1);
@ -3184,7 +3185,7 @@ array_eq(PG_FUNCTION_ARGS)
* apply the operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
NULL, NULL);
collation, NULL, NULL);
/* Loop over source data */
nitems = ArrayGetNItems(ndims1, dims1);
@ -3367,8 +3368,7 @@ array_cmp(FunctionCallInfo fcinfo)
*/
typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra;
if (typentry == NULL ||
typentry->type_id != element_type ||
typentry->cmp_proc_finfo.fn_collation != collation)
typentry->type_id != element_type)
{
typentry = lookup_type_cache(element_type,
TYPECACHE_CMP_PROC_FINFO);
@ -3378,7 +3378,6 @@ array_cmp(FunctionCallInfo fcinfo)
errmsg("could not identify a comparison function for type %s",
format_type_be(element_type))));
fcinfo->flinfo->fn_extra = (void *) typentry;
typentry->cmp_proc_finfo.fn_collation = collation;
}
typlen = typentry->typlen;
typbyval = typentry->typbyval;
@ -3388,7 +3387,7 @@ array_cmp(FunctionCallInfo fcinfo)
* apply the operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
NULL, NULL);
collation, NULL, NULL);
/* Loop over source data */
min_nitems = Min(nitems1, nitems2);
@ -3573,7 +3572,7 @@ hash_array(PG_FUNCTION_ARGS)
* apply the hash function to each array element.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->hash_proc_finfo, 1,
NULL, NULL);
InvalidOid, NULL, NULL);
/* Loop over source data */
nitems = ArrayGetNItems(ndims, dims);
@ -3647,8 +3646,8 @@ hash_array(PG_FUNCTION_ARGS)
* When matchall is false, return true if any members of array1 are in array2.
*/
static bool
array_contain_compare(ArrayType *array1, ArrayType *array2, bool matchall,
void **fn_extra)
array_contain_compare(ArrayType *array1, ArrayType *array2, Oid collation,
bool matchall, void **fn_extra)
{
bool result = matchall;
Oid element_type = ARR_ELEMTYPE(array1);
@ -3707,7 +3706,7 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, bool matchall,
* Apply the comparison operator to each pair of array elements.
*/
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
NULL, NULL);
collation, NULL, NULL);
/* Loop over source data */
nelems1 = ArrayGetNItems(ARR_NDIM(array1), ARR_DIMS(array1));
@ -3811,9 +3810,10 @@ arrayoverlap(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
Oid collation = PG_GET_COLLATION();
bool result;
result = array_contain_compare(array1, array2, false,
result = array_contain_compare(array1, array2, collation, false,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
@ -3828,9 +3828,10 @@ arraycontains(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
Oid collation = PG_GET_COLLATION();
bool result;
result = array_contain_compare(array2, array1, true,
result = array_contain_compare(array2, array1, collation, true,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */
@ -3845,9 +3846,10 @@ arraycontained(PG_FUNCTION_ARGS)
{
ArrayType *array1 = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *array2 = PG_GETARG_ARRAYTYPE_P(1);
Oid collation = PG_GET_COLLATION();
bool result;
result = array_contain_compare(array1, array2, true,
result = array_contain_compare(array1, array2, collation, true,
&fcinfo->flinfo->fn_extra);
/* Avoid leaking memory when handed toasted input. */

View File

@ -213,7 +213,8 @@ int2vectorrecv(PG_FUNCTION_ARGS)
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
* parameter.
*/
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
InvalidOid, NULL, NULL);
locfcinfo.arg[0] = PointerGetDatum(buf);
locfcinfo.arg[1] = ObjectIdGetDatum(INT2OID);

View File

@ -174,10 +174,12 @@ Generic_Text_IC_like(text *str, text *pat, Oid collation)
if (pg_database_encoding_max_length() > 1)
{
/* lower's result is never packed, so OK to use old macros here */
pat = DatumGetTextP(DirectFunctionCall1WithCollation(lower, collation, PointerGetDatum(pat)));
pat = DatumGetTextP(DirectFunctionCall1Coll(lower, collation,
PointerGetDatum(pat)));
p = VARDATA(pat);
plen = (VARSIZE(pat) - VARHDRSZ);
str = DatumGetTextP(DirectFunctionCall1WithCollation(lower, collation, PointerGetDatum(str)));
str = DatumGetTextP(DirectFunctionCall1Coll(lower, collation,
PointerGetDatum(str)));
s = VARDATA(str);
slen = (VARSIZE(str) - VARHDRSZ);
if (GetDatabaseEncoding() == PG_UTF8)

View File

@ -263,7 +263,8 @@ oidvectorrecv(PG_FUNCTION_ARGS)
* fcinfo->flinfo->fn_extra. So we need to pass it our own flinfo
* parameter.
*/
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(locfcinfo, fcinfo->flinfo, 3,
InvalidOid, NULL, NULL);
locfcinfo.arg[0] = PointerGetDatum(buf);
locfcinfo.arg[1] = ObjectIdGetDatum(OIDOID);

View File

@ -3963,7 +3963,10 @@ ri_AttributesEqual(Oid eq_opr, Oid typeid,
BoolGetDatum(false)); /* implicit coercion */
}
/* Apply the comparison operator */
/*
* Apply the comparison operator. We assume it doesn't
* care about collations.
*/
return DatumGetBool(FunctionCall2(&entry->eq_opr_finfo,
oldvalue, newvalue));
}

View File

@ -867,6 +867,7 @@ record_cmp(FunctionCallInfo fcinfo)
while (i1 < ncolumns1 || i2 < ncolumns2)
{
TypeCacheEntry *typentry;
Oid collation;
FunctionCallInfoData locfcinfo;
int32 cmpresult;
@ -898,6 +899,14 @@ record_cmp(FunctionCallInfo fcinfo)
format_type_be(tupdesc2->attrs[i2]->atttypid),
j + 1)));
/*
* If they're not same collation, we don't complain here, but the
* comparison function might.
*/
collation = tupdesc1->attrs[i1]->attcollation;
if (collation != tupdesc2->attrs[i2]->attcollation)
collation = InvalidOid;
/*
* Lookup the comparison function if not done already
*/
@ -935,7 +944,7 @@ record_cmp(FunctionCallInfo fcinfo)
/* Compare the pair of elements */
InitFunctionCallInfoData(locfcinfo, &typentry->cmp_proc_finfo, 2,
NULL, NULL);
collation, NULL, NULL);
locfcinfo.arg[0] = values1[i1];
locfcinfo.arg[1] = values2[i2];
locfcinfo.argnull[0] = false;
@ -1093,6 +1102,7 @@ record_eq(PG_FUNCTION_ARGS)
while (i1 < ncolumns1 || i2 < ncolumns2)
{
TypeCacheEntry *typentry;
Oid collation;
FunctionCallInfoData locfcinfo;
bool oprresult;
@ -1124,6 +1134,14 @@ record_eq(PG_FUNCTION_ARGS)
format_type_be(tupdesc2->attrs[i2]->atttypid),
j + 1)));
/*
* If they're not same collation, we don't complain here, but the
* equality function might.
*/
collation = tupdesc1->attrs[i1]->attcollation;
if (collation != tupdesc2->attrs[i2]->attcollation)
collation = InvalidOid;
/*
* Lookup the equality function if not done already
*/
@ -1154,7 +1172,7 @@ record_eq(PG_FUNCTION_ARGS)
/* Compare the pair of elements */
InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2,
NULL, NULL);
collation, NULL, NULL);
locfcinfo.arg[0] = values1[i1];
locfcinfo.arg[1] = values2[i2];
locfcinfo.argnull[0] = false;

View File

@ -285,19 +285,20 @@ var_eq_const(VariableStatData *vardata, Oid operator,
FmgrInfo eqproc;
fmgr_info(get_opcode(operator), &eqproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc);
for (i = 0; i < nvalues; i++)
{
/* be careful to apply operator right way 'round */
if (varonleft)
match = DatumGetBool(FunctionCall2(&eqproc,
values[i],
constval));
match = DatumGetBool(FunctionCall2Coll(&eqproc,
DEFAULT_COLLATION_OID,
values[i],
constval));
else
match = DatumGetBool(FunctionCall2(&eqproc,
constval,
values[i]));
match = DatumGetBool(FunctionCall2Coll(&eqproc,
DEFAULT_COLLATION_OID,
constval,
values[i]));
if (match)
break;
}
@ -515,7 +516,6 @@ scalarineqsel(PlannerInfo *root, Oid operator, bool isgt,
stats = (Form_pg_statistic) GETSTRUCT(vardata->statsTuple);
fmgr_info(get_opcode(operator), &opproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc);
/*
* If we have most-common-values info, add up the fractions of the MCV
@ -598,12 +598,14 @@ mcv_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
for (i = 0; i < nvalues; i++)
{
if (varonleft ?
DatumGetBool(FunctionCall2(opproc,
values[i],
constval)) :
DatumGetBool(FunctionCall2(opproc,
constval,
values[i])))
DatumGetBool(FunctionCall2Coll(opproc,
DEFAULT_COLLATION_OID,
values[i],
constval)) :
DatumGetBool(FunctionCall2Coll(opproc,
DEFAULT_COLLATION_OID,
constval,
values[i])))
mcv_selec += numbers[i];
sumcommon += numbers[i];
}
@ -678,12 +680,14 @@ histogram_selectivity(VariableStatData *vardata, FmgrInfo *opproc,
for (i = n_skip; i < nvalues - n_skip; i++)
{
if (varonleft ?
DatumGetBool(FunctionCall2(opproc,
values[i],
constval)) :
DatumGetBool(FunctionCall2(opproc,
constval,
values[i])))
DatumGetBool(FunctionCall2Coll(opproc,
DEFAULT_COLLATION_OID,
values[i],
constval)) :
DatumGetBool(FunctionCall2Coll(opproc,
DEFAULT_COLLATION_OID,
constval,
values[i])))
nmatch++;
}
result = ((double) nmatch) / ((double) (nvalues - 2 * n_skip));
@ -802,9 +806,10 @@ ineq_histogram_selectivity(PlannerInfo *root,
NULL,
&values[probe]);
ltcmp = DatumGetBool(FunctionCall2(opproc,
values[probe],
constval));
ltcmp = DatumGetBool(FunctionCall2Coll(opproc,
DEFAULT_COLLATION_OID,
values[probe],
constval));
if (isgt)
ltcmp = !ltcmp;
if (ltcmp)
@ -1255,7 +1260,6 @@ 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_set_collation(DEFAULT_COLLATION_OID, &opproc);
selec = histogram_selectivity(&vardata, &opproc, constval, true,
10, 1, &hist_size);
@ -1705,7 +1709,6 @@ scalararraysel(PlannerInfo *root,
if (!oprsel)
return (Selectivity) 0.5;
fmgr_info(oprsel, &oprselproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &oprselproc);
/* deconstruct the expression */
Assert(list_length(clause->args) == 2);
@ -2126,7 +2129,6 @@ eqjoinsel_inner(Oid operator,
nmatches;
fmgr_info(get_opcode(operator), &eqproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc);
hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool));
hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool));
@ -2146,9 +2148,10 @@ eqjoinsel_inner(Oid operator,
{
if (hasmatch2[j])
continue;
if (DatumGetBool(FunctionCall2(&eqproc,
values1[i],
values2[j])))
if (DatumGetBool(FunctionCall2Coll(&eqproc,
DEFAULT_COLLATION_OID,
values1[i],
values2[j])))
{
hasmatch1[i] = hasmatch2[j] = true;
matchprodfreq += numbers1[i] * numbers2[j];
@ -2349,7 +2352,6 @@ eqjoinsel_semi(Oid operator,
nmatches;
fmgr_info(get_opcode(operator), &eqproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &eqproc);
hasmatch1 = (bool *) palloc0(nvalues1 * sizeof(bool));
hasmatch2 = (bool *) palloc0(nvalues2 * sizeof(bool));
@ -2368,9 +2370,10 @@ eqjoinsel_semi(Oid operator,
{
if (hasmatch2[j])
continue;
if (DatumGetBool(FunctionCall2(&eqproc,
values1[i],
values2[j])))
if (DatumGetBool(FunctionCall2Coll(&eqproc,
DEFAULT_COLLATION_OID,
values1[i],
values2[j])))
{
hasmatch1[i] = hasmatch2[j] = true;
nmatches++;
@ -4503,7 +4506,6 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
FmgrInfo opproc;
fmgr_info(get_opcode(sortop), &opproc);
fmgr_info_set_collation(DEFAULT_COLLATION_OID, &opproc);
for (i = 0; i < nvalues; i++)
{
@ -4513,12 +4515,16 @@ get_variable_range(PlannerInfo *root, VariableStatData *vardata, Oid sortop,
tmin_is_mcv = tmax_is_mcv = have_data = true;
continue;
}
if (DatumGetBool(FunctionCall2(&opproc, values[i], tmin)))
if (DatumGetBool(FunctionCall2Coll(&opproc,
DEFAULT_COLLATION_OID,
values[i], tmin)))
{
tmin = values[i];
tmin_is_mcv = true;
}
if (DatumGetBool(FunctionCall2(&opproc, tmax, values[i])))
if (DatumGetBool(FunctionCall2Coll(&opproc,
DEFAULT_COLLATION_OID,
tmax, values[i])))
{
tmax = values[i];
tmax_is_mcv = true;
@ -5183,7 +5189,6 @@ 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_set_collation(DEFAULT_COLLATION_OID, &opproc);
prefixsel = ineq_histogram_selectivity(root, vardata, &opproc, true,
prefixcon->constvalue,
@ -5205,9 +5210,8 @@ 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_set_collation(DEFAULT_COLLATION_OID, &opproc);
greaterstrcon = make_greater_string(prefixcon, &opproc);
greaterstrcon = make_greater_string(prefixcon, &opproc,
DEFAULT_COLLATION_OID);
if (greaterstrcon)
{
Selectivity topsel;
@ -5502,22 +5506,21 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
* in the form of a Const node; else return NULL.
*
* The caller must provide the appropriate "less than" comparison function
* for testing the strings. In particular, ltproc->fn_collation specifies
* the locale for comparisons.
* for testing the strings, along with the collation to use.
*
* The key requirement here is that given a prefix string, say "foo",
* we must be able to generate another string "fop" that is greater than
* all strings "foobar" starting with "foo". We can test that we have
* generated a string greater than the prefix string, but in non-C locales
* generated a string greater than the prefix string, but in non-C collations
* that is not a bulletproof guarantee that an extension of the string might
* not sort after it; an example is that "foo " is less than "foo!", but it
* is not clear that a "dictionary" sort ordering will consider "foo!" less
* than "foo bar". CAUTION: Therefore, this function should be used only for
* estimation purposes when working in a non-C locale.
* estimation purposes when working in a non-C collation.
*
* To try to catch most cases where an extended string might otherwise sort
* before the result value, we determine which of the strings "Z", "z", "y",
* and "9" is seen as largest by the locale, and append that to the given
* and "9" is seen as largest by the collation, and append that to the given
* prefix before trying to find a string that compares as larger.
*
* If we max out the righthand byte, truncate off the last character
@ -5529,7 +5532,7 @@ pattern_selectivity(Const *patt, Pattern_Type ptype)
* won't have to try more than one or two strings before succeeding.
*/
Const *
make_greater_string(const Const *str_const, FmgrInfo *ltproc)
make_greater_string(const Const *str_const, FmgrInfo *ltproc, Oid collation)
{
Oid datatype = str_const->consttype;
char *workstr;
@ -5565,7 +5568,7 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
{
workstr = TextDatumGetCString(str_const->constvalue);
len = strlen(workstr);
if (lc_collate_is_c(ltproc->fn_collation) || len == 0)
if (lc_collate_is_c(collation) || len == 0)
cmpstr = str_const->constvalue;
else
{
@ -5573,19 +5576,19 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
static char suffixchar = 0;
static Oid suffixcollation = 0;
if (!suffixchar || suffixcollation != ltproc->fn_collation)
if (!suffixchar || suffixcollation != collation)
{
char *best;
best = "Z";
if (varstr_cmp(best, 1, "z", 1, ltproc->fn_collation) < 0)
if (varstr_cmp(best, 1, "z", 1, collation) < 0)
best = "z";
if (varstr_cmp(best, 1, "y", 1, ltproc->fn_collation) < 0)
if (varstr_cmp(best, 1, "y", 1, collation) < 0)
best = "y";
if (varstr_cmp(best, 1, "9", 1, ltproc->fn_collation) < 0)
if (varstr_cmp(best, 1, "9", 1, collation) < 0)
best = "9";
suffixchar = *best;
suffixcollation = ltproc->fn_collation;
suffixcollation = collation;
}
/* And build the string to compare to */
@ -5621,9 +5624,10 @@ make_greater_string(const Const *str_const, FmgrInfo *ltproc)
else
workstr_const = string_to_bytea_const(workstr, len);
if (DatumGetBool(FunctionCall2(ltproc,
cmpstr,
workstr_const->constvalue)))
if (DatumGetBool(FunctionCall2Coll(ltproc,
collation,
cmpstr,
workstr_const->constvalue)))
{
/* Successfully made a string larger than cmpstr */
if (cmptxt)

View File

@ -935,7 +935,7 @@ CatalogCacheInitializeCache(CatCache *cache)
cache->cc_skey[i].sk_strategy = BTEqualStrategyNumber;
cache->cc_skey[i].sk_subtype = InvalidOid;
/* Currently, there are no catcaches on collation-aware data types */
cache->cc_skey[i].sk_func.fn_collation = InvalidOid;
cache->cc_skey[i].sk_collation = InvalidOid;
CACHE4_elog(DEBUG2, "CatalogCacheInitializeCache %s %d %p",
cache->cc_relname,

View File

@ -71,7 +71,6 @@ 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 */
@ -92,14 +91,12 @@ 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.
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.
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.
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. Note that this
field really is information about the arguments rather than information
about the function, but it's proven to be more convenient to keep it in
FmgrInfo than in FunctionCallInfoData where it might more logically go.
During a call of a function, the following data structure is created
@ -110,6 +107,7 @@ typedef struct
FmgrInfo *flinfo; /* ptr to lookup info used for this call */
Node *context; /* pass info about context of call */
Node *resultinfo; /* pass or return extra info about result */
Oid fncollation; /* collation for function to use */
bool isnull; /* function must set true if result is NULL */
short nargs; /* # arguments actually passed */
Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
@ -137,6 +135,11 @@ function that returns a set, as discussed below.) Like the context field,
resultinfo is a hook for expansion; fmgr itself doesn't constrain the use
of the field.
fncollation is the input collation derived by the parser, or InvalidOid
when there are no inputs of collatable types or they don't share a common
collation. This is effectively a hidden additional argument, which
collation-sensitive functions can use to determine their behavior.
nargs, arg[], and argnull[] hold the arguments being passed to the function.
Notice that all the arguments passed to a function (as well as its result
value) will now uniformly be of type Datum. As discussed below, callers

View File

@ -192,7 +192,6 @@ fmgr_info_cxt_security(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt,
* elogs.
*/
finfo->fn_oid = 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 */
@ -901,7 +900,6 @@ 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,
@ -1012,12 +1010,12 @@ fmgr_security_definer(PG_FUNCTION_ARGS)
* look at FmgrInfo, since there won't be any.
*/
Datum
DirectFunctionCall1(PGFunction func, Datum arg1)
DirectFunctionCall1Coll(PGFunction func, Oid collation, Datum arg1)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 1, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 1, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.argnull[0] = false;
@ -1032,12 +1030,12 @@ DirectFunctionCall1(PGFunction func, Datum arg1)
}
Datum
DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
DirectFunctionCall2Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 2, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 2, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1054,13 +1052,13 @@ DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2)
}
Datum
DirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 3, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 3, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1079,13 +1077,13 @@ DirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 4, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 4, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1106,13 +1104,13 @@ DirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall5Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 5, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 5, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1135,14 +1133,14 @@ DirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall6Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 6, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 6, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1167,14 +1165,14 @@ DirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall7(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall7Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 7, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 7, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1201,14 +1199,14 @@ DirectFunctionCall7(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall8(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall8Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 8, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 8, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1237,7 +1235,7 @@ DirectFunctionCall8(PGFunction func, Datum arg1, Datum arg2,
}
Datum
DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2,
DirectFunctionCall9Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9)
@ -1245,7 +1243,7 @@ DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2,
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, NULL, 9, NULL, NULL);
InitFunctionCallInfoData(fcinfo, NULL, 9, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1276,72 +1274,18 @@ DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2,
}
/*
* 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)
{
FunctionCallInfoData fcinfo;
FmgrInfo flinfo;
Datum result;
MemSet(&flinfo, 0, sizeof(flinfo));
flinfo.fn_collation = collation;
InitFunctionCallInfoData(fcinfo, &flinfo, 1, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.argnull[0] = false;
result = (*func) (&fcinfo);
/* Check for null result, since caller is clearly not expecting one */
if (fcinfo.isnull)
elog(ERROR, "function %p returned NULL", (void *) func);
return result;
}
Datum
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.arg[0] = arg1;
fcinfo.arg[1] = arg2;
fcinfo.argnull[0] = false;
fcinfo.argnull[1] = false;
result = (*func) (&fcinfo);
/* Check for null result, since caller is clearly not expecting one */
if (fcinfo.isnull)
elog(ERROR, "function %p returned NULL", (void *) func);
return result;
}
/*
* These are for invocation of a previously-looked-up function with a
* directly-computed parameter list. Note that neither arguments nor result
* are allowed to be NULL.
*/
Datum
FunctionCall1(FmgrInfo *flinfo, Datum arg1)
FunctionCall1Coll(FmgrInfo *flinfo, Oid collation, Datum arg1)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 1, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 1, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.argnull[0] = false;
@ -1356,7 +1300,7 @@ FunctionCall1(FmgrInfo *flinfo, Datum arg1)
}
Datum
FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
FunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
{
/*
* XXX if you change this routine, see also the inlined version in
@ -1365,7 +1309,7 @@ FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 2, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 2, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1382,13 +1326,13 @@ FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
}
Datum
FunctionCall3(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall3Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 3, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1407,13 +1351,13 @@ FunctionCall3(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall4(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall4Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 4, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 4, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1434,13 +1378,13 @@ FunctionCall4(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall5(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall5Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 5, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 5, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1463,14 +1407,14 @@ FunctionCall5(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall6(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall6Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 6, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 6, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1495,14 +1439,14 @@ FunctionCall6(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall7(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 7, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 7, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1529,14 +1473,14 @@ FunctionCall7(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall8(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 8, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 8, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1565,7 +1509,7 @@ FunctionCall8(FmgrInfo *flinfo, Datum arg1, Datum arg2,
}
Datum
FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCall9Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9)
@ -1573,7 +1517,7 @@ FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2,
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 9, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 9, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1612,7 +1556,7 @@ FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2,
* do the fmgr_info() once and then use FunctionCallN().
*/
Datum
OidFunctionCall0(Oid functionId)
OidFunctionCall0Coll(Oid functionId, Oid collation)
{
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
@ -1620,7 +1564,7 @@ OidFunctionCall0(Oid functionId)
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 0, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 0, collation, NULL, NULL);
result = FunctionCallInvoke(&fcinfo);
@ -1632,7 +1576,7 @@ OidFunctionCall0(Oid functionId)
}
Datum
OidFunctionCall1(Oid functionId, Datum arg1)
OidFunctionCall1Coll(Oid functionId, Oid collation, Datum arg1)
{
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
@ -1640,7 +1584,7 @@ OidFunctionCall1(Oid functionId, Datum arg1)
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 1, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 1, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.argnull[0] = false;
@ -1655,7 +1599,7 @@ OidFunctionCall1(Oid functionId, Datum arg1)
}
Datum
OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2)
OidFunctionCall2Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2)
{
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
@ -1663,7 +1607,7 @@ OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2)
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 2, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 2, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1680,7 +1624,7 @@ OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2)
}
Datum
OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall3Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3)
{
FmgrInfo flinfo;
@ -1689,7 +1633,7 @@ OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 3, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1708,7 +1652,7 @@ OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall4Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4)
{
FmgrInfo flinfo;
@ -1717,7 +1661,7 @@ OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 4, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 4, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1738,7 +1682,7 @@ OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall5Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5)
{
FmgrInfo flinfo;
@ -1747,7 +1691,7 @@ OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 5, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 5, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1770,7 +1714,7 @@ OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall6Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6)
{
@ -1780,7 +1724,7 @@ OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 6, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 6, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1805,7 +1749,7 @@ OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall7Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7)
{
@ -1815,7 +1759,7 @@ OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 7, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 7, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1842,7 +1786,7 @@ OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall8Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8)
{
@ -1852,7 +1796,7 @@ OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 8, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 8, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1881,7 +1825,7 @@ OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2,
}
Datum
OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
OidFunctionCall9Coll(Oid functionId, Oid collation, Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9)
@ -1892,7 +1836,7 @@ OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
fmgr_info(functionId, &flinfo);
InitFunctionCallInfoData(fcinfo, &flinfo, 9, NULL, NULL);
InitFunctionCallInfoData(fcinfo, &flinfo, 9, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -1953,7 +1897,7 @@ InputFunctionCall(FmgrInfo *flinfo, char *str, Oid typioparam, int32 typmod)
pushed = SPI_push_conditional();
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
fcinfo.arg[0] = CStringGetDatum(str);
fcinfo.arg[1] = ObjectIdGetDatum(typioparam);
@ -2028,7 +1972,7 @@ ReceiveFunctionCall(FmgrInfo *flinfo, StringInfo buf,
pushed = SPI_push_conditional();
InitFunctionCallInfoData(fcinfo, flinfo, 3, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 3, InvalidOid, NULL, NULL);
fcinfo.arg[0] = PointerGetDatum(buf);
fcinfo.arg[1] = ObjectIdGetDatum(typioparam);

View File

@ -373,6 +373,7 @@ struct Tuplesortstate
Oid datumType;
FmgrInfo sortOpFn; /* cached lookup data for sortOperator */
int sortFnFlags; /* equivalent to sk_flags */
Oid sortCollation; /* equivalent to sk_collation */
/* we need typelen and byval in order to know how to copy the Datums. */
int datumTypeLen;
bool datumTypeByVal;
@ -582,7 +583,8 @@ tuplesort_begin_common(int workMem, bool randomAccess)
Tuplesortstate *
tuplesort_begin_heap(TupleDesc tupDesc,
int nkeys, AttrNumber *attNums,
Oid *sortOperators, Oid *collations, bool *nullsFirstFlags,
Oid *sortOperators, Oid *sortCollations,
bool *nullsFirstFlags,
int workMem, bool randomAccess)
{
Tuplesortstate *state = tuplesort_begin_common(workMem, randomAccess);
@ -647,7 +649,7 @@ tuplesort_begin_heap(TupleDesc tupDesc,
attNums[i],
InvalidStrategy,
InvalidOid,
collations ? collations[i] : InvalidOid,
sortCollations[i],
sortFunction,
(Datum) 0);
}
@ -795,8 +797,8 @@ tuplesort_begin_index_hash(Relation indexRel,
}
Tuplesortstate *
tuplesort_begin_datum(Oid datumType,
Oid sortOperator, Oid sortCollation, bool nullsFirstFlag,
tuplesort_begin_datum(Oid datumType, Oid sortOperator, Oid sortCollation,
bool nullsFirstFlag,
int workMem, bool randomAccess)
{
Tuplesortstate *state = tuplesort_begin_common(workMem, randomAccess);
@ -837,12 +839,12 @@ tuplesort_begin_datum(Oid datumType,
elog(ERROR, "operator %u is not a valid ordering operator",
sortOperator);
fmgr_info(sortFunction, &state->sortOpFn);
fmgr_info_set_collation(sortCollation, &state->sortOpFn);
/* set ordering flags */
/* set ordering flags and collation */
state->sortFnFlags = reverse ? SK_BT_DESC : 0;
if (nullsFirstFlag)
state->sortFnFlags |= SK_BT_NULLS_FIRST;
state->sortCollation = sortCollation;
/* lookup necessary attributes of the datum type */
get_typlenbyval(datumType, &typlen, &typbyval);
@ -2630,15 +2632,15 @@ SelectSortFunction(Oid sortOperator,
}
/*
* Inline-able copy of FunctionCall2() to save some cycles in sorting.
* Inline-able copy of FunctionCall2Coll() to save some cycles in sorting.
*/
static inline Datum
myFunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
myFunctionCall2Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2)
{
FunctionCallInfoData fcinfo;
Datum result;
InitFunctionCallInfoData(fcinfo, flinfo, 2, NULL, NULL);
InitFunctionCallInfoData(fcinfo, flinfo, 2, collation, NULL, NULL);
fcinfo.arg[0] = arg1;
fcinfo.arg[1] = arg2;
@ -2661,7 +2663,7 @@ myFunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2)
* NULLS_FIRST options are encoded in sk_flags the same way btree does it.
*/
static inline int32
inlineApplySortFunction(FmgrInfo *sortFunction, int sk_flags,
inlineApplySortFunction(FmgrInfo *sortFunction, int sk_flags, Oid collation,
Datum datum1, bool isNull1,
Datum datum2, bool isNull2)
{
@ -2685,8 +2687,8 @@ inlineApplySortFunction(FmgrInfo *sortFunction, int sk_flags,
}
else
{
compare = DatumGetInt32(myFunctionCall2(sortFunction,
datum1, datum2));
compare = DatumGetInt32(myFunctionCall2Coll(sortFunction, collation,
datum1, datum2));
if (sk_flags & SK_BT_DESC)
compare = -compare;
@ -2700,11 +2702,11 @@ inlineApplySortFunction(FmgrInfo *sortFunction, int sk_flags,
* C99's brain-dead notions about how to implement inline functions...
*/
int32
ApplySortFunction(FmgrInfo *sortFunction, int sortFlags,
ApplySortFunction(FmgrInfo *sortFunction, int sortFlags, Oid collation,
Datum datum1, bool isNull1,
Datum datum2, bool isNull2)
{
return inlineApplySortFunction(sortFunction, sortFlags,
return inlineApplySortFunction(sortFunction, sortFlags, collation,
datum1, isNull1,
datum2, isNull2);
}
@ -2729,6 +2731,7 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
/* Compare the leading sort key */
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
scanKey->sk_collation,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
if (compare != 0)
@ -2753,6 +2756,7 @@ comparetup_heap(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
datum2 = heap_getattr(&rtup, attno, tupDesc, &isnull2);
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
scanKey->sk_collation,
datum1, isnull1,
datum2, isnull2);
if (compare != 0)
@ -2874,6 +2878,7 @@ comparetup_cluster(const SortTuple *a, const SortTuple *b,
if (state->indexInfo->ii_KeyAttrNumbers[0] != 0)
{
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
scanKey->sk_collation,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
if (compare != 0 || state->nKeys == 1)
@ -2910,6 +2915,7 @@ comparetup_cluster(const SortTuple *a, const SortTuple *b,
compare = inlineApplySortFunction(&scanKey->sk_func,
scanKey->sk_flags,
scanKey->sk_collation,
datum1, isnull1,
datum2, isnull2);
if (compare != 0)
@ -2947,6 +2953,7 @@ comparetup_cluster(const SortTuple *a, const SortTuple *b,
{
compare = inlineApplySortFunction(&scanKey->sk_func,
scanKey->sk_flags,
scanKey->sk_collation,
l_index_values[nkey],
l_index_isnull[nkey],
r_index_values[nkey],
@ -3060,6 +3067,7 @@ comparetup_index_btree(const SortTuple *a, const SortTuple *b,
/* Compare the leading sort key */
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
scanKey->sk_collation,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
if (compare != 0)
@ -3086,6 +3094,7 @@ comparetup_index_btree(const SortTuple *a, const SortTuple *b,
datum2 = index_getattr(tuple2, nkey, tupDes, &isnull2);
compare = inlineApplySortFunction(&scanKey->sk_func, scanKey->sk_flags,
scanKey->sk_collation,
datum1, isnull1,
datum2, isnull2);
if (compare != 0)
@ -3293,6 +3302,7 @@ comparetup_datum(const SortTuple *a, const SortTuple *b, Tuplesortstate *state)
CHECK_FOR_INTERRUPTS();
return inlineApplySortFunction(&state->sortOpFn, state->sortFnFlags,
state->sortCollation,
a->datum1, a->isnull1,
b->datum1, b->isnull1);
}

View File

@ -303,6 +303,8 @@ typedef struct GinState
FmgrInfo comparePartialFn[INDEX_MAX_KEYS]; /* optional method */
/* canPartialMatch[i] is true if comparePartialFn[i] is valid */
bool canPartialMatch[INDEX_MAX_KEYS];
/* Collations to supply to the compareFns and comparePartialFns */
Oid compareCollation[INDEX_MAX_KEYS];
} GinState;
/* XLog stuff */

View File

@ -52,16 +52,16 @@ typedef uint16 StrategyNumber;
* the operator. When using a ScanKey in a heap scan, these fields are not
* used and may be set to InvalidStrategy/InvalidOid.
*
* If the operator is collation-sensitive, sk_func.fn_collation must be set
* If the operator is collation-sensitive, sk_collation must be set
* correctly as well.
*
* A ScanKey can also represent a condition "column IS NULL" or "column
* IS NOT NULL"; these cases are signaled by the SK_SEARCHNULL and
* SK_SEARCHNOTNULL flag bits respectively. The argument is always NULL,
* and the sk_strategy, sk_subtype, and sk_func fields are not used (unless
* set by the index AM). Currently, SK_SEARCHNULL and SK_SEARCHNOTNULL are
* supported only for index scans, not heap scans; and not all index AMs
* support them.
* and the sk_strategy, sk_subtype, sk_collation, and sk_func fields are
* not used (unless set by the index AM). Currently, SK_SEARCHNULL and
* SK_SEARCHNOTNULL are supported only for index scans, not heap scans;
* and not all index AMs support them.
*
* A ScanKey can also represent an ordering operator invocation, that is
* an ordering requirement "ORDER BY indexedcol op constant". This looks
@ -70,8 +70,8 @@ typedef uint16 StrategyNumber;
*
* Note: in some places, ScanKeys are used as a convenient representation
* for the invocation of an access method support procedure. In this case
* sk_strategy/sk_subtype are not meaningful, and sk_func may refer to a
* function that returns something other than boolean.
* sk_strategy/sk_subtype are not meaningful (but sk_collation can be); and
* sk_func may refer to a function that returns something other than boolean.
*/
typedef struct ScanKeyData
{
@ -79,6 +79,7 @@ typedef struct ScanKeyData
AttrNumber sk_attno; /* table or index column number */
StrategyNumber sk_strategy; /* operator strategy number */
Oid sk_subtype; /* strategy subtype */
Oid sk_collation; /* collation to use, if needed */
FmgrInfo sk_func; /* lookup info for function to call */
Datum sk_argument; /* data to compare */
} ScanKeyData;
@ -99,7 +100,7 @@ typedef ScanKeyData *ScanKey;
* sk_attno = index column number for leading column of row comparison
* sk_strategy = btree strategy code for semantics of row comparison
* (ie, < <= > or >=)
* sk_subtype, sk_func: not used
* sk_subtype, sk_collation, sk_func: not used
* sk_argument: pointer to subsidiary ScanKey array
* If the header is part of a ScanKey array that's sorted by attno, it
* must be sorted according to the leading column number.

View File

@ -54,8 +54,9 @@ do \
break; \
} \
\
__test = FunctionCall2(&__cur_keys->sk_func, \
__atp, __cur_keys->sk_argument); \
__test = FunctionCall2Coll(&__cur_keys->sk_func, \
__cur_keys->sk_collation, \
__atp, __cur_keys->sk_argument); \
\
if (!DatumGetBool(__test)) \
{ \

View File

@ -41,10 +41,10 @@ typedef Datum (*PGFunction) (FunctionCallInfo fcinfo);
* to be called multiple times, the lookup need be done only once and the
* info struct saved for re-use.
*
* Note that fn_collation and fn_expr really are parse-time-determined
* information about the arguments, rather than about the function itself.
* But it's convenient to store them here rather than in FunctionCallInfoData,
* where they might more logically belong.
* Note that fn_expr really is parse-time-determined information about the
* arguments, rather than about the function itself. But it's convenient
* to store it here rather than in FunctionCallInfoData, where it might more
* logically belong.
*/
typedef struct FmgrInfo
{
@ -55,7 +55,6 @@ typedef struct FmgrInfo
bool fn_strict; /* function is "strict" (NULL in => NULL out) */
bool fn_retset; /* function returns a set */
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 */
fmNodePtr fn_expr; /* expression parse tree for call, or NULL */
@ -69,6 +68,7 @@ typedef struct FunctionCallInfoData
FmgrInfo *flinfo; /* ptr to lookup info used for this call */
fmNodePtr context; /* pass info about context of call */
fmNodePtr resultinfo; /* pass or return extra info about result */
Oid fncollation; /* collation for function to use */
bool isnull; /* function must set true if result is NULL */
short nargs; /* # arguments actually passed */
Datum arg[FUNC_MAX_ARGS]; /* Arguments passed to function */
@ -89,9 +89,7 @@ extern void fmgr_info(Oid functionId, FmgrInfo *finfo);
extern void fmgr_info_cxt(Oid functionId, FmgrInfo *finfo,
MemoryContext mcxt);
/* Macros for setting the fn_collation and fn_expr fields */
#define fmgr_info_set_collation(collationId, finfo) \
((finfo)->fn_collation = (collationId))
/* Convenience macro for setting the fn_expr field */
#define fmgr_info_set_expr(expr, finfo) \
((finfo)->fn_expr = (expr))
@ -108,11 +106,12 @@ extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
* explicitly set each required element to false, so we don't try to zero
* out the argnull[] array in the macro.
*/
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Context, Resultinfo) \
#define InitFunctionCallInfoData(Fcinfo, Flinfo, Nargs, Collation, Context, Resultinfo) \
do { \
(Fcinfo).flinfo = (Flinfo); \
(Fcinfo).context = (Context); \
(Fcinfo).resultinfo = (Resultinfo); \
(Fcinfo).fncollation = (Collation); \
(Fcinfo).isnull = false; \
(Fcinfo).nargs = (Nargs); \
} while (0)
@ -150,8 +149,7 @@ extern void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
/*
* Get collation function should use.
*/
#define PG_GET_COLLATION() \
(fcinfo->flinfo ? fcinfo->flinfo->fn_collation : InvalidOid)
#define PG_GET_COLLATION() (fcinfo->fncollation)
/*
* Get number of arguments passed to function.
@ -434,56 +432,68 @@ extern int no_such_variable
* directly-computed parameter list. Note that neither arguments nor result
* are allowed to be NULL.
*/
extern Datum DirectFunctionCall1(PGFunction func, Datum arg1);
extern Datum DirectFunctionCall2(PGFunction func, Datum arg1, Datum arg2);
extern Datum DirectFunctionCall3(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall1Coll(PGFunction func, Oid collation,
Datum arg1);
extern Datum DirectFunctionCall2Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2);
extern Datum DirectFunctionCall3Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3);
extern Datum DirectFunctionCall4(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall4Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4);
extern Datum DirectFunctionCall5(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall5Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5);
extern Datum DirectFunctionCall6(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall6Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6);
extern Datum DirectFunctionCall7(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall7Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7);
extern Datum DirectFunctionCall8(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall8Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8);
extern Datum DirectFunctionCall9(PGFunction func, Datum arg1, Datum arg2,
extern Datum DirectFunctionCall9Coll(PGFunction func, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
/* The same, but passing a collation to use */
extern Datum DirectFunctionCall1WithCollation(PGFunction func, Oid collation,
Datum arg1);
extern Datum DirectFunctionCall2WithCollation(PGFunction func, Oid collation,
Datum arg1, Datum arg2);
/* These are for invocation of a previously-looked-up function with a
* directly-computed parameter list. Note that neither arguments nor result
* are allowed to be NULL.
*/
extern Datum FunctionCall1(FmgrInfo *flinfo, Datum arg1);
extern Datum FunctionCall2(FmgrInfo *flinfo, Datum arg1, Datum arg2);
extern Datum FunctionCall3(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall1Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1);
extern Datum FunctionCall2Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2);
extern Datum FunctionCall3Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3);
extern Datum FunctionCall4(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall4Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4);
extern Datum FunctionCall5(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall5Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5);
extern Datum FunctionCall6(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall6Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6);
extern Datum FunctionCall7(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7);
extern Datum FunctionCall8(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8);
extern Datum FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2,
extern Datum FunctionCall9Coll(FmgrInfo *flinfo, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
@ -494,29 +504,100 @@ extern Datum FunctionCall9(FmgrInfo *flinfo, Datum arg1, Datum arg2,
* by FunctionCallN(). If the same function is to be invoked repeatedly,
* do the FunctionLookup() once and then use FunctionCallN().
*/
extern Datum OidFunctionCall0(Oid functionId);
extern Datum OidFunctionCall1(Oid functionId, Datum arg1);
extern Datum OidFunctionCall2(Oid functionId, Datum arg1, Datum arg2);
extern Datum OidFunctionCall3(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall0Coll(Oid functionId, Oid collation);
extern Datum OidFunctionCall1Coll(Oid functionId, Oid collation,
Datum arg1);
extern Datum OidFunctionCall2Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2);
extern Datum OidFunctionCall3Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3);
extern Datum OidFunctionCall4(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall4Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4);
extern Datum OidFunctionCall5(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall5Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5);
extern Datum OidFunctionCall6(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall6Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6);
extern Datum OidFunctionCall7(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall7Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7);
extern Datum OidFunctionCall8(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall8Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8);
extern Datum OidFunctionCall9(Oid functionId, Datum arg1, Datum arg2,
extern Datum OidFunctionCall9Coll(Oid functionId, Oid collation,
Datum arg1, Datum arg2,
Datum arg3, Datum arg4, Datum arg5,
Datum arg6, Datum arg7, Datum arg8,
Datum arg9);
/* These macros allow the collation argument to be omitted (with a default of
* InvalidOid, ie, no collation). They exist mostly for backwards
* compatibility of source code.
*/
#define DirectFunctionCall1(func, arg1) \
DirectFunctionCall1Coll(func, InvalidOid, arg1)
#define DirectFunctionCall2(func, arg1, arg2) \
DirectFunctionCall2Coll(func, InvalidOid, arg1, arg2)
#define DirectFunctionCall3(func, arg1, arg2, arg3) \
DirectFunctionCall3Coll(func, InvalidOid, arg1, arg2, arg3)
#define DirectFunctionCall4(func, arg1, arg2, arg3, arg4) \
DirectFunctionCall4Coll(func, InvalidOid, arg1, arg2, arg3, arg4)
#define DirectFunctionCall5(func, arg1, arg2, arg3, arg4, arg5) \
DirectFunctionCall5Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define DirectFunctionCall6(func, arg1, arg2, arg3, arg4, arg5, arg6) \
DirectFunctionCall6Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define DirectFunctionCall7(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
DirectFunctionCall7Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define DirectFunctionCall8(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
DirectFunctionCall8Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define DirectFunctionCall9(func, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
DirectFunctionCall9Coll(func, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define FunctionCall1(flinfo, arg1) \
FunctionCall1Coll(flinfo, InvalidOid, arg1)
#define FunctionCall2(flinfo, arg1, arg2) \
FunctionCall2Coll(flinfo, InvalidOid, arg1, arg2)
#define FunctionCall3(flinfo, arg1, arg2, arg3) \
FunctionCall3Coll(flinfo, InvalidOid, arg1, arg2, arg3)
#define FunctionCall4(flinfo, arg1, arg2, arg3, arg4) \
FunctionCall4Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4)
#define FunctionCall5(flinfo, arg1, arg2, arg3, arg4, arg5) \
FunctionCall5Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define FunctionCall6(flinfo, arg1, arg2, arg3, arg4, arg5, arg6) \
FunctionCall6Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define FunctionCall7(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
FunctionCall7Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define FunctionCall8(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
FunctionCall8Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define FunctionCall9(flinfo, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
FunctionCall9Coll(flinfo, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
#define OidFunctionCall0(functionId) \
OidFunctionCall0Coll(functionId, InvalidOid)
#define OidFunctionCall1(functionId, arg1) \
OidFunctionCall1Coll(functionId, InvalidOid, arg1)
#define OidFunctionCall2(functionId, arg1, arg2) \
OidFunctionCall2Coll(functionId, InvalidOid, arg1, arg2)
#define OidFunctionCall3(functionId, arg1, arg2, arg3) \
OidFunctionCall3Coll(functionId, InvalidOid, arg1, arg2, arg3)
#define OidFunctionCall4(functionId, arg1, arg2, arg3, arg4) \
OidFunctionCall4Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4)
#define OidFunctionCall5(functionId, arg1, arg2, arg3, arg4, arg5) \
OidFunctionCall5Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5)
#define OidFunctionCall6(functionId, arg1, arg2, arg3, arg4, arg5, arg6) \
OidFunctionCall6Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6)
#define OidFunctionCall7(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
OidFunctionCall7Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
#define OidFunctionCall8(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) \
OidFunctionCall8Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8)
#define OidFunctionCall9(functionId, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) \
OidFunctionCall9Coll(functionId, InvalidOid, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9)
/* Special cases for convenient invocation of datatype I/O functions. */
extern Datum InputFunctionCall(FmgrInfo *flinfo, char *str,
Oid typioparam, int32 typmod);

View File

@ -864,6 +864,7 @@ typedef struct RowCompareExprState
List *largs; /* the left-hand input arguments */
List *rargs; /* the right-hand input arguments */
FmgrInfo *funcs; /* array of comparison function info */
Oid *collations; /* array of collations to use */
} RowCompareExprState;
/* ----------------

View File

@ -135,7 +135,8 @@ extern Pattern_Prefix_Status pattern_fixed_prefix(Const *patt,
Oid collation,
Const **prefix,
Const **rest);
extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc);
extern Const *make_greater_string(const Const *str_const, FmgrInfo *ltproc,
Oid collation);
extern Datum eqsel(PG_FUNCTION_ARGS);
extern Datum neqsel(PG_FUNCTION_ARGS);

View File

@ -60,7 +60,8 @@ typedef struct Tuplesortstate Tuplesortstate;
extern Tuplesortstate *tuplesort_begin_heap(TupleDesc tupDesc,
int nkeys, AttrNumber *attNums,
Oid *sortOperators, Oid *collations, bool *nullsFirstFlags,
Oid *sortOperators, Oid *sortCollations,
bool *nullsFirstFlags,
int workMem, bool randomAccess);
extern Tuplesortstate *tuplesort_begin_cluster(TupleDesc tupDesc,
Relation indexRel,
@ -72,7 +73,8 @@ extern Tuplesortstate *tuplesort_begin_index_hash(Relation indexRel,
uint32 hash_mask,
int workMem, bool randomAccess);
extern Tuplesortstate *tuplesort_begin_datum(Oid datumType,
Oid sortOperator, Oid sortCollation, bool nullsFirstFlag,
Oid sortOperator, Oid sortCollation,
bool nullsFirstFlag,
int workMem, bool randomAccess);
extern void tuplesort_set_bound(Tuplesortstate *state, int64 bound);
@ -125,6 +127,7 @@ extern void SelectSortFunction(Oid sortOperator, bool nulls_first,
* reverse-sort and NULLs-ordering properly.
*/
extern int32 ApplySortFunction(FmgrInfo *sortFunction, int sortFlags,
Oid collation,
Datum datum1, bool isNull1,
Datum datum2, bool isNull2);

View File

@ -348,7 +348,7 @@ do_compile(FunctionCallInfo fcinfo,
function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
function->fn_tid = procTup->t_self;
function->fn_is_trigger = is_trigger;
function->fn_input_collation = fcinfo->flinfo->fn_collation;
function->fn_input_collation = fcinfo->fncollation;
function->fn_cxt = func_cxt;
function->out_param_varno = -1; /* set up for no OUT param */
function->resolve_option = plpgsql_variable_conflict;
@ -2331,7 +2331,7 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
}
/* get input collation, if known */
hashkey->inputCollation = fcinfo->flinfo->fn_collation;
hashkey->inputCollation = fcinfo->fncollation;
if (procStruct->pronargs > 0)
{