summaryrefslogtreecommitdiff
path: root/client/readline.cc
diff options
context:
space:
mode:
authorAlexey Kopytov <Alexey.Kopytov@sun.com>2009-03-18 11:18:24 +0300
committerAlexey Kopytov <Alexey.Kopytov@sun.com>2009-03-18 11:18:24 +0300
commit73a7d99331d8fd0819fb9f7a10081e393590a94d (patch)
tree2165879ba56fa3d6417a48e08d8533be302af75f /client/readline.cc
parent5d2fc5335411bdd05a08a9b062d3441d4308dcaa (diff)
downloadmariadb-git-73a7d99331d8fd0819fb9f7a10081e393590a94d.tar.gz
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.
Diffstat (limited to 'client/readline.cc')
-rw-r--r--client/readline.cc46
1 files changed, 34 insertions, 12 deletions
diff --git a/client/readline.cc b/client/readline.cc
index ad42ed2ee10..726d9cd9415 100644
--- a/client/readline.cc
+++ b/client/readline.cc
@@ -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);