Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 76a39f2

Browse files
Fix nbtree high key "continuescan" row compare bug.
Commit 29b64d1 mishandled skipping over truncated high key attributes during row comparisons. The row comparison key matching loop would loop forever when a truncated attribute was encountered for a row compare subkey. Fix by following the example of other code in the loop: advance the current subkey, or break out of the loop when the last subkey is reached. Add test coverage for the relevant _bt_check_rowcompare() code path. The new test case is somewhat tied to nbtree implementation details, which isn't ideal, but seems unavoidable.
1 parent 8fba397 commit 76a39f2

File tree

3 files changed

+30
-2
lines changed

3 files changed

+30
-2
lines changed

src/backend/access/nbtree/nbtutils.c

+3
Original file line numberDiff line numberDiff line change
@@ -1543,6 +1543,9 @@ _bt_check_rowcompare(ScanKey skey, IndexTuple tuple, int tupnatts,
15431543
*/
15441544
Assert(ScanDirectionIsForward(dir));
15451545
cmpresult = 0;
1546+
if (subkey->sk_flags & SK_ROW_END)
1547+
break;
1548+
subkey++;
15461549
continue;
15471550
}
15481551

src/test/regress/expected/index_including.out

+20-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ DETAIL: Key (c1, c2)=(1, 2) already exists.
126126
INSERT INTO tbl SELECT 1, NULL, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
127127
ERROR: null value in column "c2" violates not-null constraint
128128
DETAIL: Failing row contains (1, null, 3, (4,4),(4,4)).
129-
INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,10) AS x;
129+
INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,300) AS x;
130130
explain (costs off)
131131
select * from tbl where (c1,c2,c3) < (2,5,1);
132132
QUERY PLAN
@@ -144,7 +144,26 @@ select * from tbl where (c1,c2,c3) < (2,5,1);
144144
2 | 4 | |
145145
(2 rows)
146146

147+
-- row comparison that compares high key at page boundary
148+
SET enable_seqscan = off;
149+
explain (costs off)
150+
select * from tbl where (c1,c2,c3) < (262,1,1) limit 1;
151+
QUERY PLAN
152+
----------------------------------------------------
153+
Limit
154+
-> Index Only Scan using covering on tbl
155+
Index Cond: (ROW(c1, c2) <= ROW(262, 1))
156+
Filter: (ROW(c1, c2, c3) < ROW(262, 1, 1))
157+
(4 rows)
158+
159+
select * from tbl where (c1,c2,c3) < (262,1,1) limit 1;
160+
c1 | c2 | c3 | c4
161+
----+----+----+----
162+
1 | 2 | |
163+
(1 row)
164+
147165
DROP TABLE tbl;
166+
RESET enable_seqscan;
148167
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
149168
UNIQUE(c1,c2) INCLUDE(c3,c4));
150169
SELECT indexrelid::regclass, indnatts, indnkeyatts, indisunique, indisprimary, indkey, indclass FROM pg_index WHERE indrelid = 'tbl'::regclass::oid;

src/test/regress/sql/index_including.sql

+7-1
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,17 @@ SELECT pg_get_constraintdef(oid), conname, conkey FROM pg_constraint WHERE conre
7272
-- ensure that constraint works
7373
INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
7474
INSERT INTO tbl SELECT 1, NULL, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
75-
INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,10) AS x;
75+
INSERT INTO tbl SELECT x, 2*x, NULL, NULL FROM generate_series(1,300) AS x;
7676
explain (costs off)
7777
select * from tbl where (c1,c2,c3) < (2,5,1);
7878
select * from tbl where (c1,c2,c3) < (2,5,1);
79+
-- row comparison that compares high key at page boundary
80+
SET enable_seqscan = off;
81+
explain (costs off)
82+
select * from tbl where (c1,c2,c3) < (262,1,1) limit 1;
83+
select * from tbl where (c1,c2,c3) < (262,1,1) limit 1;
7984
DROP TABLE tbl;
85+
RESET enable_seqscan;
8086

8187
CREATE TABLE tbl (c1 int,c2 int, c3 int, c4 box,
8288
UNIQUE(c1,c2) INCLUDE(c3,c4));

0 commit comments

Comments
 (0)