mirror of
https://github.com/MariaDB/server.git
synced 2026-05-15 19:37:16 +02:00
Fix for bug#41486: extra character appears in BLOB for every
~40Mb after mysqldump/import
When the input string exceeds the maximum allowed size for the
internal buffer, batch_readline() returns a truncated string.
Since there was no way for a caller to determine whether the
string was truncated or not, the command line client assumed
batch_readline() to always return the whole input string and
appended a newline character. This resulted in garbled data
when importing dumps containing strings longer than the
maximum input buffer size.
Fixed by adding a flag to the batch_readline() interface to
signal a truncated string to the caller.
Other minor problems fixed during patch implementation:
- The maximum allowed buffer size for batch_readline() was set
up depending on the client's max_allowed_packet value. It does
not actully make any sense, as those variables are not
related. The input buffer size limit is now always set to 1
MB.
- fill_buffer() did not always set the EOF flag.
- The input buffer could actually grow twice as the specified
limit due to insufficient checks in intern_read_line().
client/my_readline.h:
Changed the interface of batch_readline().
client/mysql.cc:
Honor the truncated flag returned by batch_readline() and do
not append the newline character if it was set. Since we can't
change the interfaces for readline()/fgets() used in the
interactive mode, always assume the returned string was not
truncated. In addition, always set the batch_readline()
internal buffer to 1 MB, independently from the client's
max_allowed_packet.
client/readline.cc:
Added the 'truncated' argument do batch_readline() to signal
truncated string to a caller.
Fixed fill_buffer() to set the EOF flag correctly.
Fixed checks in intern_read_line() to not allow the internal
buffer grow past the specified limit.
mysql-test/r/mysql.result:
Added a test case for bug #41486.
mysql-test/t/mysql.test:
Added a test case for bug #41486.
This commit is contained in:
parent
5d2fc53354
commit
73a7d99331
5 changed files with 86 additions and 22 deletions
|
|
@ -24,7 +24,7 @@ static bool init_line_buffer(LINE_BUFFER *buffer,File file,ulong size,
|
|||
ulong max_size);
|
||||
static bool init_line_buffer_from_string(LINE_BUFFER *buffer,my_string str);
|
||||
static uint fill_buffer(LINE_BUFFER *buffer);
|
||||
static char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length);
|
||||
static char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated);
|
||||
|
||||
|
||||
LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
|
||||
|
|
@ -42,12 +42,13 @@ LINE_BUFFER *batch_readline_init(ulong max_size,FILE *file)
|
|||
}
|
||||
|
||||
|
||||
char *batch_readline(LINE_BUFFER *line_buff)
|
||||
char *batch_readline(LINE_BUFFER *line_buff, bool *truncated)
|
||||
{
|
||||
char *pos;
|
||||
ulong out_length;
|
||||
DBUG_ASSERT(truncated != NULL);
|
||||
|
||||
if (!(pos=intern_read_line(line_buff,&out_length)))
|
||||
if (!(pos=intern_read_line(line_buff,&out_length, truncated)))
|
||||
return 0;
|
||||
if (out_length && pos[out_length-1] == '\n')
|
||||
if (--out_length && pos[out_length-1] == '\r') /* Remove '\n' */
|
||||
|
|
@ -149,6 +150,14 @@ static uint fill_buffer(LINE_BUFFER *buffer)
|
|||
read_count=(buffer->bufread - bufbytes)/IO_SIZE;
|
||||
if ((read_count*=IO_SIZE))
|
||||
break;
|
||||
if (buffer->bufread * 2 > buffer->max_size)
|
||||
{
|
||||
/*
|
||||
So we must grow the buffer but we cannot due to the max_size limit.
|
||||
Return 0 w/o setting buffer->eof to signal this condition.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
buffer->bufread *= 2;
|
||||
if (!(buffer->buffer = (char*) my_realloc(buffer->buffer,
|
||||
buffer->bufread+1,
|
||||
|
|
@ -172,11 +181,15 @@ static uint fill_buffer(LINE_BUFFER *buffer)
|
|||
|
||||
DBUG_PRINT("fill_buff", ("Got %d bytes", read_count));
|
||||
|
||||
/* Kludge to pretend every nonempty file ends with a newline. */
|
||||
if (!read_count && bufbytes && buffer->end[-1] != '\n')
|
||||
if (!read_count)
|
||||
{
|
||||
buffer->eof = read_count = 1;
|
||||
*buffer->end = '\n';
|
||||
buffer->eof = 1;
|
||||
/* Kludge to pretend every nonempty file ends with a newline. */
|
||||
if (bufbytes && buffer->end[-1] != '\n')
|
||||
{
|
||||
read_count = 1;
|
||||
*buffer->end = '\n';
|
||||
}
|
||||
}
|
||||
buffer->end_of_line=(buffer->start_of_line=buffer->buffer)+bufbytes;
|
||||
buffer->end+=read_count;
|
||||
|
|
@ -186,7 +199,7 @@ static uint fill_buffer(LINE_BUFFER *buffer)
|
|||
|
||||
|
||||
|
||||
char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length)
|
||||
char *intern_read_line(LINE_BUFFER *buffer, ulong *out_length, bool *truncated)
|
||||
{
|
||||
char *pos;
|
||||
uint length;
|
||||
|
|
@ -200,14 +213,23 @@ char *intern_read_line(LINE_BUFFER *buffer,ulong *out_length)
|
|||
pos++;
|
||||
if (pos == buffer->end)
|
||||
{
|
||||
if ((uint) (pos - buffer->start_of_line) < buffer->max_size)
|
||||
/*
|
||||
fill_buffer() can return 0 either on EOF in which case we abort
|
||||
or when the internal buffer has hit the size limit. In the latter case
|
||||
return what we have read so far and signal string truncation.
|
||||
*/
|
||||
if (!(length=fill_buffer(buffer)) || length == (uint) -1)
|
||||
{
|
||||
if (!(length=fill_buffer(buffer)) || length == (uint) -1)
|
||||
DBUG_RETURN(0);
|
||||
continue;
|
||||
if (buffer->eof)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
pos--; /* break line here */
|
||||
*truncated= 1;
|
||||
}
|
||||
else
|
||||
*truncated= 0;
|
||||
buffer->end_of_line=pos+1;
|
||||
*out_length=(ulong) (pos + 1 - buffer->eof - buffer->start_of_line);
|
||||
DBUG_RETURN(buffer->start_of_line);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue