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:
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user