From 7a50b6d18d40b0052f1f2a88f01594814634c578 Mon Sep 17 00:00:00 2001 From: Andrew Dunstan Date: Fri, 2 Oct 2026 09:21:27 -0400 Subject: [PATCH v10 2/2] pg_dump: Set table AM-specific storage parameters separately pg_dump put all of a table's storage parameters in the WITH clause of its CREATE TABLE. With --no-table-access-method, the table is created with the default access method, which may not accept parameters specific to the table's own access method. The CREATE TABLE then failed, so the table and its data were not restored at all. The same happened with pg_restore --no-table-access-method. Parameters can't all be moved to a later ALTER TABLE, because some standard ones only have an effect when the table is created, such as toast_value_type. So for tables and materialized views whose access method isn't heap, pg_dump now keeps the standard parameters in the WITH clause, and sets the others with ALTER TABLE in a separate TOC entry of type TABLE AM OPTIONS, which depends on the table. --no-table-access-method leaves that entry out, and pg_restore --table includes it with its table. To tell the two kinds of parameter apart, add a function pg_reloption_is_standard(), which returns true for parameters heap accepts. A table access method that accepts such a parameter is expected to have inherited it with add_reloption_to_kind(), so it has the same meaning as for heap. This requires that an access method's own parameters have the same effect when set by ALTER TABLE on an empty table as when given to CREATE TABLE. Document that in tableam.sgml. Discussion: https://www.postgresql.org/message-id/flat/ea1c4d33-0780-473c-96dc-1468cf733a04@dunslane.net --- doc/src/sgml/func/func-info.sgml | 17 ++ doc/src/sgml/ref/pg_dump.sgml | 4 +- doc/src/sgml/ref/pg_dumpall.sgml | 4 +- doc/src/sgml/ref/pg_restore.sgml | 4 +- doc/src/sgml/tableam.sgml | 11 ++ src/backend/access/common/reloptions.c | 17 ++ src/bin/pg_dump/pg_backup_archiver.c | 8 + src/bin/pg_dump/pg_dump.c | 64 ++++++- src/bin/pg_dump/pg_dump.h | 1 + src/include/catalog/pg_proc.dat | 5 + src/test/modules/dummy_table_am/Makefile | 1 + .../dummy_table_am/expected/reloptions.out | 8 + src/test/modules/dummy_table_am/meson.build | 5 + .../modules/dummy_table_am/sql/reloptions.sql | 4 + .../modules/dummy_table_am/t/001_pg_dump.pl | 158 ++++++++++++++++++ src/test/regress/expected/reloptions.out | 13 ++ src/test/regress/sql/reloptions.sql | 5 + 17 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 src/test/modules/dummy_table_am/t/001_pg_dump.pl diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml index e56c9a22c42..3100f9139f1 100644 --- a/doc/src/sgml/func/func-info.sgml +++ b/doc/src/sgml/func/func-info.sgml @@ -1877,6 +1877,23 @@ SELECT currval(pg_get_serial_sequence('sometable', 'id')); + + + + pg_reloption_is_standard + + pg_reloption_is_standard ( name text ) + boolean + + + Returns true if the named storage parameter is one accepted by + tables using the heap access method. A table + access method that defines its own storage parameters can also accept + these ones (see ); any other + storage parameter of a table is specific to its access method. + + + diff --git a/doc/src/sgml/ref/pg_dump.sgml b/doc/src/sgml/ref/pg_dump.sgml index 774be23b4f9..0d5433d105b 100644 --- a/doc/src/sgml/ref/pg_dump.sgml +++ b/doc/src/sgml/ref/pg_dump.sgml @@ -1146,7 +1146,9 @@ PostgreSQL documentation Do not output commands to select table access methods. With this option, all objects will be created with whichever - table access method is the default during restore. + table access method is the default during restore. Storage + parameters specific to a table's access method are not output + either (see ). diff --git a/doc/src/sgml/ref/pg_dumpall.sgml b/doc/src/sgml/ref/pg_dumpall.sgml index 238c87c13f5..9e71b35775e 100644 --- a/doc/src/sgml/ref/pg_dumpall.sgml +++ b/doc/src/sgml/ref/pg_dumpall.sgml @@ -531,7 +531,9 @@ exclude database PATTERN Do not output commands to select table access methods. With this option, all objects will be created with whichever - table access method is the default during restore. + table access method is the default during restore. Storage + parameters specific to a table's access method are not output + either (see ). diff --git a/doc/src/sgml/ref/pg_restore.sgml b/doc/src/sgml/ref/pg_restore.sgml index b6c5299c36e..48ea1c74373 100644 --- a/doc/src/sgml/ref/pg_restore.sgml +++ b/doc/src/sgml/ref/pg_restore.sgml @@ -789,7 +789,9 @@ PostgreSQL documentation Do not output commands to select table access methods. With this option, all objects will be created with whichever - table access method is the default during restore. + table access method is the default during restore. Storage + parameters specific to a table's access method are not output + either (see ). diff --git a/doc/src/sgml/tableam.sgml b/doc/src/sgml/tableam.sgml index 374cb1862b1..b33a6c7c8be 100644 --- a/doc/src/sgml/tableam.sgml +++ b/doc/src/sgml/tableam.sgml @@ -217,6 +217,17 @@ amoptions (Datum reloptions, same name. + + pg_dump puts the standard options of a table + in its CREATE TABLE command, and sets the ones specific + to its access method with a separate ALTER TABLE + command, which it leaves out if + is used. So an access method's own options must have the same effect + when set by ALTER TABLE on an empty table as when given + to CREATE TABLE. An option is treated as a standard + one if pg_reloption_is_standard returns true for it. + + Autovacuum always reads a table's autovacuum_* options using the standard heap parser, regardless of its access method. So an diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index 79a5b404ee1..b71d3ac462e 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -2455,6 +2455,23 @@ RelationHasStdRdOptions(Relation relation) } +/* + * pg_reloption_is_standard + * SQL-callable: is the named option one that heap accepts? + * + * A table AM that accepts such an option is expected to have inherited it + * with add_reloption_to_kind(), so that it has the same meaning as for heap. + * Any other option of a table must be specific to its AM. pg_dump uses this + * to tell the two apart. + */ +Datum +pg_reloption_is_standard(PG_FUNCTION_ARGS) +{ + char *name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + + PG_RETURN_BOOL(find_reloption(name, RELOPT_KIND_HEAP) != NULL); +} + /* * Parse options for indexes. * diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index abedc89b085..dcb1365f43a 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3040,6 +3040,13 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH) if (ropt->no_comments && strcmp(te->desc, "COMMENT") == 0) return 0; + /* + * If the table access method isn't to be restored, ignore the options + * specific to it. + */ + if (ropt->noTableAm && strcmp(te->desc, "TABLE AM OPTIONS") == 0) + return 0; + /* If it's a policy, maybe ignore it */ if (ropt->no_policies && (strcmp(te->desc, "POLICY") == 0 || @@ -3239,6 +3246,7 @@ _tocEntryRequired(TocEntry *te, teSection curSection, ArchiveHandle *AH) } else if (strcmp(te->desc, "TABLE") == 0 || strcmp(te->desc, "TABLE DATA") == 0 || + strcmp(te->desc, "TABLE AM OPTIONS") == 0 || strcmp(te->desc, "VIEW") == 0 || strcmp(te->desc, "FOREIGN TABLE") == 0 || strcmp(te->desc, "MATERIALIZED VIEW") == 0 || diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 388c3b9c346..86aead729ca 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -7187,6 +7187,7 @@ getTables(Archive *fout, int *numTables) int i_reloptions; int i_checkoption; int i_toastreloptions; + int i_amreloptions; int i_reloftype; int i_foreignserver; int i_amname; @@ -7261,8 +7262,37 @@ getTables(Archive *fout, int *numTables) appendPQExpBufferStr(query, "c.relminmxid, tc.relminmxid AS tminmxid, "); + /* + * The options of a table or matview whose access method isn't heap are + * split into standard ones, which go in the WITH clause, and ones + * specific to the access method, which are set separately; see + * dumpTableSchema(). + */ + if (fout->remoteVersion >= 200000) + appendPQExpBufferStr(query, + "CASE WHEN c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_MATVIEW) ") AND " + "c.relam <> " CppAsString2(HEAP_TABLE_AM_OID) " THEN " + "ARRAY(SELECT o FROM pg_catalog.unnest(c.reloptions) " + "WITH ORDINALITY AS u(o, n) " + "WHERE pg_catalog.pg_reloption_is_standard(pg_catalog.split_part(o, '=', 1)) " + "ORDER BY n) " + "ELSE array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') " + "END AS reloptions, " + "CASE WHEN c.relkind IN (" CppAsString2(RELKIND_RELATION) ", " + CppAsString2(RELKIND_MATVIEW) ") AND " + "c.relam <> " CppAsString2(HEAP_TABLE_AM_OID) " THEN " + "ARRAY(SELECT o FROM pg_catalog.unnest(c.reloptions) " + "WITH ORDINALITY AS u(o, n) " + "WHERE NOT pg_catalog.pg_reloption_is_standard(pg_catalog.split_part(o, '=', 1)) " + "ORDER BY n) " + "END AS amreloptions, "); + else + appendPQExpBufferStr(query, + "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, " + "NULL AS amreloptions, "); + appendPQExpBufferStr(query, - "array_remove(array_remove(c.reloptions,'check_option=local'),'check_option=cascaded') AS reloptions, " "CASE WHEN 'check_option=local' = ANY (c.reloptions) THEN 'LOCAL'::text " "WHEN 'check_option=cascaded' = ANY (c.reloptions) THEN 'CASCADED'::text ELSE NULL END AS checkoption, "); @@ -7377,6 +7407,7 @@ getTables(Archive *fout, int *numTables) i_reloptions = PQfnumber(res, "reloptions"); i_checkoption = PQfnumber(res, "checkoption"); i_toastreloptions = PQfnumber(res, "toast_reloptions"); + i_amreloptions = PQfnumber(res, "amreloptions"); i_reloftype = PQfnumber(res, "reloftype"); i_foreignserver = PQfnumber(res, "foreignserver"); i_amname = PQfnumber(res, "amname"); @@ -7458,6 +7489,7 @@ getTables(Archive *fout, int *numTables) else tblinfo[i].checkoption = pg_strdup(PQgetvalue(res, i, i_checkoption)); tblinfo[i].toast_reloptions = pg_strdup(PQgetvalue(res, i, i_toastreloptions)); + tblinfo[i].amreloptions = pg_strdup(PQgetvalue(res, i, i_amreloptions)); tblinfo[i].reloftype = atooid(PQgetvalue(res, i, i_reloftype)); tblinfo[i].foreign_server = atooid(PQgetvalue(res, i, i_foreignserver)); if (PQgetisnull(res, i, i_amname)) @@ -17927,6 +17959,36 @@ dumpTableSchema(Archive *fout, const TableInfo *tbinfo) SECTION_POST_DATA : SECTION_PRE_DATA, .createStmt = q->data, .dropStmt = delq->data)); + + /* + * Options specific to the access method are set in a separate entry, + * so that if the table is restored with a different access method (as + * with --no-table-access-method) they can be left out, and if they're + * not, a failure to set them doesn't stop the table being created. + * The entry has no drop command, since dropping the table covers it, + * and its owner is set so that it is run by the correct role. + */ + if (nonemptyReloptions(tbinfo->amreloptions)) + { + resetPQExpBuffer(extra); + appendPQExpBuffer(extra, "ALTER %s %s SET (", + tbinfo->relkind == RELKIND_MATVIEW ? + "MATERIALIZED VIEW" : "TABLE ONLY", + qualrelname); + appendReloptionsArrayAH(extra, tbinfo->amreloptions, "", fout); + appendPQExpBufferStr(extra, ");\n"); + + ArchiveEntry(fout, nilCatalogId, createDumpId(), + ARCHIVE_OPTS(.tag = tbinfo->dobj.name, + .namespace = tbinfo->dobj.namespace->dobj.name, + .owner = tbinfo->rolname, + .description = "TABLE AM OPTIONS", + .section = tbinfo->postponed_def ? + SECTION_POST_DATA : SECTION_PRE_DATA, + .createStmt = extra->data, + .deps = &(tbinfo->dobj.dumpId), + .nDeps = 1)); + } } /* Dump Table Comments */ diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 2bbb5d5773b..1154d2dab69 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -315,6 +315,7 @@ typedef struct _tableInfo char *reloptions; /* options specified by WITH (...) */ char *checkoption; /* WITH CHECK OPTION, if any */ char *toast_reloptions; /* WITH options for the TOAST table */ + char *amreloptions; /* options specific to the access method */ bool hasindex; /* does it have any indexes? */ bool hasrules; /* does it have any rules? */ bool hastriggers; /* does it have any triggers? */ diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index f46427258e3..d9dde8e9ed7 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -4069,6 +4069,11 @@ proargnames => '{options_array,option_name,option_value}', prosrc => 'pg_options_to_table' }, +{ oid => '8904', descr => 'whether a storage parameter is a standard one', + proname => 'pg_reloption_is_standard', provolatile => 's', + prorettype => 'bool', proargtypes => 'text', + prosrc => 'pg_reloption_is_standard' }, + { oid => '1619', descr => 'type of the argument', proname => 'pg_typeof', proisstrict => 'f', provolatile => 's', prorettype => 'regtype', proargtypes => 'any', prosrc => 'pg_typeof' }, diff --git a/src/test/modules/dummy_table_am/Makefile b/src/test/modules/dummy_table_am/Makefile index cd9f63f2897..45af951486c 100644 --- a/src/test/modules/dummy_table_am/Makefile +++ b/src/test/modules/dummy_table_am/Makefile @@ -7,6 +7,7 @@ DATA = dummy_table_am--1.0.sql PGFILEDESC = "dummy_table_am - table access method template" REGRESS = reloptions custom_layout +TAP_TESTS = 1 ifdef USE_PGXS PG_CONFIG = pg_config diff --git a/src/test/modules/dummy_table_am/expected/reloptions.out b/src/test/modules/dummy_table_am/expected/reloptions.out index 7b9853b995b..46e8e340eab 100644 --- a/src/test/modules/dummy_table_am/expected/reloptions.out +++ b/src/test/modules/dummy_table_am/expected/reloptions.out @@ -17,6 +17,14 @@ ERROR: value 9999 out of bounds for option "option_int" DETAIL: Valid values are between "-10" and "100". CREATE TABLE dummy_bad (a int) USING dummy_table_am WITH (no_such_option = 4); ERROR: unrecognized parameter "no_such_option" +-- Inherited options are standard ones, the AM's own are not +SELECT pg_reloption_is_standard('fillfactor'), + pg_reloption_is_standard('option_int'); + pg_reloption_is_standard | pg_reloption_is_standard +--------------------------+-------------------------- + t | f +(1 row) + -- Defaults are not stored in pg_class CREATE TABLE dummy_defaults (a int) USING dummy_table_am; SELECT reloptions FROM pg_class WHERE oid = 'dummy_defaults'::regclass; diff --git a/src/test/modules/dummy_table_am/meson.build b/src/test/modules/dummy_table_am/meson.build index 35ffde4d151..c15e54a6c62 100644 --- a/src/test/modules/dummy_table_am/meson.build +++ b/src/test/modules/dummy_table_am/meson.build @@ -31,4 +31,9 @@ tests += { 'custom_layout', ], }, + 'tap': { + 'tests': [ + 't/001_pg_dump.pl', + ], + }, } diff --git a/src/test/modules/dummy_table_am/sql/reloptions.sql b/src/test/modules/dummy_table_am/sql/reloptions.sql index 3b714939d74..3a823622c06 100644 --- a/src/test/modules/dummy_table_am/sql/reloptions.sql +++ b/src/test/modules/dummy_table_am/sql/reloptions.sql @@ -12,6 +12,10 @@ SELECT reloptions FROM pg_class CREATE TABLE dummy_oor (a int) USING dummy_table_am WITH (option_int = 9999); CREATE TABLE dummy_bad (a int) USING dummy_table_am WITH (no_such_option = 4); +-- Inherited options are standard ones, the AM's own are not +SELECT pg_reloption_is_standard('fillfactor'), + pg_reloption_is_standard('option_int'); + -- Defaults are not stored in pg_class CREATE TABLE dummy_defaults (a int) USING dummy_table_am; SELECT reloptions FROM pg_class WHERE oid = 'dummy_defaults'::regclass; diff --git a/src/test/modules/dummy_table_am/t/001_pg_dump.pl b/src/test/modules/dummy_table_am/t/001_pg_dump.pl new file mode 100644 index 00000000000..a263cfcfc09 --- /dev/null +++ b/src/test/modules/dummy_table_am/t/001_pg_dump.pl @@ -0,0 +1,158 @@ + +# Copyright (c) 2026, PostgreSQL Global Development Group + +# Test dumping and restoring tables whose access method has options of its +# own, with and without --no-table-access-method. + +use strict; +use warnings FATAL => 'all'; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $tempdir = PostgreSQL::Test::Utils::tempdir; + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->start; + +$node->safe_psql('postgres', 'CREATE DATABASE src'); +$node->safe_psql( + 'src', q{ + CREATE EXTENSION dummy_table_am; + CREATE TABLE t_mixed (a int, b text) USING dummy_table_am + WITH (fillfactor = 70, option_int = 7, option_bool = false); + INSERT INTO t_mixed SELECT i, 'row ' || i FROM generate_series(1, 10) i; + CREATE TABLE t_custom (a int) USING dummy_custom_table_am + WITH (option_a = 5); + INSERT INTO t_custom VALUES (1), (2); + CREATE TABLE t_heap (a int) WITH (fillfactor = 60); + CREATE MATERIALIZED VIEW mv USING dummy_table_am + WITH (fillfactor = 80, option_int = 3) + AS SELECT a FROM t_mixed; +}); + +# Show the access method and options of each relation, and the row counts +my $describe = q{ + SELECT c.relname, a.amname, c.reloptions + FROM pg_class c JOIN pg_am a ON a.oid = c.relam + WHERE c.relname IN ('t_mixed', 't_custom', 't_heap', 'mv') + ORDER BY c.relname; + SELECT count(*) FROM t_mixed; + SELECT count(*) FROM t_custom; + SELECT count(*) FROM mv; +}; +my $src_state = $node->safe_psql('src', $describe); + +# The default AM is heap, so --no-table-access-method recreates every +# relation as heap, with only the standard options. +my $noam_state = q{mv|heap|{fillfactor=80} +t_custom|heap| +t_heap|heap|{fillfactor=60} +t_mixed|heap|{fillfactor=70} +10 +2 +10}; + +my $plain = "$tempdir/plain.sql"; +my $plain_noam = "$tempdir/plain_noam.sql"; +my $archive = "$tempdir/archive.dump"; + +$node->command_ok([ 'pg_dump', '--file' => $plain, 'src' ], + 'plain dump'); +$node->command_ok( + [ + 'pg_dump', '--no-table-access-method', + '--file' => $plain_noam, 'src' + ], + 'plain dump with --no-table-access-method'); +$node->command_ok( + [ 'pg_dump', '--format' => 'custom', '--file' => $archive, 'src' ], + 'custom-format dump'); + +# Standard options stay in the WITH clause, the others are set separately +my $dump = slurp_file($plain); +like( + $dump, + qr/CREATE TABLE public\.t_mixed \(.*?\)\nWITH \(fillfactor='70'\);/s, + 'standard options of a non-heap table are in CREATE TABLE'); +like( + $dump, + qr/^ALTER TABLE ONLY public\.t_mixed SET \(option_int='7', option_bool='false'\);$/m, + 'AM-specific options of a table are set by ALTER TABLE'); +like( + $dump, + qr/^ALTER MATERIALIZED VIEW public\.mv SET \(option_int='3'\);$/m, + 'AM-specific options of a matview are set by ALTER MATERIALIZED VIEW'); +like( + $dump, + qr/^ALTER TABLE ONLY public\.t_custom SET \(option_a='5'\);$/m, + 'table with only AM-specific options'); +like( + $dump, + qr/CREATE TABLE public\.t_heap \(.*?\)\nWITH \(fillfactor='60'\);/s, + 'heap table options are in CREATE TABLE'); +unlike($dump, qr/ALTER TABLE ONLY public\.t_heap SET/, + 'heap table options are not set separately'); + +unlike(slurp_file($plain_noam), qr/TABLE AM OPTIONS|option_int|option_a/, + '--no-table-access-method leaves out AM-specific options'); + +my @psql = ('psql', '--no-psqlrc', '--set' => 'ON_ERROR_STOP=1'); + +$node->safe_psql('postgres', 'CREATE DATABASE dst_plain'); +$node->command_ok([ @psql, '--file' => $plain, '--dbname' => 'dst_plain' ], + 'restore plain dump'); +is($node->safe_psql('dst_plain', $describe), + $src_state, 'plain dump restores the same options'); + +$node->safe_psql('postgres', 'CREATE DATABASE dst_plain_noam'); +$node->command_ok( + [ @psql, '--file' => $plain_noam, '--dbname' => 'dst_plain_noam' ], + 'restore plain dump made with --no-table-access-method'); +is($node->safe_psql('dst_plain_noam', $describe), + $noam_state, + 'plain dump made with --no-table-access-method restores tables and data' +); + +$node->safe_psql('postgres', 'CREATE DATABASE dst_archive'); +$node->command_ok( + [ + 'pg_restore', '--exit-on-error', + '--dbname' => 'dst_archive', $archive + ], + 'restore custom-format dump'); +is($node->safe_psql('dst_archive', $describe), + $src_state, 'custom-format dump restores the same options'); + +$node->safe_psql('postgres', 'CREATE DATABASE dst_archive_noam'); +$node->command_ok( + [ + 'pg_restore', '--exit-on-error', '--no-table-access-method', + '--dbname' => 'dst_archive_noam', $archive + ], + 'pg_restore --no-table-access-method'); +is($node->safe_psql('dst_archive_noam', $describe), + $noam_state, + 'pg_restore --no-table-access-method restores tables and data'); + +# Selecting a table also selects its AM-specific options +$node->safe_psql('postgres', 'CREATE DATABASE dst_table'); +$node->safe_psql('dst_table', 'CREATE EXTENSION dummy_table_am'); +$node->command_ok( + [ + 'pg_restore', '--exit-on-error', + '--table' => 't_mixed', + '--dbname' => 'dst_table', $archive + ], + 'pg_restore --table'); +is( $node->safe_psql( + 'dst_table', q{SELECT reloptions FROM pg_class WHERE relname = 't_mixed'} + ), + '{fillfactor=70,option_int=7,option_bool=false}', + 'pg_restore --table restores AM-specific options'); + +$node->stop; + +done_testing(); diff --git a/src/test/regress/expected/reloptions.out b/src/test/regress/expected/reloptions.out index 95e4528f779..f66f974d336 100644 --- a/src/test/regress/expected/reloptions.out +++ b/src/test/regress/expected/reloptions.out @@ -288,3 +288,16 @@ SELECT reloptions FROM pg_class WHERE oid = 'reloptions_test_idx3'::regclass; {fillfactor=40} (1 row) +-- Which options are standard ones +SELECT name, pg_reloption_is_standard(name) + FROM unnest(ARRAY['fillfactor', 'autovacuum_enabled', 'toast_tuple_target', + 'fastupdate', 'no_such_option']) AS name; + name | pg_reloption_is_standard +--------------------+-------------------------- + fillfactor | t + autovacuum_enabled | t + toast_tuple_target | t + fastupdate | f + no_such_option | f +(5 rows) + diff --git a/src/test/regress/sql/reloptions.sql b/src/test/regress/sql/reloptions.sql index 80939ee8b5b..0d1f7d88fde 100644 --- a/src/test/regress/sql/reloptions.sql +++ b/src/test/regress/sql/reloptions.sql @@ -168,3 +168,8 @@ SELECT reloptions FROM pg_class WHERE oid = 'reloptions_test_idx'::regclass; CREATE INDEX reloptions_test_idx3 ON reloptions_test (s); ALTER INDEX reloptions_test_idx3 SET (fillfactor=40); SELECT reloptions FROM pg_class WHERE oid = 'reloptions_test_idx3'::regclass; + +-- Which options are standard ones +SELECT name, pg_reloption_is_standard(name) + FROM unnest(ARRAY['fillfactor', 'autovacuum_enabled', 'toast_tuple_target', + 'fastupdate', 'no_such_option']) AS name; -- 2.43.0