1
0
mirror of https://github.com/MariaDB/server.git synced 2026-10-23 18:49:29 +03:00

MDEV-38649: Wrong result for range w/o min endpoint, ORDER BY DESC

QUICK_SELECT_DESC::get_next() sets a stale end range on the storage engine.
When checking the first range, it sets last_range to the first range and
then, if it cannot avoid descending scan, it sets the minimum endpoint on
the storage engine.  However, get_next() may decide that this range is not
a match after updating the minimum endpoint on the storage engine.  In this
case, it will continue to the next range.  When continuing, it needs to
reset not only the state of 'last_range' to point to the next range that
it's checking, but it also needs to clear the now-stale end range set on
the storage engine.  While this explanation covers the first and second
ranges, the issue at hand extends to the general case of ranges 1...N-1 and N.

Before this change and when get_next() decided that a range was not a
match, it would clear last_range at each loop continuation point.
Rather than clearing the minimum endpoint on the storage engine at
each continuation, we move all loop cleanup to for loop update clause.
This consolidates any logic that needs to be evaluated on loop
continuation to one place and reduces code duplication.

MySQL fixed this same problem at sha b65ca959efd6ec5369165b1849407318b4886634
with a different implementation.
This commit is contained in:
Dave Gosselin
2026-02-19 09:16:15 -05:00
committed by Dave Gosselin
parent 768b6a2052
commit bbcd7defbb
3 changed files with 36 additions and 4 deletions

View File

@@ -4849,4 +4849,23 @@ ERROR 42S22: Unknown column '-5' in 'ORDER BY'
SELECT 1 FROM (select 1) dt order BY 50;
ERROR 42S22: Unknown column '50' in 'ORDER BY'
# End of 10.11 tests
#
# MDEV-38649: Wrong result (missing rows) upon condition pushdown on table with DESC key
#
CREATE TABLE t1 (a INT, b INT not null, KEY(b));
INSERT INTO t1 VALUES (2,8),(9,1),(4,6);
SELECT a, b FROM t1 WHERE b != 10 and b < 30 ORDER BY b DESC;
a b
2 8
4 6
9 1
SELECT a, b FROM t1 use index() WHERE b != 10 and b < 30 ORDER BY b DESC;
a b
2 8
4 6
9 1
DROP TABLE t1;
#
# End of 12.3 tests
#
ALTER DATABASE test CHARACTER SET utf8mb4 COLLATE utf8mb4_uca1400_ai_ci;

View File

@@ -2831,4 +2831,17 @@ SELECT 1 FROM (select 1) dt order BY 50;
--echo # End of 10.11 tests
--echo #
--echo # MDEV-38649: Wrong result (missing rows) upon condition pushdown on table with DESC key
--echo #
CREATE TABLE t1 (a INT, b INT not null, KEY(b));
INSERT INTO t1 VALUES (2,8),(9,1),(4,6);
SELECT a, b FROM t1 WHERE b != 10 and b < 30 ORDER BY b DESC;
SELECT a, b FROM t1 use index() WHERE b != 10 and b < 30 ORDER BY b DESC;
DROP TABLE t1;
--echo #
--echo # End of 12.3 tests
--echo #
--source include/test_db_charset_restore.inc

View File

@@ -13912,7 +13912,7 @@ int QUICK_SELECT_DESC::get_next()
* step back once, and move backwards
*/
for (;;)
for (;; last_range= nullptr, file->set_end_range(nullptr))
{
int result;
if (last_range)
@@ -13961,7 +13961,7 @@ int QUICK_SELECT_DESC::get_next()
DBUG_RETURN(local_error); // Empty table
if (cmp_prev(last_range) == 0)
DBUG_RETURN(0);
last_range= 0; // No match; go to next range
// No match; go to next range
continue;
}
@@ -13997,7 +13997,7 @@ int QUICK_SELECT_DESC::get_next()
{
if (result != HA_ERR_KEY_NOT_FOUND && result != HA_ERR_END_OF_FILE)
DBUG_RETURN(result);
last_range= 0; // Not found, to next range
// Not found, to next range
continue;
}
if (cmp_prev(last_range) == 0)
@@ -14006,7 +14006,7 @@ int QUICK_SELECT_DESC::get_next()
last_range= 0; // Stop searching
DBUG_RETURN(0); // Found key is in range
}
last_range= 0; // To next range
// To next range
}
}