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