From 4ec65151dc8e1b30b05a84c2f3a8bd2b9ce641c6 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 18:59:13 +0300 Subject: [PATCH 1/3] Fix for Bug#35469: server crash with LOAD DATA INFILE to a VIEW. The problem was that LOAD DATA code (sql_load.cc) didn't take into account that there may be items, representing references to other columns. This is a usual case in views. The crash happened because Item_direct_view_ref was casted to Item_user_var_as_out_param, which is not a base class. The fix is to 1) Handle references properly; 2) Ensure that an item is treated as a user variable only when it is a user variable indeed; 3) Report an error if LOAD DATA is used to load data into non-updatable column. mysql-test/r/loaddata.result: Update result file. mysql-test/t/loaddata.test: Add a test case form Bug#35469: server crash with LOAD DATA INFILE to a VIEW. sql/share/errmsg.txt: Introduce a new error. sql/sql_load.cc: Handle reference-items properly. mysql-test/std_data/bug35649.data: Add a data file for the test case. --- mysql-test/r/loaddata.result | 76 ++++++++++++++++++++++++++++ mysql-test/std_data/bug35649.data | 3 ++ mysql-test/t/loaddata.test | 82 +++++++++++++++++++++++++++++++ sql/share/errmsg.txt | 4 ++ sql/sql_load.cc | 56 +++++++++++++++------ 5 files changed, 207 insertions(+), 14 deletions(-) create mode 100644 mysql-test/std_data/bug35649.data diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 7fff2700779..156a78eb627 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -252,3 +252,79 @@ SELECT * FROM t1; c1 c2 c3 c4 10 1970-02-01 01:02:03 1.1e-100 1.1e+100 DROP TABLE t1; + +# -- +# -- Bug#35469: server crash with LOAD DATA INFILE to a VIEW. +# -- + +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; + +CREATE TABLE t1(c1 INT, c2 VARCHAR(255)); + +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE VIEW v2 AS SELECT 1 + 2 AS c0, c1, c2 FROM t1; +CREATE VIEW v3 AS SELECT 1 AS d1, 2 AS d2; + +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v1 +FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c1, c2); + +SELECT * FROM t1; +c1 c2 +1 "string1" +2 "string2" +3 "string3" + +SELECT * FROM v1; +c1 c2 +1 "string1" +2 "string2" +3 "string3" + +DELETE FROM t1; + +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c1, c2); + +SELECT * FROM t1; +c1 c2 +1 "string1" +2 "string2" +3 "string3" + +SELECT * FROM v2; +c0 c1 c2 +3 1 "string1" +3 2 "string2" +3 3 "string3" + +DELETE FROM t1; + +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c0, c2); +ERROR HY000: Invalid column reference (v2.c0) in LOAD DATA + +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v3 +FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (d1, d2); +ERROR HY000: The target table v3 of the LOAD is not updatable + +DROP TABLE t1; +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; + +# -- End of Bug#35469. diff --git a/mysql-test/std_data/bug35649.data b/mysql-test/std_data/bug35649.data new file mode 100644 index 00000000000..afcd9e9cc95 --- /dev/null +++ b/mysql-test/std_data/bug35649.data @@ -0,0 +1,3 @@ +"1", "string1" +"2", "string2" +"3", "string3" diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 9eb92015399..68cf84b7fac 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -236,4 +236,86 @@ SELECT * FROM t1; remove_file $MYSQLTEST_VARDIR/tmp/t1; DROP TABLE t1; +########################################################################### + +--echo +--echo # -- +--echo # -- Bug#35469: server crash with LOAD DATA INFILE to a VIEW. +--echo # -- + +--echo +--disable_warnings +DROP TABLE IF EXISTS t1; +DROP VIEW IF EXISTS v1; +DROP VIEW IF EXISTS v2; +DROP VIEW IF EXISTS v3; +--enable_warnings + +--echo +CREATE TABLE t1(c1 INT, c2 VARCHAR(255)); + +--echo +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE VIEW v2 AS SELECT 1 + 2 AS c0, c1, c2 FROM t1; +CREATE VIEW v3 AS SELECT 1 AS d1, 2 AS d2; + +--echo +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v1 + FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c1, c2); + +--echo +SELECT * FROM t1; + +--echo +SELECT * FROM v1; + +--echo +DELETE FROM t1; + +--echo +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 + FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c1, c2); + +--echo +SELECT * FROM t1; + +--echo +SELECT * FROM v2; + +--echo +DELETE FROM t1; + +--echo +--error ER_LOAD_DATA_INVALID_COLUMN +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 + FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (c0, c2); + +--echo +--error ER_NON_UPDATABLE_TABLE +LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v3 + FIELDS ESCAPED BY '\\' + TERMINATED BY ',' + ENCLOSED BY '"' + LINES TERMINATED BY '\n' (d1, d2); + +--echo +DROP TABLE t1; +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; + +--echo +--echo # -- End of Bug#35469. + +########################################################################### + # End of 5.0 tests diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 9e6cf462113..a3514776d6e 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5641,3 +5641,7 @@ ER_NAME_BECOMES_EMPTY eng "Name '%-.64s' has become ''" ER_AMBIGUOUS_FIELD_TERM eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" + +ER_LOAD_DATA_INVALID_COLUMN + eng "Invalid column reference (%-.64s) in LOAD DATA" + diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 4da3c19bb3c..e9fd04dff15 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -233,9 +233,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, while ((item= it++)) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field*)item)->field; + Field *field= ((Item_field*)real_item)->field; if (field->flags & BLOB_FLAG) { use_blobs= 1; @@ -244,7 +246,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else + else if (item->type() == Item::STRING_ITEM) use_vars= 1; } if (use_blobs && !ex->line_term->length() && !field_term->length()) @@ -705,6 +707,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; byte *pos; + Item *real_item; if (read_info.read_field()) break; @@ -716,14 +719,17 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, pos=read_info.row_start; length=(uint) (read_info.row_end-pos); + real_item= item->real_item(); + if (!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL"))) || (length == 1 && read_info.found_null)) { - if (item->type() == Item::FIELD_ITEM) + + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name, @@ -740,25 +746,39 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_NULL_TO_NOTNULL, 1); } } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } + continue; } - if (item->type() == Item::FIELD_ITEM) + if (real_item->type() == Item::FIELD_ITEM) { - - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker if (field == table->next_number_field) table->auto_increment_field_not_null= TRUE; field->store((char*) pos, length, read_info.read_charset); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); + read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } if (read_info.error) break; @@ -774,9 +794,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { - if (item->type() == Item::FIELD_ITEM) + Item *real_item= item->real_item(); + if (real_item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; + Field *field= ((Item_field *)real_item)->field; if (field->reset()) { my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name, @@ -796,9 +817,16 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_WARN_TOO_FEW_RECORDS, ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); } - else + else if (item->type() == Item::STRING_ITEM) + { ((Item_user_var_as_out_param *)item)->set_null_value( read_info.read_charset); + } + else + { + my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); + DBUG_RETURN(1); + } } } From 7021064aaee66583e8fb2775a335739d6c66fbe5 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 28 Mar 2008 23:39:47 +0300 Subject: [PATCH 2/3] Fix tree: 1. Use 'dat' extension, because it is handled in Makefile.am; 2. Fix typo: the bug id is 35469, not 35649. mysql-test/std_data/bug35469.dat: Rename: mysql-test/std_data/bug35649.data -> mysql-test/std_data/bug35469.dat mysql-test/r/loaddata.result: Update result file. mysql-test/t/loaddata.test: 1. Use 'dat' extension, because it is handled in Makefile.am; 2. Fix typo: the bug id is 35469, not 35649. --- mysql-test/r/loaddata.result | 8 ++++---- mysql-test/std_data/{bug35649.data => bug35469.dat} | 0 mysql-test/t/loaddata.test | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename mysql-test/std_data/{bug35649.data => bug35469.dat} (100%) diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 156a78eb627..18b0d84a296 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -268,7 +268,7 @@ CREATE VIEW v1 AS SELECT * FROM t1; CREATE VIEW v2 AS SELECT 1 + 2 AS c0, c1, c2 FROM t1; CREATE VIEW v3 AS SELECT 1 AS d1, 2 AS d2; -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v1 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v1 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' @@ -288,7 +288,7 @@ c1 c2 DELETE FROM t1; -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v2 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' @@ -308,14 +308,14 @@ c0 c1 c2 DELETE FROM t1; -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v2 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n' (c0, c2); ERROR HY000: Invalid column reference (v2.c0) in LOAD DATA -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v3 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v3 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' diff --git a/mysql-test/std_data/bug35649.data b/mysql-test/std_data/bug35469.dat similarity index 100% rename from mysql-test/std_data/bug35649.data rename to mysql-test/std_data/bug35469.dat diff --git a/mysql-test/t/loaddata.test b/mysql-test/t/loaddata.test index 68cf84b7fac..e9da2bbadc5 100644 --- a/mysql-test/t/loaddata.test +++ b/mysql-test/t/loaddata.test @@ -260,7 +260,7 @@ CREATE VIEW v2 AS SELECT 1 + 2 AS c0, c1, c2 FROM t1; CREATE VIEW v3 AS SELECT 1 AS d1, 2 AS d2; --echo -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v1 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v1 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' @@ -276,7 +276,7 @@ SELECT * FROM v1; DELETE FROM t1; --echo -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v2 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' @@ -293,7 +293,7 @@ DELETE FROM t1; --echo --error ER_LOAD_DATA_INVALID_COLUMN -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v2 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' @@ -301,7 +301,7 @@ LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v2 --echo --error ER_NON_UPDATABLE_TABLE -LOAD DATA INFILE '../std_data_ln/bug35649.data' INTO TABLE v3 +LOAD DATA INFILE '../std_data_ln/bug35469.dat' INTO TABLE v3 FIELDS ESCAPED BY '\\' TERMINATED BY ',' ENCLOSED BY '"' From 49384c0bf058937e07dd56f574634da92fb273db Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 29 Mar 2008 00:05:20 +0300 Subject: [PATCH 3/3] Fix manual merge. --- mysql-test/r/loaddata.result | 54 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/loaddata.result b/mysql-test/r/loaddata.result index 0ceef10ec5d..3a23d9de6b3 100644 --- a/mysql-test/r/loaddata.result +++ b/mysql-test/r/loaddata.result @@ -261,33 +261,6 @@ SELECT * FROM t1; c1 c2 c3 c4 10 1970-02-01 01:02:03 1.1e-100 1.1e+100 DROP TABLE t1; -CREATE TABLE t1 (a int); -INSERT INTO t1 VALUES (1); -SET NAMES latin1; -SET character_set_filesystem=filename; -select @@character_set_filesystem; -@@character_set_filesystem -filename -SELECT * INTO OUTFILE 't-1' FROM t1; -DELETE FROM t1; -LOAD DATA INFILE 't-1' INTO TABLE t1; -SELECT * FROM t1; -a -1 -DELETE FROM t1; -SET character_set_filesystem=latin1; -select @@character_set_filesystem; -@@character_set_filesystem -latin1 -LOAD DATA INFILE 't@002d1' INTO TABLE t1; -SELECT * FROM t1; -a -1 -DROP TABLE t1; -SET character_set_filesystem=default; -select @@character_set_filesystem; -@@character_set_filesystem -binary # -- # -- Bug#35469: server crash with LOAD DATA INFILE to a VIEW. @@ -364,3 +337,30 @@ DROP VIEW v2; DROP VIEW v3; # -- End of Bug#35469. +CREATE TABLE t1 (a int); +INSERT INTO t1 VALUES (1); +SET NAMES latin1; +SET character_set_filesystem=filename; +select @@character_set_filesystem; +@@character_set_filesystem +filename +SELECT * INTO OUTFILE 't-1' FROM t1; +DELETE FROM t1; +LOAD DATA INFILE 't-1' INTO TABLE t1; +SELECT * FROM t1; +a +1 +DELETE FROM t1; +SET character_set_filesystem=latin1; +select @@character_set_filesystem; +@@character_set_filesystem +latin1 +LOAD DATA INFILE 't@002d1' INTO TABLE t1; +SELECT * FROM t1; +a +1 +DROP TABLE t1; +SET character_set_filesystem=default; +select @@character_set_filesystem; +@@character_set_filesystem +binary