Skip to content

Commit c2a7044

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 6520d4a commit c2a7044

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
@@ -1638,15 +1638,15 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
16381638
*/
16391639
if (old_attno < newnatts &&
16401640
(att = new_tupdesc->attrs[old_attno]) != NULL &&
1641-
!att->attisdropped && att->attinhcount != 0 &&
1641+
!att->attisdropped &&
16421642
strcmp(attname, NameStr(att->attname)) == 0)
16431643
new_attno = old_attno;
16441644
else
16451645
{
16461646
for (new_attno = 0; new_attno < newnatts; new_attno++)
16471647
{
16481648
att = new_tupdesc->attrs[new_attno];
1649-
if (!att->attisdropped && att->attinhcount != 0 &&
1649+
if (!att->attisdropped &&
16501650
strcmp(attname, NameStr(att->attname)) == 0)
16511651
break;
16521652
}
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
@@ -56,6 +56,7 @@ test: multiple-cic
5656
test: alter-table-1
5757
test: alter-table-2
5858
test: alter-table-3
59+
test: alter-table-4
5960
test: create-trigger
6061
test: async-notify
6162
test: vacuum-reltuples
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