Commit b94e8e4b authored by Varun Gupta's avatar Varun Gupta

MDEV-23867: insert... select crash in compute_window_func

There are 2 issues here:

Issue #1: memory allocation.
An IO_CACHE that uses encryption uses a larger buffer (it needs space for the encrypted data,
decrypted data, IO_CACHE_CRYPT struct to describe encryption parameters etc).

Issue #2: IO_CACHE::seek_not_done
When IO_CACHE objects are cloned, they still share the file descriptor.
This means, operation on one IO_CACHE may change the file read position
which will confuse other IO_CACHEs using it.

The fix of these issues would be:
Allocate the buffer to also include the extra size needed for encryption.
Perform seek again after one IO_CACHE reads the file.
parent 5a9df155
...@@ -476,18 +476,19 @@ typedef struct st_io_cache /* Used when cacheing files */ ...@@ -476,18 +476,19 @@ typedef struct st_io_cache /* Used when cacheing files */
partial. partial.
*/ */
int seek_not_done,error; int seek_not_done,error;
/* buffer_length is memory size allocated for buffer or write_buffer */ /* length of the buffer used for storing un-encrypted data */
size_t buffer_length; size_t buffer_length;
/* read_length is the same as buffer_length except when we use async io */ /* read_length is the same as buffer_length except when we use async io */
size_t read_length; size_t read_length;
myf myflags; /* Flags used to my_read/my_write */ myf myflags; /* Flags used to my_read/my_write */
/* /*
alloced_buffer is 1 if the buffer was allocated by init_io_cache() and alloced_buffer is set to the size of the buffer allocated for the IO_CACHE.
0 if it was supplied by the user. Includes the overhead(storing key to ecnrypt and decrypt) for encryption.
Set to 0 if nothing is allocated.
Currently READ_NET is the only one that will use a buffer allocated Currently READ_NET is the only one that will use a buffer allocated
somewhere else somewhere else
*/ */
my_bool alloced_buffer; size_t alloced_buffer;
#ifdef HAVE_AIOWAIT #ifdef HAVE_AIOWAIT
/* /*
As inidicated by ifdef, this is for async I/O, which is not currently As inidicated by ifdef, this is for async I/O, which is not currently
......
This diff is collapsed.
--echo #
--echo # Tests when the temporary files are encrypted
--echo #
source include/have_file_key_management_plugin.inc;
source include/have_sequence.inc;
source include/have_innodb.inc;
select @@encrypt_tmp_files;
--source t/win.test
--echo #
--echo # MDEV-23867: select crash in compute_window_func
--echo #
set @save_sort_buffer_size=@@sort_buffer_size;
set sort_buffer_size= 2000;
CREATE TABLE t1( a INT, b INT, c INT);
INSERT INTO t1 select seq, seq, seq from seq_1_to_5000;
CREATE TABLE t2( a INT, b INT, c INT);
INSERT INTO t2 SELECT a, b, ROW_NUMBER() OVER (PARTITION BY b) FROM t1;
SELECT COUNT(*), MAX(c) FROM t2;
CREATE TABLE t3( a INT, b INT, c INT);
INSERT INTO t3 SELECT a, b, SUM(a) OVER () FROM t1;
SELECT COUNT(*), MAX(c) FROM t3;
set @@sort_buffer_size=@save_sort_buffer_size;
DROP TABLE t1,t2,t3;
--echo # end of 10.2 test
...@@ -250,7 +250,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize, ...@@ -250,7 +250,7 @@ int init_io_cache(IO_CACHE *info, File file, size_t cachesize,
info->write_buffer= info->buffer + cachesize; info->write_buffer= info->buffer + cachesize;
else else
info->write_buffer= info->buffer; info->write_buffer= info->buffer;
info->alloced_buffer= 1; info->alloced_buffer= buffer_block;
break; /* Enough memory found */ break; /* Enough memory found */
} }
if (cachesize == min_cache) if (cachesize == min_cache)
...@@ -324,14 +324,14 @@ int init_slave_io_cache(IO_CACHE *master, IO_CACHE *slave) ...@@ -324,14 +324,14 @@ int init_slave_io_cache(IO_CACHE *master, IO_CACHE *slave)
DBUG_ASSERT(!master->share); DBUG_ASSERT(!master->share);
DBUG_ASSERT(master->alloced_buffer); DBUG_ASSERT(master->alloced_buffer);
if (!(slave_buf= (uchar*)my_malloc(master->buffer_length, MYF(0)))) if (!(slave_buf= (uchar*)my_malloc(master->alloced_buffer, MYF(0))))
{ {
return 1; return 1;
} }
memcpy(slave, master, sizeof(IO_CACHE)); memcpy(slave, master, sizeof(IO_CACHE));
slave->buffer= slave_buf; slave->buffer= slave_buf;
memcpy(slave->buffer, master->buffer, master->buffer_length); memcpy(slave->buffer, master->buffer, master->alloced_buffer);
slave->read_pos= slave->buffer + (master->read_pos - master->buffer); slave->read_pos= slave->buffer + (master->read_pos - master->buffer);
slave->read_end= slave->buffer + (master->read_end - master->buffer); slave->read_end= slave->buffer + (master->read_end - master->buffer);
......
...@@ -71,6 +71,16 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count) ...@@ -71,6 +71,16 @@ static int my_b_encr_read(IO_CACHE *info, uchar *Buffer, size_t Count)
DBUG_RETURN(1); DBUG_RETURN(1);
} }
info->seek_not_done= 0; info->seek_not_done= 0;
if (info->next_file_user)
{
IO_CACHE *c;
for (c= info->next_file_user;
c!= info;
c= c->next_file_user)
{
c->seek_not_done= 1;
}
}
} }
do do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment