Skip to content

Commit 8b0e5e7

Browse files
committed
Avoid unnecessary failure in SELECT concurrent with ALTER NO INHERIT.
If a query against an inheritance tree runs concurrently with an ALTER TABLE that's disinheriting one of the tree members, it's possible to get a "could not find inherited attribute" error because after obtaining lock on the removed member, make_inh_translation_list sees that its columns have attinhcount=0 and decides they aren't the columns it's looking for. An ideal fix, perhaps, would avoid including such a just-removed member table in the query at all; but there seems no way to accomplish that without adding expensive catalog rechecks or creating a likelihood of deadlocks. Instead, let's just drop the check on attinhcount. In this way, a query that's included a just-disinherited child will still succeed, which is not a completely unreasonable behavior. This problem has existed for a long time, so back-patch to all supported branches. Also add an isolation test verifying related behaviors. Patch by me; the new isolation test is based on Kyotaro Horiguchi's work. Discussion: https://postgr.es/m/20170626.174612.23936762.horiguchi.kyotaro@lab.ntt.co.jp
1 parent 493cdc8 commit 8b0e5e7

File tree

4 files changed

+97
-2
lines changed

4 files changed

+97
-2
lines changed

src/backend/optimizer/prep/prepunion.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,15 +1486,15 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
14861486
*/
14871487
if (old_attno < newnatts &&
14881488
(att = new_tupdesc->attrs[old_attno]) != NULL &&
1489-
!att->attisdropped && att->attinhcount != 0 &&
1489+
!att->attisdropped &&
14901490
strcmp(attname, NameStr(att->attname)) == 0)
14911491
new_attno = old_attno;
14921492
else
14931493
{
14941494
for (new_attno = 0; new_attno < newnatts; new_attno++)
14951495
{
14961496
att = new_tupdesc->attrs[new_attno];
1497-
if (!att->attisdropped && att->attinhcount != 0 &&
1497+
if (!att->attisdropped &&
14981498
strcmp(attname, NameStr(att->attname)) == 0)
14991499
break;
15001500
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
Parsed test spec with 2 sessions
2+
3+
starting permutation: s1b s1delc1 s2sel s1c s2sel
4+
step s1b: BEGIN;
5+
step s1delc1: ALTER TABLE c1 NO INHERIT p;
6+
step s2sel: SELECT SUM(a) FROM p; <waiting ...>
7+
step s1c: COMMIT;
8+
step s2sel: <... completed>
9+
sum
10+
11+
11
12+
step s2sel: SELECT SUM(a) FROM p;
13+
sum
14+
15+
1
16+
17+
starting permutation: s1b s1delc1 s1addc2 s2sel s1c s2sel
18+
step s1b: BEGIN;
19+
step s1delc1: ALTER TABLE c1 NO INHERIT p;
20+
step s1addc2: ALTER TABLE c2 INHERIT p;
21+
step s2sel: SELECT SUM(a) FROM p; <waiting ...>
22+
step s1c: COMMIT;
23+
step s2sel: <... completed>
24+
sum
25+
26+
11
27+
step s2sel: SELECT SUM(a) FROM p;
28+
sum
29+
30+
101
31+
32+
starting permutation: s1b s1dropc1 s2sel s1c s2sel
33+
step s1b: BEGIN;
34+
step s1dropc1: DROP TABLE c1;
35+
step s2sel: SELECT SUM(a) FROM p; <waiting ...>
36+
step s1c: COMMIT;
37+
step s2sel: <... completed>
38+
sum
39+
40+
1
41+
step s2sel: SELECT SUM(a) FROM p;
42+
sum
43+
44+
1
45+
46+
starting permutation: s1b s1delc1 s1modc1a s2sel s1c s2sel
47+
step s1b: BEGIN;
48+
step s1delc1: ALTER TABLE c1 NO INHERIT p;
49+
step s1modc1a: ALTER TABLE c1 ALTER COLUMN a TYPE float;
50+
step s2sel: SELECT SUM(a) FROM p; <waiting ...>
51+
step s1c: COMMIT;
52+
step s2sel: <... completed>
53+
error in steps s1c s2sel: ERROR: attribute "a" of relation "c1" does not match parent's type
54+
step s2sel: SELECT SUM(a) FROM p;
55+
sum
56+
57+
1

src/test/isolation/isolation_schedule

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,5 @@ test: nowait-5
3939
test: drop-index-concurrently-1
4040
test: multiple-cic
4141
test: alter-table-1
42+
test: alter-table-4
4243
test: timeouts
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# ALTER TABLE - Add and remove inheritance with concurrent reads
2+
3+
setup
4+
{
5+
CREATE TABLE p (a integer);
6+
INSERT INTO p VALUES(1);
7+
CREATE TABLE c1 () INHERITS (p);
8+
INSERT INTO c1 VALUES(10);
9+
CREATE TABLE c2 (a integer);
10+
INSERT INTO c2 VALUES(100);
11+
}
12+
13+
teardown
14+
{
15+
DROP TABLE IF EXISTS c1, c2, p;
16+
}
17+
18+
session "s1"
19+
step "s1b" { BEGIN; }
20+
step "s1delc1" { ALTER TABLE c1 NO INHERIT p; }
21+
step "s1modc1a" { ALTER TABLE c1 ALTER COLUMN a TYPE float; }
22+
step "s1addc2" { ALTER TABLE c2 INHERIT p; }
23+
step "s1dropc1" { DROP TABLE c1; }
24+
step "s1c" { COMMIT; }
25+
26+
session "s2"
27+
step "s2sel" { SELECT SUM(a) FROM p; }
28+
29+
# NO INHERIT will not be visible to concurrent select,
30+
# since we identify children before locking them
31+
permutation "s1b" "s1delc1" "s2sel" "s1c" "s2sel"
32+
# adding inheritance likewise is not seen if s1 commits after s2 locks p
33+
permutation "s1b" "s1delc1" "s1addc2" "s2sel" "s1c" "s2sel"
34+
# but we do cope with DROP on a child table
35+
permutation "s1b" "s1dropc1" "s2sel" "s1c" "s2sel"
36+
# this case currently results in an error; doesn't seem worth preventing
37+
permutation "s1b" "s1delc1" "s1modc1a" "s2sel" "s1c" "s2sel"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy