Re: Allow table AMs to define their own reloptions

From: Andrew Dunstan <andrew(at)dunslane(dot)net>
To: Rui Zhao <zhaorui126(at)gmail(dot)com>
Cc: Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>, pgsql-hackers(at)lists(dot)postgresql(dot)org, Álvaro Herrera <alvherre(at)kurilemu(dot)de>, Ajit Awekar <ajitpostgres(at)gmail(dot)com>
Subject: Re: Allow table AMs to define their own reloptions
Date: 2026-10-27 13:49:43
Message-ID: 2c46e51c-15da-4ea7-94ff-538127939793@dunslane.net
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers


On 2026-10-21 We 10:56 AM, Rui Zhao wrote:
> Hi Andrew,
>
> Thanks for adding the helper for standard options, which is very helpful
> for AM extensions.
>
> I found an issue:
> In a fresh backend, ALTER TABLE can change an AM-specific option without
> taking the lock requested by the AM. dummy_table_am registers option_int
> with AccessExclusiveLock, but I got ShareUpdateExclusiveLock on v13.
>
> Setup in one connection:
>
> CREATE EXTENSION dummy_table_am;
> CREATE TABLE t_std (a int) USING dummy_table_am WITH (option_int = 7);
>
> Then, in a new connection:
>
> BEGIN;
> ALTER TABLE t_std SET (option_int = 9);
> SELECT mode FROM pg_locks
> WHERE pid = pg_backend_pid() AND relation = 't_std'::regclass;
> -- ShareUpdateExclusiveLock
> ROLLBACK;
>
> With LOAD 'dummy_table_am' before BEGIN in another new connection, the
> same commands take AccessExclusiveLock. RESET has the same problem.
>
> The reason is that ProcessUtilitySlow() calls AlterTableGetLockLevel()
> before opening the relation and loading its AM. option_int is not
> registered at that point.
> AlterTableGetRelOptionsLockLevel() ignores the unknown name and returns
> NoLock, leaving AlterTableGetLockLevel()'s ShareUpdateExclusiveLock
> minimum unchanged. Loading the AM later does not upgrade that lock.
>
> This is an existing helper issue, not a v13 regression. I reproduced it
> with bloom on unpatched master at e75fcc9867f. Setup in one connection:
>
> CREATE EXTENSION bloom;
> CREATE TABLE bloom_probe (a int);
> CREATE INDEX bloom_probe_idx ON bloom_probe USING bloom (a);
>
> Then, in a new connection:
>
> BEGIN;
> ALTER INDEX bloom_probe_idx SET (length = 100);
> SELECT mode FROM pg_locks
> WHERE pid = pg_backend_pid() AND relation = 'bloom_probe_idx'::regclass
> ORDER BY mode;
> -- ShareUpdateExclusiveLock
> ROLLBACK;
>
> With LOAD 'bloom' before BEGIN in another new connection, the same
> commands take AccessExclusiveLock.
>
> With 0001 on top of v13, an option not yet registered requires
> AccessExclusiveLock. Registered options keep their declared lock levels.
> Until the AM is loaded, we cannot tell which lock the option requires.
> This ensures the lock is strong enough. I think this is a harmless and
> safe fix with minimal changes.
>
> The TAP test checks SET and RESET for both test AMs, with and without
> loading the library first, and checks that fillfactor still uses the
> weaker lock.
>
> Core regression, isolation and dummy_table_am tests passed with the
> patch. Without the fix, the four cases without LOAD fail.
>

Nice Catch! I agree with your analysis and your fix.

I doubt this is worth backpatching.

Here's a v14 that incorporates your fix. I changed the tests some.
tableam.sgml now describes which options need AccessExclusiveLock.

One case this doesn't cover: options are matched by name across all
kinds, so an AM option with the same name as a core option but a
stronger lock gets the core option's lock in a backend that hasn't
loaded the AM. Fixing that would mean finding the AM before choosing
the lock, so I've just documented that such an option shouldn't
declare a stronger lock than the built-in one.

cheers

andrew

--
Andrew Dunstan
EDB: https://www.enterprisedb.com

Attachment Content-Type Size
v14-0001-Use-AccessExclusiveLock-for-unrecognized-options.patch text/x-patch 4.2 KB
v14-0002-Add-amoptions-callback-to-table-access-methods.patch text/x-patch 67.2 KB
v14-0003-pg_dump-Set-table-AM-specific-storage-parameters.patch text/x-patch 25.0 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Greg Burd 2026-10-27 13:54:47 Re: WAL record CRC calculated incorrectly because of underlying buffer modification
Previous Message Amit Langote 2026-10-27 13:21:44 Re: SQL/JSON DEFAULT ON ERROR/ON EMPTY evaluation fail should rethrow error unconditionally