Fix for bug #29353: inserting a negative value to a csv table leads to the table corruption

Problem: we believe a number cannot start with '-' ['+'] sign reading rows.

Fix: let field->store() check given values.
parent e62cf05f
...@@ -5261,3 +5261,34 @@ CREATE TABLE `bug21328` ( ...@@ -5261,3 +5261,34 @@ CREATE TABLE `bug21328` (
insert into bug21328 values (1,NULL,NULL); insert into bug21328 values (1,NULL,NULL);
alter table bug21328 engine=myisam; alter table bug21328 engine=myisam;
drop table bug21328; drop table bug21328;
create table t1(a int) engine=csv;
insert into t1 values(-1), (-123.34), (2), (-23);
select * from t1;
a
-1
-123
2
-23
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
create table t1(a int, b int) engine=csv;
repair table t1;
Table Op Msg_type Msg_text
test.t1 repair Warning Data truncated for column 'a' at row 1
test.t1 repair status OK
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
select * from t1;
a b
1 0
-200 1
-1 -1
-1 -100
check table t1;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
End of 5.1 tests
...@@ -1674,3 +1674,28 @@ CREATE TABLE `bug21328` ( ...@@ -1674,3 +1674,28 @@ CREATE TABLE `bug21328` (
insert into bug21328 values (1,NULL,NULL); insert into bug21328 values (1,NULL,NULL);
alter table bug21328 engine=myisam; alter table bug21328 engine=myisam;
drop table bug21328; drop table bug21328;
#
# Bug #29353: negative values
#
create table t1(a int) engine=csv;
insert into t1 values(-1), (-123.34), (2), (-23);
select * from t1;
check table t1;
drop table t1;
create table t1(a int, b int) engine=csv;
--write_file $MYSQLTEST_VARDIR/master-data/test/t1.CSV
1, 1E-2
-2E2, .9
-10E-1, -.9
-1, -100.1
1a, -2b
EOF
repair table t1;
check table t1;
select * from t1;
check table t1;
drop table t1;
--echo End of 5.1 tests
...@@ -45,11 +45,12 @@ TODO: ...@@ -45,11 +45,12 @@ TODO:
#pragma implementation // gcc: Class implementation #pragma implementation // gcc: Class implementation
#endif #endif
#include "mysql_priv.h" #define MYSQL_SERVER 1
#include "mysql_priv.h"
#include <mysql/plugin.h>
#include "ha_tina.h" #include "ha_tina.h"
#include <mysql/plugin.h>
/* /*
uchar + uchar + ulonglong + ulonglong + ulonglong + ulonglong + uchar uchar + uchar + ulonglong + ulonglong + ulonglong + ulonglong + uchar
...@@ -609,37 +610,41 @@ int ha_tina::find_current_row(uchar *buf) ...@@ -609,37 +610,41 @@ int ha_tina::find_current_row(uchar *buf)
for (Field **field=table->field ; *field ; field++) for (Field **field=table->field ; *field ; field++)
{ {
char curr_char;
buffer.length(0); buffer.length(0);
if (curr_offset < end_offset && if (curr_offset >= end_offset)
file_buff->get_value(curr_offset) == '"') goto err;
curr_char= file_buff->get_value(curr_offset);
if (curr_char == '"')
{ {
curr_offset++; // Incrementpast the first quote curr_offset++; // Incrementpast the first quote
for(;curr_offset < end_offset; curr_offset++) for(; curr_offset < end_offset; curr_offset++)
{ {
curr_char= file_buff->get_value(curr_offset);
// Need to convert line feeds! // Need to convert line feeds!
if (file_buff->get_value(curr_offset) == '"' && if (curr_char == '"' &&
((file_buff->get_value(curr_offset + 1) == ',') || (curr_offset == end_offset - 1 ||
(curr_offset == end_offset -1 ))) file_buff->get_value(curr_offset + 1) == ','))
{ {
curr_offset+= 2; // Move past the , and the " curr_offset+= 2; // Move past the , and the "
break; break;
} }
if (file_buff->get_value(curr_offset) == '\\' && if (curr_char == '\\' && curr_offset != (end_offset - 1))
curr_offset != (end_offset - 1))
{ {
curr_offset++; curr_offset++;
if (file_buff->get_value(curr_offset) == 'r') curr_char= file_buff->get_value(curr_offset);
if (curr_char == 'r')
buffer.append('\r'); buffer.append('\r');
else if (file_buff->get_value(curr_offset) == 'n' ) else if (curr_char == 'n' )
buffer.append('\n'); buffer.append('\n');
else if ((file_buff->get_value(curr_offset) == '\\') || else if (curr_char == '\\' || curr_char == '"')
(file_buff->get_value(curr_offset) == '"')) buffer.append(curr_char);
buffer.append(file_buff->get_value(curr_offset));
else /* This could only happed with an externally created file */ else /* This could only happed with an externally created file */
{ {
buffer.append('\\'); buffer.append('\\');
buffer.append(file_buff->get_value(curr_offset)); buffer.append(curr_char);
} }
} }
else // ordinary symbol else // ordinary symbol
...@@ -650,36 +655,29 @@ int ha_tina::find_current_row(uchar *buf) ...@@ -650,36 +655,29 @@ int ha_tina::find_current_row(uchar *buf)
*/ */
if (curr_offset == end_offset - 1) if (curr_offset == end_offset - 1)
goto err; goto err;
buffer.append(file_buff->get_value(curr_offset)); buffer.append(curr_char);
} }
} }
} }
else if (my_isdigit(system_charset_info, else
file_buff->get_value(curr_offset)))
{ {
for(;curr_offset < end_offset; curr_offset++) for(; curr_offset < end_offset; curr_offset++)
{ {
if (file_buff->get_value(curr_offset) == ',') curr_char= file_buff->get_value(curr_offset);
if (curr_char == ',')
{ {
curr_offset+= 1; // Move past the , curr_offset++; // Skip the ,
break; break;
} }
buffer.append(curr_char);
if (my_isdigit(system_charset_info, file_buff->get_value(curr_offset)))
buffer.append(file_buff->get_value(curr_offset));
else if (file_buff->get_value(curr_offset) == '.')
buffer.append(file_buff->get_value(curr_offset));
else
goto err;
} }
} }
else
if (bitmap_is_set(table->read_set, (*field)->field_index))
{ {
if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset()))
goto err; goto err;
} }
if (bitmap_is_set(table->read_set, (*field)->field_index))
(*field)->store(buffer.ptr(), buffer.length(), buffer.charset());
} }
next_position= end_offset + eoln_len; next_position= end_offset + eoln_len;
error= 0; error= 0;
...@@ -1004,6 +1002,7 @@ int ha_tina::delete_row(const uchar * buf) ...@@ -1004,6 +1002,7 @@ int ha_tina::delete_row(const uchar * buf)
int ha_tina::rnd_init(bool scan) int ha_tina::rnd_init(bool scan)
{ {
THD *thd= table ? table->in_use : current_thd;
DBUG_ENTER("ha_tina::rnd_init"); DBUG_ENTER("ha_tina::rnd_init");
/* set buffer to the beginning of the file */ /* set buffer to the beginning of the file */
...@@ -1015,6 +1014,7 @@ int ha_tina::rnd_init(bool scan) ...@@ -1015,6 +1014,7 @@ int ha_tina::rnd_init(bool scan)
stats.records= 0; stats.records= 0;
records_is_known= 0; records_is_known= 0;
chain_ptr= chain; chain_ptr= chain;
thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong values
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -1298,6 +1298,7 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1298,6 +1298,7 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt)
current_position= next_position= 0; current_position= next_position= 0;
/* Read the file row-by-row. If everything is ok, repair is not needed. */ /* Read the file row-by-row. If everything is ok, repair is not needed. */
thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong values
while (!(rc= find_current_row(buf))) while (!(rc= find_current_row(buf)))
{ {
rows_repaired++; rows_repaired++;
...@@ -1463,6 +1464,7 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -1463,6 +1464,7 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt)
/* set current position to the beginning of the file */ /* set current position to the beginning of the file */
current_position= next_position= 0; current_position= next_position= 0;
/* Read the file row-by-row. If everything is ok, repair is not needed. */ /* Read the file row-by-row. If everything is ok, repair is not needed. */
thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong values
while (!(rc= find_current_row(buf))) while (!(rc= find_current_row(buf)))
{ {
count--; count--;
......
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