diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index d679fef951c..b8d0a5449cc 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -1160,6 +1160,7 @@ DefineIndex(Oid relationId, IndexStmt *childStmt = copyObject(stmt); bool found_whole_row; ListCell *lc; + ObjectAddress childAddr; /* * We can't use the same index name for the child index, @@ -1212,14 +1213,24 @@ DefineIndex(Oid relationId, Assert(GetUserId() == child_save_userid); SetUserIdAndSecContext(root_save_userid, root_save_sec_context); - DefineIndex(childRelid, childStmt, - InvalidOid, /* no predefined OID */ - indexRelationId, /* this is our child */ - createdConstraintId, - is_alter_table, check_rights, check_not_in_use, - skip_build, quiet); + childAddr = + DefineIndex(childRelid, childStmt, + InvalidOid, /* no predefined OID */ + indexRelationId, /* this is our child */ + createdConstraintId, + is_alter_table, check_rights, + check_not_in_use, + skip_build, quiet); SetUserIdAndSecContext(child_save_userid, child_save_sec_context); + + /* + * Check if the index just created is valid or not, as it + * could be possible that it has been switched as invalid + * when recursing across multiple partition levels. + */ + if (!get_index_isvalid(childAddr.objectId)) + invalidate_parent = true; } pfree(attmap); @@ -1249,6 +1260,12 @@ DefineIndex(Oid relationId, ReleaseSysCache(tup); heap_close(pg_index, RowExclusiveLock); heap_freetuple(newtup); + + /* + * CCI here to make this update visible, in case this recurses + * across multiple partition levels. + */ + CommandCounterIncrement(); } } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index 913cad35105..d3fca7129a9 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -3204,3 +3204,26 @@ get_index_isclustered(Oid index_oid) return isclustered; } + +/* + * get_index_isvalid + * + * Given the index OID, return pg_index.indisvalid. + */ +bool +get_index_isvalid(Oid index_oid) +{ + bool isvalid; + HeapTuple tuple; + Form_pg_index rd_index; + + tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(index_oid)); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for index %u", index_oid); + + rd_index = (Form_pg_index) GETSTRUCT(tuple); + isvalid = rd_index->indisvalid; + ReleaseSysCache(tuple); + + return isvalid; +} diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 21ec4cbd355..c9d6aa7f1c3 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -179,6 +179,7 @@ extern char *get_namespace_name_or_temp(Oid nspid); extern Oid get_range_subtype(Oid rangeOid); extern Oid get_range_collation(Oid rangeOid); extern bool get_index_isreplident(Oid index_oid); +extern bool get_index_isvalid(Oid index_oid); extern bool get_index_isclustered(Oid index_oid); #define type_is_array(typid) (get_element_type(typid) != InvalidOid) diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out index 2544f389e2f..3eec572e917 100644 --- a/src/test/regress/expected/indexing.out +++ b/src/test/regress/expected/indexing.out @@ -1537,3 +1537,38 @@ select indexrelid::regclass, indisvalid, (5 rows) drop table parted_inval_tab; +-- Check setup of indisvalid across a complex partition tree on index +-- creation. If one index in a partition index is invalid, so should its +-- partitioned index. +create table parted_isvalid_tab (a int, b int) partition by range (a); +create table parted_isvalid_tab_1 partition of parted_isvalid_tab + for values from (1) to (10) partition by range (a); +create table parted_isvalid_tab_2 partition of parted_isvalid_tab + for values from (10) to (20) partition by range (a); +create table parted_isvalid_tab_11 partition of parted_isvalid_tab_1 + for values from (1) to (5); +create table parted_isvalid_tab_12 partition of parted_isvalid_tab_1 + for values from (5) to (10); +-- create an invalid index on one of the partitions. +insert into parted_isvalid_tab_11 values (1, 0); +create index concurrently parted_isvalid_idx_11 on parted_isvalid_tab_11 ((a/b)); +ERROR: division by zero +-- The previous invalid index is selected, invalidating all the indexes up to +-- the top-most parent. +create index parted_isvalid_idx on parted_isvalid_tab ((a/b)); +select indexrelid::regclass, indisvalid, + indrelid::regclass, inhparent::regclass + from pg_index idx left join + pg_inherits inh on (idx.indexrelid = inh.inhrelid) + where indexrelid::regclass::text like 'parted_isvalid%' + order by indexrelid::regclass::text collate "C"; + indexrelid | indisvalid | indrelid | inhparent +--------------------------------+------------+-----------------------+------------------------------- + parted_isvalid_idx | f | parted_isvalid_tab | + parted_isvalid_idx_11 | f | parted_isvalid_tab_11 | parted_isvalid_tab_1_expr_idx + parted_isvalid_tab_12_expr_idx | t | parted_isvalid_tab_12 | parted_isvalid_tab_1_expr_idx + parted_isvalid_tab_1_expr_idx | f | parted_isvalid_tab_1 | parted_isvalid_idx + parted_isvalid_tab_2_expr_idx | t | parted_isvalid_tab_2 | parted_isvalid_idx +(5 rows) + +drop table parted_isvalid_tab; diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql index 6f8233dd445..5e89a0bcd9b 100644 --- a/src/test/regress/sql/indexing.sql +++ b/src/test/regress/sql/indexing.sql @@ -817,3 +817,29 @@ select indexrelid::regclass, indisvalid, where indexrelid::regclass::text like 'parted_inval%' order by indexrelid::regclass::text collate "C"; drop table parted_inval_tab; + +-- Check setup of indisvalid across a complex partition tree on index +-- creation. If one index in a partition index is invalid, so should its +-- partitioned index. +create table parted_isvalid_tab (a int, b int) partition by range (a); +create table parted_isvalid_tab_1 partition of parted_isvalid_tab + for values from (1) to (10) partition by range (a); +create table parted_isvalid_tab_2 partition of parted_isvalid_tab + for values from (10) to (20) partition by range (a); +create table parted_isvalid_tab_11 partition of parted_isvalid_tab_1 + for values from (1) to (5); +create table parted_isvalid_tab_12 partition of parted_isvalid_tab_1 + for values from (5) to (10); +-- create an invalid index on one of the partitions. +insert into parted_isvalid_tab_11 values (1, 0); +create index concurrently parted_isvalid_idx_11 on parted_isvalid_tab_11 ((a/b)); +-- The previous invalid index is selected, invalidating all the indexes up to +-- the top-most parent. +create index parted_isvalid_idx on parted_isvalid_tab ((a/b)); +select indexrelid::regclass, indisvalid, + indrelid::regclass, inhparent::regclass + from pg_index idx left join + pg_inherits inh on (idx.indexrelid = inh.inhrelid) + where indexrelid::regclass::text like 'parted_isvalid%' + order by indexrelid::regclass::text collate "C"; +drop table parted_isvalid_tab;