Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8f1911d

Browse files
committed
Fix possible crash in ALTER TABLE ... REPLICA IDENTITY USING INDEX.
Careless coding added by commit 07cacba could result in a crash or a bizarre error message if someone tried to select an index on the OID column as the replica identity index for a table. Back-patch to 9.4 where the feature was introduced. Discussion: CAKJS1f8TQYgTRDyF1_u9PVCKWRWz+DkieH=U7954HeHVPJKaKg@mail.gmail.com David Rowley
1 parent da7d44b commit 8f1911d

File tree

3 files changed

+27
-6
lines changed

3 files changed

+27
-6
lines changed

src/backend/commands/tablecmds.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11052,10 +11052,20 @@ ATExecReplicaIdentity(Relation rel, ReplicaIdentityStmt *stmt, LOCKMODE lockmode
1105211052
int16 attno = indexRel->rd_index->indkey.values[key];
1105311053
Form_pg_attribute attr;
1105411054

11055-
/* Of the system columns, only oid is indexable. */
11056-
if (attno <= 0 && attno != ObjectIdAttributeNumber)
11057-
elog(ERROR, "internal column %u in unique index \"%s\"",
11058-
attno, RelationGetRelationName(indexRel));
11055+
/* Allow OID column to be indexed; it's certainly not nullable */
11056+
if (attno == ObjectIdAttributeNumber)
11057+
continue;
11058+
11059+
/*
11060+
* Reject any other system columns. (Going forward, we'll disallow
11061+
* indexes containing such columns in the first place, but they might
11062+
* exist in older branches.)
11063+
*/
11064+
if (attno <= 0)
11065+
ereport(ERROR,
11066+
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
11067+
errmsg("index \"%s\" cannot be used as replica identity because column %d is a system column",
11068+
RelationGetRelationName(indexRel), attno)));
1105911069

1106011070
attr = rel->rd_att->attrs[attno - 1];
1106111071
if (!attr->attnotnull)

src/test/regress/expected/replica_identity.out

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ CREATE TABLE test_replica_identity (
55
nonkey text,
66
CONSTRAINT test_replica_identity_unique_defer UNIQUE (keya, keyb) DEFERRABLE,
77
CONSTRAINT test_replica_identity_unique_nondefer UNIQUE (keya, keyb)
8-
);
8+
) WITH OIDS;
99
CREATE TABLE test_replica_identity_othertable (id serial primary key);
1010
CREATE INDEX test_replica_identity_keyab ON test_replica_identity (keya, keyb);
1111
CREATE UNIQUE INDEX test_replica_identity_keyab_key ON test_replica_identity (keya, keyb);
12+
CREATE UNIQUE INDEX test_replica_identity_oid_idx ON test_replica_identity (oid);
1213
CREATE UNIQUE INDEX test_replica_identity_nonkey ON test_replica_identity (keya, nonkey);
1314
CREATE INDEX test_replica_identity_hash ON test_replica_identity USING hash (nonkey);
1415
WARNING: hash indexes are not WAL-logged and their use is discouraged
@@ -88,12 +89,15 @@ Indexes:
8889
"test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3))
8990
"test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb)
9091
"test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey)
92+
"test_replica_identity_oid_idx" UNIQUE, btree (oid)
9193
"test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text
9294
"test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE
9395
"test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb)
9496
"test_replica_identity_hash" hash (nonkey)
9597
"test_replica_identity_keyab" btree (keya, keyb)
9698

99+
-- succeed, oid unique index
100+
ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_oid_idx;
97101
-- succeed, nondeferrable unique constraint over nonullable cols
98102
ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_unique_nondefer;
99103
-- succeed unique index over nonnullable cols
@@ -118,6 +122,7 @@ Indexes:
118122
"test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3))
119123
"test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb) REPLICA IDENTITY
120124
"test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey)
125+
"test_replica_identity_oid_idx" UNIQUE, btree (oid)
121126
"test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text
122127
"test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE
123128
"test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb)
@@ -166,12 +171,14 @@ Indexes:
166171
"test_replica_identity_expr" UNIQUE, btree (keya, keyb, (3))
167172
"test_replica_identity_keyab_key" UNIQUE, btree (keya, keyb)
168173
"test_replica_identity_nonkey" UNIQUE, btree (keya, nonkey)
174+
"test_replica_identity_oid_idx" UNIQUE, btree (oid)
169175
"test_replica_identity_partial" UNIQUE, btree (keya, keyb) WHERE keyb <> '3'::text
170176
"test_replica_identity_unique_defer" UNIQUE CONSTRAINT, btree (keya, keyb) DEFERRABLE
171177
"test_replica_identity_unique_nondefer" UNIQUE CONSTRAINT, btree (keya, keyb)
172178
"test_replica_identity_hash" hash (nonkey)
173179
"test_replica_identity_keyab" btree (keya, keyb)
174180
Replica Identity: FULL
181+
Has OIDs: yes
175182

176183
ALTER TABLE test_replica_identity REPLICA IDENTITY NOTHING;
177184
SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;

src/test/regress/sql/replica_identity.sql

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ CREATE TABLE test_replica_identity (
55
nonkey text,
66
CONSTRAINT test_replica_identity_unique_defer UNIQUE (keya, keyb) DEFERRABLE,
77
CONSTRAINT test_replica_identity_unique_nondefer UNIQUE (keya, keyb)
8-
);
8+
) WITH OIDS;
99

1010
CREATE TABLE test_replica_identity_othertable (id serial primary key);
1111

1212
CREATE INDEX test_replica_identity_keyab ON test_replica_identity (keya, keyb);
1313
CREATE UNIQUE INDEX test_replica_identity_keyab_key ON test_replica_identity (keya, keyb);
14+
CREATE UNIQUE INDEX test_replica_identity_oid_idx ON test_replica_identity (oid);
1415
CREATE UNIQUE INDEX test_replica_identity_nonkey ON test_replica_identity (keya, nonkey);
1516
CREATE INDEX test_replica_identity_hash ON test_replica_identity USING hash (nonkey);
1617
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
5253
SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
5354
\d test_replica_identity
5455

56+
-- succeed, oid unique index
57+
ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_oid_idx;
58+
5559
-- succeed, nondeferrable unique constraint over nonullable cols
5660
ALTER TABLE test_replica_identity REPLICA IDENTITY USING INDEX test_replica_identity_unique_nondefer;
5761

0 commit comments

Comments
 (0)