Skip to content

Commit dffe80e

Browse files
committed
Block ALTER TABLE .. DROP NOT NULL on columns in replica identity index
Replica identities that depend directly on an index rely on a set of properties, one of them being that all the columns defined in this index have to be marked as NOT NULL. There was a hole in the logic with ALTER TABLE DROP NOT NULL, where it was possible to remove the NOT NULL property of a column part of an index used as replica identity, so block it to avoid problems with logical decoding down the road. The same check was already done columns part of a primary key, so the fix is straight-forward. Author: Haiying Tang, Hou Zhijie Reviewed-by: Dilip Kumar, Michael Paquier Discussion: https://postgr.es/m/OS0PR01MB6113338C102BEE8B2FFC5BD9FB619@OS0PR01MB6113.jpnprd01.prod.outlook.com Backpatch-through: 10
1 parent b0a7161 commit dffe80e

File tree

3 files changed

+30
-9
lines changed

3 files changed

+30
-9
lines changed

src/backend/commands/tablecmds.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6090,7 +6090,8 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
60906090
colName, RelationGetRelationName(rel))));
60916091

60926092
/*
6093-
* Check that the attribute is not in a primary key
6093+
* Check that the attribute is not in a primary key or in an index used as
6094+
* a replica identity.
60946095
*
60956096
* Note: we'll throw error even if the pkey index is not valid.
60966097
*/
@@ -6110,20 +6111,32 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
61106111
elog(ERROR, "cache lookup failed for index %u", indexoid);
61116112
indexStruct = (Form_pg_index) GETSTRUCT(indexTuple);
61126113

6113-
/* If the index is not a primary key, skip the check */
6114-
if (indexStruct->indisprimary)
6114+
/*
6115+
* If the index is not a primary key or an index used as replica
6116+
* identity, skip the check.
6117+
*/
6118+
if (indexStruct->indisprimary || indexStruct->indisreplident)
61156119
{
61166120
/*
6117-
* Loop over each attribute in the primary key and see if it
6118-
* matches the to-be-altered attribute
6121+
* Loop over each attribute in the primary key or the index used
6122+
* as replica identity and see if it matches the to-be-altered
6123+
* attribute.
61196124
*/
61206125
for (i = 0; i < indexStruct->indnkeyatts; i++)
61216126
{
61226127
if (indexStruct->indkey.values[i] == attnum)
6123-
ereport(ERROR,
6124-
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6125-
errmsg("column \"%s\" is in a primary key",
6126-
colName)));
6128+
{
6129+
if (indexStruct->indisprimary)
6130+
ereport(ERROR,
6131+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6132+
errmsg("column \"%s\" is in a primary key",
6133+
colName)));
6134+
else
6135+
ereport(ERROR,
6136+
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
6137+
errmsg("column \"%s\" is in index used as replica identity",
6138+
colName)));
6139+
}
61276140
}
61286141
}
61296142

src/test/regress/expected/replica_identity.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
230230
Indexes:
231231
"test_replica_identity3_id_key" UNIQUE, btree (id) REPLICA IDENTITY
232232

233+
-- ALTER TABLE DROP NOT NULL is not allowed for columns part of an index
234+
-- used as replica identity.
235+
ALTER TABLE test_replica_identity3 ALTER COLUMN id DROP NOT NULL;
236+
ERROR: column "id" is in index used as replica identity
233237
DROP TABLE test_replica_identity;
234238
DROP TABLE test_replica_identity2;
235239
DROP TABLE test_replica_identity3;

src/test/regress/sql/replica_identity.sql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ ALTER TABLE test_replica_identity3 REPLICA IDENTITY USING INDEX test_replica_ide
9898
ALTER TABLE test_replica_identity3 ALTER COLUMN id TYPE bigint;
9999
\d test_replica_identity3
100100

101+
-- ALTER TABLE DROP NOT NULL is not allowed for columns part of an index
102+
-- used as replica identity.
103+
ALTER TABLE test_replica_identity3 ALTER COLUMN id DROP NOT NULL;
104+
101105
DROP TABLE test_replica_identity;
102106
DROP TABLE test_replica_identity2;
103107
DROP TABLE test_replica_identity3;

0 commit comments

Comments
 (0)