diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index f8398dd..e847a2b 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -742,6 +742,20 @@ index_create(Relation heapRelation, errmsg("user-defined indexes on system catalog tables are not supported"))); /* + * Indexes on any system columns, apart from OID are not properly updated. + * Let's just disallow them. + */ + for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) + { + AttrNumber attno = indexInfo->ii_KeyAttrNumbers[i]; + + if (attno < 0 && attno != ObjectIdAttributeNumber) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("index creation on system columns is not supported"))); + } + + /* * concurrent index build on a system catalog is unsafe because we tend to * release locks before committing in catalogs */ diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index eaf76d2..2d2ed3a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -11052,12 +11052,24 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode int16 attno = indexRel->rd_index->indkey.values[key]; Form_pg_attribute attr; - /* Of the system columns, only oid is indexable. */ - if (attno <= 0 && attno != ObjectIdAttributeNumber) - elog(ERROR, "internal column %u in unique index \"%s\"", - attno, RelationGetRelationName(indexRel)); + /* Allow OIDs to be indexed. No need to check for nullabiliy here */ + if (attno == ObjectIdAttributeNumber) + continue; + + /* + * Reject any other system columns. Technically a unique index cannot + * be created on any other system columns, however this was not always + * the case, so it seems like we should handle such indexes gracefully + */ + if (attno < 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column", + RelationGetRelationName(indexRel), attno))); attr = rel->rd_att->attrs[attno - 1]; + + /* Must be a non-system column. Check it's not nullable */ if (!attr->attnotnull) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index b72e65d..7953c67 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -2913,6 +2913,16 @@ explain (costs off) (2 rows) -- +-- Check indexes on system columns +-- +CREATE TABLE oid_table (a INT) WITH OIDS; +-- we don't allow indexes on any system columns, apart from OID +CREATE INDEX oid_table_ctid_idx ON oid_table (ctid); +ERROR: index creation on system columns is not supported +-- a index on the OID column should be allowed +CREATE INDEX oid_table_oid_idx ON oid_table (oid); +DROP TABLE oid_table; +-- -- REINDEX (VERBOSE) -- CREATE TABLE reindex_verbose(id integer primary key); diff --git a/src/test/regress/expected/replica_identity.out b/src/test/regress/expected/replica_identity.out index 60d9a42..39a60a5 100644 --- a/src/test/regress/expected/replica_identity.out +++ b/src/test/regress/expected/replica_identity.out @@ -5,10 +5,11 @@ CREATE TABLE test_replica_identity ( nonkey text, CONSTRAINT test_replica_identity_unique_defer UNIQUE (keya, keyb) DEFERRABLE, CONSTRAINT test_replica_identity_unique_nondefer UNIQUE (keya, keyb) -); +) WITH OIDS; CREATE TABLE test_replica_identity_othertable (id serial primary key); CREATE INDEX test_replica_identity_keyab ON test_replica_identity (keya, keyb); CREATE UNIQUE INDEX test_replica_identity_keyab_key ON test_replica_identity (keya, keyb); +CREATE UNIQUE INDEX test_replica_identity_oid_idx ON test_replica_identity (oid); CREATE UNIQUE INDEX test_replica_identity_nonkey ON test_replica_identity (keya, nonkey); CREATE INDEX test_replica_identity_hash ON test_replica_identity USING hash (nonkey); WARNING: hash indexes are not WAL-logged and their use is discouraged @@ -88,12 +89,15 @@ Indexes: "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) "test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb) "test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey) + "test_replica_identity_oid_idx" UNIQUE, btree (oid) "test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text "test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE "test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb) "test_replica_identity_hash" hash (nonkey) "test_replica_identity_keyab" btree (keya, keyb) +-- succeed, oid unique index +ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_oid_idx; -- succeed, nondeferrable unique constraint over nonullable cols ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_unique_nondefer; -- succeed unique index over nonnullable cols @@ -118,6 +122,7 @@ Indexes: "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) "test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb) REPLICA IDENTITY "test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey) + "test_replica_identity_oid_idx" UNIQUE, btree (oid) "test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text "test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE "test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb) @@ -166,12 +171,14 @@ Indexes: "test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3)) "test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb) "test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey) + "test_replica_identity_oid_idx" UNIQUE, btree (oid) "test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text "test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE "test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb) "test_replica_identity_hash" hash (nonkey) "test_replica_identity_keyab" btree (keya, keyb) Replica Identity: FULL +Has OIDs: yes ALTER TABLE test_replica_identity REPLICA IDENTITY NOTHING; SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass; diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql index ff86953..9ada7b5 100644 --- a/src/test/regress/sql/create_index.sql +++ b/src/test/regress/sql/create_index.sql @@ -982,6 +982,20 @@ explain (costs off) select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null)); -- +-- Check indexes on system columns +-- + +CREATE TABLE oid_table (a INT) WITH OIDS; + +-- we don't allow indexes on any system columns, apart from OID +CREATE INDEX oid_table_ctid_idx ON oid_table (ctid); + +-- a index on the OID column should be allowed +CREATE INDEX oid_table_oid_idx ON oid_table (oid); + +DROP TABLE oid_table; + +-- -- REINDEX (VERBOSE) -- CREATE TABLE reindex_verbose(id integer primary key); diff --git a/src/test/regress/sql/replica_identity.sql b/src/test/regress/sql/replica_identity.sql index 20b6826..68824a3 100644 --- a/src/test/regress/sql/replica_identity.sql +++ b/src/test/regress/sql/replica_identity.sql @@ -5,12 +5,13 @@ CREATE TABLE test_replica_identity ( nonkey text, CONSTRAINT test_replica_identity_unique_defer UNIQUE (keya, keyb) DEFERRABLE, CONSTRAINT test_replica_identity_unique_nondefer UNIQUE (keya, keyb) -); +) WITH OIDS; CREATE TABLE test_replica_identity_othertable (id serial primary key); CREATE INDEX test_replica_identity_keyab ON test_replica_identity (keya, keyb); CREATE UNIQUE INDEX test_replica_identity_keyab_key ON test_replica_identity (keya, keyb); +CREATE UNIQUE INDEX test_replica_identity_oid_idx ON test_replica_identity (oid); CREATE UNIQUE INDEX test_replica_identity_nonkey ON test_replica_identity (keya, nonkey); CREATE INDEX test_replica_identity_hash ON test_replica_identity USING hash (nonkey); CREATE UNIQUE INDEX test_replica_identity_expr ON test_replica_identity (keya, keyb, (3)); @@ -52,6 +53,9 @@ ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_iden SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass; \d test_replica_identity +-- succeed, oid unique index +ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_oid_idx; + -- succeed, nondeferrable unique constraint over nonullable cols ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_unique_nondefer;