Commit db0917f6 authored by Alexander Barkov's avatar Alexander Barkov

MDEV-12696 Crash with LOAD XML and non-updatable VIEW column

parent 96247be1
...@@ -123,3 +123,14 @@ col1 col2 col3 ...@@ -123,3 +123,14 @@ col1 col2 col3
ABC DEF NULL ABC DEF NULL
GHI NULL 123 GHI NULL 123
DROP TABLE t1; DROP TABLE t1;
#
# MDEV-12696 Crash with LOAD XML and non-updatable VIEW column
#
CREATE TABLE t1 (c1 TEXT);
CREATE VIEW v1 AS SELECT CONCAT(c1,'') AS c1, NULL AS c2 FROM t1;
LOAD XML INFILE '../../std_data/loaddata/mdev12696.xml' INTO TABLE v1 (c1);
ERROR HY000: Invalid column reference (v1.c1) in LOAD DATA
LOAD XML INFILE '../../std_data/loaddata/mdev12696.xml' INTO TABLE v1 (c2);
ERROR HY000: Invalid column reference (v1.c2) in LOAD DATA
DROP VIEW v1;
DROP TABLE t1;
<?xml version="1.0"?>
<resultset statement="SELECT 'test' AS c1, NULL AS c2
" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<row>
<field name="c1">test</field>
<field name="c2" xsi:nil="true" />
</row>
</resultset>
...@@ -130,3 +130,16 @@ CREATE TABLE t1 (col1 VARCHAR(3), col2 VARCHAR(3), col3 INTEGER); ...@@ -130,3 +130,16 @@ CREATE TABLE t1 (col1 VARCHAR(3), col2 VARCHAR(3), col3 INTEGER);
LOAD XML INFILE '../../std_data/bug16171518_2.dat' INTO TABLE t1; LOAD XML INFILE '../../std_data/bug16171518_2.dat' INTO TABLE t1;
SELECT * FROM t1 ORDER BY col1, col2, col3; SELECT * FROM t1 ORDER BY col1, col2, col3;
DROP TABLE t1; DROP TABLE t1;
--echo #
--echo # MDEV-12696 Crash with LOAD XML and non-updatable VIEW column
--echo #
CREATE TABLE t1 (c1 TEXT);
CREATE VIEW v1 AS SELECT CONCAT(c1,'') AS c1, NULL AS c2 FROM t1;
--error ER_LOAD_DATA_INVALID_COLUMN
LOAD XML INFILE '../../std_data/loaddata/mdev12696.xml' INTO TABLE v1 (c1);
--error ER_LOAD_DATA_INVALID_COLUMN,
LOAD XML INFILE '../../std_data/loaddata/mdev12696.xml' INTO TABLE v1 (c2);
DROP VIEW v1;
DROP TABLE t1;
...@@ -439,6 +439,19 @@ typedef struct replace_equal_field_arg ...@@ -439,6 +439,19 @@ typedef struct replace_equal_field_arg
struct st_join_table *context_tab; struct st_join_table *context_tab;
} REPLACE_EQUAL_FIELD_ARG; } REPLACE_EQUAL_FIELD_ARG;
class Load_data_out_param
{
public:
Load_data_out_param() { }
virtual ~Load_data_out_param() { }
virtual void load_data_set_null_value(CHARSET_INFO *cs) = 0;
virtual void load_data_set_value(const char *str, uint length,
CHARSET_INFO *cs) = 0;
virtual void load_data_print(THD *thd, String *str) = 0;
};
class Settable_routine_parameter class Settable_routine_parameter
{ {
public: public:
...@@ -1789,6 +1802,14 @@ class Item: public Value_source, ...@@ -1789,6 +1802,14 @@ class Item: public Value_source,
delete this; delete this;
} }
virtual Load_data_out_param *get_load_data_out_param() { return 0; }
Load_data_out_param *get_load_data_out_param_or_error()
{
Load_data_out_param *res= get_load_data_out_param();
if (!res)
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), full_name());
return res;
}
virtual Item_splocal *get_item_splocal() { return 0; } virtual Item_splocal *get_item_splocal() { return 0; }
virtual Rewritable_query_parameter *get_rewritable_query_parameter() virtual Rewritable_query_parameter *get_rewritable_query_parameter()
{ return 0; } { return 0; }
......
...@@ -5675,14 +5675,15 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref) ...@@ -5675,14 +5675,15 @@ bool Item_user_var_as_out_param::fix_fields(THD *thd, Item **ref)
} }
void Item_user_var_as_out_param::set_null_value(CHARSET_INFO* cs) void Item_user_var_as_out_param::load_data_set_null_value(CHARSET_INFO* cs)
{ {
::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */); ::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, 0 /* unsigned_arg */);
} }
void Item_user_var_as_out_param::set_value(const char *str, uint length, void Item_user_var_as_out_param::load_data_set_value(const char *str,
CHARSET_INFO* cs) uint length,
CHARSET_INFO* cs)
{ {
::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs,
0 /* unsigned_arg */); 0 /* unsigned_arg */);
...@@ -5717,7 +5718,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer) ...@@ -5717,7 +5718,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
} }
void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) void Item_user_var_as_out_param::load_data_print(THD *thd, String *str)
{ {
str->append('@'); str->append('@');
append_identifier(thd, str, name.str, name.length); append_identifier(thd, str, name.str, name.length);
......
...@@ -2006,7 +2006,8 @@ class Item_func_get_user_var :public Item_func_user_var, ...@@ -2006,7 +2006,8 @@ class Item_func_get_user_var :public Item_func_user_var,
in List<Item> and desire to place this code somewhere near other functions in List<Item> and desire to place this code somewhere near other functions
working with user variables. working with user variables.
*/ */
class Item_user_var_as_out_param :public Item class Item_user_var_as_out_param :public Item,
public Load_data_out_param
{ {
LEX_STRING name; LEX_STRING name;
user_var_entry *entry; user_var_entry *entry;
...@@ -2021,9 +2022,10 @@ class Item_user_var_as_out_param :public Item ...@@ -2021,9 +2022,10 @@ class Item_user_var_as_out_param :public Item
my_decimal *val_decimal(my_decimal *decimal_buffer); my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */ /* fix_fields() binds variable name with its entry structure */
bool fix_fields(THD *thd, Item **ref); bool fix_fields(THD *thd, Item **ref);
void print_for_load(THD *thd, String *str); Load_data_out_param *get_load_data_out_param() { return this; }
void set_null_value(CHARSET_INFO* cs); void load_data_print(THD *thd, String *str);
void set_value(const char *str, uint length, CHARSET_INFO* cs); void load_data_set_null_value(CHARSET_INFO* cs);
void load_data_set_value(const char *str, uint length, CHARSET_INFO* cs);
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; } enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root) Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); } { return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); }
......
...@@ -431,7 +431,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, ...@@ -431,7 +431,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 if (item->type() == Item::STRING_ITEM) else if (item->get_load_data_out_param())
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())
...@@ -814,11 +814,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex, ...@@ -814,11 +814,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
if (item->real_type() == Item::FIELD_ITEM) if (item->real_type() == Item::FIELD_ITEM)
append_identifier(thd, &query_str, item->name, strlen(item->name)); append_identifier(thd, &query_str, item->name, strlen(item->name));
else else
{ item->get_load_data_out_param()->load_data_print(thd, &query_str);
/* Actually Item_user_var_as_out_param despite claiming STRING_ITEM. */
DBUG_ASSERT(item->type() == Item::STRING_ITEM);
((Item_user_var_as_out_param *)item)->print_for_load(thd, &query_str);
}
} }
query_str.append(")"); query_str.append(")");
} }
...@@ -1062,6 +1058,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1062,6 +1058,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
uint length; uint length;
uchar *pos; uchar *pos;
Item *real_item; Item *real_item;
Load_data_out_param *out_param;
if (read_info.read_field()) if (read_info.read_field())
break; break;
...@@ -1104,18 +1101,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1104,18 +1101,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
} }
/* Do not auto-update this field. */ /* Do not auto-update this field. */
field->set_has_explicit_value(); field->set_has_explicit_value();
}
else if (item->type() == Item::STRING_ITEM)
{
((Item_user_var_as_out_param *)item)->set_null_value(
read_info.read_charset);
} }
else if ((out_param= item->get_load_data_out_param_or_error()))
out_param->load_data_set_null_value(read_info.read_charset);
else else
{
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1); DBUG_RETURN(1);
}
continue; continue;
} }
...@@ -1129,16 +1119,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1129,16 +1119,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
field->store((char*) pos, length, read_info.read_charset); field->store((char*) pos, length, read_info.read_charset);
field->set_has_explicit_value(); field->set_has_explicit_value();
} }
else if (item->type() == Item::STRING_ITEM) else if ((out_param= item->get_load_data_out_param_or_error()))
{ out_param->load_data_set_value((const char *) pos, length,
((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, read_info.read_charset);
read_info.read_charset);
}
else else
{
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1); DBUG_RETURN(1);
}
} }
if (thd->is_error()) if (thd->is_error())
...@@ -1158,6 +1143,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1158,6 +1143,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
break; break;
for (; item ; item= it++) for (; item ; item= it++)
{ {
Load_data_out_param *out_param;
Item *real_item= item->real_item(); Item *real_item= item->real_item();
if (real_item->type() == Item::FIELD_ITEM) if (real_item->type() == Item::FIELD_ITEM)
{ {
...@@ -1183,16 +1169,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1183,16 +1169,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), ER_THD(thd, ER_WARN_TOO_FEW_RECORDS),
thd->get_stmt_da()->current_row_for_warning()); thd->get_stmt_da()->current_row_for_warning());
} }
else if (item->type() == Item::STRING_ITEM) else if ((out_param= item->get_load_data_out_param_or_error()))
{ out_param->load_data_set_null_value(read_info.read_charset);
((Item_user_var_as_out_param *)item)->set_null_value(
read_info.read_charset);
}
else else
{
my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name());
DBUG_RETURN(1); DBUG_RETURN(1);
}
} }
} }
...@@ -1288,6 +1268,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1288,6 +1268,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
while ((item= it++)) while ((item= it++))
{ {
Load_data_out_param *out_param;
/* If this line is to be skipped we don't want to fill field or var */ /* If this line is to be skipped we don't want to fill field or var */
if (skip_lines) if (skip_lines)
continue; continue;
...@@ -1319,14 +1300,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1319,14 +1300,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
/* Do not auto-update this field. */ /* Do not auto-update this field. */
field->set_has_explicit_value(); field->set_has_explicit_value();
} }
else if ((out_param= item->get_load_data_out_param_or_error()))
out_param->load_data_set_null_value(cs);
else else
((Item_user_var_as_out_param *) item)->set_null_value(cs); DBUG_RETURN(1);
continue; continue;
} }
if (item->type() == Item::FIELD_ITEM) if (item->type() == Item::FIELD_ITEM)
{ {
Field *field= ((Item_field *)item)->field; Field *field= ((Item_field *)item)->field;
field->set_notnull(); field->set_notnull();
if (field == table->next_number_field) if (field == table->next_number_field)
...@@ -1334,10 +1316,12 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1334,10 +1316,12 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
field->store((char *) tag->value.ptr(), tag->value.length(), cs); field->store((char *) tag->value.ptr(), tag->value.length(), cs);
field->set_has_explicit_value(); field->set_has_explicit_value();
} }
else if ((out_param= item->get_load_data_out_param_or_error()))
out_param->load_data_set_value((const char *) tag->value.ptr(),
tag->value.length(), cs);
else else
((Item_user_var_as_out_param *) item)->set_value( DBUG_RETURN(1);
(char *) tag->value.ptr(),
tag->value.length(), cs);
} }
if (read_info.error) if (read_info.error)
...@@ -1357,6 +1341,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1357,6 +1341,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
for ( ; item; item= it++) for ( ; item; item= it++)
{ {
Load_data_out_param *out_param;
if (item->type() == Item::FIELD_ITEM) if (item->type() == Item::FIELD_ITEM)
{ {
/* /*
...@@ -1371,8 +1356,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ...@@ -1371,8 +1356,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), ER_THD(thd, ER_WARN_TOO_FEW_RECORDS),
thd->get_stmt_da()->current_row_for_warning()); thd->get_stmt_da()->current_row_for_warning());
} }
else if ((out_param= item->get_load_data_out_param_or_error()))
out_param->load_data_set_null_value(cs);
else else
((Item_user_var_as_out_param *)item)->set_null_value(cs); 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