Change IndexAmRoutines to be statically-allocated structs.

Up to now, index amhandlers were expected to produce a new, palloc'd
struct on each call.  That requires palloc/pfree overhead, and creates
a risk of memory leaks if the caller fails to pfree, and the time
taken to fill such a large structure isn't nil.  Moreover, we were
storing these things in the relcache, eating several hundred bytes for
each cached index.  There is not anything in these structs that needs
to vary at runtime, so let's change the definition so that an
amhandler can return a pointer to a "static const" struct of which
there's only one copy per index AM.  Mark all the core code's
IndexAmRoutine pointers const so that we catch anyplace that might
still try to change or pfree one.

(This is similar to the way we were already handling TableAmRoutine
structs.  This commit does fix one comment that was infelicitously
copied-and-pasted into tableamapi.c.)

This commit needs to be called out in the v19 release notes as an API
change for extension index AMs.  An un-updated AM will still work
(as of now, anyway) but it risks memory leaks and will be slower than
necessary.

Author: Matthias van de Meent <boekewurm+postgres@gmail.com>
Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us>
Discussion: https://postgr.es/m/CAEoWx2=vApYk2LRu8R0DdahsPNEhWUxGBZ=rbZo1EXE=uA+opQ@mail.gmail.com
master
Tom Lane 6 days ago
parent 736f754eed
commit bc6374cd76
  1. 111
      contrib/bloom/blutils.c
  2. 12
      doc/src/sgml/indexam.sgml
  3. 113
      src/backend/access/brin/brin.c
  4. 109
      src/backend/access/gin/ginutil.c
  5. 113
      src/backend/access/gist/gist.c
  6. 113
      src/backend/access/hash/hash.c
  7. 18
      src/backend/access/index/amapi.c
  8. 113
      src/backend/access/nbtree/nbtree.c
  9. 113
      src/backend/access/spgist/spgutils.c
  10. 5
      src/backend/access/table/tableamapi.c
  11. 4
      src/backend/catalog/index.c
  12. 5
      src/backend/commands/indexcmds.c
  13. 10
      src/backend/commands/opclasscmds.c
  14. 3
      src/backend/executor/execAmi.c
  15. 2
      src/backend/optimizer/util/plancat.c
  16. 4
      src/backend/utils/adt/amutils.c
  17. 2
      src/backend/utils/adt/ruleutils.c
  18. 35
      src/backend/utils/cache/lsyscache.c
  19. 21
      src/backend/utils/cache/relcache.c
  20. 8
      src/include/access/amapi.h
  21. 2
      src/include/utils/rel.h
  22. 101
      src/test/modules/dummy_index_am/dummy_index_am.c

@ -102,61 +102,62 @@ makeDefaultBloomOptions(void)
Datum
blhandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = BLOOM_NSTRATEGIES;
amroutine->amsupport = BLOOM_NPROC;
amroutine->amoptsprocnum = BLOOM_OPTIONS_PROC;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = true;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = false;
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = false;
amroutine->amcaninclude = false;
amroutine->amusemaintenanceworkmem = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = blbuild;
amroutine->ambuildempty = blbuildempty;
amroutine->aminsert = blinsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = blbulkdelete;
amroutine->amvacuumcleanup = blvacuumcleanup;
amroutine->amcanreturn = NULL;
amroutine->amcostestimate = blcostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = bloptions;
amroutine->amproperty = NULL;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = blvalidate;
amroutine->amadjustmembers = NULL;
amroutine->ambeginscan = blbeginscan;
amroutine->amrescan = blrescan;
amroutine->amgettuple = NULL;
amroutine->amgetbitmap = blgetbitmap;
amroutine->amendscan = blendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = NULL;
amroutine->amtranslatecmptype = NULL;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = BLOOM_NSTRATEGIES,
.amsupport = BLOOM_NPROC,
.amoptsprocnum = BLOOM_OPTIONS_PROC,
.amcanorder = false,
.amcanorderbyop = false,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = true,
.amoptionalkey = true,
.amsearcharray = false,
.amsearchnulls = false,
.amstorage = false,
.amclusterable = false,
.ampredlocks = false,
.amcanparallel = false,
.amcanbuildparallel = false,
.amcaninclude = false,
.amusemaintenanceworkmem = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = blbuild,
.ambuildempty = blbuildempty,
.aminsert = blinsert,
.aminsertcleanup = NULL,
.ambulkdelete = blbulkdelete,
.amvacuumcleanup = blvacuumcleanup,
.amcanreturn = NULL,
.amcostestimate = blcostestimate,
.amgettreeheight = NULL,
.amoptions = bloptions,
.amproperty = NULL,
.ambuildphasename = NULL,
.amvalidate = blvalidate,
.amadjustmembers = NULL,
.ambeginscan = blbeginscan,
.amrescan = blrescan,
.amgettuple = NULL,
.amgetbitmap = blgetbitmap,
.amendscan = blendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
.amtranslatestrategy = NULL,
.amtranslatecmptype = NULL,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -70,9 +70,15 @@
single argument of type <type>internal</type> and to return the
pseudo-type <type>index_am_handler</type>. The argument is a dummy value that
simply serves to prevent handler functions from being called directly from
SQL commands. The result of the function must be a palloc'd struct of
type <structname>IndexAmRoutine</structname>, which contains everything
that the core code needs to know to make use of the index access method.
SQL commands.
The result of the handler function must be a pointer to a permanently
allocated struct of type <structname>IndexAmRoutine</structname>, which
contains everything that the core code needs to know to make use of the
index access method. (Typically this struct can be pre-initialized and
marked <literal>static const</literal>; but if that is inconvenient,
build it in some long-lived context. In any case, repeat calls within
a process should return the same pointer. The core code will treat the
struct as <literal>const</literal>, and will never free it.)
The <structname>IndexAmRoutine</structname> struct, also called the access
method's <firstterm>API struct</firstterm>, includes fields specifying assorted
fixed properties of the access method, such as whether it can support

@ -249,62 +249,63 @@ static void _brin_parallel_scan_and_build(BrinBuildState *state,
Datum
brinhandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = 0;
amroutine->amsupport = BRIN_LAST_OPTIONAL_PROCNUM;
amroutine->amoptsprocnum = BRIN_PROCNUM_OPTIONS;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = true;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = true;
amroutine->amstorage = true;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = true;
amroutine->amcaninclude = false;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = true;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = brinbuild;
amroutine->ambuildempty = brinbuildempty;
amroutine->aminsert = brininsert;
amroutine->aminsertcleanup = brininsertcleanup;
amroutine->ambulkdelete = brinbulkdelete;
amroutine->amvacuumcleanup = brinvacuumcleanup;
amroutine->amcanreturn = NULL;
amroutine->amcostestimate = brincostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = brinoptions;
amroutine->amproperty = NULL;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = brinvalidate;
amroutine->amadjustmembers = NULL;
amroutine->ambeginscan = brinbeginscan;
amroutine->amrescan = brinrescan;
amroutine->amgettuple = NULL;
amroutine->amgetbitmap = bringetbitmap;
amroutine->amendscan = brinendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = NULL;
amroutine->amtranslatecmptype = NULL;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = 0,
.amsupport = BRIN_LAST_OPTIONAL_PROCNUM,
.amoptsprocnum = BRIN_PROCNUM_OPTIONS,
.amcanorder = false,
.amcanorderbyop = false,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = true,
.amoptionalkey = true,
.amsearcharray = false,
.amsearchnulls = true,
.amstorage = true,
.amclusterable = false,
.ampredlocks = false,
.amcanparallel = false,
.amcanbuildparallel = true,
.amcaninclude = false,
.amusemaintenanceworkmem = false,
.amsummarizing = true,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = brinbuild,
.ambuildempty = brinbuildempty,
.aminsert = brininsert,
.aminsertcleanup = brininsertcleanup,
.ambulkdelete = brinbulkdelete,
.amvacuumcleanup = brinvacuumcleanup,
.amcanreturn = NULL,
.amcostestimate = brincostestimate,
.amgettreeheight = NULL,
.amoptions = brinoptions,
.amproperty = NULL,
.ambuildphasename = NULL,
.amvalidate = brinvalidate,
.amadjustmembers = NULL,
.ambeginscan = brinbeginscan,
.amrescan = brinrescan,
.amgettuple = NULL,
.amgetbitmap = bringetbitmap,
.amendscan = brinendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
.amtranslatestrategy = NULL,
.amtranslatecmptype = NULL,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -37,60 +37,61 @@
Datum
ginhandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = 0;
amroutine->amsupport = GINNProcs;
amroutine->amoptsprocnum = GIN_OPTIONS_PROC;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = true;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = false;
amroutine->amstorage = true;
amroutine->amclusterable = false;
amroutine->ampredlocks = true;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = true;
amroutine->amcaninclude = false;
amroutine->amusemaintenanceworkmem = true;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = ginbuild;
amroutine->ambuildempty = ginbuildempty;
amroutine->aminsert = gininsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = ginbulkdelete;
amroutine->amvacuumcleanup = ginvacuumcleanup;
amroutine->amcanreturn = NULL;
amroutine->amcostestimate = gincostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = ginoptions;
amroutine->amproperty = NULL;
amroutine->ambuildphasename = ginbuildphasename;
amroutine->amvalidate = ginvalidate;
amroutine->amadjustmembers = ginadjustmembers;
amroutine->ambeginscan = ginbeginscan;
amroutine->amrescan = ginrescan;
amroutine->amgettuple = NULL;
amroutine->amgetbitmap = gingetbitmap;
amroutine->amendscan = ginendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = 0,
.amsupport = GINNProcs,
.amoptsprocnum = GIN_OPTIONS_PROC,
.amcanorder = false,
.amcanorderbyop = false,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = true,
.amoptionalkey = true,
.amsearcharray = false,
.amsearchnulls = false,
.amstorage = true,
.amclusterable = false,
.ampredlocks = true,
.amcanparallel = false,
.amcanbuildparallel = true,
.amcaninclude = false,
.amusemaintenanceworkmem = true,
.amsummarizing = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = ginbuild,
.ambuildempty = ginbuildempty,
.aminsert = gininsert,
.aminsertcleanup = NULL,
.ambulkdelete = ginbulkdelete,
.amvacuumcleanup = ginvacuumcleanup,
.amcanreturn = NULL,
.amcostestimate = gincostestimate,
.amgettreeheight = NULL,
.amoptions = ginoptions,
.amproperty = NULL,
.ambuildphasename = ginbuildphasename,
.amvalidate = ginvalidate,
.amadjustmembers = ginadjustmembers,
.ambeginscan = ginbeginscan,
.amrescan = ginrescan,
.amgettuple = NULL,
.amgetbitmap = gingetbitmap,
.amendscan = ginendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -58,62 +58,63 @@ static void gistprunepage(Relation rel, Page page, Buffer buffer,
Datum
gisthandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = 0;
amroutine->amsupport = GISTNProcs;
amroutine->amoptsprocnum = GIST_OPTIONS_PROC;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = true;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = true;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = true;
amroutine->amstorage = true;
amroutine->amclusterable = true;
amroutine->ampredlocks = true;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = false;
amroutine->amcaninclude = true;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = gistbuild;
amroutine->ambuildempty = gistbuildempty;
amroutine->aminsert = gistinsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = gistbulkdelete;
amroutine->amvacuumcleanup = gistvacuumcleanup;
amroutine->amcanreturn = gistcanreturn;
amroutine->amcostestimate = gistcostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = gistoptions;
amroutine->amproperty = gistproperty;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = gistvalidate;
amroutine->amadjustmembers = gistadjustmembers;
amroutine->ambeginscan = gistbeginscan;
amroutine->amrescan = gistrescan;
amroutine->amgettuple = gistgettuple;
amroutine->amgetbitmap = gistgetbitmap;
amroutine->amendscan = gistendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = NULL;
amroutine->amtranslatecmptype = gisttranslatecmptype;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = 0,
.amsupport = GISTNProcs,
.amoptsprocnum = GIST_OPTIONS_PROC,
.amcanorder = false,
.amcanorderbyop = true,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = true,
.amoptionalkey = true,
.amsearcharray = false,
.amsearchnulls = true,
.amstorage = true,
.amclusterable = true,
.ampredlocks = true,
.amcanparallel = false,
.amcanbuildparallel = false,
.amcaninclude = true,
.amusemaintenanceworkmem = false,
.amsummarizing = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = gistbuild,
.ambuildempty = gistbuildempty,
.aminsert = gistinsert,
.aminsertcleanup = NULL,
.ambulkdelete = gistbulkdelete,
.amvacuumcleanup = gistvacuumcleanup,
.amcanreturn = gistcanreturn,
.amcostestimate = gistcostestimate,
.amgettreeheight = NULL,
.amoptions = gistoptions,
.amproperty = gistproperty,
.ambuildphasename = NULL,
.amvalidate = gistvalidate,
.amadjustmembers = gistadjustmembers,
.ambeginscan = gistbeginscan,
.amrescan = gistrescan,
.amgettuple = gistgettuple,
.amgetbitmap = gistgetbitmap,
.amendscan = gistendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
.amtranslatestrategy = NULL,
.amtranslatecmptype = gisttranslatecmptype,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -57,62 +57,63 @@ static void hashbuildCallback(Relation index,
Datum
hashhandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = HTMaxStrategyNumber;
amroutine->amsupport = HASHNProcs;
amroutine->amoptsprocnum = HASHOPTIONS_PROC;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = true;
amroutine->amconsistentequality = true;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = true;
amroutine->amcanunique = false;
amroutine->amcanmulticol = false;
amroutine->amoptionalkey = false;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = false;
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = true;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = false;
amroutine->amcaninclude = false;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL;
amroutine->amkeytype = INT4OID;
amroutine->ambuild = hashbuild;
amroutine->ambuildempty = hashbuildempty;
amroutine->aminsert = hashinsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = hashbulkdelete;
amroutine->amvacuumcleanup = hashvacuumcleanup;
amroutine->amcanreturn = NULL;
amroutine->amcostestimate = hashcostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = hashoptions;
amroutine->amproperty = NULL;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = hashvalidate;
amroutine->amadjustmembers = hashadjustmembers;
amroutine->ambeginscan = hashbeginscan;
amroutine->amrescan = hashrescan;
amroutine->amgettuple = hashgettuple;
amroutine->amgetbitmap = hashgetbitmap;
amroutine->amendscan = hashendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = hashtranslatestrategy;
amroutine->amtranslatecmptype = hashtranslatecmptype;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = HTMaxStrategyNumber,
.amsupport = HASHNProcs,
.amoptsprocnum = HASHOPTIONS_PROC,
.amcanorder = false,
.amcanorderbyop = false,
.amcanhash = true,
.amconsistentequality = true,
.amconsistentordering = false,
.amcanbackward = true,
.amcanunique = false,
.amcanmulticol = false,
.amoptionalkey = false,
.amsearcharray = false,
.amsearchnulls = false,
.amstorage = false,
.amclusterable = false,
.ampredlocks = true,
.amcanparallel = false,
.amcanbuildparallel = false,
.amcaninclude = false,
.amusemaintenanceworkmem = false,
.amsummarizing = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL,
.amkeytype = INT4OID,
.ambuild = hashbuild,
.ambuildempty = hashbuildempty,
.aminsert = hashinsert,
.aminsertcleanup = NULL,
.ambulkdelete = hashbulkdelete,
.amvacuumcleanup = hashvacuumcleanup,
.amcanreturn = NULL,
.amcostestimate = hashcostestimate,
.amgettreeheight = NULL,
.amoptions = hashoptions,
.amproperty = NULL,
.ambuildphasename = NULL,
.amvalidate = hashvalidate,
.amadjustmembers = hashadjustmembers,
.ambeginscan = hashbeginscan,
.amrescan = hashrescan,
.amgettuple = hashgettuple,
.amgetbitmap = hashgetbitmap,
.amendscan = hashendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
.amtranslatestrategy = hashtranslatestrategy,
.amtranslatecmptype = hashtranslatecmptype,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -23,20 +23,20 @@
/*
* GetIndexAmRoutine - call the specified access method handler routine to get
* its IndexAmRoutine struct, which will be palloc'd in the caller's context.
* its IndexAmRoutine struct, which we expect to be statically allocated.
*
* Note that if the amhandler function is built-in, this will not involve
* any catalog access. It's therefore safe to use this while bootstrapping
* indexes for the system catalogs. relcache.c relies on that.
*/
IndexAmRoutine *
const IndexAmRoutine *
GetIndexAmRoutine(Oid amhandler)
{
Datum datum;
IndexAmRoutine *routine;
const IndexAmRoutine *routine;
datum = OidFunctionCall0(amhandler);
routine = (IndexAmRoutine *) DatumGetPointer(datum);
routine = (const IndexAmRoutine *) DatumGetPointer(datum);
if (routine == NULL || !IsA(routine, IndexAmRoutine))
elog(ERROR, "index access method handler function %u did not return an IndexAmRoutine struct",
@ -65,7 +65,7 @@ GetIndexAmRoutine(Oid amhandler)
* If the given OID isn't a valid index access method, returns NULL if
* noerror is true, else throws error.
*/
IndexAmRoutine *
const IndexAmRoutine *
GetIndexAmRoutineByAmId(Oid amoid, bool noerror)
{
HeapTuple tuple;
@ -131,7 +131,7 @@ CompareType
IndexAmTranslateStrategy(StrategyNumber strategy, Oid amoid, Oid opfamily, bool missing_ok)
{
CompareType result;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
/* shortcut for common case */
if (amoid == BTREE_AM_OID &&
@ -161,7 +161,7 @@ StrategyNumber
IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok)
{
StrategyNumber result;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
/* shortcut for common case */
if (amoid == BTREE_AM_OID &&
@ -191,7 +191,7 @@ amvalidate(PG_FUNCTION_ARGS)
HeapTuple classtup;
Form_pg_opclass classform;
Oid amoid;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
classtup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclassoid));
if (!HeapTupleIsValid(classtup))
@ -210,7 +210,5 @@ amvalidate(PG_FUNCTION_ARGS)
result = amroutine->amvalidate(opclassoid);
pfree(amroutine);
PG_RETURN_BOOL(result);
}

@ -115,62 +115,63 @@ static BTVacuumPosting btreevacuumposting(BTVacState *vstate,
Datum
bthandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = BTMaxStrategyNumber;
amroutine->amsupport = BTNProcs;
amroutine->amoptsprocnum = BTOPTIONS_PROC;
amroutine->amcanorder = true;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = false;
amroutine->amconsistentequality = true;
amroutine->amconsistentordering = true;
amroutine->amcanbackward = true;
amroutine->amcanunique = true;
amroutine->amcanmulticol = true;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = true;
amroutine->amsearchnulls = true;
amroutine->amstorage = false;
amroutine->amclusterable = true;
amroutine->ampredlocks = true;
amroutine->amcanparallel = true;
amroutine->amcanbuildparallel = true;
amroutine->amcaninclude = true;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = btbuild;
amroutine->ambuildempty = btbuildempty;
amroutine->aminsert = btinsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = btbulkdelete;
amroutine->amvacuumcleanup = btvacuumcleanup;
amroutine->amcanreturn = btcanreturn;
amroutine->amcostestimate = btcostestimate;
amroutine->amgettreeheight = btgettreeheight;
amroutine->amoptions = btoptions;
amroutine->amproperty = btproperty;
amroutine->ambuildphasename = btbuildphasename;
amroutine->amvalidate = btvalidate;
amroutine->amadjustmembers = btadjustmembers;
amroutine->ambeginscan = btbeginscan;
amroutine->amrescan = btrescan;
amroutine->amgettuple = btgettuple;
amroutine->amgetbitmap = btgetbitmap;
amroutine->amendscan = btendscan;
amroutine->ammarkpos = btmarkpos;
amroutine->amrestrpos = btrestrpos;
amroutine->amestimateparallelscan = btestimateparallelscan;
amroutine->aminitparallelscan = btinitparallelscan;
amroutine->amparallelrescan = btparallelrescan;
amroutine->amtranslatestrategy = bttranslatestrategy;
amroutine->amtranslatecmptype = bttranslatecmptype;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = BTMaxStrategyNumber,
.amsupport = BTNProcs,
.amoptsprocnum = BTOPTIONS_PROC,
.amcanorder = true,
.amcanorderbyop = false,
.amcanhash = false,
.amconsistentequality = true,
.amconsistentordering = true,
.amcanbackward = true,
.amcanunique = true,
.amcanmulticol = true,
.amoptionalkey = true,
.amsearcharray = true,
.amsearchnulls = true,
.amstorage = false,
.amclusterable = true,
.ampredlocks = true,
.amcanparallel = true,
.amcanbuildparallel = true,
.amcaninclude = true,
.amusemaintenanceworkmem = false,
.amsummarizing = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = btbuild,
.ambuildempty = btbuildempty,
.aminsert = btinsert,
.aminsertcleanup = NULL,
.ambulkdelete = btbulkdelete,
.amvacuumcleanup = btvacuumcleanup,
.amcanreturn = btcanreturn,
.amcostestimate = btcostestimate,
.amgettreeheight = btgettreeheight,
.amoptions = btoptions,
.amproperty = btproperty,
.ambuildphasename = btbuildphasename,
.amvalidate = btvalidate,
.amadjustmembers = btadjustmembers,
.ambeginscan = btbeginscan,
.amrescan = btrescan,
.amgettuple = btgettuple,
.amgetbitmap = btgetbitmap,
.amendscan = btendscan,
.ammarkpos = btmarkpos,
.amrestrpos = btrestrpos,
.amestimateparallelscan = btestimateparallelscan,
.aminitparallelscan = btinitparallelscan,
.amparallelrescan = btparallelrescan,
.amtranslatestrategy = bttranslatestrategy,
.amtranslatecmptype = bttranslatecmptype,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -43,62 +43,63 @@
Datum
spghandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = 0;
amroutine->amsupport = SPGISTNProc;
amroutine->amoptsprocnum = SPGIST_OPTIONS_PROC;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = true;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = false;
amroutine->amoptionalkey = true;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = true;
amroutine->amstorage = true;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = false;
amroutine->amcaninclude = true;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = spgbuild;
amroutine->ambuildempty = spgbuildempty;
amroutine->aminsert = spginsert;
amroutine->aminsertcleanup = NULL;
amroutine->ambulkdelete = spgbulkdelete;
amroutine->amvacuumcleanup = spgvacuumcleanup;
amroutine->amcanreturn = spgcanreturn;
amroutine->amcostestimate = spgcostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = spgoptions;
amroutine->amproperty = spgproperty;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = spgvalidate;
amroutine->amadjustmembers = spgadjustmembers;
amroutine->ambeginscan = spgbeginscan;
amroutine->amrescan = spgrescan;
amroutine->amgettuple = spggettuple;
amroutine->amgetbitmap = spggetbitmap;
amroutine->amendscan = spgendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
amroutine->amtranslatestrategy = NULL;
amroutine->amtranslatecmptype = NULL;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = 0,
.amsupport = SPGISTNProc,
.amoptsprocnum = SPGIST_OPTIONS_PROC,
.amcanorder = false,
.amcanorderbyop = true,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = false,
.amoptionalkey = true,
.amsearcharray = false,
.amsearchnulls = true,
.amstorage = true,
.amclusterable = false,
.ampredlocks = false,
.amcanparallel = false,
.amcanbuildparallel = false,
.amcaninclude = true,
.amusemaintenanceworkmem = false,
.amsummarizing = false,
.amparallelvacuumoptions =
VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP,
.amkeytype = InvalidOid,
.ambuild = spgbuild,
.ambuildempty = spgbuildempty,
.aminsert = spginsert,
.aminsertcleanup = NULL,
.ambulkdelete = spgbulkdelete,
.amvacuumcleanup = spgvacuumcleanup,
.amcanreturn = spgcanreturn,
.amcostestimate = spgcostestimate,
.amgettreeheight = NULL,
.amoptions = spgoptions,
.amproperty = spgproperty,
.ambuildphasename = NULL,
.amvalidate = spgvalidate,
.amadjustmembers = spgadjustmembers,
.ambeginscan = spgbeginscan,
.amrescan = spgrescan,
.amgettuple = spggettuple,
.amgetbitmap = spggetbitmap,
.amendscan = spgendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
.amtranslatestrategy = NULL,
.amtranslatecmptype = NULL,
};
PG_RETURN_POINTER(&amroutine);
}
/*

@ -21,8 +21,7 @@
/*
* GetTableAmRoutine
* Call the specified access method handler routine to get its
* TableAmRoutine struct, which will be palloc'd in the caller's
* memory context.
* TableAmRoutine struct, which we expect to be statically allocated.
*/
const TableAmRoutine *
GetTableAmRoutine(Oid amhandler)
@ -31,7 +30,7 @@ GetTableAmRoutine(Oid amhandler)
const TableAmRoutine *routine;
datum = OidFunctionCall0(amhandler);
routine = (TableAmRoutine *) DatumGetPointer(datum);
routine = (const TableAmRoutine *) DatumGetPointer(datum);
if (routine == NULL || !IsA(routine, TableAmRoutine))
elog(ERROR, "table access method handler %u did not return a TableAmRoutine struct",

@ -289,7 +289,7 @@ ConstructTupleDescriptor(Relation heapRelation,
int numkeyatts = indexInfo->ii_NumIndexKeyAttrs;
ListCell *colnames_item = list_head(indexColNames);
ListCell *indexpr_item = list_head(indexInfo->ii_Expressions);
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
TupleDesc heapTupDesc;
TupleDesc indexTupDesc;
int natts; /* #atts in heap rel --- for error checks */
@ -481,8 +481,6 @@ ConstructTupleDescriptor(Relation heapRelation,
populate_compact_attribute(indexTupDesc, i);
}
pfree(amroutine);
return indexTupDesc;
}

@ -190,7 +190,7 @@ CheckIndexCompatible(Oid oldId,
HeapTuple tuple;
Form_pg_index indexForm;
Form_pg_am accessMethodForm;
IndexAmRoutine *amRoutine;
const IndexAmRoutine *amRoutine;
bool amcanorder;
bool amsummarizing;
int16 *coloptions;
@ -566,7 +566,7 @@ DefineIndex(Oid tableId,
Relation rel;
HeapTuple tuple;
Form_pg_am accessMethodForm;
IndexAmRoutine *amRoutine;
const IndexAmRoutine *amRoutine;
bool amcanorder;
bool amissummarizing;
amoptions_function amoptions;
@ -895,7 +895,6 @@ DefineIndex(Oid tableId,
amoptions = amRoutine->amoptions;
amissummarizing = amRoutine->amsummarizing;
pfree(amRoutine);
ReleaseSysCache(tuple);
/*

@ -349,7 +349,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
Relation rel;
HeapTuple tup;
Form_pg_am amform;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
Datum values[Natts_pg_opclass];
bool nulls[Natts_pg_opclass];
AclResult aclresult;
@ -823,7 +823,7 @@ AlterOpFamily(AlterOpFamilyStmt *stmt)
maxProcNumber; /* amsupport value */
HeapTuple tup;
Form_pg_am amform;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
/* Get necessary info about access method */
tup = SearchSysCache1(AMNAME, CStringGetDatum(stmt->amname));
@ -882,7 +882,7 @@ AlterOpFamilyAdd(AlterOpFamilyStmt *stmt, Oid amoid, Oid opfamilyoid,
int maxOpNumber, int maxProcNumber, int optsProcNumber,
List *items)
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
const IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
List *operators; /* OpFamilyMember list for operators */
List *procedures; /* OpFamilyMember list for support procs */
ListCell *l;
@ -1165,9 +1165,7 @@ assignOperTypes(OpFamilyMember *member, Oid amoid, Oid typeoid)
* the family has been created but not yet populated with the required
* operators.)
*/
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
if (!amroutine->amcanorderbyop)
if (!GetIndexAmRoutineByAmId(amoid, false)->amcanorderbyop)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("access method \"%s\" does not support ordering operators",

@ -605,7 +605,7 @@ IndexSupportsBackwardScan(Oid indexid)
bool result;
HeapTuple ht_idxrel;
Form_pg_class idxrelrec;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
/* Fetch the pg_class tuple of the index relation */
ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
@ -618,7 +618,6 @@ IndexSupportsBackwardScan(Oid indexid)
result = amroutine->amcanbackward;
pfree(amroutine);
ReleaseSysCache(ht_idxrel);
return result;

@ -231,7 +231,7 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
Oid indexoid = lfirst_oid(l);
Relation indexRelation;
Form_pg_index index;
IndexAmRoutine *amroutine = NULL;
const IndexAmRoutine *amroutine = NULL;
IndexOptInfo *info;
int ncolumns,
nkeycolumns;

@ -156,7 +156,7 @@ indexam_property(FunctionCallInfo fcinfo,
bool isnull = false;
int natts = 0;
IndexAMProperty prop;
IndexAmRoutine *routine;
const IndexAmRoutine *routine;
/* Try to convert property name to enum (no error if not known) */
prop = lookup_prop_name(propname);
@ -452,7 +452,7 @@ pg_indexam_progress_phasename(PG_FUNCTION_ARGS)
{
Oid amoid = PG_GETARG_OID(0);
int32 phasenum = PG_GETARG_INT32(1);
IndexAmRoutine *routine;
const IndexAmRoutine *routine;
char *name;
routine = GetIndexAmRoutineByAmId(amoid, true);

@ -1281,7 +1281,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
Form_pg_index idxrec;
Form_pg_class idxrelrec;
Form_pg_am amrec;
IndexAmRoutine *amroutine;
const IndexAmRoutine *amroutine;
List *indexprs;
ListCell *indexpr_item;
List *context;

@ -231,14 +231,7 @@ get_opmethod_canorder(Oid amoid)
case BRIN_AM_OID:
return false;
default:
{
bool result;
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(amoid, false);
result = amroutine->amcanorder;
pfree(amroutine);
return result;
}
return GetIndexAmRoutineByAmId(amoid, false)->amcanorder;
}
}
@ -729,7 +722,7 @@ get_op_index_interpretation(Oid opno)
{
HeapTuple op_tuple = &catlist->members[i]->tuple;
Form_pg_amop op_form = (Form_pg_amop) GETSTRUCT(op_tuple);
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
const IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
CompareType cmptype;
/* must be ordering index */
@ -800,15 +793,11 @@ equality_ops_are_compatible(Oid opno1, Oid opno2)
* op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
* check it first
*/
if (op_in_opfamily(opno2, op_form->amopfamily))
if (op_in_opfamily(opno2, op_form->amopfamily) &&
GetIndexAmRoutineByAmId(op_form->amopmethod, false)->amconsistentequality)
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
if (amroutine->amconsistentequality)
{
result = true;
break;
}
result = true;
break;
}
}
@ -856,15 +845,11 @@ comparison_ops_are_compatible(Oid opno1, Oid opno2)
* op_in_opfamily() is cheaper than GetIndexAmRoutineByAmId(), so
* check it first
*/
if (op_in_opfamily(opno2, op_form->amopfamily))
if (op_in_opfamily(opno2, op_form->amopfamily) &&
GetIndexAmRoutineByAmId(op_form->amopmethod, false)->amconsistentordering)
{
IndexAmRoutine *amroutine = GetIndexAmRoutineByAmId(op_form->amopmethod, false);
if (amroutine->amconsistentordering)
{
result = true;
break;
}
result = true;
break;
}
}

@ -1420,22 +1420,17 @@ RelationInitPhysicalAddr(Relation relation)
static void
InitIndexAmRoutine(Relation relation)
{
IndexAmRoutine *cached,
*tmp;
MemoryContext oldctx;
/*
* Call the amhandler in current, short-lived memory context, just in case
* it leaks anything (it probably won't, but let's be paranoid).
* We formerly specified that the amhandler should return a palloc'd
* struct. That's now deprecated in favor of returning a pointer to a
* static struct, but to avoid completely breaking old external AMs, run
* the amhandler in the relation's rd_indexcxt.
*/
tmp = GetIndexAmRoutine(relation->rd_amhandler);
/* OK, now transfer the data into relation's rd_indexcxt. */
cached = (IndexAmRoutine *) MemoryContextAlloc(relation->rd_indexcxt,
sizeof(IndexAmRoutine));
memcpy(cached, tmp, sizeof(IndexAmRoutine));
relation->rd_indam = cached;
pfree(tmp);
oldctx = MemoryContextSwitchTo(relation->rd_indexcxt);
relation->rd_indam = GetIndexAmRoutine(relation->rd_amhandler);
MemoryContextSwitchTo(oldctx);
}
/*

@ -226,8 +226,8 @@ typedef void (*aminitparallelscan_function) (void *target);
typedef void (*amparallelrescan_function) (IndexScanDesc scan);
/*
* API struct for an index AM. Note this must be stored in a single palloc'd
* chunk of memory.
* API struct for an index AM. Note we expect index AMs to allocate these
* structs statically; the core code never copies nor frees them.
*/
typedef struct IndexAmRoutine
{
@ -326,8 +326,8 @@ typedef struct IndexAmRoutine
/* Functions in access/index/amapi.c */
extern IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror);
extern const IndexAmRoutine *GetIndexAmRoutine(Oid amhandler);
extern const IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid, bool noerror);
extern CompareType IndexAmTranslateStrategy(StrategyNumber strategy, Oid amoid, Oid opfamily, bool missing_ok);
extern StrategyNumber IndexAmTranslateCompareType(CompareType cmptype, Oid amoid, Oid opfamily, bool missing_ok);

@ -203,7 +203,7 @@ typedef struct RelationData
*/
MemoryContext rd_indexcxt; /* private memory cxt for this stuff */
/* use "struct" here to avoid needing to include amapi.h: */
struct IndexAmRoutine *rd_indam; /* index AM's API struct */
const struct IndexAmRoutine *rd_indam; /* index AM's API struct */
Oid *rd_opfamily; /* OIDs of op families for each index col */
Oid *rd_opcintype; /* OIDs of opclass declared input data types */
RegProcedure *rd_support; /* OIDs of support procedures */

@ -276,56 +276,57 @@ diendscan(IndexScanDesc scan)
Datum
dihandler(PG_FUNCTION_ARGS)
{
IndexAmRoutine *amroutine = makeNode(IndexAmRoutine);
amroutine->amstrategies = 0;
amroutine->amsupport = 1;
amroutine->amcanorder = false;
amroutine->amcanorderbyop = false;
amroutine->amcanhash = false;
amroutine->amconsistentequality = false;
amroutine->amconsistentordering = false;
amroutine->amcanbackward = false;
amroutine->amcanunique = false;
amroutine->amcanmulticol = false;
amroutine->amoptionalkey = false;
amroutine->amsearcharray = false;
amroutine->amsearchnulls = false;
amroutine->amstorage = false;
amroutine->amclusterable = false;
amroutine->ampredlocks = false;
amroutine->amcanparallel = false;
amroutine->amcanbuildparallel = false;
amroutine->amcaninclude = false;
amroutine->amusemaintenanceworkmem = false;
amroutine->amsummarizing = false;
amroutine->amparallelvacuumoptions = VACUUM_OPTION_NO_PARALLEL;
amroutine->amkeytype = InvalidOid;
amroutine->ambuild = dibuild;
amroutine->ambuildempty = dibuildempty;
amroutine->aminsert = diinsert;
amroutine->ambulkdelete = dibulkdelete;
amroutine->amvacuumcleanup = divacuumcleanup;
amroutine->amcanreturn = NULL;
amroutine->amcostestimate = dicostestimate;
amroutine->amgettreeheight = NULL;
amroutine->amoptions = dioptions;
amroutine->amproperty = NULL;
amroutine->ambuildphasename = NULL;
amroutine->amvalidate = divalidate;
amroutine->ambeginscan = dibeginscan;
amroutine->amrescan = direscan;
amroutine->amgettuple = NULL;
amroutine->amgetbitmap = NULL;
amroutine->amendscan = diendscan;
amroutine->ammarkpos = NULL;
amroutine->amrestrpos = NULL;
amroutine->amestimateparallelscan = NULL;
amroutine->aminitparallelscan = NULL;
amroutine->amparallelrescan = NULL;
PG_RETURN_POINTER(amroutine);
static const IndexAmRoutine amroutine = {
.type = T_IndexAmRoutine,
.amstrategies = 0,
.amsupport = 1,
.amcanorder = false,
.amcanorderbyop = false,
.amcanhash = false,
.amconsistentequality = false,
.amconsistentordering = false,
.amcanbackward = false,
.amcanunique = false,
.amcanmulticol = false,
.amoptionalkey = false,
.amsearcharray = false,
.amsearchnulls = false,
.amstorage = false,
.amclusterable = false,
.ampredlocks = false,
.amcanparallel = false,
.amcanbuildparallel = false,
.amcaninclude = false,
.amusemaintenanceworkmem = false,
.amsummarizing = false,
.amparallelvacuumoptions = VACUUM_OPTION_NO_PARALLEL,
.amkeytype = InvalidOid,
.ambuild = dibuild,
.ambuildempty = dibuildempty,
.aminsert = diinsert,
.ambulkdelete = dibulkdelete,
.amvacuumcleanup = divacuumcleanup,
.amcanreturn = NULL,
.amcostestimate = dicostestimate,
.amgettreeheight = NULL,
.amoptions = dioptions,
.amproperty = NULL,
.ambuildphasename = NULL,
.amvalidate = divalidate,
.ambeginscan = dibeginscan,
.amrescan = direscan,
.amgettuple = NULL,
.amgetbitmap = NULL,
.amendscan = diendscan,
.ammarkpos = NULL,
.amrestrpos = NULL,
.amestimateparallelscan = NULL,
.aminitparallelscan = NULL,
.amparallelrescan = NULL,
};
PG_RETURN_POINTER(&amroutine);
}
void

Loading…
Cancel
Save