1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
# In the past we supported index-only bitmap heapscans. However the
# implementation was unsound, see
# https://postgr.es/m/873c33c5-ef9e-41f6-80b2-2f5e11869f1c%40garret.ru
#
# This test reliably triggered the problem before we removed the
# optimization. We keep the test around to make it less likely for a similar
# problem to be re-introduced.
setup
{
-- by using a low fillfactor and a wide tuple we can get multiple blocks
-- with just few rows
CREATE TABLE ios_bitmap (a int NOT NULL, b int not null, pad char(1024) default '')
WITH (AUTOVACUUM_ENABLED = false, FILLFACTOR = 10);
INSERT INTO ios_bitmap SELECT g.i, g.i FROM generate_series(1, 10) g(i);
CREATE INDEX ios_bitmap_a ON ios_bitmap(a);
CREATE INDEX ios_bitmap_b ON ios_bitmap(b);
}
teardown
{
DROP TABLE ios_bitmap;
}
session s1
setup
{
SET enable_seqscan = false;
}
step s1_begin { BEGIN; }
step s1_commit { COMMIT; }
# The test query uses an or between two indexes to ensure make it more likely
# to use a bitmap index scan
#
# The row_number() hack is a way to have something returned (isolationtester
# doesn't display empty rows) while still allowing for the index-only scan
# optimization in bitmap heap scans, which requires an empty targetlist.
step s1_prepare
{
DECLARE foo NO SCROLL CURSOR FOR SELECT row_number() OVER () FROM ios_bitmap WHERE a > 0 or b > 0;
}
step s1_explain
{
EXPlAIN (COSTS OFF) DECLARE foo NO SCROLL CURSOR FOR SELECT row_number() OVER () FROM ios_bitmap WHERE a > 0 or b > 0;
}
step s1_fetch_1
{
FETCH FROM foo;
}
step s1_fetch_all
{
FETCH ALL FROM foo;
}
session s2
# Don't delete row 1 so we have a row for the cursor to "rest" on.
step s2_mod
{
DELETE FROM ios_bitmap WHERE a > 1;
}
# Disable truncation, as otherwise we'll just wait for a timeout while trying
# to acquire the lock
step s2_vacuum
{
VACUUM (TRUNCATE false) ios_bitmap;
}
permutation
# Vacuum first, to ensure VM exists, otherwise the bitmapscan will consider
# VM to be size 0, due to caching. Can't do that in setup because
s2_vacuum
# Delete nearly all rows, to make issue visible
s2_mod
# Verify that the appropriate plan is chosen
s1_explain
# Create a cursor
s1_begin
s1_prepare
# Fetch one row from the cursor, that ensures the index scan portion is done
# before the vacuum in the next step
s1_fetch_1
# With the bug this vacuum would have marked pages as all-visible that the
# scan in the next step then would have considered all-visible, despite all
# rows from those pages having been removed.
s2_vacuum
# If this returns any rows, the bug is present
s1_fetch_all
s1_commit
|