From 2a76abce96bed0b60274e443a0922534ee610b59 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 27 Jun 2007 16:20:00 +0500 Subject: [PATCH] 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. mysql-test/r/csv.result: Fix for bug #29353: inserting a negative value to a csv table leads to the table corruption - test result. mysql-test/t/csv.test: Fix for bug #29353: inserting a negative value to a csv table leads to the table corruption - test case. storage/csv/ha_tina.cc: Fix for bug #29353: inserting a negative value to a csv table leads to the table corruption - code optimization: removed unnecessary file_buff->get_value() calls. - let field->store() check given value correctness. --- mysql-test/r/csv.result | 31 ++++++++++++++++++ mysql-test/t/csv.test | 25 +++++++++++++++ storage/csv/ha_tina.cc | 70 +++++++++++++++++++++-------------------- 3 files changed, 92 insertions(+), 34 deletions(-) diff --git a/mysql-test/r/csv.result b/mysql-test/r/csv.result index 34dc1cb5b2e..e7cdd612a25 100644 --- a/mysql-test/r/csv.result +++ b/mysql-test/r/csv.result @@ -5261,3 +5261,34 @@ CREATE TABLE `bug21328` ( insert into bug21328 values (1,NULL,NULL); alter table bug21328 engine=myisam; 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 diff --git a/mysql-test/t/csv.test b/mysql-test/t/csv.test index c7c7f3e13ab..6d24b38ee10 100644 --- a/mysql-test/t/csv.test +++ b/mysql-test/t/csv.test @@ -1674,3 +1674,28 @@ CREATE TABLE `bug21328` ( insert into bug21328 values (1,NULL,NULL); alter table bug21328 engine=myisam; 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 diff --git a/storage/csv/ha_tina.cc b/storage/csv/ha_tina.cc index 6de153c82d7..239d47890ed 100644 --- a/storage/csv/ha_tina.cc +++ b/storage/csv/ha_tina.cc @@ -45,11 +45,12 @@ TODO: #pragma implementation // gcc: Class implementation #endif -#include "mysql_priv.h" +#define MYSQL_SERVER 1 +#include "mysql_priv.h" +#include #include "ha_tina.h" -#include /* uchar + uchar + ulonglong + ulonglong + ulonglong + ulonglong + uchar @@ -609,37 +610,41 @@ int ha_tina::find_current_row(uchar *buf) for (Field **field=table->field ; *field ; field++) { + char curr_char; + buffer.length(0); - if (curr_offset < end_offset && - file_buff->get_value(curr_offset) == '"') + if (curr_offset >= end_offset) + goto err; + curr_char= file_buff->get_value(curr_offset); + if (curr_char == '"') { 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! - if (file_buff->get_value(curr_offset) == '"' && - ((file_buff->get_value(curr_offset + 1) == ',') || - (curr_offset == end_offset -1 ))) + if (curr_char == '"' && + (curr_offset == end_offset - 1 || + file_buff->get_value(curr_offset + 1) == ',')) { curr_offset+= 2; // Move past the , and the " break; } - if (file_buff->get_value(curr_offset) == '\\' && - curr_offset != (end_offset - 1)) + if (curr_char == '\\' && curr_offset != (end_offset - 1)) { 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'); - else if (file_buff->get_value(curr_offset) == 'n' ) + else if (curr_char == 'n' ) buffer.append('\n'); - else if ((file_buff->get_value(curr_offset) == '\\') || - (file_buff->get_value(curr_offset) == '"')) - buffer.append(file_buff->get_value(curr_offset)); + else if (curr_char == '\\' || curr_char == '"') + buffer.append(curr_char); else /* This could only happed with an externally created file */ { buffer.append('\\'); - buffer.append(file_buff->get_value(curr_offset)); + buffer.append(curr_char); } } else // ordinary symbol @@ -650,36 +655,29 @@ int ha_tina::find_current_row(uchar *buf) */ if (curr_offset == end_offset - 1) goto err; - buffer.append(file_buff->get_value(curr_offset)); + buffer.append(curr_char); } } } - else if (my_isdigit(system_charset_info, - file_buff->get_value(curr_offset))) + else { - 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; } - - 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; + buffer.append(curr_char); } } - else - { - goto err; - } if (bitmap_is_set(table->read_set, (*field)->field_index)) - (*field)->store(buffer.ptr(), buffer.length(), buffer.charset()); + { + if ((*field)->store(buffer.ptr(), buffer.length(), buffer.charset())) + goto err; + } } next_position= end_offset + eoln_len; error= 0; @@ -1004,6 +1002,7 @@ int ha_tina::delete_row(const uchar * buf) int ha_tina::rnd_init(bool scan) { + THD *thd= table ? table->in_use : current_thd; DBUG_ENTER("ha_tina::rnd_init"); /* set buffer to the beginning of the file */ @@ -1015,6 +1014,7 @@ int ha_tina::rnd_init(bool scan) stats.records= 0; records_is_known= 0; chain_ptr= chain; + thd->count_cuted_fields= CHECK_FIELD_WARN; // To find wrong values DBUG_RETURN(0); } @@ -1298,6 +1298,7 @@ int ha_tina::repair(THD* thd, HA_CHECK_OPT* check_opt) current_position= next_position= 0; /* 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))) { rows_repaired++; @@ -1463,6 +1464,7 @@ int ha_tina::check(THD* thd, HA_CHECK_OPT* check_opt) /* set current position to the beginning of the file */ current_position= next_position= 0; /* 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))) { count--;