diff options
author | Alexander Barkov <bar@mariadb.org> | 2017-05-05 11:05:55 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-05-05 11:05:55 +0400 |
commit | db0917f68f2681882974afd53935aa8cba29c6b8 (patch) | |
tree | 32a9f600b1913a5193e94c09ec442ea2cac14e19 /sql | |
parent | 96247be1a0dfa3035580b53b1c27a7247a410713 (diff) | |
download | mariadb-git-db0917f68f2681882974afd53935aa8cba29c6b8.tar.gz |
MDEV-12696 Crash with LOAD XML and non-updatable VIEW column
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.h | 21 | ||||
-rw-r--r-- | sql/item_func.cc | 9 | ||||
-rw-r--r-- | sql/item_func.h | 10 | ||||
-rw-r--r-- | sql/sql_load.cc | 61 |
4 files changed, 56 insertions, 45 deletions
diff --git a/sql/item.h b/sql/item.h index 42e9fd94331..2f33d72136c 100644 --- a/sql/item.h +++ b/sql/item.h @@ -439,6 +439,19 @@ typedef struct replace_equal_field_arg struct st_join_table *context_tab; } 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 { public: @@ -1789,6 +1802,14 @@ public: 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 Rewritable_query_parameter *get_rewritable_query_parameter() { return 0; } diff --git a/sql/item_func.cc b/sql/item_func.cc index 903d792db75..ba31f2794be 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -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 */); } -void Item_user_var_as_out_param::set_value(const char *str, uint length, - CHARSET_INFO* cs) +void Item_user_var_as_out_param::load_data_set_value(const char *str, + uint length, + CHARSET_INFO* cs) { ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, 0 /* unsigned_arg */); @@ -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('@'); append_identifier(thd, str, name.str, name.length); diff --git a/sql/item_func.h b/sql/item_func.h index 133074122dd..37d3d4b1122 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2006,7 +2006,8 @@ public: in List<Item> and desire to place this code somewhere near other functions 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; user_var_entry *entry; @@ -2021,9 +2022,10 @@ public: my_decimal *val_decimal(my_decimal *decimal_buffer); /* fix_fields() binds variable name with its entry structure */ bool fix_fields(THD *thd, Item **ref); - void print_for_load(THD *thd, String *str); - void set_null_value(CHARSET_INFO* cs); - void set_value(const char *str, uint length, CHARSET_INFO* cs); + Load_data_out_param *get_load_data_out_param() { return this; } + void load_data_print(THD *thd, String *str); + 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; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy<Item_user_var_as_out_param>(thd, mem_root, this); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 6f0e97a61c9..95da65a1c63 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -431,7 +431,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else tot_length+= field->field_length; } - else if (item->type() == Item::STRING_ITEM) + else if (item->get_load_data_out_param()) use_vars= 1; } 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, if (item->real_type() == Item::FIELD_ITEM) append_identifier(thd, &query_str, item->name, strlen(item->name)); else - { - /* 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); - } + item->get_load_data_out_param()->load_data_print(thd, &query_str); } query_str.append(")"); } @@ -1062,6 +1058,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, uint length; uchar *pos; Item *real_item; + Load_data_out_param *out_param; if (read_info.read_field()) break; @@ -1104,18 +1101,11 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, } /* Do not auto-update this field. */ 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 - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } - continue; } @@ -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->set_has_explicit_value(); } - else if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); - } + else if ((out_param= item->get_load_data_out_param_or_error())) + out_param->load_data_set_value((const char *) pos, length, + read_info.read_charset); else - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } } if (thd->is_error()) @@ -1158,6 +1143,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { + Load_data_out_param *out_param; Item *real_item= item->real_item(); if (real_item->type() == Item::FIELD_ITEM) { @@ -1183,16 +1169,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), thd->get_stmt_da()->current_row_for_warning()); } - 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 - { - my_error(ER_LOAD_DATA_INVALID_COLUMN, MYF(0), item->full_name()); DBUG_RETURN(1); - } } } @@ -1288,6 +1268,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, 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 (skip_lines) continue; @@ -1319,14 +1300,15 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, /* Do not auto-update this field. */ 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 - ((Item_user_var_as_out_param *) item)->set_null_value(cs); + DBUG_RETURN(1); continue; } if (item->type() == Item::FIELD_ITEM) { - Field *field= ((Item_field *)item)->field; field->set_notnull(); if (field == table->next_number_field) @@ -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->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 - ((Item_user_var_as_out_param *) item)->set_value( - (char *) tag->value.ptr(), - tag->value.length(), cs); + DBUG_RETURN(1); + } if (read_info.error) @@ -1357,6 +1341,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, for ( ; item; item= it++) { + Load_data_out_param *out_param; if (item->type() == Item::FIELD_ITEM) { /* @@ -1371,8 +1356,10 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), 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 - ((Item_user_var_as_out_param *)item)->set_null_value(cs); + DBUG_RETURN(1); } } |