summaryrefslogtreecommitdiff
path: root/sql/sql_window.cc
diff options
context:
space:
mode:
authorVicențiu Ciorbaru <vicentiu@mariadb.org>2017-02-14 18:31:30 +0200
committerVicențiu Ciorbaru <vicentiu@mariadb.org>2017-02-15 14:09:27 +0200
commitd4746422547f1901831f9c891a3600275daf6534 (patch)
tree81a0b2e136358f2f0f153394196f641c6a03000a /sql/sql_window.cc
parent9fe9fb68acd763ad3908c03d82d4de577d6f0c21 (diff)
downloadmariadb-git-d4746422547f1901831f9c891a3600275daf6534.tar.gz
MDEV-10092: Server crashes in in ha_heap::rnd_pos / Table_read_cursor::get_next
The bug was caused by several issues. 2 problems in seek_io_cache. Due to wrong offsets used, we would end up seeking way too much (first change), or over the intended seek point (second change). Fixing it requires correctly detecting available data in buffer (first change), and not using "IO_SIZE alligned" reads. The second is needed because _my_b_cache_read adjusts the pos_in_file itself based on read_pos and read_end. Pretending buffer is empty when we want to force a read will aleviate this problem. Secondly, the big-table cursors didn't repect the interface definitions of always returning the rownumber that Table_read_cursor::fetch() would activate. At the same time, next(), prev() and move_to() should not perform any row activation.
Diffstat (limited to 'sql/sql_window.cc')
-rw-r--r--sql/sql_window.cc59
1 files changed, 35 insertions, 24 deletions
diff --git a/sql/sql_window.cc b/sql/sql_window.cc
index 2bdac89f293..eb06824402d 100644
--- a/sql/sql_window.cc
+++ b/sql/sql_window.cc
@@ -632,9 +632,10 @@ private:
/* If io_cache=!NULL, use it */
IO_CACHE *io_cache;
uchar *ref_buffer; /* Buffer for the last returned rowid */
- uint rownum; /* Number of the rowid that is about to be returned */
- bool cache_eof; /* whether we've reached EOF */
-
+ ha_rows rownum; /* Number of the rowid that is about to be returned */
+ ha_rows current_ref_buffer_rownum;
+ bool ref_buffer_valid;
+
/* The following are used when we are reading from an array of pointers */
uchar *cache_start;
uchar *cache_pos;
@@ -655,34 +656,26 @@ public:
{
//DBUG_ASSERT(info->read_record == rr_from_tempfile);
rownum= 0;
- cache_eof= false;
io_cache= (IO_CACHE*)my_malloc(sizeof(IO_CACHE), MYF(0));
init_slave_io_cache(info->io_cache, io_cache);
ref_buffer= (uchar*)my_malloc(ref_length, MYF(0));
+ ref_buffer_valid= false;
}
}
virtual int next()
{
+ /* Allow multiple next() calls in EOF state. */
+ if (at_eof())
+ return -1;
+
if (io_cache)
{
- if (cache_eof)
- return 1;
-
- if (my_b_read(io_cache,ref_buffer,ref_length))
- {
- cache_eof= 1; // TODO: remove cache_eof
- return -1;
- }
rownum++;
- return 0;
}
else
{
- /* Allow multiple next() calls in EOF state. */
- if (cache_pos == cache_end)
- return -1;
cache_pos+= ref_length;
DBUG_ASSERT(cache_pos <= cache_end);
}
@@ -696,7 +689,7 @@ public:
if (rownum == 0)
return -1;
- move_to(rownum - 1);
+ rownum--;
return 0;
}
else
@@ -722,9 +715,7 @@ public:
{
if (io_cache)
{
- seek_io_cache(io_cache, row_number * ref_length);
rownum= row_number;
- Rowid_seq_cursor::next();
}
else
{
@@ -738,18 +729,36 @@ protected:
{
if (io_cache)
{
- return cache_eof;
+ return rownum * ref_length >= io_cache->end_of_file;
}
else
return (cache_pos == cache_end);
}
- uchar *get_curr_rowid()
+ bool get_curr_rowid(uchar **row_id)
{
if (io_cache)
- return ref_buffer;
+ {
+ DBUG_ASSERT(!at_eof());
+ if (!ref_buffer_valid || current_ref_buffer_rownum != rownum)
+ {
+ seek_io_cache(io_cache, rownum * ref_length);
+ if (my_b_read(io_cache,ref_buffer,ref_length))
+ {
+ /* Error reading from file. */
+ return true;
+ }
+ ref_buffer_valid= true;
+ current_ref_buffer_rownum = rownum;
+ }
+ *row_id = ref_buffer;
+ return false;
+ }
else
- return cache_pos;
+ {
+ *row_id= cache_pos;
+ return false;
+ }
}
};
@@ -775,7 +784,9 @@ public:
if (at_eof())
return -1;
- uchar* curr_rowid= get_curr_rowid();
+ uchar* curr_rowid;
+ if (get_curr_rowid(&curr_rowid))
+ return -1;
return table->file->ha_rnd_pos(record, curr_rowid);
}