From f056cb2deddde2ff0cbef894be2699710720507b Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 9 Jun 2019 21:18:18 +0200 Subject: [PATCH 03/10] Add opclass parameters to GIN --- doc/src/sgml/xindex.sgml | 7 ++++++ src/backend/access/gin/ginget.c | 11 +++++----- src/backend/access/gin/ginlogic.c | 15 +++++++------ src/backend/access/gin/ginscan.c | 6 ++++-- src/backend/access/gin/ginutil.c | 27 +++++++++++++++++------ src/backend/access/gin/ginvalidate.c | 32 +++++++++++++++++----------- src/backend/utils/adt/selfuncs.c | 6 ++++-- src/include/access/gin.h | 3 ++- src/include/access/gin_private.h | 5 +++++ 9 files changed, 78 insertions(+), 34 deletions(-) diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index 8c5b5289d7..658ec9bc5a 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -665,6 +665,13 @@ 6 + + options + + parse opclass-specific options (optional) + + 7 + diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index b18ae2b3ed..547b7b4762 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -188,13 +188,13 @@ collectMatchBitmap(GinBtreeData *btree, GinBtreeStack *stack, * case cmp < 0 => not match and continue scan *---------- */ - cmp = DatumGetInt32(FunctionCall4Coll(&btree->ginstate->comparePartialFn[attnum - 1], + cmp = DatumGetInt32(FunctionCall5Coll(&btree->ginstate->comparePartialFn[attnum - 1], btree->ginstate->supportCollation[attnum - 1], scanEntry->queryKey, idatum, UInt16GetDatum(scanEntry->strategy), - PointerGetDatum(scanEntry->extra_data))); - + PointerGetDatum(scanEntry->extra_data), + PointerGetDatum(btree->ginstate->opclassOptions[attnum - 1]))); if (cmp > 0) return true; else if (cmp < 0) @@ -1508,12 +1508,13 @@ matchPartialInPendingList(GinState *ginstate, Page page, * case cmp < 0 => not match and continue scan *---------- */ - cmp = DatumGetInt32(FunctionCall4Coll(&ginstate->comparePartialFn[entry->attnum - 1], + cmp = DatumGetInt32(FunctionCall5Coll(&ginstate->comparePartialFn[entry->attnum - 1], ginstate->supportCollation[entry->attnum - 1], entry->queryKey, datum[off - 1], UInt16GetDatum(entry->strategy), - PointerGetDatum(entry->extra_data))); + PointerGetDatum(entry->extra_data), + PointerGetDatum(ginstate->opclassOptions[entry->attnum - 1]))); if (cmp == 0) return true; else if (cmp > 0) diff --git a/src/backend/access/gin/ginlogic.c b/src/backend/access/gin/ginlogic.c index 8f85978972..028b29a8c0 100644 --- a/src/backend/access/gin/ginlogic.c +++ b/src/backend/access/gin/ginlogic.c @@ -76,7 +76,7 @@ directBoolConsistentFn(GinScanKey key) */ key->recheckCurItem = true; - return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo, + return DatumGetBool(FunctionCall9Coll(key->consistentFmgrInfo, key->collation, PointerGetDatum(key->entryRes), UInt16GetDatum(key->strategy), @@ -85,7 +85,8 @@ directBoolConsistentFn(GinScanKey key) PointerGetDatum(key->extra_data), PointerGetDatum(&key->recheckCurItem), PointerGetDatum(key->queryValues), - PointerGetDatum(key->queryCategories))); + PointerGetDatum(key->queryCategories), + PointerGetDatum(key->opclassOptions))); } /* @@ -94,7 +95,7 @@ directBoolConsistentFn(GinScanKey key) static GinTernaryValue directTriConsistentFn(GinScanKey key) { - return DatumGetGinTernaryValue(FunctionCall7Coll( + return DatumGetGinTernaryValue(FunctionCall8Coll( key->triConsistentFmgrInfo, key->collation, PointerGetDatum(key->entryRes), @@ -103,7 +104,8 @@ directTriConsistentFn(GinScanKey key) UInt32GetDatum(key->nuserentries), PointerGetDatum(key->extra_data), PointerGetDatum(key->queryValues), - PointerGetDatum(key->queryCategories))); + PointerGetDatum(key->queryCategories), + PointerGetDatum(key->opclassOptions))); } /* @@ -116,7 +118,7 @@ shimBoolConsistentFn(GinScanKey key) { GinTernaryValue result; - result = DatumGetGinTernaryValue(FunctionCall7Coll( + result = DatumGetGinTernaryValue(FunctionCall8Coll( key->triConsistentFmgrInfo, key->collation, PointerGetDatum(key->entryRes), @@ -125,7 +127,8 @@ shimBoolConsistentFn(GinScanKey key) UInt32GetDatum(key->nuserentries), PointerGetDatum(key->extra_data), PointerGetDatum(key->queryValues), - PointerGetDatum(key->queryCategories))); + PointerGetDatum(key->queryCategories), + PointerGetDatum(key->opclassOptions))); if (result == GIN_MAYBE) { key->recheckCurItem = true; diff --git a/src/backend/access/gin/ginscan.c b/src/backend/access/gin/ginscan.c index 74d9821ac1..d1384a33d4 100644 --- a/src/backend/access/gin/ginscan.c +++ b/src/backend/access/gin/ginscan.c @@ -156,6 +156,7 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum, key->strategy = strategy; key->searchMode = searchMode; key->attnum = attnum; + key->opclassOptions = ginstate->opclassOptions[attnum - 1]; ItemPointerSetMin(&key->curItem); key->curItemMatches = false; @@ -310,7 +311,7 @@ ginNewScanKey(IndexScanDesc scan) /* OK to call the extractQueryFn */ queryValues = (Datum *) - DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1], + DatumGetPointer(FunctionCall8Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1], so->ginstate.supportCollation[skey->sk_attno - 1], skey->sk_argument, PointerGetDatum(&nQueryValues), @@ -318,7 +319,8 @@ ginNewScanKey(IndexScanDesc scan) PointerGetDatum(&partial_matches), PointerGetDatum(&extra_data), PointerGetDatum(&nullFlags), - PointerGetDatum(&searchMode))); + PointerGetDatum(&searchMode), + PointerGetDatum(so->ginstate.opclassOptions[skey->sk_attno - 1]))); /* * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index cf9699ad18..03874909b0 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -63,6 +63,7 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amcanreturn = NULL; amroutine->amcostestimate = gincostestimate; amroutine->amoptions = ginoptions; + amroutine->amopclassoptions = ginopclassoptions; amroutine->amproperty = NULL; amroutine->ambuildphasename = NULL; amroutine->amvalidate = ginvalidate; @@ -96,6 +97,7 @@ initGinState(GinState *state, Relation index) state->index = index; state->oneCol = (origTupdesc->natts == 1) ? true : false; state->origTupdesc = origTupdesc; + state->opclassOptions = RelationGetParsedOpclassOptions(index); for (i = 0; i < origTupdesc->natts; i++) { @@ -399,9 +401,10 @@ ginCompareEntries(GinState *ginstate, OffsetNumber attnum, return 0; /* both not null, so safe to call the compareFn */ - return DatumGetInt32(FunctionCall2Coll(&ginstate->compareFn[attnum - 1], + return DatumGetInt32(FunctionCall3Coll(&ginstate->compareFn[attnum - 1], ginstate->supportCollation[attnum - 1], - a, b)); + a, b, + PointerGetDatum(ginstate->opclassOptions[attnum - 1]))); } /* @@ -437,6 +440,7 @@ typedef struct { FmgrInfo *cmpDatumFunc; Oid collation; + Datum options; bool haveDups; } cmpEntriesArg; @@ -458,9 +462,10 @@ cmpEntries(const void *a, const void *b, void *arg) else if (bb->isnull) res = -1; /* not-NULL "<" NULL */ else - res = DatumGetInt32(FunctionCall2Coll(data->cmpDatumFunc, + res = DatumGetInt32(FunctionCall3Coll(data->cmpDatumFunc, data->collation, - aa->datum, bb->datum)); + aa->datum, bb->datum, + data->options)); /* * Detect if we have any duplicates. If there are equal keys, qsort must @@ -506,11 +511,12 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum, /* OK, call the opclass's extractValueFn */ nullFlags = NULL; /* in case extractValue doesn't set it */ entries = (Datum *) - DatumGetPointer(FunctionCall3Coll(&ginstate->extractValueFn[attnum - 1], + DatumGetPointer(FunctionCall4Coll(&ginstate->extractValueFn[attnum - 1], ginstate->supportCollation[attnum - 1], value, PointerGetDatum(nentries), - PointerGetDatum(&nullFlags))); + PointerGetDatum(&nullFlags), + PointerGetDatum(ginstate->opclassOptions[attnum - 1]))); /* * Generate a placeholder if the item contained no keys. @@ -553,6 +559,7 @@ ginExtractEntries(GinState *ginstate, OffsetNumber attnum, arg.cmpDatumFunc = &ginstate->compareFn[attnum - 1]; arg.collation = ginstate->supportCollation[attnum - 1]; + arg.options = PointerGetDatum(ginstate->opclassOptions[attnum - 1]); arg.haveDups = false; qsort_arg(keydata, *nentries, sizeof(keyEntryData), cmpEntries, (void *) &arg); @@ -628,6 +635,14 @@ ginoptions(Datum reloptions, bool validate) return (bytea *) rdopts; } +bytea * +ginopclassoptions(Relation index, AttrNumber colno, Datum attoptions, + bool validate) +{ + return index_opclass_options_generic(index, colno, GIN_OPCLASSOPTIONS_PROC, + attoptions, validate); +} + /* * Fetch index's statistical data into *stats * diff --git a/src/backend/access/gin/ginvalidate.c b/src/backend/access/gin/ginvalidate.c index 63bd7f2adc..a000052f09 100644 --- a/src/backend/access/gin/ginvalidate.c +++ b/src/backend/access/gin/ginvalidate.c @@ -108,40 +108,47 @@ ginvalidate(Oid opclassoid) { case GIN_COMPARE_PROC: ok = check_amproc_signature(procform->amproc, INT4OID, false, - 2, 2, opckeytype, opckeytype); + 2, 3, opckeytype, opckeytype, + INTERNALOID); break; case GIN_EXTRACTVALUE_PROC: /* Some opclasses omit nullFlags */ ok = check_amproc_signature(procform->amproc, INTERNALOID, false, - 2, 3, opcintype, INTERNALOID, - INTERNALOID); + 2, 4, opcintype, INTERNALOID, + INTERNALOID, INTERNALOID); break; case GIN_EXTRACTQUERY_PROC: /* Some opclasses omit nullFlags and searchMode */ ok = check_amproc_signature(procform->amproc, INTERNALOID, false, - 5, 7, opcintype, INTERNALOID, + 5, 8, opcintype, INTERNALOID, INT2OID, INTERNALOID, INTERNALOID, - INTERNALOID, INTERNALOID); + INTERNALOID, INTERNALOID, + INTERNALOID); break; case GIN_CONSISTENT_PROC: /* Some opclasses omit queryKeys and nullFlags */ ok = check_amproc_signature(procform->amproc, BOOLOID, false, - 6, 8, INTERNALOID, INT2OID, + 6, 9, INTERNALOID, INT2OID, opcintype, INT4OID, INTERNALOID, INTERNALOID, - INTERNALOID, INTERNALOID); + INTERNALOID, INTERNALOID, + INTERNALOID); break; case GIN_COMPARE_PARTIAL_PROC: ok = check_amproc_signature(procform->amproc, INT4OID, false, - 4, 4, opckeytype, opckeytype, - INT2OID, INTERNALOID); + 4, 5, opckeytype, opckeytype, + INT2OID, INTERNALOID, INTERNALOID); break; case GIN_TRICONSISTENT_PROC: ok = check_amproc_signature(procform->amproc, CHAROID, false, - 7, 7, INTERNALOID, INT2OID, + 7, 8, INTERNALOID, INT2OID, opcintype, INT4OID, INTERNALOID, INTERNALOID, - INTERNALOID); + INTERNALOID, INTERNALOID); + break; + case GIN_OPCLASSOPTIONS_PROC: + ok = check_amproc_signature(procform->amproc, INTERNALOID, + false, 2, 2, INTERNALOID, BOOLOID); break; default: ereport(INFO, @@ -238,7 +245,8 @@ ginvalidate(Oid opclassoid) if (opclassgroup && (opclassgroup->functionset & (((uint64) 1) << i)) != 0) continue; /* got it */ - if (i == GIN_COMPARE_PROC || i == GIN_COMPARE_PARTIAL_PROC) + if (i == GIN_COMPARE_PROC || i == GIN_COMPARE_PARTIAL_PROC || + i == GIN_OPCLASSOPTIONS_PROC) continue; /* optional method */ if (i == GIN_CONSISTENT_PROC || i == GIN_TRICONSISTENT_PROC) continue; /* don't need both, see check below loop */ diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index d7e3f09f1a..d491bdd7ae 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -135,6 +135,7 @@ #include "utils/lsyscache.h" #include "utils/pg_locale.h" #include "utils/rel.h" +#include "utils/relcache.h" #include "utils/selfuncs.h" #include "utils/snapmgr.h" #include "utils/spccache.h" @@ -6242,7 +6243,7 @@ gincost_pattern(IndexOptInfo *index, int indexcol, else collation = DEFAULT_COLLATION_OID; - OidFunctionCall7Coll(extractProcOid, + OidFunctionCall8Coll(extractProcOid, collation, query, PointerGetDatum(&nentries), @@ -6250,7 +6251,8 @@ gincost_pattern(IndexOptInfo *index, int indexcol, PointerGetDatum(&partial_matches), PointerGetDatum(&extra_data), PointerGetDatum(&nullFlags), - PointerGetDatum(&searchMode)); + PointerGetDatum(&searchMode), + PointerGetDatum(index->opclassoptions[indexcol])); if (nentries <= 0 && searchMode == GIN_SEARCH_MODE_DEFAULT) { diff --git a/src/include/access/gin.h b/src/include/access/gin.h index a8eef5a379..aabfbcd5ce 100644 --- a/src/include/access/gin.h +++ b/src/include/access/gin.h @@ -25,7 +25,8 @@ #define GIN_CONSISTENT_PROC 4 #define GIN_COMPARE_PARTIAL_PROC 5 #define GIN_TRICONSISTENT_PROC 6 -#define GINNProcs 6 +#define GIN_OPCLASSOPTIONS_PROC 7 +#define GINNProcs 7 /* * searchMode settings for extractQueryFn. diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index afb3e15721..0f626a7dbb 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -67,6 +67,8 @@ typedef struct GinState TupleDesc origTupdesc; TupleDesc tupdesc[INDEX_MAX_KEYS]; + bytea **opclassOptions; /* per-index-column opclass options */ + /* * Per-index-column opclass support functions */ @@ -85,6 +87,8 @@ typedef struct GinState /* ginutil.c */ extern bytea *ginoptions(Datum reloptions, bool validate); +extern bytea *ginopclassoptions(Relation index, AttrNumber colno, + Datum attoptions, bool validate); extern void initGinState(GinState *state, Relation index); extern Buffer GinNewBuffer(Relation index); extern void GinInitBuffer(Buffer b, uint32 f); @@ -297,6 +301,7 @@ typedef struct GinScanKeyData StrategyNumber strategy; int32 searchMode; OffsetNumber attnum; + bytea *opclassOptions; /* * Match status data. curItem is the TID most recently tested (could be a -- 2.20.1