Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf7d510a

Browse files
committed
Fix some more bugs in foreign keys connecting partitioned tables
* In DetachPartitionFinalize() we were applying a tuple conversion map to tuples that didn't need one, which can lead to erratic behavior if a partitioned table has a partition with a different column order, as reported by Alexander Lakhin. This was introduced by53af949. Don't do that. Also, modify a recently added test case to exercise this.* The same function as well as CloneFkReferenced() were acquiring AccessShareLock on a partition, only to have CreateTrigger() later acquire ShareRowExclusiveLock on it. This can lead to deadlock by lock escalation, unnecessarily. Avoid that by acquiring the stronger lock to begin with. This probably dates back to branch 12, but I have never seen a report of this being a problem in the field.* Innocuous but wasteful: also introduced by53af949, we were reading a pg_constraint tuple from syscache that we don't need, as reported by Tender Wang. Don't.Backpatch to 15.Discussion:https://postgr.es/m/461e9c26-2076-8224-e119-84998b6a784e@gmail.com
1 parent370bc77 commitf7d510a

File tree

3 files changed

+27
-30
lines changed

3 files changed

+27
-30
lines changed

‎src/backend/commands/tablecmds.c‎

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9875,6 +9875,9 @@ addFkRecurseReferenced(Constraint *fkconstraint, Relation rel,
98759875
OiddeleteTriggerOid,
98769876
updateTriggerOid;
98779877

9878+
Assert(CheckRelationLockedByMe(pkrel, ShareRowExclusiveLock, true));
9879+
Assert(CheckRelationLockedByMe(rel, ShareRowExclusiveLock, true));
9880+
98789881
/*
98799882
* Create the action triggers that enforce the constraint.
98809883
*/
@@ -9901,6 +9904,7 @@ addFkRecurseReferenced(Constraint *fkconstraint, Relation rel,
99019904
OidpartIndexId;
99029905
ObjectAddress address;
99039906

9907+
/* XXX would it be better to acquire these locks beforehand? */
99049908
partRel = table_open(pd->oids[i], ShareRowExclusiveLock);
99059909

99069910
/*
@@ -10003,6 +10007,8 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
1000310007
updateTriggerOid;
1000410008

1000510009
Assert(OidIsValid(parentConstr));
10010+
Assert(CheckRelationLockedByMe(rel, ShareRowExclusiveLock, true));
10011+
Assert(CheckRelationLockedByMe(pkrel, ShareRowExclusiveLock, true));
1000610012

1000710013
if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
1000810014
ereport(ERROR,
@@ -10293,13 +10299,8 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel)
1029310299
continue;
1029410300
}
1029510301

10296-
/*
10297-
* Because we're only expanding the key space at the referenced side,
10298-
* we don't need to prevent any operation in the referencing table, so
10299-
* AccessShareLock suffices (assumes that dropping the constraint
10300-
* acquires AccessExclusiveLock).
10301-
*/
10302-
fkRel = table_open(constrForm->conrelid, AccessShareLock);
10302+
/* We need the same lock level that CreateTrigger will acquire */
10303+
fkRel = table_open(constrForm->conrelid, ShareRowExclusiveLock);
1030310304

1030410305
indexOid = constrForm->conindid;
1030510306
DeconstructFkConstraintRow(tuple,
@@ -18801,8 +18802,7 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
1880118802
foreach(cell, fks)
1880218803
{
1880318804
ForeignKeyCacheInfo *fk = lfirst(cell);
18804-
HeapTuplecontup,
18805-
parentConTup;
18805+
HeapTuplecontup;
1880618806
Form_pg_constraint conform;
1880718807
OidinsertTriggerOid,
1880818808
updateTriggerOid;
@@ -18820,13 +18820,6 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
1882018820
continue;
1882118821
}
1882218822

18823-
Assert(OidIsValid(conform->conparentid));
18824-
parentConTup = SearchSysCache1(CONSTROID,
18825-
ObjectIdGetDatum(conform->conparentid));
18826-
if (!HeapTupleIsValid(parentConTup))
18827-
elog(ERROR, "cache lookup failed for constraint %u",
18828-
conform->conparentid);
18829-
1883018823
/*
1883118824
* The constraint on this table must be marked no longer a child of
1883218825
* the parent's constraint, as do its check triggers.
@@ -18867,7 +18860,6 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
1886718860
Oidconffeqop[INDEX_MAX_KEYS];
1886818861
intnumfkdelsetcols;
1886918862
AttrNumberconfdelsetcols[INDEX_MAX_KEYS];
18870-
AttrMap *attmap;
1887118863
RelationrefdRel;
1887218864

1887318865
DeconstructFkConstraintRow(contup,
@@ -18900,20 +18892,19 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
1890018892
fkconstraint->old_pktable_oid = InvalidOid;
1890118893
fkconstraint->location = -1;
1890218894

18903-
attmap = build_attrmap_by_name(RelationGetDescr(partRel),
18904-
RelationGetDescr(rel),
18905-
false);
18895+
/* set up colnames, used to generate the constraint name */
1890618896
for (int i = 0; i < numfks; i++)
1890718897
{
1890818898
Form_pg_attribute att;
1890918899

1891018900
att = TupleDescAttr(RelationGetDescr(partRel),
18911-
attmap->attnums[conkey[i] - 1] - 1);
18901+
conkey[i] - 1);
18902+
1891218903
fkconstraint->fk_attrs = lappend(fkconstraint->fk_attrs,
1891318904
makeString(NameStr(att->attname)));
1891418905
}
1891518906

18916-
refdRel = table_open(fk->confrelid,AccessShareLock);
18907+
refdRel = table_open(fk->confrelid,ShareRowExclusiveLock);
1891718908

1891818909
addFkRecurseReferenced(fkconstraint, partRel,
1891918910
refdRel,
@@ -18929,11 +18920,10 @@ DetachPartitionFinalize(Relation rel, Relation partRel, bool concurrent,
1892918920
confdelsetcols,
1893018921
true,
1893118922
InvalidOid, InvalidOid);
18932-
table_close(refdRel,AccessShareLock);
18923+
table_close(refdRel,NoLock);/* keep lock till end of xact */
1893318924
}
1893418925

1893518926
ReleaseSysCache(contup);
18936-
ReleaseSysCache(parentConTup);
1893718927
}
1893818928
list_free_deep(fks);
1893918929
if (trigrel)

‎src/test/regress/expected/foreign_key.out‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2944,17 +2944,20 @@ CREATE SCHEMA fkpart12
29442944
CREATE TABLE fk_p ( id int, jd int, PRIMARY KEY(id, jd)) PARTITION BY list (id)
29452945
CREATE TABLE fk_p_1 PARTITION OF fk_p FOR VALUES IN (1) PARTITION BY list (jd)
29462946
CREATE TABLE fk_p_1_1 PARTITION OF fk_p_1 FOR VALUES IN (1)
2947-
CREATE TABLE fk_p_1_2PARTITION OF fk_p_1 FOR VALUES IN (2)
2947+
CREATE TABLE fk_p_1_2(x int, y int, jd int NOT NULL, id int NOT NULL)
29482948
CREATE TABLE fk_p_2 PARTITION OF fk_p FOR VALUES IN (2) PARTITION BY list (jd)
29492949
CREATE TABLE fk_p_2_1 PARTITION OF fk_p_2 FOR VALUES IN (1)
29502950
CREATE TABLE fk_p_2_2 PARTITION OF fk_p_2 FOR VALUES IN (2)
2951-
CREATE TABLE fk_r_1 (id intPRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL)
2951+
CREATE TABLE fk_r_1 (p_jd intNOT NULL, x int, id int PRIMARY KEY, p_id int NOT NULL)
29522952
CREATE TABLE fk_r_2 ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL) PARTITION BY list (id)
29532953
CREATE TABLE fk_r_2_1 PARTITION OF fk_r_2 FOR VALUES IN (2, 1)
29542954
CREATE TABLE fk_r ( id int PRIMARY KEY, p_id int NOT NULL, p_jd int NOT NULL,
29552955
FOREIGN KEY (p_id, p_jd) REFERENCES fk_p (id, jd)
29562956
) PARTITION BY list (id);
29572957
SET search_path TO fkpart12;
2958+
ALTER TABLE fk_p_1_2 DROP COLUMN x, DROP COLUMN y;
2959+
ALTER TABLE fk_p_1 ATTACH PARTITION fk_p_1_2 FOR VALUES IN (2);
2960+
ALTER TABLE fk_r_1 DROP COLUMN x;
29582961
INSERT INTO fk_p VALUES (1, 1);
29592962
ALTER TABLE fk_r ATTACH PARTITION fk_r_1 FOR VALUES IN (1);
29602963
ALTER TABLE fk_r ATTACH PARTITION fk_r_2 FOR VALUES IN (2);
@@ -2993,7 +2996,7 @@ Foreign-key constraints:
29932996
"fk_r_p_id_p_jd_fkey" FOREIGN KEY (p_id, p_jd) REFERENCES fk_p(id, jd)
29942997
Number of partitions: 1 (Use \d+ to list them.)
29952998

2996-
INSERT INTO fk_r_1 VALUES (2, 1, 2); -- should fail
2999+
INSERT INTO fk_r_1(id, p_id, p_jd)VALUES (2, 1, 2); -- should fail
29973000
ERROR: insert or update on table "fk_r_1" violates foreign key constraint "fk_r_p_id_p_jd_fkey"
29983001
DETAIL: Key (p_id, p_jd)=(1, 2) is not present in table "fk_p".
29993002
DELETE FROM fk_p; -- should fail

‎src/test/regress/sql/foreign_key.sql‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2097,18 +2097,22 @@ CREATE SCHEMA fkpart12
20972097
CREATETABLEfk_p ( idint, jdint,PRIMARY KEY(id, jd)) PARTITION BY list (id)
20982098
CREATETABLEfk_p_1 PARTITION OF fk_p FORVALUESIN (1) PARTITION BY list (jd)
20992099
CREATETABLEfk_p_1_1 PARTITION OF fk_p_1 FORVALUESIN (1)
2100-
CREATETABLEfk_p_1_2PARTITION OF fk_p_1 FORVALUESIN (2)
2100+
CREATETABLEfk_p_1_2(xint, yint, jdintNOT NULL, idintNOT NULL)
21012101
CREATETABLEfk_p_2 PARTITION OF fk_p FORVALUESIN (2) PARTITION BY list (jd)
21022102
CREATETABLEfk_p_2_1 PARTITION OF fk_p_2 FORVALUESIN (1)
21032103
CREATETABLEfk_p_2_2 PARTITION OF fk_p_2 FORVALUESIN (2)
2104-
CREATETABLEfk_r_1 (idintPRIMARY KEY, p_idintNOT NULL, p_jdintNOT NULL)
2104+
CREATETABLEfk_r_1 (p_jdintNOT NULL, xint, idintPRIMARY KEY, p_idintNOT NULL)
21052105
CREATETABLEfk_r_2 ( idintPRIMARY KEY, p_idintNOT NULL, p_jdintNOT NULL) PARTITION BY list (id)
21062106
CREATETABLEfk_r_2_1 PARTITION OF fk_r_2 FORVALUESIN (2,1)
21072107
CREATETABLEfk_r ( idintPRIMARY KEY, p_idintNOT NULL, p_jdintNOT NULL,
21082108
FOREIGN KEY (p_id, p_jd)REFERENCES fk_p (id, jd)
21092109
) PARTITION BY list (id);
21102110
SET search_path TO fkpart12;
21112111

2112+
ALTERTABLE fk_p_1_2 DROP COLUMN x, DROP COLUMN y;
2113+
ALTERTABLE fk_p_1 ATTACH PARTITION fk_p_1_2 FORVALUESIN (2);
2114+
ALTERTABLE fk_r_1 DROP COLUMN x;
2115+
21122116
INSERT INTO fk_pVALUES (1,1);
21132117

21142118
ALTERTABLE fk_r ATTACH PARTITION fk_r_1 FORVALUESIN (1);
@@ -2124,7 +2128,7 @@ ALTER TABLE fk_r DETACH PARTITION fk_r_2;
21242128

21252129
\d fk_r_2
21262130

2127-
INSERT INTO fk_r_1VALUES (2,1,2);-- should fail
2131+
INSERT INTO fk_r_1(id, p_id, p_jd)VALUES (2,1,2);-- should fail
21282132
DELETEFROM fk_p;-- should fail
21292133

21302134
ALTERTABLE fk_r ATTACH PARTITION fk_r_1 FORVALUESIN (1);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp