From ddd99a8fb48774cfaf9ca151ebb8a5238bc1d2b3 Mon Sep 17 00:00:00 2001 From: Tomas Vondra Date: Sun, 9 Jun 2019 21:17:42 +0200 Subject: [PATCH 02/10] Add opclass parameters to GiST --- doc/src/sgml/xindex.sgml | 5 +++ src/backend/access/gist/gist.c | 2 ++ src/backend/access/gist/gistget.c | 12 ++++--- src/backend/access/gist/gistsplit.c | 15 +++++---- src/backend/access/gist/gistutil.c | 44 ++++++++++++++++++-------- src/backend/access/gist/gistvalidate.c | 34 +++++++++++++------- src/include/access/gist.h | 3 +- src/include/access/gist_private.h | 4 +++ 8 files changed, 82 insertions(+), 37 deletions(-) diff --git a/doc/src/sgml/xindex.sgml b/doc/src/sgml/xindex.sgml index 9446f8b836..8c5b5289d7 100644 --- a/doc/src/sgml/xindex.sgml +++ b/doc/src/sgml/xindex.sgml @@ -546,6 +546,11 @@ index-only scans (optional) 9 + + options + parse opclass-specific options (optional) + 10 + diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index 470b121e7d..8e3460f456 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -98,6 +98,7 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amestimateparallelscan = NULL; amroutine->aminitparallelscan = NULL; amroutine->amparallelrescan = NULL; + amroutine->amopclassoptions = gistopclassoptions; PG_RETURN_POINTER(amroutine); } @@ -1528,6 +1529,7 @@ initGISTstate(Relation index) giststate->scanCxt = scanCxt; giststate->tempCxt = scanCxt; /* caller must change this if needed */ giststate->leafTupdesc = index->rd_att; + giststate->opclassoptions = RelationGetParsedOpclassOptions(index); /* * The truncated tupdesc for non-leaf index tuples, which doesn't contain diff --git a/src/backend/access/gist/gistget.c b/src/backend/access/gist/gistget.c index 8108fbb7d8..abfe659ca5 100644 --- a/src/backend/access/gist/gistget.c +++ b/src/backend/access/gist/gistget.c @@ -196,6 +196,7 @@ gistindex_keytest(IndexScanDesc scan, Datum test; bool recheck; GISTENTRY de; + bytea *options = giststate->opclassoptions[key->sk_attno - 1]; gistdentryinit(giststate, key->sk_attno - 1, &de, datum, r, page, offset, @@ -216,13 +217,14 @@ gistindex_keytest(IndexScanDesc scan, */ recheck = true; - test = FunctionCall5Coll(&key->sk_func, + test = FunctionCall6Coll(&key->sk_func, key->sk_collation, PointerGetDatum(&de), key->sk_argument, Int16GetDatum(key->sk_strategy), ObjectIdGetDatum(key->sk_subtype), - PointerGetDatum(&recheck)); + PointerGetDatum(&recheck), + PointerGetDatum(options)); if (!DatumGetBool(test)) return false; @@ -257,6 +259,7 @@ gistindex_keytest(IndexScanDesc scan, Datum dist; bool recheck; GISTENTRY de; + bytea *options = giststate->opclassoptions[key->sk_attno - 1]; gistdentryinit(giststate, key->sk_attno - 1, &de, datum, r, page, offset, @@ -279,13 +282,14 @@ gistindex_keytest(IndexScanDesc scan, * about the flag, but are expected to never be lossy. */ recheck = false; - dist = FunctionCall5Coll(&key->sk_func, + dist = FunctionCall6Coll(&key->sk_func, key->sk_collation, PointerGetDatum(&de), key->sk_argument, Int16GetDatum(key->sk_strategy), ObjectIdGetDatum(key->sk_subtype), - PointerGetDatum(&recheck)); + PointerGetDatum(&recheck), + PointerGetDatum(options)); *recheck_distances_p |= recheck; *distance_p = DatumGetFloat8(dist); } diff --git a/src/backend/access/gist/gistsplit.c b/src/backend/access/gist/gistsplit.c index 6a9c54d86c..2b3cb967e1 100644 --- a/src/backend/access/gist/gistsplit.c +++ b/src/backend/access/gist/gistsplit.c @@ -378,18 +378,20 @@ genericPickSplit(GISTSTATE *giststate, GistEntryVector *entryvec, GIST_SPLITVEC evec->n = v->spl_nleft; memcpy(evec->vector, entryvec->vector + FirstOffsetNumber, sizeof(GISTENTRY) * evec->n); - v->spl_ldatum = FunctionCall2Coll(&giststate->unionFn[attno], + v->spl_ldatum = FunctionCall3Coll(&giststate->unionFn[attno], giststate->supportCollation[attno], PointerGetDatum(evec), - PointerGetDatum(&nbytes)); + PointerGetDatum(&nbytes), + PointerGetDatum(giststate->opclassoptions[attno])); evec->n = v->spl_nright; memcpy(evec->vector, entryvec->vector + FirstOffsetNumber + v->spl_nleft, sizeof(GISTENTRY) * evec->n); - v->spl_rdatum = FunctionCall2Coll(&giststate->unionFn[attno], + v->spl_rdatum = FunctionCall3Coll(&giststate->unionFn[attno], giststate->supportCollation[attno], PointerGetDatum(evec), - PointerGetDatum(&nbytes)); + PointerGetDatum(&nbytes), + PointerGetDatum(giststate->opclassoptions[attno])); } /* @@ -430,10 +432,11 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec * Let the opclass-specific PickSplit method do its thing. Note that at * this point we know there are no null keys in the entryvec. */ - FunctionCall2Coll(&giststate->picksplitFn[attno], + FunctionCall3Coll(&giststate->picksplitFn[attno], giststate->supportCollation[attno], PointerGetDatum(entryvec), - PointerGetDatum(sv)); + PointerGetDatum(sv), + PointerGetDatum(giststate->opclassoptions[attno])); if (sv->spl_nleft == 0 || sv->spl_nright == 0) { diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c index 49df05653b..000f10103c 100644 --- a/src/backend/access/gist/gistutil.c +++ b/src/backend/access/gist/gistutil.c @@ -201,10 +201,11 @@ gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, } /* Make union and store in attr array */ - attr[i] = FunctionCall2Coll(&giststate->unionFn[i], + attr[i] = FunctionCall3Coll(&giststate->unionFn[i], giststate->supportCollation[i], PointerGetDatum(evec), - PointerGetDatum(&attrsize)); + PointerGetDatum(&attrsize), + PointerGetDatum(giststate->opclassoptions[i])); isnull[i] = false; } @@ -270,10 +271,11 @@ gistMakeUnionKey(GISTSTATE *giststate, int attno, } *dstisnull = false; - *dst = FunctionCall2Coll(&giststate->unionFn[attno], + *dst = FunctionCall3Coll(&giststate->unionFn[attno], giststate->supportCollation[attno], PointerGetDatum(evec), - PointerGetDatum(&dstsize)); + PointerGetDatum(&dstsize), + PointerGetDatum(giststate->opclassoptions[attno])); } } @@ -282,10 +284,11 @@ gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) { bool result; - FunctionCall3Coll(&giststate->equalFn[attno], + FunctionCall4Coll(&giststate->equalFn[attno], giststate->supportCollation[attno], a, b, - PointerGetDatum(&result)); + PointerGetDatum(&result), + PointerGetDatum(giststate->opclassoptions[attno])); return result; } @@ -559,9 +562,10 @@ gistdentryinit(GISTSTATE *giststate, int nkey, GISTENTRY *e, return; dep = (GISTENTRY *) - DatumGetPointer(FunctionCall1Coll(&giststate->decompressFn[nkey], + DatumGetPointer(FunctionCall2Coll(&giststate->decompressFn[nkey], giststate->supportCollation[nkey], - PointerGetDatum(e))); + PointerGetDatum(e), + PointerGetDatum(giststate->opclassoptions[nkey]))); /* decompressFn may just return the given pointer */ if (dep != e) gistentryinit(*e, dep->key, dep->rel, dep->page, dep->offset, @@ -596,9 +600,10 @@ gistFormTuple(GISTSTATE *giststate, Relation r, /* there may not be a compress function in opclass */ if (OidIsValid(giststate->compressFn[i].fn_oid)) cep = (GISTENTRY *) - DatumGetPointer(FunctionCall1Coll(&giststate->compressFn[i], + DatumGetPointer(FunctionCall2Coll(&giststate->compressFn[i], giststate->supportCollation[i], - PointerGetDatum(¢ry))); + PointerGetDatum(¢ry), + PointerGetDatum(giststate->opclassoptions[i]))); else cep = ¢ry; compatt[i] = cep->key; @@ -643,9 +648,10 @@ gistFetchAtt(GISTSTATE *giststate, int nkey, Datum k, Relation r) gistentryinit(fentry, k, r, NULL, (OffsetNumber) 0, false); fep = (GISTENTRY *) - DatumGetPointer(FunctionCall1Coll(&giststate->fetchFn[nkey], + DatumGetPointer(FunctionCall2Coll(&giststate->fetchFn[nkey], giststate->supportCollation[nkey], - PointerGetDatum(&fentry))); + PointerGetDatum(&fentry), + PointerGetDatum(giststate->opclassoptions[nkey]))); /* fetchFn set 'key', return it to the caller */ return fep->key; @@ -722,11 +728,12 @@ gistpenalty(GISTSTATE *giststate, int attno, if (giststate->penaltyFn[attno].fn_strict == false || (isNullOrig == false && isNullAdd == false)) { - FunctionCall3Coll(&giststate->penaltyFn[attno], + FunctionCall4Coll(&giststate->penaltyFn[attno], giststate->supportCollation[attno], PointerGetDatum(orig), PointerGetDatum(add), - PointerGetDatum(&penalty)); + PointerGetDatum(&penalty), + PointerGetDatum(giststate->opclassoptions[attno])); /* disallow negative or NaN penalty */ if (isnan(penalty) || penalty < 0.0) penalty = 0.0; @@ -915,6 +922,15 @@ gistoptions(Datum reloptions, bool validate) return (bytea *) rdopts; } +bytea * +gistopclassoptions(Relation index, AttrNumber attnum, Datum attoptions, + bool validate) +{ + return index_opclass_options_generic(index, attnum, GIST_OPCLASSOPT_PROC, + attoptions, validate); +} + + /* * gistproperty() -- Check boolean properties of indexes. * diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c index dfc1a87a75..7ae820070b 100644 --- a/src/backend/access/gist/gistvalidate.c +++ b/src/backend/access/gist/gistvalidate.c @@ -108,37 +108,46 @@ gistvalidate(Oid opclassoid) { case GIST_CONSISTENT_PROC: ok = check_amproc_signature(procform->amproc, BOOLOID, false, - 5, 5, INTERNALOID, opcintype, - INT2OID, OIDOID, INTERNALOID); + 5, 6, INTERNALOID, opcintype, + INT2OID, OIDOID, INTERNALOID, + INTERNALOID); break; case GIST_UNION_PROC: ok = check_amproc_signature(procform->amproc, opckeytype, false, - 2, 2, INTERNALOID, INTERNALOID); + 2, 3, INTERNALOID, INTERNALOID, + INTERNALOID); break; case GIST_COMPRESS_PROC: case GIST_DECOMPRESS_PROC: case GIST_FETCH_PROC: ok = check_amproc_signature(procform->amproc, INTERNALOID, true, - 1, 1, INTERNALOID); + 1, 2, INTERNALOID, INTERNALOID); break; case GIST_PENALTY_PROC: ok = check_amproc_signature(procform->amproc, INTERNALOID, true, - 3, 3, INTERNALOID, - INTERNALOID, INTERNALOID); + 3, 4, INTERNALOID, + INTERNALOID, INTERNALOID, + INTERNALOID); break; case GIST_PICKSPLIT_PROC: ok = check_amproc_signature(procform->amproc, INTERNALOID, true, - 2, 2, INTERNALOID, INTERNALOID); + 2, 3, INTERNALOID, INTERNALOID, + INTERNALOID); break; case GIST_EQUAL_PROC: ok = check_amproc_signature(procform->amproc, INTERNALOID, false, - 3, 3, opckeytype, opckeytype, - INTERNALOID); + 3, 4, opckeytype, opckeytype, + INTERNALOID, INTERNALOID); break; case GIST_DISTANCE_PROC: ok = check_amproc_signature(procform->amproc, FLOAT8OID, false, - 5, 5, INTERNALOID, opcintype, - INT2OID, OIDOID, INTERNALOID); + 5, 6, INTERNALOID, opcintype, + INT2OID, OIDOID, INTERNALOID, + INTERNALOID); + break; + case GIST_OPCLASSOPT_PROC: + ok = check_amproc_signature(procform->amproc, INTERNALOID, false, + 2, 2, INTERNALOID, BOOLOID); break; default: ereport(INFO, @@ -259,7 +268,8 @@ gistvalidate(Oid opclassoid) (opclassgroup->functionset & (((uint64) 1) << i)) != 0) continue; /* got it */ if (i == GIST_DISTANCE_PROC || i == GIST_FETCH_PROC || - i == GIST_COMPRESS_PROC || i == GIST_DECOMPRESS_PROC) + i == GIST_COMPRESS_PROC || i == GIST_DECOMPRESS_PROC || + i == GIST_OPCLASSOPT_PROC) continue; /* optional methods */ ereport(INFO, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), diff --git a/src/include/access/gist.h b/src/include/access/gist.h index 6902f4115b..0c57a64369 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -34,7 +34,8 @@ #define GIST_EQUAL_PROC 7 #define GIST_DISTANCE_PROC 8 #define GIST_FETCH_PROC 9 -#define GISTNProcs 9 +#define GIST_OPCLASSOPT_PROC 10 +#define GISTNProcs 10 /* * Page opaque data in a GiST index page. diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index f80694bf9a..d46b6b89f9 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -96,6 +96,8 @@ typedef struct GISTSTATE /* Collations to pass to the support functions */ Oid supportCollation[INDEX_MAX_KEYS]; + + bytea **opclassoptions; /* parsed opclass-specific options */ } GISTSTATE; @@ -462,6 +464,8 @@ extern bool gistvalidate(Oid opclassoid); #define GIST_DEFAULT_FILLFACTOR 90 extern bytea *gistoptions(Datum reloptions, bool validate); +extern bytea *gistopclassoptions(Relation index, AttrNumber colno, + Datum options, bool validate); extern bool gistproperty(Oid index_oid, int attno, IndexAMProperty prop, const char *propname, bool *res, bool *isnull); -- 2.20.1