Choose FK name correctly during partition attachment
During ALTER TABLE ATTACH PARTITION, if the name of a parent's foreign key constraint is already used on the partition, the code tries to choose another one before the FK attributes list has been populated, so the resulting constraint name was "<relname>__fkey" instead of "<relname>_<attrs>_fkey". Repair, and add a test case. Backpatch to 12. In 11, the code to attach a partition was not smart enough to cope with conflicting constraint names, so the problem doesn't exist there. Author: Jehan-Guillaume de Rorthais <jgdr@dalibo.com> Discussion: https://postgr.es/m/20220901184156.738ebee5@karst
This commit is contained in:
parent
adb466150b
commit
e7936f8b3e
@ -10304,16 +10304,6 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
|
|||||||
|
|
||||||
/* No dice. Set up to create our own constraint */
|
/* No dice. Set up to create our own constraint */
|
||||||
fkconstraint = makeNode(Constraint);
|
fkconstraint = makeNode(Constraint);
|
||||||
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
|
||||||
RelationGetRelid(partRel),
|
|
||||||
NameStr(constrForm->conname)))
|
|
||||||
fkconstraint->conname =
|
|
||||||
ChooseConstraintName(RelationGetRelationName(partRel),
|
|
||||||
ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
|
|
||||||
"fkey",
|
|
||||||
RelationGetNamespace(partRel), NIL);
|
|
||||||
else
|
|
||||||
fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
|
|
||||||
fkconstraint->fk_upd_action = constrForm->confupdtype;
|
fkconstraint->fk_upd_action = constrForm->confupdtype;
|
||||||
fkconstraint->fk_del_action = constrForm->confdeltype;
|
fkconstraint->fk_del_action = constrForm->confdeltype;
|
||||||
fkconstraint->deferrable = constrForm->condeferrable;
|
fkconstraint->deferrable = constrForm->condeferrable;
|
||||||
@ -10328,6 +10318,16 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
|
|||||||
fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
|
fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
|
||||||
makeString(NameStr(att->attname)));
|
makeString(NameStr(att->attname)));
|
||||||
}
|
}
|
||||||
|
if (ConstraintNameIsUsed(CONSTRAINT_RELATION,
|
||||||
|
RelationGetRelid(partRel),
|
||||||
|
NameStr(constrForm->conname)))
|
||||||
|
fkconstraint->conname =
|
||||||
|
ChooseConstraintName(RelationGetRelationName(partRel),
|
||||||
|
ChooseForeignKeyConstraintNameAddition(fkconstraint->fk_attrs),
|
||||||
|
"fkey",
|
||||||
|
RelationGetNamespace(partRel), NIL);
|
||||||
|
else
|
||||||
|
fkconstraint->conname = pstrdup(NameStr(constrForm->conname));
|
||||||
|
|
||||||
indexOid = constrForm->conindid;
|
indexOid = constrForm->conindid;
|
||||||
constrOid =
|
constrOid =
|
||||||
|
@ -603,6 +603,29 @@ COMMIT;
|
|||||||
ERROR: duplicate key value violates unique constraint "parted_uniq_tbl_1_i_key"
|
ERROR: duplicate key value violates unique constraint "parted_uniq_tbl_1_i_key"
|
||||||
DETAIL: Key (i)=(1) already exists.
|
DETAIL: Key (i)=(1) already exists.
|
||||||
DROP TABLE parted_uniq_tbl;
|
DROP TABLE parted_uniq_tbl;
|
||||||
|
-- test naming a constraint in a partition when a conflict exists
|
||||||
|
CREATE TABLE parted_fk_naming (
|
||||||
|
id bigint NOT NULL default 1,
|
||||||
|
id_abc bigint,
|
||||||
|
CONSTRAINT dummy_constr FOREIGN KEY (id_abc)
|
||||||
|
REFERENCES parted_fk_naming (id),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
PARTITION BY LIST (id);
|
||||||
|
CREATE TABLE parted_fk_naming_1 (
|
||||||
|
id bigint NOT NULL default 1,
|
||||||
|
id_abc bigint,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
CONSTRAINT dummy_constr CHECK (true)
|
||||||
|
);
|
||||||
|
ALTER TABLE parted_fk_naming ATTACH PARTITION parted_fk_naming_1 FOR VALUES IN ('1');
|
||||||
|
SELECT conname FROM pg_constraint WHERE conrelid = 'parted_fk_naming_1'::regclass AND contype = 'f';
|
||||||
|
conname
|
||||||
|
--------------------------------
|
||||||
|
parted_fk_naming_1_id_abc_fkey
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE parted_fk_naming;
|
||||||
-- test a HOT update that invalidates the conflicting tuple.
|
-- test a HOT update that invalidates the conflicting tuple.
|
||||||
-- the trigger should still fire and catch the violation
|
-- the trigger should still fire and catch the violation
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
@ -430,6 +430,25 @@ INSERT INTO parted_uniq_tbl VALUES (1); -- OK now, fail at commit
|
|||||||
COMMIT;
|
COMMIT;
|
||||||
DROP TABLE parted_uniq_tbl;
|
DROP TABLE parted_uniq_tbl;
|
||||||
|
|
||||||
|
-- test naming a constraint in a partition when a conflict exists
|
||||||
|
CREATE TABLE parted_fk_naming (
|
||||||
|
id bigint NOT NULL default 1,
|
||||||
|
id_abc bigint,
|
||||||
|
CONSTRAINT dummy_constr FOREIGN KEY (id_abc)
|
||||||
|
REFERENCES parted_fk_naming (id),
|
||||||
|
PRIMARY KEY (id)
|
||||||
|
)
|
||||||
|
PARTITION BY LIST (id);
|
||||||
|
CREATE TABLE parted_fk_naming_1 (
|
||||||
|
id bigint NOT NULL default 1,
|
||||||
|
id_abc bigint,
|
||||||
|
PRIMARY KEY (id),
|
||||||
|
CONSTRAINT dummy_constr CHECK (true)
|
||||||
|
);
|
||||||
|
ALTER TABLE parted_fk_naming ATTACH PARTITION parted_fk_naming_1 FOR VALUES IN ('1');
|
||||||
|
SELECT conname FROM pg_constraint WHERE conrelid = 'parted_fk_naming_1'::regclass AND contype = 'f';
|
||||||
|
DROP TABLE parted_fk_naming;
|
||||||
|
|
||||||
-- test a HOT update that invalidates the conflicting tuple.
|
-- test a HOT update that invalidates the conflicting tuple.
|
||||||
-- the trigger should still fire and catch the violation
|
-- the trigger should still fire and catch the violation
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user