From: Álvaro Herrera Date: Mon, 20 Jul 2026 15:21:20 +0000 (+0200) Subject: Fix restore of partitions with exclusion constraints X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d049a31a4cd2d43739ae0039002c24c63a24d48c;p=thirdparty%2Fpostgresql.git Fix restore of partitions with exclusion constraints Commit 8c852ba9a4 allowed exclusion constraints to be added to partitioned tables, but wasn't careful to verify that pg_restore worked correctly for them. Fix that by making CompareIndexInfo() more selective about what needs to be rejected. Author: Japin Li Reported-by: Keith Paskett Discussion: https://postgr.es/m/2A40921D-83AB-411E-ADA6-7E509A46F1E4@logansw.com --- diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 81bba4beac7..31ef84d0a16 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2663,9 +2663,21 @@ CompareIndexInfo(const IndexInfo *info1, const IndexInfo *info2, return false; } - /* No support currently for comparing exclusion indexes. */ - if (info1->ii_ExclusionOps != NULL || info2->ii_ExclusionOps != NULL) + /* If they're exclusion indexes, their properties must be identical */ + if ((info1->ii_ExclusionOps == NULL) != (info2->ii_ExclusionOps == NULL)) return false; + if (info1->ii_ExclusionOps != NULL) + { + for (i = 0; i < info1->ii_NumIndexKeyAttrs; i++) + { + if (info1->ii_ExclusionOps[i] != info2->ii_ExclusionOps[i]) + return false; + if (info1->ii_ExclusionProcs[i] != info2->ii_ExclusionProcs[i]) + return false; + if (info1->ii_ExclusionStrats[i] != info2->ii_ExclusionStrats[i]) + return false; + } + } return true; } diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out index 4d350fbc658..4a0a652e9f6 100644 --- a/src/test/regress/expected/indexing.out +++ b/src/test/regress/expected/indexing.out @@ -1785,3 +1785,18 @@ insert into test_pg_wholerow_index values (2, 'addition', 0); drop index row_image_index; drop function row_image(test_pg_wholerow_index); drop table test_pg_wholerow_index; +-- Test of a partitioned index attach, when there are exclusion constraints. +create table idx_excl_part (a int4range, b int4range) partition by list (a); +create table idx_excl_part_1 (a int4range, b int4range); +alter table only idx_excl_part attach partition idx_excl_part_1 for values in ('[0,1)'::int4range); +alter table only idx_excl_part add constraint idxpart_id_data_excl exclude using gist (a with =, b with &&); +alter table idx_excl_part_1 add constraint idxpart_1_id_data_excl exclude using gist (a with &&, b with &&); +-- This should be disallowed, because the constraints don't match. +alter index idxpart_id_data_excl attach partition idxpart_1_id_data_excl; +ERROR: cannot attach index "idxpart_1_id_data_excl" as a partition of index "idxpart_id_data_excl" +DETAIL: The index definitions do not match. +-- but if we recreate the constraint differently, it's allowed: +alter table idx_excl_part_1 drop constraint idxpart_1_id_data_excl; +alter table idx_excl_part_1 add constraint idxpart_1_id_data_excl exclude using gist (a with =, b with &&); +alter index idxpart_id_data_excl attach partition idxpart_1_id_data_excl; +-- leave these tables around, for pg_upgrade testing diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql index 561403cc7f7..bbcfb365281 100644 --- a/src/test/regress/sql/indexing.sql +++ b/src/test/regress/sql/indexing.sql @@ -1005,3 +1005,17 @@ insert into test_pg_wholerow_index values (2, 'addition', 0); drop index row_image_index; drop function row_image(test_pg_wholerow_index); drop table test_pg_wholerow_index; + +-- Test of a partitioned index attach, when there are exclusion constraints. +create table idx_excl_part (a int4range, b int4range) partition by list (a); +create table idx_excl_part_1 (a int4range, b int4range); +alter table only idx_excl_part attach partition idx_excl_part_1 for values in ('[0,1)'::int4range); +alter table only idx_excl_part add constraint idxpart_id_data_excl exclude using gist (a with =, b with &&); +alter table idx_excl_part_1 add constraint idxpart_1_id_data_excl exclude using gist (a with &&, b with &&); +-- This should be disallowed, because the constraints don't match. +alter index idxpart_id_data_excl attach partition idxpart_1_id_data_excl; +-- but if we recreate the constraint differently, it's allowed: +alter table idx_excl_part_1 drop constraint idxpart_1_id_data_excl; +alter table idx_excl_part_1 add constraint idxpart_1_id_data_excl exclude using gist (a with =, b with &&); +alter index idxpart_id_data_excl attach partition idxpart_1_id_data_excl; +-- leave these tables around, for pg_upgrade testing