From bc6374cd76abb2e6a48c4b57c0b5a7baa5babd67 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 30 Dec 2025 18:26:23 -0500 Subject: [PATCH] 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 Reviewed-by: Tom Lane Discussion: https://postgr.es/m/CAEoWx2=vApYk2LRu8R0DdahsPNEhWUxGBZ=rbZo1EXE=uA+opQ@mail.gmail.com --- contrib/bloom/blutils.c | 111 ++++++++--------- doc/src/sgml/indexam.sgml | 12 +- src/backend/access/brin/brin.c | 113 +++++++++--------- src/backend/access/gin/ginutil.c | 109 ++++++++--------- src/backend/access/gist/gist.c | 113 +++++++++--------- src/backend/access/hash/hash.c | 113 +++++++++--------- src/backend/access/index/amapi.c | 18 ++- src/backend/access/nbtree/nbtree.c | 113 +++++++++--------- src/backend/access/spgist/spgutils.c | 113 +++++++++--------- src/backend/access/table/tableamapi.c | 5 +- src/backend/catalog/index.c | 4 +- src/backend/commands/indexcmds.c | 5 +- src/backend/commands/opclasscmds.c | 10 +- src/backend/executor/execAmi.c | 3 +- src/backend/optimizer/util/plancat.c | 2 +- src/backend/utils/adt/amutils.c | 4 +- src/backend/utils/adt/ruleutils.c | 2 +- src/backend/utils/cache/lsyscache.c | 35 ++---- src/backend/utils/cache/relcache.c | 21 ++-- src/include/access/amapi.h | 8 +- src/include/utils/rel.h | 2 +- .../modules/dummy_index_am/dummy_index_am.c | 101 ++++++++-------- 22 files changed, 501 insertions(+), 516 deletions(-) diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c index 7a468b4a173..50f461fa540 100644 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.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); } /* diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index 63d7e376f19..f48da318530 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -70,9 +70,15 @@ single argument of type internal and to return the pseudo-type index_am_handler. 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 IndexAmRoutine, 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 IndexAmRoutine, 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 static const; 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 const, and will never free it.) The IndexAmRoutine struct, also called the access method's API struct, includes fields specifying assorted fixed properties of the access method, such as whether it can support diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 45d306037a4..ec5086a9521 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -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); } /* diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index 605f80aad39..e4589de2aab 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -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); } /* diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index c26d8538f05..4b943b7f43e 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -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); } /* diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index e388252afdc..a2172d1063f 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -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); } /* diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c index 60684c53422..453fd2a1dcf 100644 --- a/src/backend/access/index/amapi.c +++ b/src/backend/access/index/amapi.c @@ -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); } diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index b4425231935..4a421f0b8f7 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -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); } /* diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index a60ec85e8be..a6866bd3520 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -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); } /* diff --git a/src/backend/access/table/tableamapi.c b/src/backend/access/table/tableamapi.c index 476663b66aa..6745d608f93 100644 --- a/src/backend/access/table/tableamapi.c +++ b/src/backend/access/table/tableamapi.c @@ -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", diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 8dea58ad96b..86db0541f29 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -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; } diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d9cccb6ac18..67a451463ed 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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); /* diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 992ae789b00..20c54a523c5 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -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", diff --git a/src/backend/executor/execAmi.c b/src/backend/executor/execAmi.c index 1d0e8ad57b4..4893ea3ce91 100644 --- a/src/backend/executor/execAmi.c +++ b/src/backend/executor/execAmi.c @@ -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; diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index bf45c355b77..43ca5fd0213 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -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; diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c index 0af26d6acfa..59c0112c696 100644 --- a/src/backend/utils/adt/amutils.c +++ b/src/backend/utils/adt/amutils.c @@ -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); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 9f85eb86da1..ef6978111e8 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -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; diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 9be36583835..bbe634f0f32 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -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; } } diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2d0cb7bcfd4..88259f7c228 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -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); } /* diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index 63dd41c1f21..278da36bc08 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -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); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 80286076a11..82d0e419e4b 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -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 */ diff --git a/src/test/modules/dummy_index_am/dummy_index_am.c b/src/test/modules/dummy_index_am/dummy_index_am.c index a34382a5f79..d18b18106af 100644 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@ -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