BUG #19664: nbtree: Assertion failure when a custom index AM reuses bthandler

Started by PG Bug reporting form3 days ago2 messagesbugs
Jump to latest
#1PG Bug reporting form
noreply@postgresql.org

The following bug has been logged on the website:

Bug reference: 19664
Logged by: Jingtang Zhang
Email address: mrdrivingduck@gmail.com
PostgreSQL version: 19beta3
Operating system: Linux
Description:

## Repro

Build with assertions enabled, for example:

./configure --enable-debug --enable-cassert
make

---

Run SQL:

CREATE ACCESS METHOD hx_orph_ix TYPE INDEX HANDLER bthandler;

CREATE TABLE hx_orph_tab(a int, b text);
INSERT INTO hx_orph_tab
SELECT g, 'x' || g FROM generate_series(1, 100) AS g;

CREATE OPERATOR CLASS hx_orph_ix_int4_ops
DEFAULT FOR TYPE integer USING hx_orph_ix AS
OPERATOR 1 <,
OPERATOR 2 <=,
OPERATOR 3 =,
OPERATOR 4 >=,
OPERATOR 5 >,
FUNCTION 1 btint4cmp(integer, integer);

CREATE INDEX hx_orph_idx ON hx_orph_tab USING hx_orph_ix(a);

---

Get:

TRAP: failed Assert("wstate->index->rd_rel->relkind == RELKIND_INDEX &&
wstate->index->rd_rel->relam == BTREE_AM_OID")
File: "nbtsort.c"

---

## Thoughts

hx_orph_ix has a newly allocated AM OID, while its handler is bthandler. The
btree build path is therefore used, but BTGetFillFactor() and
BTGetDeduplicateItems() require the AM OID to be the built-in BTREE_AM_OID.

The OID check is not the relevant safety condition. These macros interpret
rd_options as BTOptions, so they should verify that the relation options
were parsed by btoptions. bthandler returns an IndexAmRoutine with
.amoptions = btoptions, making the layout compatible. Reusing built-in index
handlers is also an established pattern, e.g. the existing gist2 regression
test reuses gisthandler.

Proposed fix:

#define BTGetFillFactor(relation) \
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_indam->amoptions == btoptions), \
...)

#define BTGetDeduplicateItems(relation) \
(AssertMacro(relation->rd_rel->relkind == RELKIND_INDEX && \
relation->rd_indam->amoptions == btoptions), \
...)

#2Andrey Borodin
amborodin@acm.org
In reply to: PG Bug reporting form (#1)
Re: BUG #19664: nbtree: Assertion failure when a custom index AM reuses bthandler

On 7 Sep 2026, at 16:51, PG Bug reporting form <noreply@postgresql.org> wrote:

CREATE ACCESS METHOD hx_orph_ix TYPE INDEX HANDLER bthandler;

I've toyed with reusing B-tree code in another index AM. It is possible,
but this Assert is far from the only assumption that the code is dealing
with the built-in B-tree AM. A grep finds 32 BTREE_AM_OID references in
19 files under src/, including nbtree, tuplesort, the planner, catalog and
DDL code, typcache, and RI triggers. B-tree has grown into the core, and
that is not necessarily a problem.

I once made a working btree-fork extension by copying nbtree and fixing the
relevant assumptions [0]https://github.com/x4m/postgres_g/commit/58ced18d8901d9cf58c6aa8d82cc20e426e9517d. So the implementation can be detached, but
that is quite different from registering the in-core bthandler under
another AM OID. I don't think that use is documented or promised.

The gist2 regression case is a test hack, not a documented interface. I
therefore don't think removing this one Assert would make this usage
valid. The assertion failure could perhaps be replaced with a regular
error instead.

Best regards, Andrey Borodin.

[0]: https://github.com/x4m/postgres_g/commit/58ced18d8901d9cf58c6aa8d82cc20e426e9517d