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

MDEV-39644 Wrong result with ICP in reverse ordered partition scans

Ordered partition scans keep one row per partition in queue buffers.
However, pushed index conditions use Field objects bound to
table->record[0]. Reading directly into a queue buffer can therefore
evaluate the condition against a different row and skip matching rows.

Route ha_index_last() and ha_index_prev() through read_with_icp(), as
already done for forward ordered reads. With ICP, read into
table->record[0] and copy the row to the queue buffer only on success.
Preserve the queue buffer when a read returns EOF or another error.

Full forward index scans do not use ICP. Assert this invariant before
calling ha_index_first() directly. Add a minimal MyISAM regression with
matching and rejected rows in two partitions.

Bug report: https://jira.mariadb.org/browse/MDEV-39644
This commit is contained in:
DerZc
2026-09-28 14:18:20 +08:00
committed by Sergei Petrunia
parent 9a1123dc45
commit 5a3a6b5582
3 changed files with 38 additions and 3 deletions

View File

@@ -796,3 +796,13 @@ a b
2 2
3 3
drop table t1;
# MDEV-39644 Evaluate ICP on the current row in reverse partition scans
CREATE TABLE t1 (c1 INT,c2 INT,c3 INT,KEY k(c2,c3))
ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 2;
INSERT INTO t1 VALUES (1,4,1),(2,3,1),(3,2,0),(4,1,1);
SELECT * FROM t1 WHERE c2>=1 AND c3=1 ORDER BY c2 DESC;
c1 c2 c3
1 4 1
2 3 1
4 1 1
DROP TABLE t1;

View File

@@ -846,3 +846,9 @@ insert into t1 values (1,1),(2,2),(3,3),(4,4),(5,5),(6,6);
explain select * from t1 order by a limit 3;
select * from t1 order by a limit 3;
drop table t1;
--echo # MDEV-39644 Evaluate ICP on the current row in reverse partition scans
CREATE TABLE t1 (c1 INT,c2 INT,c3 INT,KEY k(c2,c3))
ENGINE=MyISAM PARTITION BY HASH(c1) PARTITIONS 2;
INSERT INTO t1 VALUES (1,4,1),(2,3,1),(3,2,0),(4,1,1);
SELECT * FROM t1 WHERE c2>=1 AND c3=1 ORDER BY c2 DESC;
DROP TABLE t1;

View File

@@ -104,7 +104,8 @@ static int read_with_icp(TABLE* table,
return func(record_buf);
int error= func(table->record[0]);
memcpy(record_buf, table->record[0], record_buf_len);
if (likely(!error))
memcpy(record_buf, table->record[0], record_buf_len);
return error;
}
@@ -8208,11 +8209,22 @@ int ha_partition::handle_ordered_index_scan(uchar *buf, bool reverse_order)
/* Caller has specified reverse_order */
break;
case partition_index_first:
/*
We don't call read_with_icp() here as full index scans are not done
with ICP.
*/
DBUG_ASSERT(!pushed_idx_cond);
error= file->ha_index_first(rec_buf_ptr);
reverse_order= FALSE;
break;
case partition_index_last:
error= file->ha_index_last(rec_buf_ptr);
error= read_with_icp(table,
pushed_idx_cond != nullptr,
rec_buf_ptr,
m_rec_length,
[file] (uchar* read_buf) {
return file->ha_index_last(read_buf);
});
reverse_order= TRUE;
break;
case partition_read_range:
@@ -8738,7 +8750,14 @@ int ha_partition::handle_ordered_prev(uchar *buf)
uchar *rec_buf= queue_top(&m_queue) + ORDERED_REC_OFFSET;
handler *file= m_file[part_id];
if (unlikely((error= file->ha_index_prev(rec_buf))))
error= read_with_icp(table,
pushed_idx_cond != nullptr,
rec_buf,
m_rec_length,
[file] (uchar* read_buf) {
return file->ha_index_prev(read_buf);
});
if (unlikely(error))
{
if (error == HA_ERR_END_OF_FILE && m_queue.elements)
{