Skip to content

Commit

Permalink
Bug#35854362 - Incorrect results when using group by loose
Browse files Browse the repository at this point in the history
               index scan

Description:
- Indexes are ordered based on their keys. Loose
  index scan effectively jumps from one unique value
  (or set of values) to the next based on the index’s prefix
  keys.

- To “jump” values in an index, we use the handler
  call: ha_index_read_map().

- the first range read sets an end-of-range
  value to indicate the end of the first range.

- The next range read does not clear the previous end-of-range value
  and applies it to the current range.

- Since the end-of-range value has already been crossed in the
  previous range read, this causes the reads to stop. So the
  iteration is finished with the current range without moving
  onto the next range(unique set of values)resulting in an
  incorrect query result.

Fix:
- In order to find the next unique value, the old end-of-range
  value is cleared.

Change-Id: I84290fb794db13ec6f0795dd14a92cf85b9dad09
  • Loading branch information
Ayush Gupta committed Feb 21, 2024
1 parent 6a5a4a5 commit c7e824d
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 0 deletions.
75 changes: 75 additions & 0 deletions mysql-test/r/select_distinct_debug.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#
# Bug #35854362: INCORRECT RESULTS WHEN USING GROUP BY LOOSE
# INDEX SCAN
#
CREATE TABLE t1 (
a1 CHAR(64),
a2 CHAR(64),
b CHAR(16),
c CHAR(16) NOT NULL,
d CHAR(16),
dummy CHAR(248) DEFAULT ' '
);
INSERT INTO t1 (a1, a2, b, c, d) VALUES
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');
CREATE INDEX idx_t1_0 ON t1 (a1);
CREATE INDEX idx_t1_1 ON t1 (a1,a2,b,c);
CREATE INDEX idx_t1_2 on t1 (a1,a2,b);
SET SESSION DEBUG="+d,force_lis_for_group_by";
INSERT INTO t1 (
WITH RECURSIVE a (i) AS (
SELECT 0
UNION ALL
SELECT i+1 FROM a where i < 9
),
b (i) AS (
SELECT x.i + y.i * 10 + z.i * 100
FROM a x, a y, a z
)
SELECT 'b','a','a','a211','xy1','' FROM b
);
SELECT @@innodb_purge_stop_now INTO @old_val;
SET GLOBAL innodb_purge_stop_now = 1;
DELETE FROM t1 WHERE a1 = 'b';
SELECT DISTINCT a1
FROM t1
WHERE a1 IN ('a', 'd')
AND a2 = 'b';
a1
a
d
SET SESSION DEBUG="-d,force_lis_for_group_by";
SET GLOBAL innodb_purge_stop_now = @old_val;
SET GLOBAL innodb_purge_run_now=1;
DROP TABLE t1;
84 changes: 84 additions & 0 deletions mysql-test/t/select_distinct_debug.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# for innodb_purge_stop_now=ON
--source include/have_debug.inc

--echo #
--echo # Bug #35854362: INCORRECT RESULTS WHEN USING GROUP BY LOOSE
--echo # INDEX SCAN
--echo #

CREATE TABLE t1 (
a1 CHAR(64),
a2 CHAR(64),
b CHAR(16),
c CHAR(16) NOT NULL,
d CHAR(16),
dummy CHAR(248) DEFAULT ' '
);

INSERT INTO t1 (a1, a2, b, c, d) VALUES
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4'),
('a','a','a','a111','xy1'),('a','a','a','b111','xy2'),('a','a','a','c111','xy3'),('a','a','a','d111','xy4'),
('a','a','b','e112','xy1'),('a','a','b','f112','xy2'),('a','a','b','g112','xy3'),('a','a','b','h112','xy4'),
('a','b','a','i121','xy1'),('a','b','a','j121','xy2'),('a','b','a','k121','xy3'),('a','b','a','l121','xy4'),
('a','b','b','m122','xy1'),('a','b','b','n122','xy2'),('a','b','b','o122','xy3'),('a','b','b','p122','xy4'),
('b','a','a','a211','xy1'),('b','a','a','b211','xy2'),('b','a','a','c211','xy3'),('b','a','a','d211','xy4'),
('b','a','b','e212','xy1'),('b','a','b','f212','xy2'),('b','a','b','g212','xy3'),('b','a','b','h212','xy4'),
('b','b','a','i221','xy1'),('b','b','a','j221','xy2'),('b','b','a','k221','xy3'),('b','b','a','l221','xy4'),
('b','b','b','m222','xy1'),('b','b','b','n222','xy2'),('b','b','b','o222','xy3'),('b','b','b','p222','xy4'),
('c','a','a','a311','xy1'),('c','a','a','b311','xy2'),('c','a','a','c311','xy3'),('c','a','a','d311','xy4'),
('c','a','b','e312','xy1'),('c','a','b','f312','xy2'),('c','a','b','g312','xy3'),('c','a','b','h312','xy4'),
('c','b','a','i321','xy1'),('c','b','a','j321','xy2'),('c','b','a','k321','xy3'),('c','b','a','l321','xy4'),
('c','b','b','m322','xy1'),('c','b','b','n322','xy2'),('c','b','b','o322','xy3'),('c','b','b','p322','xy4'),
('d','a','a','a411','xy1'),('d','a','a','b411','xy2'),('d','a','a','c411','xy3'),('d','a','a','d411','xy4'),
('d','a','b','e412','xy1'),('d','a','b','f412','xy2'),('d','a','b','g412','xy3'),('d','a','b','h412','xy4'),
('d','b','a','i421','xy1'),('d','b','a','j421','xy2'),('d','b','a','k421','xy3'),('d','b','a','l421','xy4'),
('d','b','b','m422','xy1'),('d','b','b','n422','xy2'),('d','b','b','o422','xy3'),('d','b','b','p422','xy4');

CREATE INDEX idx_t1_0 ON t1 (a1);
CREATE INDEX idx_t1_1 ON t1 (a1,a2,b,c);
CREATE INDEX idx_t1_2 on t1 (a1,a2,b);
SET SESSION DEBUG="+d,force_lis_for_group_by";

INSERT INTO t1 (
WITH RECURSIVE a (i) AS (
SELECT 0
UNION ALL
SELECT i+1 FROM a where i < 9
),
b (i) AS (
SELECT x.i + y.i * 10 + z.i * 100
FROM a x, a y, a z
)
SELECT 'b','a','a','a211','xy1','' FROM b
);

SELECT @@innodb_purge_stop_now INTO @old_val;
SET GLOBAL innodb_purge_stop_now = 1;

DELETE FROM t1 WHERE a1 = 'b';

SELECT DISTINCT a1
FROM t1
WHERE a1 IN ('a', 'd')
AND a2 = 'b';

SET SESSION DEBUG="-d,force_lis_for_group_by";
SET GLOBAL innodb_purge_stop_now = @old_val;
SET GLOBAL innodb_purge_run_now=1;

DROP TABLE t1;
1 change: 1 addition & 0 deletions sql/range_optimizer/group_index_skip_scan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ int GroupIndexSkipScanIterator::get_next_prefix(uint prefix_length,
if (last_prefix_range != nullptr) {
/* Read the next record in the same range with prefix after cur_prefix. */
assert(cur_prefix != nullptr);
table()->file->set_end_range(nullptr, handler::RANGE_SCAN_ASC);
int result = table()->file->ha_index_read_map(
table()->record[0], cur_prefix, keypart_map, HA_READ_AFTER_KEY);
if (result || last_prefix_range->max_keypart_map == 0) return result;
Expand Down

0 comments on commit c7e824d

Please sign in to comment.