From c516a0c36e246a0c746be73cc75cda441a5f748d Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Wed, 6 Oct 2021 22:11:42 +0000 Subject: [PATCH v1 1/1] Add object type validation in RenameRelation(). RenameRelation() is used for renaming several object types, but there is presently no verification that the object type matches the statement type. For example, ALTER TABLE ... RENAME can be used to rename indexes. Since the renaming logic can differ between object types, it is important to ensure that the object type and statement type match. --- src/backend/commands/cluster.c | 4 ++-- src/backend/commands/tablecmds.c | 16 ++++++++++++---- src/backend/commands/typecmds.c | 2 +- src/include/commands/tablecmds.h | 2 +- src/test/regress/expected/alter_table.out | 6 +++++- src/test/regress/expected/sequence.out | 4 ++-- src/test/regress/sql/alter_table.sql | 5 ++++- src/test/regress/sql/sequence.sql | 4 ++-- 8 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 9d22f648a8..7ee00691ab 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1518,14 +1518,14 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u", OIDOldHeap); RenameRelationInternal(newrel->rd_rel->reltoastrelid, - NewToastName, true, false); + NewToastName, true, OBJECT_TABLE); /* ... and its valid index too. */ snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index", OIDOldHeap); RenameRelationInternal(toastidx, - NewToastName, true, true); + NewToastName, true, OBJECT_INDEX); /* * Reset the relrewrite for the toast. The command-counter diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index ff97b618e6..f8f5b6f85d 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3660,7 +3660,7 @@ rename_constraint_internal(Oid myrelid, || con->contype == CONSTRAINT_UNIQUE || con->contype == CONSTRAINT_EXCLUSION)) /* rename the index; this renames the constraint as well */ - RenameRelationInternal(con->conindid, newconname, false, true); + RenameRelationInternal(con->conindid, newconname, false, OBJECT_INDEX); else RenameConstraintById(constraintOid, newconname); @@ -3762,7 +3762,7 @@ RenameRelation(RenameStmt *stmt) } /* Do the work */ - RenameRelationInternal(relid, stmt->newname, false, is_index); + RenameRelationInternal(relid, stmt->newname, false, stmt->renameType); ObjectAddressSet(address, RelationRelationId, relid); @@ -3773,13 +3773,14 @@ RenameRelation(RenameStmt *stmt) * RenameRelationInternal - change the name of a relation */ void -RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bool is_index) +RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, ObjectType renameType) { Relation targetrelation; Relation relrelation; /* for RELATION relation */ HeapTuple reltup; Form_pg_class relform; Oid namespaceId; + bool is_index = renameType == OBJECT_INDEX; /* * Grab a lock on the target relation, which we will NOT release until end @@ -3804,6 +3805,13 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo elog(ERROR, "cache lookup failed for relation %u", myrelid); relform = (Form_pg_class) GETSTRUCT(reltup); + if (get_relkind_objtype(relform->relkind) != renameType) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("cannot rename \"%s\"", + NameStr(relform->relname)), + errdetail_relkind_not_supported(relform->relkind))); + if (get_relname_relid(newrelname, namespaceId) != InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), @@ -8620,7 +8628,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, ereport(NOTICE, (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"", indexName, constraintName))); - RenameRelationInternal(index_oid, constraintName, false, true); + RenameRelationInternal(index_oid, constraintName, false, OBJECT_INDEX); } /* Extra checks needed if making primary key */ diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index b290629a45..4a971a103d 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3659,7 +3659,7 @@ RenameType(RenameStmt *stmt) * RenameRelationInternal will call RenameTypeInternal automatically. */ if (typTup->typtype == TYPTYPE_COMPOSITE) - RenameRelationInternal(typTup->typrelid, newTypeName, false, false); + RenameRelationInternal(typTup->typrelid, newTypeName, false, stmt->renameType); else RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 336549cc5f..48d3a782af 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -76,7 +76,7 @@ extern ObjectAddress RenameRelation(RenameStmt *stmt); extern void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, - bool is_index); + ObjectType renameType); extern void ResetRelRewrite(Oid myrelid); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 4bee0c1173..fb1909de3c 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -232,9 +232,13 @@ SET ROLE regress_alter_table_user1; ALTER INDEX onek_unique1 RENAME TO fail; -- permission denied ERROR: must be owner of index onek_unique1 RESET ROLE; +-- ALTER TABLE ... RENAME on index fails +ALTER TABLE onek_unique1 RENAME TO fail; +ERROR: cannot rename "onek_unique1" +DETAIL: This operation is not supported for indexes. -- renaming views CREATE VIEW attmp_view (unique1) AS SELECT unique1 FROM tenk1; -ALTER TABLE attmp_view RENAME TO attmp_view_new; +ALTER VIEW attmp_view RENAME TO attmp_view_new; SET ROLE regress_alter_table_user1; ALTER VIEW attmp_view_new RENAME TO fail; -- permission denied ERROR: must be owner of view attmp_view_new diff --git a/src/test/regress/expected/sequence.out b/src/test/regress/expected/sequence.out index 71c2b0f1df..d0a5dd8d76 100644 --- a/src/test/regress/expected/sequence.out +++ b/src/test/regress/expected/sequence.out @@ -241,7 +241,7 @@ ERROR: currval of sequence "sequence_test" is not yet defined in this session DROP SEQUENCE sequence_test; -- renaming sequences CREATE SEQUENCE foo_seq; -ALTER TABLE foo_seq RENAME TO foo_seq_new; +ALTER SEQUENCE foo_seq RENAME TO foo_seq_new; SELECT * FROM foo_seq_new; last_value | log_cnt | is_called ------------+---------+----------- @@ -270,7 +270,7 @@ SELECT last_value, log_cnt IN (31, 32) AS log_cnt_ok, is_called FROM foo_seq_new DROP SEQUENCE foo_seq_new; -- renaming serial sequences -ALTER TABLE serialtest1_f2_seq RENAME TO serialtest1_f2_foo; +ALTER SEQUENCE serialtest1_f2_seq RENAME TO serialtest1_f2_foo; INSERT INTO serialTest1 VALUES ('more'); SELECT * FROM serialTest1; f1 | f2 diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index dc0200adcb..8106c8617b 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -227,9 +227,12 @@ SET ROLE regress_alter_table_user1; ALTER INDEX onek_unique1 RENAME TO fail; -- permission denied RESET ROLE; +-- ALTER TABLE ... RENAME on index fails +ALTER TABLE onek_unique1 RENAME TO fail; + -- renaming views CREATE VIEW attmp_view (unique1) AS SELECT unique1 FROM tenk1; -ALTER TABLE attmp_view RENAME TO attmp_view_new; +ALTER VIEW attmp_view RENAME TO attmp_view_new; SET ROLE regress_alter_table_user1; ALTER VIEW attmp_view_new RENAME TO fail; -- permission denied diff --git a/src/test/regress/sql/sequence.sql b/src/test/regress/sql/sequence.sql index 7928ee23ee..3d3a90b544 100644 --- a/src/test/regress/sql/sequence.sql +++ b/src/test/regress/sql/sequence.sql @@ -132,7 +132,7 @@ DROP SEQUENCE sequence_test; -- renaming sequences CREATE SEQUENCE foo_seq; -ALTER TABLE foo_seq RENAME TO foo_seq_new; +ALTER SEQUENCE foo_seq RENAME TO foo_seq_new; SELECT * FROM foo_seq_new; SELECT nextval('foo_seq_new'); SELECT nextval('foo_seq_new'); @@ -142,7 +142,7 @@ SELECT last_value, log_cnt IN (31, 32) AS log_cnt_ok, is_called FROM foo_seq_new DROP SEQUENCE foo_seq_new; -- renaming serial sequences -ALTER TABLE serialtest1_f2_seq RENAME TO serialtest1_f2_foo; +ALTER SEQUENCE serialtest1_f2_seq RENAME TO serialtest1_f2_foo; INSERT INTO serialTest1 VALUES ('more'); SELECT * FROM serialTest1; -- 2.16.6