[PG19] pg_upgrade transfers temporal keys using gist_inet_ops with the wrong opclass

From: Zsolt Parragi <zsolt(dot)parragi(at)percona(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: [PG19] pg_upgrade transfers temporal keys using gist_inet_ops with the wrong opclass
Date: 2026-10-16 21:09:26
Message-ID: CAN4CZFO4z7PGJnPWtiP5tgA7vDiKFE2DiNikRTBtauBEtnNi1A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello

check_for_gist_inet_ops skips gist_inet_ops/gist_cidr_ops indexes when
the opclass is not opcdefault in the old cluster, as pg_dump then
prints the opclass
explicitly. That works for CREATE INDEX and EXCLUDE constraints, but a
PRIMARY KEY or UNIQUE constraint using WITHOUT OVERLAPS is dumped as a
constraint clause with only column names.

pg_upgrade restores the index with 19's default inet_ops, while the
transferred files still contain btree_gist keys.

Repro, on 18, simulating "copying btree_gist--1.8--1.9.sql into a v18
installation"[1]:

CREATE EXTENSION btree_gist;
CREATE TABLE tn(ip inet, valid int4range,
PRIMARY KEY (ip, valid WITHOUT OVERLAPS));
INSERT INTO tn SELECT ('10.' || (g % 200) || '.' || (g/200 % 250) || '.'
|| (g % 7) || '/' || (16 + g % 17))::inet,
int4range(g, g+1)
FROM generate_series(1, 20000) g;
UPDATE pg_opclass SET opcdefault = false
WHERE opcmethod = (SELECT oid FROM pg_am WHERE amname = 'gist')
AND opcname IN ('gist_inet_ops', 'gist_cidr_ops');

then pg_upgrade to master or 19rc1. Both --check and the upgrade
succeed, pg_index shows inet_ops for tn_pkey, and

SET enable_seqscan = off;
SELECT count(*) FROM tn WHERE ip = '10.5.0.5/21';

fails with TRAP: failed Assert("!GIST_LEAF(ent)"), network_gist.c:139.
A non-assert build reads the btree_gist keys as inet_ops keys instead.

The fix pg_upgrade and the documentation suggests: replacing the index
with an inet_ops one, isn't possible on 18 for them, as a PRIMARY
KEY/UNIQUE constraint can't name an opclass, and ADD CONSTRAINT ...
USING INDEX rejects GiST indexes.

0001 adds "OR i.indisunique" to the check query. GiST can't create
plain unique indexes, so this only matches the WITHOUT OVERLAPS case.
Flipped plain indexes and EXCLUDE constraints still get through and
work after the upgrade, the PK and UNIQUE variants are now refused. It
also adds a paragraph to btree-gist.sgml saying that such constraints
(and foreign keys referencing them) have to be dropped before the
upgrade and re-created afterwards.

0002 is a docs-only fix in the same area: gist.sgml still says the
built-in inet_ops is not the default for inet and cidr, and tells
users to name it in CREATE INDEX. It now says it is the default as of
19, with a link to the btree_gist section for the background.

[1]: https://www.postgresql.org/message-id/3356576.1766168877%40sss.pgh.pa.us

Attachment Content-Type Size
v1-0001-Don-t-let-pg_upgrade-carry-over-temporal-keys-usi.patch application/octet-stream 3.5 KB
v1-0002-Doc-GiST-inet_ops-is-now-the-default-opclass-for-.patch application/octet-stream 1.6 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Bharath Rupireddy 2026-10-16 21:25:07 Re: Teach pg_upgrade to deal with invalid databases
Previous Message Masahiko Sawada 2026-10-16 20:49:23 Re: Add a hook for handling logical decoding messages on subscribers.