diff --git a/contrib/btree_gin/btree_gin.c b/contrib/btree_gin/btree_gin.c index 144f6db184..7ca153e092 100644 --- a/contrib/btree_gin/btree_gin.c +++ b/contrib/btree_gin/btree_gin.c @@ -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 || \ diff --git a/contrib/btree_gist/btree_text.c b/contrib/btree_gist/btree_text.c index 665dfe78b4..c6b57f82de 100644 --- a/contrib/btree_gist/btree_text.c +++ b/contrib/btree_gist/btree_text.c @@ -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 = diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index d2e0531e35..465742556f 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -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); diff --git a/src/backend/access/common/scankey.c b/src/backend/access/common/scankey.c index b632408da4..c879b8aaa4 100644 --- a/src/backend/access/common/scankey.c +++ b/src/backend/access/common/scankey.c @@ -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; } diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index a4771654a6..227f84d988 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -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) diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 716cf3a734..a712331cf4 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -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); diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index e4488a925d..4eb31318ff 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -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); } diff --git a/src/backend/access/gist/gistscan.c b/src/backend/access/gist/gistscan.c index 67308ed37e..5662a3a4aa 100644 --- a/src/backend/access/gist/gistscan.c +++ b/src/backend/access/gist/gistscan.c @@ -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)) diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index b00b32d69f..ac238d9f7d 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -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; diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index 66af2c37c5..6e0db79517 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -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; diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c index 219f94fd0d..d758659c31 100644 --- a/src/backend/access/nbtree/nbtinsert.c +++ b/src/backend/access/nbtree/nbtinsert.c @@ -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; diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index 91f8cadea5..2ce2bc2f00 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -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); } diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 256a7f9f98..55136e9cc4 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -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; diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c index d448ba6a50..71bcb42c19 100644 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@ -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; diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index dde301b89a..0568a1bcf8 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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; diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 6b1ade8990..ce36ea8be4 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -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); diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c index ce0086ffa1..d08c9bbbc5 100644 --- a/src/backend/commands/tsearchcmds.c +++ b/src/backend/commands/tsearchcmds.c @@ -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)); diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 1f02428a5b..bfb8cbb303 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -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 * diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 5f0b58f43b..80f08d8b92 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -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; diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index 0cbbe04d3b..073ef8d23b 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -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; } diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 9c867bbae2..13946cab23 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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; diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 47555bab55..13d7723480 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -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); diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index d8e59ca39e..dbc1467d5b 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -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)) diff --git a/src/backend/executor/nodeMergeAppend.c b/src/backend/executor/nodeMergeAppend.c index 4ebe0cbe03..43059664b9 100644 --- a/src/backend/executor/nodeMergeAppend.c +++ b/src/backend/executor/nodeMergeAppend.c @@ -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) diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index d6245e6187..208c0fb76a 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -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; diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 08a3017e61..4fcb66bbb0 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -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, diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 25d9298cef..c90d40506f 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -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); } diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index c7ed1b6ee9..1cace6d596 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -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), <proc); - fmgr_info_set_collation(collation, <proc); - greaterstr = make_greater_string(prefix_const, <proc); + greaterstr = make_greater_string(prefix_const, <proc, collation); if (greaterstr) { expr = make_opclause(oproid, BOOLOID, false, diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index d0a23d007a..30863bb7b9 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -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); diff --git a/src/backend/tsearch/wparser.c b/src/backend/tsearch/wparser.c index f636c2d23b..bda8d2632d 100644 --- a/src/backend/tsearch/wparser.c +++ b/src/backend/tsearch/wparser.c @@ -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; diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 0869de66ce..a234f35eb8 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -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. */ diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index dcb31586b2..019fcaaa36 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -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); diff --git a/src/backend/utils/adt/like.c b/src/backend/utils/adt/like.c index 0934c69ebe..09e8698af2 100644 --- a/src/backend/utils/adt/like.c +++ b/src/backend/utils/adt/like.c @@ -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) diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index b2152a2491..495b6261e6 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -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); diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 4e5dd4b772..fde01a0f57 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -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)); } diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c index 2c552e173b..919ed9582a 100644 --- a/src/backend/utils/adt/rowtypes.c +++ b/src/backend/utils/adt/rowtypes.c @@ -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; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index b046bc05e6..4d800f8a00 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -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) diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 5caa53d4d2..350e040474 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -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, diff --git a/src/backend/utils/fmgr/README b/src/backend/utils/fmgr/README index 6647fe95f7..a650eb14a3 100644 --- a/src/backend/utils/fmgr/README +++ b/src/backend/utils/fmgr/README @@ -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 diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index 0288fbab4b..ffa19d5a2d 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -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); diff --git a/src/backend/utils/sort/tuplesort.c b/src/backend/utils/sort/tuplesort.c index bd5b4b0a7d..dcfb8f957a 100644 --- a/src/backend/utils/sort/tuplesort.c +++ b/src/backend/utils/sort/tuplesort.c @@ -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); } diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index 74c1098458..06c6fa2f9c 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -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 */ diff --git a/src/include/access/skey.h b/src/include/access/skey.h index 1d0071ac2d..a82e46ee0e 100644 --- a/src/include/access/skey.h +++ b/src/include/access/skey.h @@ -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. diff --git a/src/include/access/valid.h b/src/include/access/valid.h index e81f4cb723..f52ff4fb17 100644 --- a/src/include/access/valid.h +++ b/src/include/access/valid.h @@ -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)) \ { \ diff --git a/src/include/fmgr.h b/src/include/fmgr.h index e58060f834..60d47d97b9 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -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); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 9c688c0368..16756616e5 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -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; /* ---------------- diff --git a/src/include/utils/selfuncs.h b/src/include/utils/selfuncs.h index c1b417ad8f..dd38a0292f 100644 --- a/src/include/utils/selfuncs.h +++ b/src/include/utils/selfuncs.h @@ -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); diff --git a/src/include/utils/tuplesort.h b/src/include/utils/tuplesort.h index a2085df869..1ebcbfe172 100644 --- a/src/include/utils/tuplesort.h +++ b/src/include/utils/tuplesort.h @@ -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); diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 9f919b88c2..535fea9257 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -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) {