=== Applying patches on top of PostgreSQL commit ID bb26a81ee28c9d9c64e6f233fafa2792768ece1b === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Fri Jan 30 02:03:26 UTC 2026 On branch cf/4688 nothing to commit, working tree clean === using 'git am' to apply patch ./v-13-0001-New-options-engine.patch === Applying: 1/1] New options engine Using index info to reconstruct a base tree... M contrib/bloom/bloom.h M contrib/bloom/blutils.c M contrib/dblink/dblink.c M contrib/file_fdw/file_fdw.c M contrib/postgres_fdw/option.c M doc/src/sgml/indexam.sgml M src/backend/access/brin/brin.c M src/backend/access/common/meson.build M src/backend/access/common/reloptions.c M src/backend/access/gin/ginutil.c M src/backend/access/gist/gist.c M src/backend/access/gist/gistutil.c M src/backend/access/hash/hash.c M src/backend/access/hash/hashutil.c M src/backend/access/nbtree/nbtree.c M src/backend/access/nbtree/nbtutils.c M src/backend/access/spgist/spgutils.c M src/backend/commands/createas.c M src/backend/commands/foreigncmds.c M src/backend/commands/indexcmds.c M src/backend/commands/tablecmds.c M src/backend/commands/tablespace.c M src/backend/foreign/foreign.c M src/backend/parser/parse_utilcmd.c M src/backend/tcop/utility.c M src/backend/utils/cache/attoptcache.c M src/backend/utils/cache/relcache.c M src/backend/utils/cache/spccache.c M src/include/access/amapi.h M src/include/access/brin.h M src/include/access/brin_internal.h M src/include/access/gin_private.h M src/include/access/gist_private.h M src/include/access/hash.h M src/include/access/nbtree.h M src/include/access/reloptions.h M src/include/access/spgist.h M src/include/access/spgist_private.h M src/include/commands/tablecmds.h M src/test/modules/dummy_index_am/dummy_index_am.c M src/test/regress/expected/reloptions.out M src/test/regress/sql/reloptions.sql Falling back to patching base and 3-way merge... Auto-merging src/test/regress/sql/reloptions.sql Auto-merging src/test/regress/expected/reloptions.out Auto-merging src/test/modules/dummy_index_am/dummy_index_am.c CONFLICT (content): Merge conflict in src/test/modules/dummy_index_am/dummy_index_am.c Auto-merging src/include/commands/tablecmds.h Auto-merging src/include/access/spgist_private.h Auto-merging src/include/access/spgist.h Auto-merging src/include/access/reloptions.h CONFLICT (content): Merge conflict in src/include/access/reloptions.h Auto-merging src/include/access/nbtree.h Auto-merging src/include/access/hash.h Auto-merging src/include/access/gist_private.h Auto-merging src/include/access/gin_private.h Auto-merging src/include/access/brin_internal.h Auto-merging src/include/access/brin.h Auto-merging src/include/access/amapi.h CONFLICT (content): Merge conflict in src/include/access/amapi.h Auto-merging src/backend/utils/cache/spccache.c Auto-merging src/backend/utils/cache/relcache.c Auto-merging src/backend/utils/cache/attoptcache.c Auto-merging src/backend/tcop/utility.c Auto-merging src/backend/parser/parse_utilcmd.c Auto-merging src/backend/foreign/foreign.c Auto-merging src/backend/commands/tablespace.c Auto-merging src/backend/commands/tablecmds.c Auto-merging src/backend/commands/indexcmds.c Auto-merging src/backend/commands/foreigncmds.c Auto-merging src/backend/commands/createas.c Auto-merging src/backend/access/spgist/spgutils.c CONFLICT (content): Merge conflict in src/backend/access/spgist/spgutils.c Auto-merging src/backend/access/nbtree/nbtutils.c CONFLICT (content): Merge conflict in src/backend/access/nbtree/nbtutils.c Auto-merging src/backend/access/nbtree/nbtree.c CONFLICT (content): Merge conflict in src/backend/access/nbtree/nbtree.c Auto-merging src/backend/access/hash/hashutil.c Auto-merging src/backend/access/hash/hash.c CONFLICT (content): Merge conflict in src/backend/access/hash/hash.c Auto-merging src/backend/access/gist/gistutil.c Auto-merging src/backend/access/gist/gist.c CONFLICT (content): Merge conflict in src/backend/access/gist/gist.c Auto-merging src/backend/access/gin/ginutil.c CONFLICT (content): Merge conflict in src/backend/access/gin/ginutil.c Auto-merging src/backend/access/common/reloptions.c CONFLICT (content): Merge conflict in src/backend/access/common/reloptions.c Auto-merging src/backend/access/common/meson.build Auto-merging src/backend/access/brin/brin.c CONFLICT (content): Merge conflict in src/backend/access/brin/brin.c Auto-merging doc/src/sgml/indexam.sgml Auto-merging contrib/postgres_fdw/option.c Auto-merging contrib/file_fdw/file_fdw.c Auto-merging contrib/dblink/dblink.c Auto-merging contrib/bloom/blutils.c CONFLICT (content): Merge conflict in contrib/bloom/blutils.c Auto-merging contrib/bloom/bloom.h error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 1/1] New options engine When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". Unstaged changes after reset: M contrib/bloom/bloom.h M contrib/bloom/blutils.c M contrib/dblink/dblink.c M contrib/file_fdw/file_fdw.c M contrib/postgres_fdw/option.c M contrib/test_decoding/expected/twophase.out M doc/src/sgml/indexam.sgml M src/backend/access/brin/brin.c M src/backend/access/common/Makefile M src/backend/access/common/meson.build M src/backend/access/common/reloptions.c M src/backend/access/gin/ginutil.c M src/backend/access/gist/gist.c M src/backend/access/gist/gistutil.c M src/backend/access/hash/hash.c M src/backend/access/hash/hashutil.c M src/backend/access/nbtree/nbtree.c M src/backend/access/nbtree/nbtutils.c M src/backend/access/spgist/spgutils.c M src/backend/commands/createas.c M src/backend/commands/foreigncmds.c M src/backend/commands/indexcmds.c M src/backend/commands/tablecmds.c M src/backend/commands/tablespace.c M src/backend/foreign/foreign.c M src/backend/parser/parse_utilcmd.c M src/backend/tcop/utility.c M src/backend/utils/cache/attoptcache.c M src/backend/utils/cache/relcache.c M src/backend/utils/cache/spccache.c M src/include/access/amapi.h M src/include/access/brin.h M src/include/access/brin_internal.h M src/include/access/gin_private.h M src/include/access/gist_private.h M src/include/access/hash.h M src/include/access/nbtree.h M src/include/access/reloptions.h M src/include/access/spgist.h M src/include/access/spgist_private.h M src/include/commands/tablecmds.h M src/test/modules/dummy_index_am/dummy_index_am.c M src/test/modules/test_oat_hooks/expected/alter_table.out M src/test/regress/expected/reloptions.out M src/test/regress/sql/reloptions.sql Removing src/backend/access/common/options.c Removing src/include/access/options.h === using patch(1) to apply patch ./v-13-0001-New-options-engine.patch === patching file contrib/bloom/bloom.h patching file contrib/bloom/blutils.c Hunk #3 FAILED at 98. Hunk #4 succeeded at 120 with fuzz 1 (offset 1 line). Hunk #5 succeeded at 443 (offset 1 line). 1 out of 5 hunks FAILED -- saving rejects to file contrib/bloom/blutils.c.rej patching file contrib/dblink/dblink.c Hunk #1 succeeded at 1929 (offset -7 lines). patching file contrib/file_fdw/file_fdw.c Hunk #1 succeeded at 206 (offset 3 lines). patching file contrib/postgres_fdw/option.c Hunk #1 succeeded at 65 (offset -5 lines). patching file contrib/test_decoding/expected/twophase.out patching file doc/src/sgml/indexam.sgml Hunk #1 succeeded at 512 (offset 6 lines). patching file src/backend/access/brin/brin.c Hunk #2 FAILED at 285. Hunk #3 FAILED at 302. Hunk #4 succeeded at 1341 (offset 1 line). Hunk #5 succeeded at 3012 (offset 14 lines). 2 out of 5 hunks FAILED -- saving rejects to file src/backend/access/brin/brin.c.rej patching file src/backend/access/common/Makefile patching file src/backend/access/common/meson.build patching file src/backend/access/common/options.c patching file src/backend/access/common/reloptions.c Hunk #1 succeeded at 1 with fuzz 2. Hunk #4 FAILED at 89. Hunk #5 succeeded at 518 (offset 14 lines). Hunk #6 FAILED at 513. Hunk #7 succeeded at 770 (offset 29 lines). Hunk #8 FAILED at 756. Hunk #9 FAILED at 872. Hunk #10 succeeded at 1007 (offset 81 lines). Hunk #11 succeeded at 1017 (offset 81 lines). Hunk #12 FAILED at 974. Hunk #13 succeeded at 1321 (offset 90 lines). Hunk #14 FAILED at 1251. Hunk #15 FAILED at 1803. Hunk #16 succeeded at 2074 (offset 110 lines). 7 out of 16 hunks FAILED -- saving rejects to file src/backend/access/common/reloptions.c.rej patching file src/backend/access/gin/ginutil.c Hunk #3 FAILED at 75. Hunk #4 FAILED at 90. Hunk #5 succeeded at 567 (offset -37 lines). Hunk #6 succeeded at 678 (offset -37 lines). 2 out of 6 hunks FAILED -- saving rejects to file src/backend/access/gin/ginutil.c.rej patching file src/backend/access/gist/gist.c Hunk #1 FAILED at 95. Hunk #2 FAILED at 112. 2 out of 2 hunks FAILED -- saving rejects to file src/backend/access/gist/gist.c.rej patching file src/backend/access/gist/gistutil.c patching file src/backend/access/hash/hash.c Hunk #1 FAILED at 94. Hunk #2 FAILED at 111. 2 out of 2 hunks FAILED -- saving rejects to file src/backend/access/hash/hash.c.rej patching file src/backend/access/hash/hashutil.c patching file src/backend/access/nbtree/nbtree.c Hunk #2 FAILED at 138. Hunk #3 FAILED at 155. Hunk #4 succeeded at 1856 (offset 300 lines). 2 out of 4 hunks FAILED -- saving rejects to file src/backend/access/nbtree/nbtree.c.rej patching file src/backend/access/nbtree/nbtutils.c Hunk #1 FAILED at 18. Hunk #2 succeeded at 600 (offset -2115 lines). 1 out of 2 hunks FAILED -- saving rejects to file src/backend/access/nbtree/nbtutils.c.rej patching file src/backend/access/spgist/spgutils.c Hunk #2 FAILED at 80. Hunk #3 FAILED at 97. Hunk #4 succeeded at 753 (offset 1 line). Hunk #5 succeeded at 1351 (offset 1 line). 2 out of 5 hunks FAILED -- saving rejects to file src/backend/access/spgist/spgutils.c.rej patching file src/backend/commands/createas.c patching file src/backend/commands/foreigncmds.c Hunk #1 succeeded at 123 (offset 11 lines). patching file src/backend/commands/indexcmds.c Hunk #2 succeeded at 574 with fuzz 1 (offset 3 lines). Hunk #3 succeeded at 897 with fuzz 1 (offset 3 lines). Hunk #4 succeeded at 911 (offset 2 lines). Hunk #5 succeeded at 2272 (offset 25 lines). patching file src/backend/commands/tablecmds.c Hunk #2 succeeded at 786 (offset 34 lines). Hunk #3 succeeded at 934 (offset 34 lines). Hunk #4 succeeded at 4578 (offset 37 lines). Hunk #5 succeeded at 4620 (offset 37 lines). Hunk #6 succeeded at 4841 (offset 37 lines). Hunk #7 succeeded at 9136 (offset 168 lines). Hunk #8 succeeded at 16707 (offset 761 lines). Hunk #9 succeeded at 16742 (offset 761 lines). Hunk #10 succeeded at 16784 (offset 761 lines). Hunk #11 succeeded at 16880 (offset 761 lines). patching file src/backend/commands/tablespace.c patching file src/backend/foreign/foreign.c Hunk #1 succeeded at 81 (offset 1 line). Hunk #2 succeeded at 168 (offset 1 line). Hunk #3 succeeded at 240 (offset 1 line). Hunk #4 succeeded at 277 (offset 1 line). Hunk #5 succeeded at 310 (offset 1 line). Hunk #6 succeeded at 527 (offset 1 line). Hunk #7 succeeded at 625 (offset 1 line). patching file src/backend/parser/parse_utilcmd.c Hunk #1 succeeded at 1935 (offset 10 lines). Hunk #2 succeeded at 2003 (offset 14 lines). patching file src/backend/tcop/utility.c Hunk #1 succeeded at 1157 (offset -2 lines). Hunk #2 succeeded at 1181 (offset -2 lines). Hunk #3 succeeded at 1300 (offset -1 lines). patching file src/backend/utils/cache/attoptcache.c patching file src/backend/utils/cache/relcache.c patching file src/backend/utils/cache/spccache.c patching file src/include/access/amapi.h Hunk #1 FAILED at 15. Hunk #2 succeeded at 161 (offset 2 lines). Hunk #3 succeeded at 301 (offset 3 lines). 1 out of 3 hunks FAILED -- saving rejects to file src/include/access/amapi.h.rej patching file src/include/access/brin.h Hunk #1 succeeded at 38 (offset 1 line). patching file src/include/access/brin_internal.h patching file src/include/access/gin_private.h Hunk #1 succeeded at 105 (offset -5 lines). patching file src/include/access/gist_private.h patching file src/include/access/hash.h patching file src/include/access/nbtree.h Hunk #1 succeeded at 1303 (offset -4 lines). patching file src/include/access/options.h patching file src/include/access/reloptions.h Hunk #1 FAILED at 1. Hunk #2 FAILED at 25. Hunk #3 succeeded at 223 (offset 13 lines). Hunk #4 FAILED at 219. 3 out of 4 hunks FAILED -- saving rejects to file src/include/access/reloptions.h.rej patching file src/include/access/spgist.h patching file src/include/access/spgist_private.h Hunk #1 succeeded at 532 (offset 2 lines). patching file src/include/commands/tablecmds.h Hunk #1 succeeded at 37 with fuzz 2 (offset 1 line). patching file src/test/modules/dummy_index_am/dummy_index_am.c Hunk #1 FAILED at 14. Hunk #2 succeeded at 46 (offset 1 line). Hunk #3 FAILED at 59. Hunk #4 succeeded at 231 (offset 17 lines). Hunk #5 FAILED at 297. Hunk #6 FAILED at 311. 4 out of 6 hunks FAILED -- saving rejects to file src/test/modules/dummy_index_am/dummy_index_am.c.rej patching file src/test/modules/test_oat_hooks/expected/alter_table.out patching file src/test/regress/expected/reloptions.out Hunk #1 succeeded at 193 (offset 18 lines). Hunk #2 succeeded at 212 (offset 18 lines). patching file src/test/regress/sql/reloptions.sql Hunk #1 succeeded at 123 (offset 11 lines). Unstaged changes after reset: M contrib/bloom/bloom.h M contrib/bloom/blutils.c M contrib/dblink/dblink.c M contrib/file_fdw/file_fdw.c M contrib/postgres_fdw/option.c M contrib/test_decoding/expected/twophase.out M doc/src/sgml/indexam.sgml M src/backend/access/brin/brin.c M src/backend/access/common/Makefile M src/backend/access/common/meson.build M src/backend/access/common/reloptions.c M src/backend/access/gin/ginutil.c M src/backend/access/gist/gistutil.c M src/backend/access/hash/hashutil.c M src/backend/access/nbtree/nbtree.c M src/backend/access/nbtree/nbtutils.c M src/backend/access/spgist/spgutils.c M src/backend/commands/createas.c M src/backend/commands/foreigncmds.c M src/backend/commands/indexcmds.c M src/backend/commands/tablecmds.c M src/backend/commands/tablespace.c M src/backend/foreign/foreign.c M src/backend/parser/parse_utilcmd.c M src/backend/tcop/utility.c M src/backend/utils/cache/attoptcache.c M src/backend/utils/cache/relcache.c M src/backend/utils/cache/spccache.c M src/include/access/amapi.h M src/include/access/brin.h M src/include/access/brin_internal.h M src/include/access/gin_private.h M src/include/access/gist_private.h M src/include/access/hash.h M src/include/access/nbtree.h M src/include/access/reloptions.h M src/include/access/spgist.h M src/include/access/spgist_private.h M src/include/commands/tablecmds.h M src/test/modules/dummy_index_am/dummy_index_am.c M src/test/modules/test_oat_hooks/expected/alter_table.out M src/test/regress/expected/reloptions.out M src/test/regress/sql/reloptions.sql Removing contrib/bloom/blutils.c.rej Removing src/backend/access/brin/brin.c.rej Removing src/backend/access/common/options.c Removing src/backend/access/common/reloptions.c.rej Removing src/backend/access/gin/ginutil.c.rej Removing src/backend/access/gist/gist.c.rej Removing src/backend/access/hash/hash.c.rej Removing src/backend/access/nbtree/nbtree.c.rej Removing src/backend/access/nbtree/nbtutils.c.rej Removing src/backend/access/spgist/spgutils.c.rej Removing src/include/access/amapi.h.rej Removing src/include/access/options.h Removing src/include/access/reloptions.h.rej Removing src/test/modules/dummy_index_am/dummy_index_am.c.rej === using 'git apply' to apply patch ./v-13-0001-New-options-engine.patch === Applied patch to 'contrib/bloom/bloom.h' cleanly. Applied patch to 'contrib/bloom/blutils.c' with conflicts. Applied patch to 'contrib/dblink/dblink.c' cleanly. Applied patch to 'contrib/file_fdw/file_fdw.c' cleanly. Applied patch to 'contrib/postgres_fdw/option.c' cleanly. Applied patch to 'contrib/test_decoding/expected/twophase.out' cleanly. Applied patch to 'doc/src/sgml/indexam.sgml' cleanly. Applied patch to 'src/backend/access/brin/brin.c' with conflicts. Applied patch to 'src/backend/access/common/Makefile' cleanly. Applied patch to 'src/backend/access/common/meson.build' cleanly. Falling back to direct application... Applied patch to 'src/backend/access/common/reloptions.c' with conflicts. Applied patch to 'src/backend/access/gin/ginutil.c' with conflicts. Applied patch to 'src/backend/access/gist/gist.c' with conflicts. Applied patch to 'src/backend/access/gist/gistutil.c' cleanly. Applied patch to 'src/backend/access/hash/hash.c' with conflicts. Applied patch to 'src/backend/access/hash/hashutil.c' cleanly. Applied patch to 'src/backend/access/nbtree/nbtree.c' with conflicts. Applied patch to 'src/backend/access/nbtree/nbtutils.c' with conflicts. Applied patch to 'src/backend/access/spgist/spgutils.c' with conflicts. Applied patch to 'src/backend/commands/createas.c' cleanly. Applied patch to 'src/backend/commands/foreigncmds.c' cleanly. Applied patch to 'src/backend/commands/indexcmds.c' cleanly. Applied patch to 'src/backend/commands/tablecmds.c' cleanly. Applied patch to 'src/backend/commands/tablespace.c' cleanly. Applied patch to 'src/backend/foreign/foreign.c' cleanly. Applied patch to 'src/backend/parser/parse_utilcmd.c' cleanly. Applied patch to 'src/backend/tcop/utility.c' cleanly. Applied patch to 'src/backend/utils/cache/attoptcache.c' cleanly. Applied patch to 'src/backend/utils/cache/relcache.c' cleanly. Applied patch to 'src/backend/utils/cache/spccache.c' cleanly. Applied patch to 'src/include/access/amapi.h' with conflicts. Applied patch to 'src/include/access/brin.h' cleanly. Applied patch to 'src/include/access/brin_internal.h' cleanly. Applied patch to 'src/include/access/gin_private.h' cleanly. Applied patch to 'src/include/access/gist_private.h' cleanly. Applied patch to 'src/include/access/hash.h' cleanly. Applied patch to 'src/include/access/nbtree.h' cleanly. Falling back to direct application... Applied patch to 'src/include/access/reloptions.h' with conflicts. Applied patch to 'src/include/access/spgist.h' cleanly. Applied patch to 'src/include/access/spgist_private.h' cleanly. Applied patch to 'src/include/commands/tablecmds.h' cleanly. Applied patch to 'src/test/modules/dummy_index_am/dummy_index_am.c' with conflicts. Applied patch to 'src/test/modules/test_oat_hooks/expected/alter_table.out' cleanly. Applied patch to 'src/test/regress/expected/reloptions.out' cleanly. Applied patch to 'src/test/regress/sql/reloptions.sql' cleanly. U contrib/bloom/blutils.c U src/backend/access/brin/brin.c U src/backend/access/common/reloptions.c U src/backend/access/gin/ginutil.c U src/backend/access/gist/gist.c U src/backend/access/hash/hash.c U src/backend/access/nbtree/nbtree.c U src/backend/access/nbtree/nbtutils.c U src/backend/access/spgist/spgutils.c U src/include/access/amapi.h U src/include/access/reloptions.h U src/test/modules/dummy_index_am/dummy_index_am.c diff --cc contrib/bloom/blutils.c index 5111cdc6dd6,e0c1bf2952d..00000000000 --- a/contrib/bloom/blutils.c +++ b/contrib/bloom/blutils.c @@@ -102,64 -62,72 +62,131 @@@ makeDefaultBloomOptions(void Datum blhandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->amreloptspecset = blrelopt_specset; + 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); ++>>>>>>> theirs } + void + blReloptionPostprocess(void *data, bool validate) + { + BloomOptions *opts = (BloomOptions *) data; + /* Convert signature length from # of bits to # to words, rounding up */ + opts->bloomLength = (opts->bloomLength + SIGNWORDBITS - 1) / SIGNWORDBITS; + } + + /* * Fill BloomState structure for particular index. */ diff --cc src/backend/access/brin/brin.c index 6887e421442,eb32716c34e..00000000000 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@@ -249,63 -248,62 +248,122 @@@ static void _brin_parallel_scan_and_bui Datum brinhandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = bringetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/backend/access/common/reloptions.c index 237ab8d0ed9,45e8eaaee25..00000000000 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@@ -1,9 -1,9 +1,9 @@@ /*------------------------------------------------------------------------- * * reloptions.c - * Core support for relation options (pg_class.reloptions) + * Support for relation options (pg_class.reloptions) * - * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * @@@ -95,418 -89,8 +93,421 @@@ * value has no effect until the next VACUUM, so no need for stronger lock. */ ++<<<<<<< ours +static relopt_bool boolRelOpts[] = +{ + { + { + "autosummarize", + "Enables automatic summarization on this BRIN index", + RELOPT_KIND_BRIN, + AccessExclusiveLock + }, + false + }, + { + { + "autovacuum_enabled", + "Enables autovacuum in this relation", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + true + }, + { + { + "user_catalog_table", + "Declare a table as an additional catalog table, e.g. for the purpose of logical replication", + RELOPT_KIND_HEAP, + AccessExclusiveLock + }, + false + }, + { + { + "fastupdate", + "Enables \"fast update\" feature for this GIN index", + RELOPT_KIND_GIN, + AccessExclusiveLock + }, + true + }, + { + { + "security_barrier", + "View acts as a row security barrier", + RELOPT_KIND_VIEW, + AccessExclusiveLock + }, + false + }, + { + { + "security_invoker", + "Privileges on underlying relations are checked as the invoking user, not the view owner", + RELOPT_KIND_VIEW, + AccessExclusiveLock + }, + false + }, + { + { + "deduplicate_items", + "Enables \"deduplicate items\" feature for this btree index", + RELOPT_KIND_BTREE, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + true + }, + /* list terminator */ + {{NULL}} +}; + +static relopt_ternary ternaryRelOpts[] = +{ + { + { + "vacuum_truncate", + "Enables vacuum to truncate empty pages at the end of this table", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + } + }, + /* list terminator */ + { + { + NULL + } + } +}; + +static relopt_int intRelOpts[] = +{ + { + { + "fillfactor", + "Packs table pages only to this percentage", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100 + }, + { + { + "fillfactor", + "Packs btree index pages only to this percentage", + RELOPT_KIND_BTREE, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + BTREE_DEFAULT_FILLFACTOR, BTREE_MIN_FILLFACTOR, 100 + }, + { + { + "fillfactor", + "Packs hash index pages only to this percentage", + RELOPT_KIND_HASH, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + HASH_DEFAULT_FILLFACTOR, HASH_MIN_FILLFACTOR, 100 + }, + { + { + "fillfactor", + "Packs gist index pages only to this percentage", + RELOPT_KIND_GIST, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100 + }, + { + { + "fillfactor", + "Packs spgist index pages only to this percentage", + RELOPT_KIND_SPGIST, + ShareUpdateExclusiveLock /* since it applies only to later + * inserts */ + }, + SPGIST_DEFAULT_FILLFACTOR, SPGIST_MIN_FILLFACTOR, 100 + }, + { + { + "autovacuum_vacuum_threshold", + "Minimum number of tuple updates or deletes prior to vacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0, INT_MAX + }, + { + { + "autovacuum_vacuum_max_threshold", + "Maximum number of tuple updates or deletes prior to vacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -2, -1, INT_MAX + }, + { + { + "autovacuum_vacuum_insert_threshold", + "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -2, -1, INT_MAX + }, + { + { + "autovacuum_analyze_threshold", + "Minimum number of tuple inserts, updates or deletes prior to analyze", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + -1, 0, INT_MAX + }, + { + { + "autovacuum_vacuum_cost_limit", + "Vacuum cost amount available before napping, for autovacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 1, 10000 + }, + { + { + "autovacuum_freeze_min_age", + "Minimum age at which VACUUM should freeze a table row, for autovacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0, 1000000000 + }, + { + { + "autovacuum_multixact_freeze_min_age", + "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0, 1000000000 + }, + { + { + "autovacuum_freeze_max_age", + "Age at which to autovacuum a table to prevent transaction ID wraparound", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 100000, 2000000000 + }, + { + { + "autovacuum_multixact_freeze_max_age", + "Multixact age at which to autovacuum a table to prevent multixact wraparound", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 10000, 2000000000 + }, + { + { + "autovacuum_freeze_table_age", + "Age at which VACUUM should perform a full table sweep to freeze row versions", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, -1, 0, 2000000000 + }, + { + { + "autovacuum_multixact_freeze_table_age", + "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, -1, 0, 2000000000 + }, + { + { + "log_autovacuum_min_duration", + "Sets the minimum execution time above which vacuum actions by autovacuum will be logged", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, -1, INT_MAX + }, + { + { + "log_autoanalyze_min_duration", + "Sets the minimum execution time above which analyze actions by autovacuum will be logged", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + -1, -1, INT_MAX + }, + { + { + "toast_tuple_target", + "Sets the target tuple length at which external columns will be toasted", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + TOAST_TUPLE_TARGET, 128, TOAST_TUPLE_TARGET_MAIN + }, + { + { + "pages_per_range", + "Number of pages that each page range covers in a BRIN index", + RELOPT_KIND_BRIN, + AccessExclusiveLock + }, 128, 1, 131072 + }, + { + { + "gin_pending_list_limit", + "Maximum size of the pending list for this GIN index, in kilobytes.", + RELOPT_KIND_GIN, + AccessExclusiveLock + }, + -1, 64, MAX_KILOBYTES + }, + { + { + "effective_io_concurrency", + "Number of simultaneous requests that can be handled efficiently by the disk subsystem.", + RELOPT_KIND_TABLESPACE, + ShareUpdateExclusiveLock + }, + -1, 0, MAX_IO_CONCURRENCY + }, + { + { + "maintenance_io_concurrency", + "Number of simultaneous requests that can be handled efficiently by the disk subsystem for maintenance work.", + RELOPT_KIND_TABLESPACE, + ShareUpdateExclusiveLock + }, + -1, 0, MAX_IO_CONCURRENCY + }, + { + { + "parallel_workers", + "Number of parallel processes that can be used per executor node for this relation.", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + -1, 0, 1024 + }, + + /* list terminator */ + {{NULL}} +}; + +static relopt_real realRelOpts[] = +{ + { + { + "autovacuum_vacuum_cost_delay", + "Vacuum cost delay in milliseconds, for autovacuum", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0.0, 100.0 + }, + { + { + "autovacuum_vacuum_scale_factor", + "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0.0, 100.0 + }, + { + { + "autovacuum_vacuum_insert_scale_factor", + "Number of tuple inserts prior to vacuum as a fraction of reltuples", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0.0, 100.0 + }, + { + { + "autovacuum_analyze_scale_factor", + "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + -1, 0.0, 100.0 + }, + { + { + "vacuum_max_eager_freeze_failure_rate", + "Fraction of pages in a relation vacuum can scan and fail to freeze before disabling eager scanning.", + RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, + ShareUpdateExclusiveLock + }, + -1, 0.0, 1.0 + }, + + { + { + "seq_page_cost", + "Sets the planner's estimate of the cost of a sequentially fetched disk page.", + RELOPT_KIND_TABLESPACE, + ShareUpdateExclusiveLock + }, + -1, 0.0, DBL_MAX + }, + { + { + "random_page_cost", + "Sets the planner's estimate of the cost of a nonsequentially fetched disk page.", + RELOPT_KIND_TABLESPACE, + ShareUpdateExclusiveLock + }, + -1, 0.0, DBL_MAX + }, + { + { + "n_distinct", + "Sets the planner's estimate of the number of distinct values appearing in a column (excluding child relations).", + RELOPT_KIND_ATTRIBUTE, + ShareUpdateExclusiveLock + }, + 0, -1.0, DBL_MAX + }, + { + { + "n_distinct_inherited", + "Sets the planner's estimate of the number of distinct values appearing in a column (including child relations).", + RELOPT_KIND_ATTRIBUTE, + ShareUpdateExclusiveLock + }, + 0, -1.0, DBL_MAX + }, + { + { + "vacuum_cleanup_index_scale_factor", + "Deprecated B-Tree parameter.", + RELOPT_KIND_BTREE, + ShareUpdateExclusiveLock + }, + -1, 0.0, 1e10 + }, + /* list terminator */ + {{NULL}} +}; + ++======= ++>>>>>>> theirs /* values from StdRdOptIndexCleanup */ - static relopt_enum_elt_def StdRdOptIndexCleanupValues[] = + static opt_enum_elt_def StdRdOptIndexCleanupValues[] = { {"auto", STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO}, {"on", STDRD_OPTION_VACUUM_INDEX_CLEANUP_ON}, @@@ -538,240 -113,9 +530,198 @@@ static opt_enum_elt_def viewCheckOptVal {(const char *) NULL} /* list terminator */ }; - static relopt_enum enumRelOpts[] = - { - { - { - "vacuum_index_cleanup", - "Controls index vacuuming and index cleanup", - RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, - ShareUpdateExclusiveLock - }, - StdRdOptIndexCleanupValues, - STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "buffering", - "Enables buffering build for this GiST index", - RELOPT_KIND_GIST, - AccessExclusiveLock - }, - gistBufferingOptValues, - GIST_OPTION_BUFFERING_AUTO, - gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") - }, - { - { - "check_option", - "View has WITH CHECK OPTION defined (local or cascaded).", - RELOPT_KIND_VIEW, - AccessExclusiveLock - }, - viewCheckOptValues, - VIEW_OPTION_CHECK_OPTION_NOT_SET, - gettext_noop("Valid values are \"local\" and \"cascaded\".") - }, - /* list terminator */ - {{NULL}} - }; - - static relopt_string stringRelOpts[] = - { - /* list terminator */ - {{NULL}} - }; - - static relopt_gen **relOpts = NULL; - static bits32 last_assigned_kind = RELOPT_KIND_LAST_DEFAULT; ++<<<<<<< ours +static int num_custom_options = 0; +static relopt_gen **custom_options = NULL; +static bool need_initialization = true; + +static void initialize_reloptions(void); +static void parse_one_reloption(relopt_value *option, char *text_str, + int text_len, bool validate); + +/* + * Get the length of a string reloption (either default or the user-defined + * value). This is used for allocation purposes when building a set of + * relation options. + */ +#define GET_STRING_RELOPTION_LEN(option) \ + ((option).isset ? strlen((option).string_val) : \ + ((relopt_string *) (option).gen)->default_len) + +/* + * initialize_reloptions + * initialization routine, must be called before parsing + * + * Initialize the relOpts array and fill each variable's type and name length. + */ +static void +initialize_reloptions(void) +{ + int i; + int j; + + j = 0; + for (i = 0; boolRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(boolRelOpts[i].gen.lockmode, + boolRelOpts[i].gen.lockmode)); + j++; + } + for (i = 0; ternaryRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(ternaryRelOpts[i].gen.lockmode, + ternaryRelOpts[i].gen.lockmode)); + j++; + } + + for (i = 0; intRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(intRelOpts[i].gen.lockmode, + intRelOpts[i].gen.lockmode)); + j++; + } + for (i = 0; realRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(realRelOpts[i].gen.lockmode, + realRelOpts[i].gen.lockmode)); + j++; + } + for (i = 0; enumRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(enumRelOpts[i].gen.lockmode, + enumRelOpts[i].gen.lockmode)); + j++; + } + for (i = 0; stringRelOpts[i].gen.name; i++) + { + Assert(DoLockModesConflict(stringRelOpts[i].gen.lockmode, + stringRelOpts[i].gen.lockmode)); + j++; + } + j += num_custom_options; + + if (relOpts) + pfree(relOpts); + relOpts = MemoryContextAlloc(TopMemoryContext, + (j + 1) * sizeof(relopt_gen *)); + + j = 0; + for (i = 0; boolRelOpts[i].gen.name; i++) + { + relOpts[j] = &boolRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_BOOL; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; ternaryRelOpts[i].gen.name; i++) + { + relOpts[j] = &ternaryRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_TERNARY; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; intRelOpts[i].gen.name; i++) + { + relOpts[j] = &intRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_INT; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; realRelOpts[i].gen.name; i++) + { + relOpts[j] = &realRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_REAL; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; enumRelOpts[i].gen.name; i++) + { + relOpts[j] = &enumRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_ENUM; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; stringRelOpts[i].gen.name; i++) + { + relOpts[j] = &stringRelOpts[i].gen; + relOpts[j]->type = RELOPT_TYPE_STRING; + relOpts[j]->namelen = strlen(relOpts[j]->name); + j++; + } + + for (i = 0; i < num_custom_options; i++) + { + relOpts[j] = custom_options[i]; + j++; + } + + /* add a list terminator */ + relOpts[j] = NULL; + + /* flag the work is complete */ + need_initialization = false; +} + +/* + * add_reloption_kind + * Create a new relopt_kind value, to be used in custom reloptions by + * user-defined AMs. + */ +relopt_kind +add_reloption_kind(void) +{ + /* don't hand out the last bit so that the enum's behavior is portable */ + if (last_assigned_kind >= RELOPT_KIND_MAX) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("user-defined relation parameter types limit exceeded"))); + last_assigned_kind <<= 1; + return (relopt_kind) last_assigned_kind; +} + +/* + * add_reloption + * Add an already-created custom reloption to the list, and recompute the + * main parser table. + */ +static void +add_reloption(relopt_gen *newoption) +{ + static int max_custom_options = 0; + + if (num_custom_options >= max_custom_options) + { + MemoryContext oldcxt; + + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + + if (max_custom_options == 0) + { + max_custom_options = 8; + custom_options = palloc(max_custom_options * sizeof(relopt_gen *)); + } + else + { + max_custom_options *= 2; + custom_options = repalloc(custom_options, + max_custom_options * sizeof(relopt_gen *)); + } + MemoryContextSwitchTo(oldcxt); + } + custom_options[num_custom_options++] = newoption; + + need_initialization = true; +} ++======= + options_spec_set *get_stdrd_relopt_spec_set(bool is_heap); + void oid_postvalidate(option_value *value); ++>>>>>>> theirs /* * init_local_reloptions @@@ -798,115 -141,6 +747,118 @@@ register_reloptions_validator(local_rel } /* ++<<<<<<< ours + * add_local_reloption + * Add an already-created custom reloption to the local list. + */ +static void +add_local_reloption(local_relopts *relopts, relopt_gen *newoption, int offset) +{ + local_relopt *opt = palloc_object(local_relopt); + + Assert(offset < relopts->relopt_struct_size); + + opt->option = newoption; + opt->offset = offset; + + relopts->options = lappend(relopts->options, opt); +} + +/* + * allocate_reloption + * Allocate a new reloption and initialize the type-agnostic fields + * (for types other than string) + */ +static relopt_gen * +allocate_reloption(bits32 kinds, int type, const char *name, const char *desc, + LOCKMODE lockmode) +{ + MemoryContext oldcxt; + size_t size; + relopt_gen *newoption; + + if (kinds != RELOPT_KIND_LOCAL) + oldcxt = MemoryContextSwitchTo(TopMemoryContext); + else + oldcxt = NULL; + + switch (type) + { + case RELOPT_TYPE_BOOL: + size = sizeof(relopt_bool); + break; + case RELOPT_TYPE_TERNARY: + size = sizeof(relopt_ternary); + break; + case RELOPT_TYPE_INT: + size = sizeof(relopt_int); + break; + case RELOPT_TYPE_REAL: + size = sizeof(relopt_real); + break; + case RELOPT_TYPE_ENUM: + size = sizeof(relopt_enum); + break; + case RELOPT_TYPE_STRING: + size = sizeof(relopt_string); + break; + default: + elog(ERROR, "unsupported reloption type %d", type); + return NULL; /* keep compiler quiet */ + } + + newoption = palloc(size); + + newoption->name = pstrdup(name); + if (desc) + newoption->desc = pstrdup(desc); + else + newoption->desc = NULL; + newoption->kinds = kinds; + newoption->namelen = strlen(name); + newoption->type = type; + newoption->lockmode = lockmode; + + if (oldcxt != NULL) + MemoryContextSwitchTo(oldcxt); + + return newoption; +} + +/* + * init_bool_reloption + * Allocate and initialize a new boolean reloption + */ +static relopt_bool * +init_bool_reloption(bits32 kinds, const char *name, const char *desc, + bool default_val, LOCKMODE lockmode) +{ + relopt_bool *newoption; + + newoption = (relopt_bool *) allocate_reloption(kinds, RELOPT_TYPE_BOOL, + name, desc, lockmode); + newoption->default_val = default_val; + + return newoption; +} + +/* + * add_bool_reloption + * Add a new boolean reloption + */ +void +add_bool_reloption(bits32 kinds, const char *name, const char *desc, + bool default_val, LOCKMODE lockmode) +{ + relopt_bool *newoption = init_bool_reloption(kinds, name, desc, + default_val, lockmode); + + add_reloption((relopt_gen *) newoption); +} + +/* ++======= ++>>>>>>> theirs * add_local_bool_reloption * Add a new boolean local reloption * @@@ -916,96 -150,8 +868,101 @@@ voi add_local_bool_reloption(local_relopts *relopts, const char *name, const char *desc, bool default_val, int offset) { ++<<<<<<< ours + relopt_bool *newoption = init_bool_reloption(RELOPT_KIND_LOCAL, + name, desc, + default_val, 0); + + add_local_reloption(relopts, (relopt_gen *) newoption, offset); +} + +/* + * init_ternary_reloption + * Allocate and initialize a new ternary reloption + */ +static relopt_ternary * +init_ternary_reloption(bits32 kinds, const char *name, const char *desc, + LOCKMODE lockmode) +{ + relopt_ternary *newoption; + + newoption = (relopt_ternary *) + allocate_reloption(kinds, RELOPT_TYPE_TERNARY, name, desc, lockmode); + + return newoption; +} + +/* + * add_ternary_reloption + * Add a new ternary reloption + */ +void +add_ternary_reloption(bits32 kinds, const char *name, const char *desc, + LOCKMODE lockmode) +{ + relopt_ternary *newoption; + + newoption = + init_ternary_reloption(kinds, name, desc, lockmode); + + add_reloption((relopt_gen *) newoption); +} + +/* + * add_local_ternary_reloption + * Add a new ternary local reloption + * + * 'offset' is offset of ternary-typed field. + */ +void +add_local_ternary_reloption(local_relopts *relopts, const char *name, + const char *desc, int offset) +{ + relopt_ternary *newoption; + + newoption = + init_ternary_reloption(RELOPT_KIND_LOCAL, name, desc, 0); + + add_local_reloption(relopts, (relopt_gen *) newoption, offset); +} + +/* + * init_real_reloption + * Allocate and initialize a new integer reloption + */ +static relopt_int * +init_int_reloption(bits32 kinds, const char *name, const char *desc, + int default_val, int min_val, int max_val, + LOCKMODE lockmode) +{ + relopt_int *newoption; + + newoption = (relopt_int *) allocate_reloption(kinds, RELOPT_TYPE_INT, + name, desc, lockmode); + newoption->default_val = default_val; + newoption->min = min_val; + newoption->max = max_val; + + return newoption; +} + +/* + * add_int_reloption + * Add a new integer reloption + */ +void +add_int_reloption(bits32 kinds, const char *name, const char *desc, int default_val, + int min_val, int max_val, LOCKMODE lockmode) +{ + relopt_int *newoption = init_int_reloption(kinds, name, desc, + default_val, min_val, + max_val, lockmode); + + add_reloption((relopt_gen *) newoption); ++======= + optionsSpecSetAddBool(relopts->spec_set, name, desc, NoLock, offset, NULL, + default_val); ++>>>>>>> theirs } /* @@@ -1220,256 -213,8 +1024,261 @@@ add_local_string_reloption(local_relopt validate_string_relopt validator, fill_string_relopt filler, int offset) { ++<<<<<<< ours + relopt_string *newoption = init_string_reloption(RELOPT_KIND_LOCAL, + name, desc, + default_val, + validator, filler, + 0); + + add_local_reloption(relopts, (relopt_gen *) newoption, offset); +} + +/* + * Transform a relation options list (list of DefElem) into the text array + * format that is kept in pg_class.reloptions, including only those options + * that are in the passed namespace. The output values do not include the + * namespace. + * + * This is used for three cases: CREATE TABLE/INDEX, ALTER TABLE SET, and + * ALTER TABLE RESET. In the ALTER cases, oldOptions is the existing + * reloptions value (possibly NULL), and we replace or remove entries + * as needed. + * + * If acceptOidsOff is true, then we allow oids = false, but throw error when + * on. This is solely needed for backwards compatibility. + * + * Note that this is not responsible for determining whether the options + * are valid, but it does check that namespaces for all the options given are + * listed in validnsps. The NULL namespace is always valid and need not be + * explicitly listed. Passing a NULL pointer means that only the NULL + * namespace is valid. + * + * Both oldOptions and the result are text arrays (or NULL for "default"), + * but we declare them as Datums to avoid including array.h in reloptions.h. + */ +Datum +transformRelOptions(Datum oldOptions, List *defList, const char *nameSpace, + const char *const validnsps[], bool acceptOidsOff, bool isReset) +{ + Datum result; + ArrayBuildState *astate; + ListCell *cell; + + /* no change if empty list */ + if (defList == NIL) + return oldOptions; + + /* We build new array using accumArrayResult */ + astate = NULL; + + /* Copy any oldOptions that aren't to be replaced */ + if (DatumGetPointer(oldOptions) != NULL) + { + ArrayType *array = DatumGetArrayTypeP(oldOptions); + Datum *oldoptions; + int noldoptions; + int i; + + deconstruct_array_builtin(array, TEXTOID, &oldoptions, NULL, &noldoptions); + + for (i = 0; i < noldoptions; i++) + { + char *text_str = VARDATA(DatumGetPointer(oldoptions[i])); + int text_len = VARSIZE(DatumGetPointer(oldoptions[i])) - VARHDRSZ; + + /* Search for a match in defList */ + foreach(cell, defList) + { + DefElem *def = (DefElem *) lfirst(cell); + int kw_len; + + /* ignore if not in the same namespace */ + if (nameSpace == NULL) + { + if (def->defnamespace != NULL) + continue; + } + else if (def->defnamespace == NULL) + continue; + else if (strcmp(def->defnamespace, nameSpace) != 0) + continue; + + kw_len = strlen(def->defname); + if (text_len > kw_len && text_str[kw_len] == '=' && + strncmp(text_str, def->defname, kw_len) == 0) + break; + } + if (!cell) + { + /* No match, so keep old option */ + astate = accumArrayResult(astate, oldoptions[i], + false, TEXTOID, + CurrentMemoryContext); + } + } + } + + /* + * If CREATE/SET, add new options to array; if RESET, just check that the + * user didn't say RESET (option=val). (Must do this because the grammar + * doesn't enforce it.) + */ + foreach(cell, defList) + { + DefElem *def = (DefElem *) lfirst(cell); + + if (isReset) + { + if (def->arg != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("RESET must not include values for parameters"))); + } + else + { + const char *name; + const char *value; + text *t; + Size len; + + /* + * Error out if the namespace is not valid. A NULL namespace is + * always valid. + */ + if (def->defnamespace != NULL) + { + bool valid = false; + int i; + + if (validnsps) + { + for (i = 0; validnsps[i]; i++) + { + if (strcmp(def->defnamespace, validnsps[i]) == 0) + { + valid = true; + break; + } + } + } + + if (!valid) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized parameter namespace \"%s\"", + def->defnamespace))); + } + + /* ignore if not in the same namespace */ + if (nameSpace == NULL) + { + if (def->defnamespace != NULL) + continue; + } + else if (def->defnamespace == NULL) + continue; + else if (strcmp(def->defnamespace, nameSpace) != 0) + continue; + + /* + * Flatten the DefElem into a text string like "name=arg". If we + * have just "name", assume "name=true" is meant. Note: the + * namespace is not output. + */ + name = def->defname; + if (def->arg != NULL) + value = defGetString(def); + else + value = "true"; + + /* Insist that name not contain "=", else "a=b=c" is ambiguous */ + if (strchr(name, '=') != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid option name \"%s\": must not contain \"=\"", + name))); + + /* + * This is not a great place for this test, but there's no other + * convenient place to filter the option out. As WITH (oids = + * false) will be removed someday, this seems like an acceptable + * amount of ugly. + */ + if (acceptOidsOff && def->defnamespace == NULL && + strcmp(name, "oids") == 0) + { + if (defGetBoolean(def)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("tables declared WITH OIDS are not supported"))); + /* skip over option, reloptions machinery doesn't know it */ + continue; + } + + len = VARHDRSZ + strlen(name) + 1 + strlen(value); + /* +1 leaves room for sprintf's trailing null */ + t = (text *) palloc(len + 1); + SET_VARSIZE(t, len); + sprintf(VARDATA(t), "%s=%s", name, value); + + astate = accumArrayResult(astate, PointerGetDatum(t), + false, TEXTOID, + CurrentMemoryContext); + } + } + + if (astate) + result = makeArrayResult(astate, CurrentMemoryContext); + else + result = (Datum) 0; + + return result; +} + + +/* + * Convert the text-array format of reloptions into a List of DefElem. + * This is the inverse of transformRelOptions(). + */ +List * +untransformRelOptions(Datum options) +{ + List *result = NIL; + ArrayType *array; + Datum *optiondatums; + int noptions; + int i; + + /* Nothing to do if no options */ + if (DatumGetPointer(options) == NULL) + return result; + + array = DatumGetArrayTypeP(options); + + deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions); + + for (i = 0; i < noptions; i++) + { + char *s; + char *p; + Node *val = NULL; + + s = TextDatumGetCString(optiondatums[i]); + p = strchr(s, '='); + if (p) + { + *p++ = '\0'; + val = (Node *) makeString(p); + } + result = lappend(result, makeDefElem(s, val, -1)); + } + + return result; ++======= + optionsSpecSetAddString(relopts->spec_set, name, desc, NoLock, offset, + NULL, default_val, validator, filler); ++>>>>>>> theirs } /* @@@ -1532,541 -286,312 +1350,666 @@@ extractRelOptions(HeapTuple tuple, Tupl return options; } - static void - parseRelOptionsInternal(Datum options, bool validate, - relopt_value *reloptions, int numoptions) + void + oid_postvalidate(option_value *value) { ++<<<<<<< ours + ArrayType *array = DatumGetArrayTypeP(options); + Datum *optiondatums; + int noptions; + int i; + + deconstruct_array_builtin(array, TEXTOID, &optiondatums, NULL, &noptions); + + for (i = 0; i < noptions; i++) + { + char *text_str = VARDATA(DatumGetPointer(optiondatums[i])); + int text_len = VARSIZE(DatumGetPointer(optiondatums[i])) - VARHDRSZ; + int j; + + /* Search for a match in reloptions */ + for (j = 0; j < numoptions; j++) + { + int kw_len = reloptions[j].gen->namelen; + + if (text_len > kw_len && text_str[kw_len] == '=' && + strncmp(text_str, reloptions[j].gen->name, kw_len) == 0) + { + parse_one_reloption(&reloptions[j], text_str, text_len, + validate); + break; + } + } + + if (j >= numoptions && validate) + { + char *s; + char *p; + + s = TextDatumGetCString(optiondatums[i]); + p = strchr(s, '='); + if (p) + *p = '\0'; + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized parameter \"%s\"", s))); + } + } + + /* It's worth avoiding memory leaks in this function */ + pfree(optiondatums); + + if (((void *) array) != DatumGetPointer(options)) + pfree(array); ++======= + if (value->values.bool_val) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("tables declared WITH OIDS are not supported"))); ++>>>>>>> theirs } /* - * Interpret reloptions that are given in text-array format. + * Relation options and Lock levels: + * + * The default choice for any new option should be AccessExclusiveLock. + * In some cases the lock level can be reduced from there, but the lock + * level chosen should always conflict with itself to ensure that multiple + * changes aren't lost when we attempt concurrent changes. + * The choice of lock level depends completely upon how that parameter + * is used within the server, not upon how and when you'd like to change it. + * Safety first. Existing choices are documented here, and elsewhere in + * backend code where the parameters are used. * - * options is a reloption text array as constructed by transformRelOptions. - * kind specifies the family of options to be processed. + * In general, anything that affects the results obtained from a SELECT must be + * protected by AccessExclusiveLock. * - * The return value is a relopt_value * array on which the options actually - * set in the options array are marked with isset=true. The length of this - * array is returned in *numrelopts. Options not set are also present in the - * array; this is so that the caller can easily locate the default values. + * Autovacuum related parameters can be set at ShareUpdateExclusiveLock + * since they are only used by the AV procs and don't change anything + * currently executing. + * + * Fillfactor can be set because it applies only to subsequent changes made to + * data blocks, as documented in heapio.c * - * If there are no options of the given kind, numrelopts is set to 0 and NULL - * is returned (unless options are illegally supplied despite none being - * defined, in which case an error occurs). + * n_distinct options can be set at ShareUpdateExclusiveLock because they + * are only used during ANALYZE, which uses a ShareUpdateExclusiveLock, + * so the ANALYZE will not be affected by in-flight changes. Changing those + * values has no affect until the next ANALYZE, so no need for stronger lock. * - * Note: values of type int, bool and real are allocated as part of the - * returned array. Values of type string are allocated separately and must - * be freed by the caller. + * Planner-related parameters can be set with ShareUpdateExclusiveLock because + * they only affect planning and not the correctness of the execution. Plans + * cannot be changed in mid-flight, so changes here could not easily result in + * new improved plans in any case. So we allow existing queries to continue + * and existing plans to survive, a small price to pay for allowing better + * plans to be introduced concurrently without interfering with users. + * + * Setting parallel_workers is safe, since it acts the same as + * max_parallel_workers_per_gather which is a USERSET parameter that doesn't + * affect existing plans or queries. */ - static relopt_value * - parseRelOptions(Datum options, bool validate, relopt_kind kind, - int *numrelopts) - { - relopt_value *reloptions = NULL; - int numoptions = 0; - int i; - int j; - - if (need_initialization) - initialize_reloptions(); - - /* Build a list of expected options, based on kind */ - for (i = 0; relOpts[i]; i++) - if (relOpts[i]->kinds & kind) - numoptions++; - if (numoptions > 0) - { - reloptions = palloc(numoptions * sizeof(relopt_value)); - - for (i = 0, j = 0; relOpts[i]; i++) - { - if (relOpts[i]->kinds & kind) - { - reloptions[j].gen = relOpts[i]; - reloptions[j].isset = false; - j++; - } - } + options_spec_set * + get_stdrd_relopt_spec_set(bool is_heap) + { + options_spec_set *stdrd_relopt_spec_set = allocateOptionsSpecSet( + is_heap ? NULL : "toast", sizeof(StdRdOptions), false, 0); + + if (is_heap) + optionsSpecSetAddInt(stdrd_relopt_spec_set, "fillfactor", + "Packs table pages only to this percentag", + ShareUpdateExclusiveLock, /* since it applies only + * to later inserts */ + offsetof(StdRdOptions, fillfactor), NULL, + HEAP_DEFAULT_FILLFACTOR, HEAP_MIN_FILLFACTOR, 100); + + optionsSpecSetAddBool(stdrd_relopt_spec_set, "autovacuum_enabled", + "Enables autovacuum in this relation", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, enabled), + NULL, true); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_vacuum_threshold", + "Minimum number of tuple updates or deletes prior to vacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_threshold), + NULL, -1, 0, INT_MAX); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_vacuum_max_threshold", + "Maximum number of tuple updates or deletes prior to vacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_max_threshold), + NULL, -2, -1, INT_MAX); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_vacuum_insert_threshold", + "Minimum number of tuple inserts prior to vacuum, or -1 to disable insert vacuums", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_ins_threshold), + NULL, -2, -1, INT_MAX); + + if (is_heap) + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_analyze_threshold", + "Minimum number of tuple updates or deletes prior to vacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, analyze_threshold), + NULL, -1, 0, INT_MAX); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_vacuum_cost_limit", + "Vacuum cost amount available before napping, for autovacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_cost_limit), + NULL, -1, 0, 10000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_freeze_min_age", + "Minimum age at which VACUUM should freeze a table row, for autovacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, freeze_min_age), + NULL, -1, 0, 1000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_freeze_max_age", + "Age at which to autovacuum a table to prevent transaction ID wraparound", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, freeze_max_age), + NULL, -1, 100000, 2000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_freeze_table_age", + "Age at which VACUUM should perform a full table sweep to freeze row versions", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, freeze_table_age), + NULL, -1, 0, 2000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_multixact_freeze_min_age", + "Minimum multixact age at which VACUUM should freeze a row multixact's, for autovacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, multixact_freeze_min_age), + NULL, -1, 0, 1000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_multixact_freeze_max_age", + "Multixact age at which to autovacuum a table to prevent multixact wraparound", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, multixact_freeze_max_age), + NULL, -1, 10000, 2000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "autovacuum_multixact_freeze_table_age", + "Age of multixact at which VACUUM should perform a full table sweep to freeze row versions", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, multixact_freeze_table_age), + NULL, -1, 0, 2000000000); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "log_autovacuum_min_duration", + "Sets the minimum execution time above which autovacuum actions will be logged", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, log_min_duration), + NULL, -1, -1, INT_MAX); + + optionsSpecSetAddReal(stdrd_relopt_spec_set, "autovacuum_vacuum_cost_delay", + "Vacuum cost delay in milliseconds, for autovacuum", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_cost_delay), + NULL, -1, 0.0, 100.0); + + optionsSpecSetAddReal(stdrd_relopt_spec_set, "autovacuum_vacuum_scale_factor", + "Number of tuple updates or deletes prior to vacuum as a fraction of reltuples", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_scale_factor), + NULL, -1, 0.0, 100.0); + + optionsSpecSetAddReal(stdrd_relopt_spec_set, "autovacuum_vacuum_insert_scale_factor", + "Number of tuple inserts prior to vacuum as a fraction of reltuples", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, vacuum_ins_scale_factor), + NULL, -1, 0.0, 100.0); + if (is_heap) + { + optionsSpecSetAddReal(stdrd_relopt_spec_set, "autovacuum_analyze_scale_factor", + "Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, autovacuum) + + offsetof(AutoVacOpts, analyze_scale_factor), + NULL, -1, 0.0, 100.0); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "toast_tuple_target", + "Sets the target tuple length at which external columns will be toasted", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, toast_tuple_target), + NULL, TOAST_TUPLE_TARGET, 128, + TOAST_TUPLE_TARGET_MAIN); + + optionsSpecSetAddBool(stdrd_relopt_spec_set, "user_catalog_table", + "Declare a table as an additional catalog table, e.g. for the purpose of logical replication", + AccessExclusiveLock, + offsetof(StdRdOptions, user_catalog_table), + NULL, false); + + optionsSpecSetAddInt(stdrd_relopt_spec_set, "parallel_workers", + "Number of parallel processes that can be used per executor node for this relation.", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, parallel_workers), + NULL, -1, 0, 1024); } ++<<<<<<< ours + /* Done if no options */ + if (DatumGetPointer(options) != NULL) + parseRelOptionsInternal(options, validate, reloptions, numoptions); + + *numrelopts = numoptions; + return reloptions; +} + +/* Parse local unregistered options. */ +static relopt_value * +parseLocalRelOptions(local_relopts *relopts, Datum options, bool validate) +{ + int nopts = list_length(relopts->options); + relopt_value *values = palloc_array(relopt_value, nopts); + ListCell *lc; + int i = 0; - - foreach(lc, relopts->options) - { - local_relopt *opt = lfirst(lc); - - values[i].gen = opt->option; - values[i].isset = false; - - i++; - } - - if (options != (Datum) 0) - parseRelOptionsInternal(options, validate, values, nopts); - - return values; ++======= + optionsSpecSetAddEnum(stdrd_relopt_spec_set, "vacuum_index_cleanup", + "Controls index vacuuming and index cleanup", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, vacuum_index_cleanup), + NULL, StdRdOptIndexCleanupValues, + STDRD_OPTION_VACUUM_INDEX_CLEANUP_AUTO, + gettext_noop("Valid values are \"on\", \"off\", and \"auto\".")); + + optionsSpecSetAddBool(stdrd_relopt_spec_set, "vacuum_truncate", + "Enables vacuum to truncate empty pages at the end of this table", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, vacuum_truncate), + NULL, true); ++>>>>>>> theirs + + optionsSpecSetAddReal(stdrd_relopt_spec_set, "vacuum_max_eager_freeze_failure_rate", + "Fraction of pages in a relation vacuum can scan and fail to freeze before disabling eager scanning", + ShareUpdateExclusiveLock, + offsetof(StdRdOptions, + vacuum_max_eager_freeze_failure_rate), + NULL, -1, 0.0, 1.0); + + if (is_heap) + optionsSpecSetAddBool(stdrd_relopt_spec_set, "oids", + "Backward compatibility option. Will do nothing when false, will throw error when true", + NoLock, + -1, /* Do not actually store it's value */ + &oid_postvalidate, false); + + return stdrd_relopt_spec_set; } - /* - * Subroutine for parseRelOptions, to parse and validate a single option's - * value - */ - static void - parse_one_reloption(relopt_value *option, char *text_str, int text_len, - bool validate) - { - char *value; - int value_len; - bool parsed; - bool nofree = false; ++<<<<<<< ours + if (option->isset && validate) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("parameter \"%s\" specified more than once", + option->gen->name))); + + value_len = text_len - option->gen->namelen - 1; + value = (char *) palloc(value_len + 1); + memcpy(value, text_str + option->gen->namelen + 1, value_len); + value[value_len] = '\0'; + + switch (option->gen->type) + { + case RELOPT_TYPE_BOOL: + { + parsed = parse_bool(value, &option->bool_val); + if (validate && !parsed) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for boolean option \"%s\": %s", + option->gen->name, value))); + } + break; + case RELOPT_TYPE_TERNARY: + { + bool b; + + parsed = parse_bool(value, &b); + option->ternary_val = b ? PG_TERNARY_TRUE : + PG_TERNARY_FALSE; + if (validate && !parsed) + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for boolean option \"%s\": %s", + option->gen->name, value)); + } + break; + case RELOPT_TYPE_INT: + { + relopt_int *optint = (relopt_int *) option->gen; + + parsed = parse_int(value, &option->int_val, 0, NULL); + if (validate && !parsed) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for integer option \"%s\": %s", + option->gen->name, value))); + if (validate && (option->int_val < optint->min || + option->int_val > optint->max)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value %s out of bounds for option \"%s\"", + value, option->gen->name), + errdetail("Valid values are between \"%d\" and \"%d\".", + optint->min, optint->max))); + } + break; + case RELOPT_TYPE_REAL: + { + relopt_real *optreal = (relopt_real *) option->gen; + + parsed = parse_real(value, &option->real_val, 0, NULL); + if (validate && !parsed) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for floating point option \"%s\": %s", + option->gen->name, value))); + if (validate && (option->real_val < optreal->min || + option->real_val > optreal->max)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("value %s out of bounds for option \"%s\"", + value, option->gen->name), + errdetail("Valid values are between \"%f\" and \"%f\".", + optreal->min, optreal->max))); + } + break; + case RELOPT_TYPE_ENUM: + { + relopt_enum *optenum = (relopt_enum *) option->gen; + relopt_enum_elt_def *elt; + + parsed = false; + for (elt = optenum->members; elt->string_val; elt++) + { + if (pg_strcasecmp(value, elt->string_val) == 0) + { + option->enum_val = elt->symbol_val; + parsed = true; + break; + } + } + if (validate && !parsed) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid value for enum option \"%s\": %s", + option->gen->name, value), + optenum->detailmsg ? + errdetail_internal("%s", _(optenum->detailmsg)) : 0)); + + /* + * If value is not among the allowed string values, but we are + * not asked to validate, just use the default numeric value. + */ + if (!parsed) + option->enum_val = optenum->default_val; + } + break; + case RELOPT_TYPE_STRING: + { + relopt_string *optstring = (relopt_string *) option->gen; + + option->string_val = value; + nofree = true; + if (validate && optstring->validate_cb) + (optstring->validate_cb) (value); + parsed = true; + } + break; + default: + elog(ERROR, "unsupported reloption type %d", option->gen->type); + parsed = true; /* quiet compiler */ + break; + } ++======= + static options_spec_set *heap_relopt_spec_set = NULL; ++>>>>>>> theirs - if (parsed) - option->isset = true; - if (!nofree) - pfree(value); + options_spec_set * + get_heap_relopt_spec_set(void) + { + if (heap_relopt_spec_set) + return heap_relopt_spec_set; + heap_relopt_spec_set = get_stdrd_relopt_spec_set(true); + return heap_relopt_spec_set; } /* - * Given the result from parseRelOptions, allocate a struct that's of the - * specified base size plus any extra space that's needed for string variables. - * - * "base" should be sizeof(struct) of the reloptions struct (StdRdOptions or - * equivalent). + * These toast options are can't be set via SQL, but we should set them + * to their defaults in binary representation, to make postgres work properly */ - static void * - allocateReloptStruct(Size base, relopt_value *options, int numoptions) + static void + toast_options_postprocess(void *data, bool validate) { - Size size = base; - int i; - - for (i = 0; i < numoptions; i++) + if (data) { - relopt_value *optval = &options[i]; + StdRdOptions *toast_options = (StdRdOptions *) data; ++<<<<<<< ours + if (optval->gen->type == RELOPT_TYPE_STRING) + { + relopt_string *optstr = (relopt_string *) optval->gen; + + if (optstr->fill_cb) + { + const char *val = optval->isset ? optval->string_val : + optstr->default_isnull ? NULL : optstr->default_val; + + size += optstr->fill_cb(val, NULL); + } + else + size += GET_STRING_RELOPTION_LEN(*optval) + 1; + } ++======= + toast_options->fillfactor = 100; + toast_options->autovacuum.analyze_threshold = -1; + toast_options->autovacuum.analyze_scale_factor = -1; ++>>>>>>> theirs } - - return palloc0(size); } - /* - * Given the result of parseRelOptions and a parsing table, fill in the - * struct (previously allocated with allocateReloptStruct) with the parsed - * values. - * - * rdopts is the pointer to the allocated struct to be filled. - * basesize is the sizeof(struct) that was passed to allocateReloptStruct. - * options, of length numoptions, is parseRelOptions' output. - * elems, of length numelems, is the table describing the allowed options. - * When validate is true, it is expected that all options appear in elems. - */ - static void - fillRelOptions(void *rdopts, Size basesize, - relopt_value *options, int numoptions, - bool validate, - const relopt_parse_elt *elems, int numelems) + static options_spec_set *toast_relopt_spec_set = NULL; + options_spec_set * + get_toast_relopt_spec_set(void) { - int i; - int offset = basesize; + if (toast_relopt_spec_set) + return toast_relopt_spec_set; - for (i = 0; i < numoptions; i++) - { - int j; - bool found = false; + toast_relopt_spec_set = get_stdrd_relopt_spec_set(false); + toast_relopt_spec_set->postprocess_fun = toast_options_postprocess; ++<<<<<<< ours + for (j = 0; j < numelems; j++) + { + if (strcmp(options[i].gen->name, elems[j].optname) == 0) + { + relopt_string *optstring; + char *itempos = ((char *) rdopts) + elems[j].offset; + char *string_val; + + switch (options[i].gen->type) + { + case RELOPT_TYPE_BOOL: + *(bool *) itempos = options[i].isset ? + options[i].bool_val : + ((relopt_bool *) options[i].gen)->default_val; + break; + case RELOPT_TYPE_TERNARY: + *(pg_ternary *) itempos = options[i].isset ? + options[i].ternary_val : PG_TERNARY_UNSET; + break; + case RELOPT_TYPE_INT: + *(int *) itempos = options[i].isset ? + options[i].int_val : + ((relopt_int *) options[i].gen)->default_val; + break; + case RELOPT_TYPE_REAL: + *(double *) itempos = options[i].isset ? + options[i].real_val : + ((relopt_real *) options[i].gen)->default_val; + break; + case RELOPT_TYPE_ENUM: + *(int *) itempos = options[i].isset ? + options[i].enum_val : + ((relopt_enum *) options[i].gen)->default_val; + break; + case RELOPT_TYPE_STRING: + optstring = (relopt_string *) options[i].gen; + if (options[i].isset) + string_val = options[i].string_val; + else if (!optstring->default_isnull) + string_val = optstring->default_val; + else + string_val = NULL; + + if (optstring->fill_cb) + { + Size size = + optstring->fill_cb(string_val, + (char *) rdopts + offset); + + if (size) + { + *(int *) itempos = offset; + offset += size; + } + else + *(int *) itempos = 0; + } + else if (string_val == NULL) + *(int *) itempos = 0; + else + { + strcpy((char *) rdopts + offset, string_val); + *(int *) itempos = offset; + offset += strlen(string_val) + 1; + } + break; + default: + elog(ERROR, "unsupported reloption type %d", + options[i].gen->type); + break; + } + found = true; + break; + } + } + if (validate && !found) + elog(ERROR, "reloption \"%s\" not found in parse table", + options[i].gen->name); + } + SET_VARSIZE(rdopts, offset); ++======= + return toast_relopt_spec_set; ++>>>>>>> theirs } /* - * Option parser for anything that uses StdRdOptions. + * Do not allow to set any option on partitioned table */ - bytea * - default_reloptions(Datum reloptions, bool validate, relopt_kind kind) + static void + partitioned_options_postprocess(void *data, bool validate) { ++<<<<<<< ours + static const relopt_parse_elt tab[] = { + {"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}, + {"autovacuum_enabled", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)}, + {"autovacuum_vacuum_threshold", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)}, + {"autovacuum_vacuum_max_threshold", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_max_threshold)}, + {"autovacuum_vacuum_insert_threshold", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_threshold)}, + {"autovacuum_analyze_threshold", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)}, + {"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)}, + {"autovacuum_freeze_min_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)}, + {"autovacuum_freeze_max_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)}, + {"autovacuum_freeze_table_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)}, + {"autovacuum_multixact_freeze_min_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_min_age)}, + {"autovacuum_multixact_freeze_max_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_max_age)}, + {"autovacuum_multixact_freeze_table_age", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, multixact_freeze_table_age)}, + {"log_autovacuum_min_duration", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_vacuum_min_duration)}, + {"log_autoanalyze_min_duration", RELOPT_TYPE_INT, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_analyze_min_duration)}, + {"toast_tuple_target", RELOPT_TYPE_INT, + offsetof(StdRdOptions, toast_tuple_target)}, + {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)}, + {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)}, + {"autovacuum_vacuum_insert_scale_factor", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_ins_scale_factor)}, + {"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}, + {"user_catalog_table", RELOPT_TYPE_BOOL, + offsetof(StdRdOptions, user_catalog_table)}, + {"parallel_workers", RELOPT_TYPE_INT, + offsetof(StdRdOptions, parallel_workers)}, + {"vacuum_index_cleanup", RELOPT_TYPE_ENUM, + offsetof(StdRdOptions, vacuum_index_cleanup)}, + {"vacuum_truncate", RELOPT_TYPE_TERNARY, + offsetof(StdRdOptions, vacuum_truncate)}, + {"vacuum_max_eager_freeze_failure_rate", RELOPT_TYPE_REAL, + offsetof(StdRdOptions, vacuum_max_eager_freeze_failure_rate)} + }; + + return (bytea *) build_reloptions(reloptions, validate, kind, + sizeof(StdRdOptions), + tab, lengthof(tab)); ++======= + if (data && validate) + ereport(ERROR, + errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot specify storage parameters for a partitioned table"), + errhint("Specify storage parameters for its leaf partitions instead.")); ++>>>>>>> theirs } - /* - * build_reloptions - * - * Parses "reloptions" provided by the caller, returning them in a - * structure containing the parsed options. The parsing is done with - * the help of a parsing table describing the allowed options, defined - * by "relopt_elems" of length "num_relopt_elems". - * - * "validate" must be true if reloptions value is freshly built by - * transformRelOptions(), as opposed to being read from the catalog, in which - * case the values contained in it must already be valid. - * - * NULL is returned if the passed-in options did not match any of the options - * in the parsing table, unless validate is true in which case an error would - * be reported. - */ - void * - build_reloptions(Datum reloptions, bool validate, - relopt_kind kind, - Size relopt_struct_size, - const relopt_parse_elt *relopt_elems, - int num_relopt_elems) - { - int numoptions; - relopt_value *options; - void *rdopts; - - /* parse options specific to given relation option kind */ - options = parseRelOptions(reloptions, validate, kind, &numoptions); - Assert(numoptions <= num_relopt_elems); - /* if none set, we're done */ - if (numoptions == 0) - { - Assert(options == NULL); - return NULL; - } + static options_spec_set *partitioned_relopt_spec_set = NULL; - /* allocate and fill the structure */ - rdopts = allocateReloptStruct(relopt_struct_size, options, numoptions); - fillRelOptions(rdopts, relopt_struct_size, options, numoptions, - validate, relopt_elems, num_relopt_elems); + options_spec_set * + get_partitioned_relopt_spec_set(void) + { + if (partitioned_relopt_spec_set) + return partitioned_relopt_spec_set; + partitioned_relopt_spec_set = get_stdrd_relopt_spec_set(true); - pfree(options); + /* No options for now, so Spec Set is empty */ + partitioned_relopt_spec_set->postprocess_fun = + partitioned_options_postprocess; - return rdopts; + return partitioned_relopt_spec_set; } /* @@@ -2077,122 -602,79 +2020,91 @@@ void * build_local_reloptions(local_relopts *relopts, Datum options, bool validate) { ++<<<<<<< ours + int noptions = list_length(relopts->options); + relopt_parse_elt *elems = palloc_array(relopt_parse_elt, noptions); + relopt_value *vals; ++======= ++>>>>>>> theirs void *opts; - int i = 0; ListCell *lc; + List *values; - foreach(lc, relopts->options) + values = optionsTextArrayToRawValues(options); + values = optionsParseRawValues(values, relopts->spec_set, validate); + opts = optionsValuesToBytea(values, relopts->spec_set); + + /* + * Kind of ugly conversion here for backward compatibility. Would be + * removed while moving opclass options to options.c API + */ + + if (validate && relopts->validators) { - local_relopt *opt = lfirst(lc); + int val_count = list_length(values); + int i; + option_value *val_array; - elems[i].optname = opt->option->name; - elems[i].opttype = opt->option->type; - elems[i].offset = opt->offset; + val_array = palloc(sizeof(option_value) * val_count); - i++; - } + i = 0; + foreach(lc, values) + { + option_value *val = lfirst(lc); - vals = parseLocalRelOptions(relopts, options, validate); - opts = allocateReloptStruct(relopts->relopt_struct_size, vals, noptions); - fillRelOptions(opts, relopts->relopt_struct_size, vals, noptions, validate, - elems, noptions); + memcpy(&(val_array[i]), val, sizeof(option_value)); + i++; + } - if (validate) foreach(lc, relopts->validators) - ((relopts_validator) lfirst(lc)) (opts, vals, noptions); + ((relopts_validator) lfirst(lc)) (opts, val_array, val_count); - if (elems) - pfree(elems); + pfree(val_array); + } return opts; } /* - * Option parser for partitioned tables - */ - bytea * - partitioned_table_reloptions(Datum reloptions, bool validate) - { - if (validate && reloptions) - ereport(ERROR, - errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("cannot specify storage parameters for a partitioned table"), - errhint("Specify storage parameters for its leaf partitions instead.")); - return NULL; - } - - /* - * Option parser for views + * get_view_relopt_spec_set + * Returns an options catalog for view relation. */ - bytea * - view_reloptions(Datum reloptions, bool validate) - { - static const relopt_parse_elt tab[] = { - {"security_barrier", RELOPT_TYPE_BOOL, - offsetof(ViewOptions, security_barrier)}, - {"security_invoker", RELOPT_TYPE_BOOL, - offsetof(ViewOptions, security_invoker)}, - {"check_option", RELOPT_TYPE_ENUM, - offsetof(ViewOptions, check_option)} - }; + static options_spec_set *view_relopt_spec_set = NULL; - return (bytea *) build_reloptions(reloptions, validate, - RELOPT_KIND_VIEW, - sizeof(ViewOptions), - tab, lengthof(tab)); - } - - /* - * Parse options for heaps, views and toast tables. - */ - bytea * - heap_reloptions(char relkind, Datum reloptions, bool validate) + options_spec_set * + get_view_relopt_spec_set(void) { - StdRdOptions *rdopts; + if (view_relopt_spec_set) + return view_relopt_spec_set; - switch (relkind) - { - case RELKIND_TOASTVALUE: - rdopts = (StdRdOptions *) - default_reloptions(reloptions, validate, RELOPT_KIND_TOAST); - if (rdopts != NULL) - { - /* adjust default-only parameters for TOAST relations */ - rdopts->fillfactor = 100; - rdopts->autovacuum.analyze_threshold = -1; - rdopts->autovacuum.analyze_scale_factor = -1; - } - return (bytea *) rdopts; - case RELKIND_RELATION: - case RELKIND_MATVIEW: - return default_reloptions(reloptions, validate, RELOPT_KIND_HEAP); - default: - /* other relkinds are not supported */ - return NULL; - } - } + view_relopt_spec_set = allocateOptionsSpecSet(NULL, + sizeof(ViewOptions), false, 3); + optionsSpecSetAddBool(view_relopt_spec_set, "security_barrier", + "View acts as a row security barrier", + AccessExclusiveLock, + offsetof(ViewOptions, security_barrier), NULL, false); - /* - * Parse options for indexes. - * - * amoptions index AM's option parser function - * reloptions options as text[] datum - * validate error flag - */ - bytea * - index_reloptions(amoptions_function amoptions, Datum reloptions, bool validate) - { - Assert(amoptions != NULL); + optionsSpecSetAddBool(view_relopt_spec_set, "security_invoker", + "Privileges on underlying relations are checked as the invoking user, not the view owner", + AccessExclusiveLock, + offsetof(ViewOptions, security_invoker), NULL, false); ++<<<<<<< ours + /* Assume function is strict */ + if (DatumGetPointer(reloptions) == NULL) + return NULL; - - return amoptions(reloptions, validate); ++======= + optionsSpecSetAddEnum(view_relopt_spec_set, "check_option", + "View has WITH CHECK OPTION defined (local or cascaded)", + AccessExclusiveLock, + offsetof(ViewOptions, check_option), NULL, + viewCheckOptValues, + VIEW_OPTION_CHECK_OPTION_NOT_SET, + gettext_noop("Valid values are \"local\" and \"cascaded\".")); ++>>>>>>> theirs + + return view_relopt_spec_set; } /* diff --cc src/backend/access/gin/ginutil.c index d205093e21d,6d4248ffe09..00000000000 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@@ -37,61 -38,60 +38,118 @@@ Datum ginhandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = gingetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/backend/access/gist/gist.c index dfffce3e396,611d4b523d0..00000000000 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@@ -58,63 -58,62 +58,122 @@@ static void gistprunepage(Relation rel Datum gisthandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = gistgetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/backend/access/hash/hash.c index e88ddb32a05,d83a26e39a3..00000000000 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@@ -57,63 -57,62 +57,122 @@@ static void hashbuildCallback(Relation Datum hashhandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = hashgetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/backend/access/nbtree/nbtree.c index 3dec1ee657d,5ccf2f9d5bc..00000000000 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@@ -115,63 -101,62 +116,122 @@@ static BTVacuumPosting btreevacuumposti Datum bthandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = btgetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/backend/access/nbtree/nbtutils.c index 5c50f0dd1bd,28a3c0be76b..00000000000 --- a/src/backend/access/nbtree/nbtutils.c +++ b/src/backend/access/nbtree/nbtutils.c @@@ -18,11 -18,9 +18,15 @@@ #include #include "access/nbtree.h" ++<<<<<<< ours +#include "access/reloptions.h" ++======= + #include "storage/lock.h" ++>>>>>>> theirs #include "access/relscan.h" #include "commands/progress.h" +#include "common/int.h" +#include "lib/qunique.h" #include "miscadmin.h" #include "utils/datum.h" #include "utils/lsyscache.h" diff --cc src/backend/access/spgist/spgutils.c index 9f5379b87ac,b1c0a37311e..00000000000 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@@ -43,63 -43,62 +43,122 @@@ Datum spghandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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); ++======= + 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->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; + amroutine->amreloptspecset = spggetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs } /* diff --cc src/include/access/amapi.h index ecfbd017d66,1d8c28b7c8e..00000000000 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@@ -15,8 -15,7 +15,12 @@@ #include "access/cmptype.h" #include "access/genam.h" #include "access/stratnum.h" ++<<<<<<< ours +#include "nodes/nodes.h" +#include "nodes/pg_list.h" ++======= + #include "access/options.h" ++>>>>>>> theirs /* * We don't wish to include planner header files here, since most of an index diff --cc src/include/access/reloptions.h index 0bd17b30ca7,b42bb614e03..00000000000 --- a/src/include/access/reloptions.h +++ b/src/include/access/reloptions.h @@@ -1,15 -1,10 +1,19 @@@ /*------------------------------------------------------------------------- * * reloptions.h - * Core support for relation and tablespace options (pg_class.reloptions + * Support for relation view and tablespace options (pg_class.reloptions * and pg_tablespace.spcoptions) * ++<<<<<<< ours + * Note: the functions dealing with text-array reloptions values declare + * them as Datum, not ArrayType *, to avoid needing to include array.h + * into a lot of low-level code. + * + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group ++======= + * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group ++>>>>>>> theirs * Portions Copyright (c) 1994, Regents of the University of California * * src/include/access/reloptions.h @@@ -25,185 -20,36 +29,162 @@@ #include "nodes/pg_list.h" #include "storage/lock.h" ++<<<<<<< ours +/* types supported by reloptions */ +typedef enum relopt_type +{ + RELOPT_TYPE_BOOL, + RELOPT_TYPE_TERNARY, /* on, off, unset */ + RELOPT_TYPE_INT, + RELOPT_TYPE_REAL, + RELOPT_TYPE_ENUM, + RELOPT_TYPE_STRING, +} relopt_type; + +/* kinds supported by reloptions */ +typedef enum relopt_kind +{ + RELOPT_KIND_LOCAL = 0, + RELOPT_KIND_HEAP = (1 << 0), + RELOPT_KIND_TOAST = (1 << 1), + RELOPT_KIND_BTREE = (1 << 2), + RELOPT_KIND_HASH = (1 << 3), + RELOPT_KIND_GIN = (1 << 4), + RELOPT_KIND_GIST = (1 << 5), + RELOPT_KIND_ATTRIBUTE = (1 << 6), + RELOPT_KIND_TABLESPACE = (1 << 7), + RELOPT_KIND_SPGIST = (1 << 8), + RELOPT_KIND_VIEW = (1 << 9), + RELOPT_KIND_BRIN = (1 << 10), + RELOPT_KIND_PARTITIONED = (1 << 11), + /* if you add a new kind, make sure you update "last_default" too */ + RELOPT_KIND_LAST_DEFAULT = RELOPT_KIND_PARTITIONED, + /* some compilers treat enums as signed ints, so we can't use 1 << 31 */ + RELOPT_KIND_MAX = (1 << 30) +} relopt_kind; + /* reloption namespaces allowed for heaps -- currently only TOAST */ #define HEAP_RELOPT_NAMESPACES { "toast", NULL } +/* generic struct to hold shared data */ +typedef struct relopt_gen +{ + const char *name; /* must be first (used as list termination + * marker) */ + const char *desc; + bits32 kinds; + LOCKMODE lockmode; + int namelen; + relopt_type type; +} relopt_gen; + +/* holds a parsed value */ +typedef struct relopt_value +{ + relopt_gen *gen; + bool isset; + union + { + bool bool_val; + pg_ternary ternary_val; + int int_val; + double real_val; + int enum_val; + char *string_val; /* allocated separately */ + }; +} relopt_value; + +/* reloptions records for specific variable types */ +typedef struct relopt_bool +{ + relopt_gen gen; + bool default_val; +} relopt_bool; + +typedef struct relopt_ternary +{ + relopt_gen gen; + /* ternaries have no default_val: otherwise they'd just be bools */ +} relopt_ternary; + +typedef struct relopt_int +{ + relopt_gen gen; + int default_val; + int min; + int max; +} relopt_int; + +typedef struct relopt_real +{ + relopt_gen gen; + double default_val; + double min; + double max; +} relopt_real; + ++======= ++/* reloption namespaces allowed for heaps -- currently only TOAST */ ++#define HEAP_RELOPT_NAMESPACES { "toast", NULL } ++ ++>>>>>>> theirs /* - * relopt_enum_elt_def -- One member of the array of acceptable values - * of an enum reloption. + * backward compatibility aliases so local reloption code of custom validator + * can work. */ - typedef struct relopt_enum_elt_def - { - const char *string_val; - int symbol_val; - } relopt_enum_elt_def; + typedef option_value relopt_value; + typedef fill_string_option fill_string_relopt; + typedef validate_string_option validate_string_relopt; + #define GET_STRING_RELOPTION(optstruct, member) \ + GET_STRING_OPTION(optstruct, member) - typedef struct relopt_enum - { - relopt_gen gen; - relopt_enum_elt_def *members; - int default_val; - const char *detailmsg; - /* null-terminated array of members */ - } relopt_enum; - /* validation routines for strings */ - typedef void (*validate_string_relopt) (const char *value); - typedef Size (*fill_string_relopt) (const char *value, void *ptr); + /* + * relopts_validator functions is left for backward compatibility for using + * with local reloptions. Should not be used elsewhere + */ /* validation routine for the whole option set */ - typedef void (*relopts_validator) (void *parsed_options, relopt_value *vals, int nvals); - - typedef struct relopt_string - { - relopt_gen gen; - int default_len; - bool default_isnull; - validate_string_relopt validate_cb; - fill_string_relopt fill_cb; - char *default_val; - } relopt_string; - - /* This is the table datatype for build_reloptions() */ - typedef struct - { - const char *optname; /* option's name */ - relopt_type opttype; /* option's datatype */ - int offset; /* offset of field in result struct */ - } relopt_parse_elt; - - /* Local reloption definition */ - typedef struct local_relopt - { - relopt_gen *option; /* option definition */ - int offset; /* offset of parsed value in bytea structure */ - } local_relopt; + typedef void (*relopts_validator) (void *parsed_options, relopt_value *vals, + int nvals); /* Structure to hold local reloption data for build_local_reloptions() */ typedef struct local_relopts { - List *options; /* list of local_relopt definitions */ List *validators; /* list of relopts_validator callbacks */ - Size relopt_struct_size; /* size of parsed bytea structure */ + options_spec_set *spec_set; /* Spec Set to store options info */ } local_relopts; ++<<<<<<< ours +/* + * Utility macro to get a value for a string reloption once the options + * are parsed. This gets a pointer to the string value itself. "optstruct" + * is the StdRdOptions struct or equivalent, "member" is the struct member + * corresponding to the string option. + */ +#define GET_STRING_RELOPTION(optstruct, member) \ + ((optstruct)->member == 0 ? NULL : \ + (char *)(optstruct) + (optstruct)->member) + +extern relopt_kind add_reloption_kind(void); +extern void add_bool_reloption(bits32 kinds, const char *name, const char *desc, + bool default_val, LOCKMODE lockmode); +extern void add_ternary_reloption(bits32 kinds, const char *name, + const char *desc, LOCKMODE lockmode); +extern void add_int_reloption(bits32 kinds, const char *name, const char *desc, + int default_val, int min_val, int max_val, + LOCKMODE lockmode); +extern void add_real_reloption(bits32 kinds, const char *name, const char *desc, + double default_val, double min_val, double max_val, + LOCKMODE lockmode); +extern void add_enum_reloption(bits32 kinds, const char *name, const char *desc, + relopt_enum_elt_def *members, int default_val, + const char *detailmsg, LOCKMODE lockmode); +extern void add_string_reloption(bits32 kinds, const char *name, const char *desc, + const char *default_val, validate_string_relopt validator, + LOCKMODE lockmode); ++======= ++>>>>>>> theirs extern void init_local_reloptions(local_relopts *relopts, Size relopt_struct_size); extern void register_reloptions_validator(local_relopts *relopts, @@@ -232,17 -75,8 +213,15 @@@ extern void add_local_string_reloption( validate_string_relopt validator, fill_string_relopt filler, int offset); ++<<<<<<< ours +extern Datum transformRelOptions(Datum oldOptions, List *defList, + const char *nameSpace, const char *const validnsps[], + bool acceptOidsOff, bool isReset); +extern List *untransformRelOptions(Datum options); ++======= ++>>>>>>> theirs extern bytea *extractRelOptions(HeapTuple tuple, TupleDesc tupdesc, - amoptions_function amoptions); - extern void *build_reloptions(Datum reloptions, bool validate, - relopt_kind kind, - Size relopt_struct_size, - const relopt_parse_elt *relopt_elems, - int num_relopt_elems); + amreloptspecset_function amoptions_def_set); extern void *build_local_reloptions(local_relopts *relopts, Datum options, bool validate); diff --cc src/test/modules/dummy_index_am/dummy_index_am.c index 31f8d2b8161,5f6066a6654..00000000000 --- a/src/test/modules/dummy_index_am/dummy_index_am.c +++ b/src/test/modules/dummy_index_am/dummy_index_am.c @@@ -21,11 -21,7 +21,15 @@@ PG_MODULE_MAGIC; ++<<<<<<< ours +/* parse table for fillRelOptions */ +static relopt_parse_elt di_relopt_tab[8]; + +/* Kind of relation options for dummy index */ +static relopt_kind di_relopt_kind; ++======= + void _PG_init(void); ++>>>>>>> theirs typedef enum DummyAmEnum { @@@ -67,83 -62,71 +71,142 @@@ divalidate_string_option(const char *va value ? value : "NULL"))); } - /* - * This function creates a full set of relation option types, - * with various patterns. - */ - static void - create_reloptions_table(void) + static options_spec_set *di_relopt_specset = NULL; + options_spec_set *digetreloptspecset(void); + + options_spec_set * + digetreloptspecset(void) { ++<<<<<<< ours + int i = 0; + + di_relopt_kind = add_reloption_kind(); + + add_int_reloption(di_relopt_kind, "option_int", + "Integer option for dummy_index_am", + 10, -10, 100, AccessExclusiveLock); + di_relopt_tab[i].optname = "option_int"; + di_relopt_tab[i].opttype = RELOPT_TYPE_INT; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_int); + i++; + + add_real_reloption(di_relopt_kind, "option_real", + "Real option for dummy_index_am", + 3.1415, -10, 100, AccessExclusiveLock); + di_relopt_tab[i].optname = "option_real"; + di_relopt_tab[i].opttype = RELOPT_TYPE_REAL; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_real); + i++; + + add_bool_reloption(di_relopt_kind, "option_bool", + "Boolean option for dummy_index_am", + true, AccessExclusiveLock); + di_relopt_tab[i].optname = "option_bool"; + di_relopt_tab[i].opttype = RELOPT_TYPE_BOOL; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_bool); + i++; + + add_ternary_reloption(di_relopt_kind, "option_ternary_1", + "One ternary option for dummy_index_am", + AccessExclusiveLock); + di_relopt_tab[i].optname = "option_ternary_1"; + di_relopt_tab[i].opttype = RELOPT_TYPE_TERNARY; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_ternary_1); + i++; + + add_enum_reloption(di_relopt_kind, "option_enum", + "Enum option for dummy_index_am", + dummyAmEnumValues, + DUMMY_AM_ENUM_ONE, + "Valid values are \"one\" and \"two\".", + AccessExclusiveLock); + di_relopt_tab[i].optname = "option_enum"; + di_relopt_tab[i].opttype = RELOPT_TYPE_ENUM; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, option_enum); + i++; + + add_string_reloption(di_relopt_kind, "option_string_val", + "String option for dummy_index_am with non-NULL default", + "DefaultValue", &validate_string_option, + AccessExclusiveLock); + di_relopt_tab[i].optname = "option_string_val"; + di_relopt_tab[i].opttype = RELOPT_TYPE_STRING; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, + option_string_val_offset); + i++; ++======= + if (di_relopt_specset) + return di_relopt_specset; + + di_relopt_specset = allocateOptionsSpecSet(NULL, + sizeof(DummyIndexOptions), false, 6); + + optionsSpecSetAddInt( + di_relopt_specset, "option_int", + "Integer option for dummy_index_am", + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_int), NULL, + 10, -10, 100 + ); + + + optionsSpecSetAddReal( + di_relopt_specset, "option_real", + "Real option for dummy_index_am", + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_real), NULL, + 3.1415, -10, 100 + ); + + optionsSpecSetAddBool( + di_relopt_specset, "option_bool", + "Boolean option for dummy_index_am", + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_bool), NULL, true + ); + + optionsSpecSetAddEnum(di_relopt_specset, "option_enum", + "Enum option for dummy_index_am", + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_enum), NULL, + dummyAmEnumValues, + DUMMY_AM_ENUM_ONE, + "Valid values are \"one\" and \"two\"." + ); + + optionsSpecSetAddString(di_relopt_specset, "option_string_val", + "String option for dummy_index_am with non-NULL default", + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_string_val_offset), NULL, + "DefaultValue", &divalidate_string_option, NULL + ); ++>>>>>>> theirs /* * String option for dummy_index_am with NULL default, and without * description. */ ++<<<<<<< ours + add_string_reloption(di_relopt_kind, "option_string_null", + NULL, /* description */ + NULL, &validate_string_option, + AccessExclusiveLock); + di_relopt_tab[i].optname = "option_string_null"; + di_relopt_tab[i].opttype = RELOPT_TYPE_STRING; + di_relopt_tab[i].offset = offsetof(DummyIndexOptions, + option_string_null_offset); + i++; ++======= + + optionsSpecSetAddString(di_relopt_specset, "option_string_null", + NULL, /* description */ + AccessExclusiveLock, + offsetof(DummyIndexOptions, option_string_null_offset), NULL, + NULL, &divalidate_string_option, NULL + ); + + return di_relopt_specset; ++>>>>>>> theirs } @@@ -293,61 -264,54 +344,108 @@@ diendscan(IndexScanDesc scan Datum dihandler(PG_FUNCTION_ARGS) { ++<<<<<<< ours + 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 - _PG_init(void) - { - create_reloptions_table(); ++======= + 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->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; + amroutine->amreloptspecset = digetreloptspecset; + + PG_RETURN_POINTER(amroutine); ++>>>>>>> theirs }