Commit 4ec65151 authored by unknown's avatar unknown

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.
parent 7c156537
...@@ -252,3 +252,79 @@ SELECT * FROM t1; ...@@ -252,3 +252,79 @@ SELECT * FROM t1;
c1 c2 c3 c4 c1 c2 c3 c4
10 1970-02-01 01:02:03 1.1e-100 1.1e+100 10 1970-02-01 01:02:03 1.1e-100 1.1e+100
DROP TABLE t1; 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.
"1", "string1"
"2", "string2"
"3", "string3"
...@@ -236,4 +236,86 @@ SELECT * FROM t1; ...@@ -236,4 +236,86 @@ SELECT * FROM t1;
remove_file $MYSQLTEST_VARDIR/tmp/t1; remove_file $MYSQLTEST_VARDIR/tmp/t1;
DROP TABLE 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 # End of 5.0 tests
...@@ -5641,3 +5641,7 @@ ER_NAME_BECOMES_EMPTY ...@@ -5641,3 +5641,7 @@ ER_NAME_BECOMES_EMPTY
eng "Name '%-.64s' has become ''" eng "Name '%-.64s' has become ''"
ER_AMBIGUOUS_FIELD_TERM ER_AMBIGUOUS_FIELD_TERM
eng "First character of the FIELDS TERMINATED string is ambiguous; please use non-optional and non-empty FIELDS ENCLOSED BY" 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"
...@@ -233,9 +233,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -233,9 +233,11 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
while ((item= it++)) 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) if (field->flags & BLOB_FLAG)
{ {
use_blobs= 1; use_blobs= 1;
...@@ -244,7 +246,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -244,7 +246,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
else else
tot_length+= field->field_length; tot_length+= field->field_length;
} }
else else if (item->type() == Item::STRING_ITEM)
use_vars= 1; use_vars= 1;
} }
if (use_blobs && !ex->line_term->length() && !field_term->length()) 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, ...@@ -705,6 +707,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
{ {
uint length; uint length;
byte *pos; byte *pos;
Item *real_item;
if (read_info.read_field()) if (read_info.read_field())
break; break;
...@@ -716,14 +719,17 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -716,14 +719,17 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
pos=read_info.row_start; pos=read_info.row_start;
length=(uint) (read_info.row_end-pos); length=(uint) (read_info.row_end-pos);
real_item= item->real_item();
if (!read_info.enclosed && if (!read_info.enclosed &&
(enclosed_length && length == 4 && (enclosed_length && length == 4 &&
!memcmp(pos, STRING_WITH_LEN("NULL"))) || !memcmp(pos, STRING_WITH_LEN("NULL"))) ||
(length == 1 && read_info.found_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()) if (field->reset())
{ {
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0), field->field_name, 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, ...@@ -740,25 +746,39 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_WARN_NULL_TO_NOTNULL, 1); ER_WARN_NULL_TO_NOTNULL, 1);
} }
} }
else else if (item->type() == Item::STRING_ITEM)
{
((Item_user_var_as_out_param *)item)->set_null_value( ((Item_user_var_as_out_param *)item)->set_null_value(
read_info.read_charset); read_info.read_charset);
}
else
{
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1);
}
continue; continue;
} }
if (item->type() == Item::FIELD_ITEM) if (real_item->type() == Item::FIELD_ITEM)
{ {
Field *field= ((Item_field *)real_item)->field;
Field *field= ((Item_field *)item)->field;
field->set_notnull(); field->set_notnull();
read_info.row_end[0]=0; // Safe to change end marker read_info.row_end[0]=0; // Safe to change end marker
if (field == table->next_number_field) if (field == table->next_number_field)
table->auto_increment_field_not_null= TRUE; table->auto_increment_field_not_null= TRUE;
field->store((char*) pos, length, read_info.read_charset); 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, ((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) if (read_info.error)
break; break;
...@@ -774,9 +794,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -774,9 +794,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
break; break;
for (; item ; item= it++) 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()) if (field->reset())
{ {
my_error(ER_WARN_NULL_TO_NOTNULL, MYF(0),field->field_name, 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, ...@@ -796,9 +817,16 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_WARN_TOO_FEW_RECORDS, ER_WARN_TOO_FEW_RECORDS,
ER(ER_WARN_TOO_FEW_RECORDS), thd->row_count); 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( ((Item_user_var_as_out_param *)item)->set_null_value(
read_info.read_charset); read_info.read_charset);
}
else
{
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1);
}
} }
} }
......
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