diff options
author | Alexander Barkov <bar@mariadb.com> | 2018-03-20 13:02:44 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.com> | 2018-03-20 13:02:44 +0400 |
commit | e263530bea641e610a2cb6dac20da369272551b1 (patch) | |
tree | 49f4f10ea7710af1da81e653eea0fa8b872cf7e7 /sql | |
parent | 85ddd9e8ce11bef089ccc6c86745142d09639c14 (diff) | |
download | mariadb-git-e263530bea641e610a2cb6dac20da369272551b1.tar.gz |
MDEV-15597 Add class Load_data_outvar and avoid using Item::STRING_ITEM for Item_user_var_as_out_param detection
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 18 | ||||
-rw-r--r-- | sql/item.cc | 25 | ||||
-rw-r--r-- | sql/item.h | 45 | ||||
-rw-r--r-- | sql/item_func.cc | 4 | ||||
-rw-r--r-- | sql/item_func.h | 33 | ||||
-rw-r--r-- | sql/sql_load.cc | 286 | ||||
-rw-r--r-- | sql/structs.h | 36 |
7 files changed, 253 insertions, 194 deletions
diff --git a/sql/field.cc b/sql/field.cc index 447061d70b7..9da65526e14 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1267,7 +1267,25 @@ bool Field::load_data_set_no_data(THD *thd, bool fixed_format) { reset(); // Do not use the DEFAULT value if (fixed_format) + { set_notnull(); + /* + We're loading a fixed format file, e.g.: + LOAD DATA INFILE 't1.txt' INTO TABLE t1 FIELDS TERMINATED BY ''; + Suppose the file ended unexpectedly and no data was provided for an + auto-increment column in the current row. + Historically, if sql_mode=NO_AUTO_VALUE_ON_ZERO, then the column value + is set to 0 in such case (the next auto_increment value is not used). + This behaviour was introduced by the fix for "bug#12053" in mysql-4.1. + Note, loading a delimited file works differently: + "no data" is not converted to 0 on NO_AUTO_VALUE_ON_ZERO: + it's considered as equal to setting the column to NULL, + which is then replaced to the next auto_increment value. + This difference seems to be intentional. + */ + if (this == table->next_number_field) + table->auto_increment_field_not_null= true; + } set_has_explicit_value(); // Do not auto-update this field return false; } diff --git a/sql/item.cc b/sql/item.cc index 9f0280b678c..215c1450a3c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3252,6 +3252,31 @@ void Item_field::reset_field(Field *f) } +void Item_field::load_data_print_for_log_event(THD *thd, String *to) const +{ + append_identifier(thd, to, name.str, name.length); +} + + +bool Item_field::load_data_set_no_data(THD *thd, const Load_data_param *param) +{ + if (field->load_data_set_no_data(thd, param->is_fixed_length())) + return true; + /* + TODO: We probably should not throw warning for each field. + But how about intention to always have the same number + of warnings in THD::cuted_fields (and get rid of cuted_fields + in the end ?) + */ + thd->cuted_fields++; + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, + ER_WARN_TOO_FEW_RECORDS, + ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), + thd->get_stmt_da()->current_row_for_warning()); + return false; +} + + bool Item_field::enumerate_field_refs_processor(void *arg) { Field_enumerator *fe= (Field_enumerator*)arg; diff --git a/sql/item.h b/sql/item.h index 42442468be9..06720a33cf8 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1887,6 +1887,20 @@ public: { return 0; } + + virtual Load_data_outvar *get_load_data_outvar() + { + return 0; + } + Load_data_outvar *get_load_data_outvar_or_error() + { + Load_data_outvar *dst= get_load_data_outvar(); + if (dst) + return dst; + my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), name.str); + return NULL; + } + /** Test whether an expression is expensive to compute. Used during optimization to avoid computing expensive expressions during this @@ -2819,7 +2833,8 @@ public: }; -class Item_field :public Item_ident +class Item_field :public Item_ident, + public Load_data_outvar { protected: void set_field(Field *field); @@ -2866,6 +2881,30 @@ public: bool val_bool_result(); bool is_null_result(); bool send(Protocol *protocol, st_value *buffer); + Load_data_outvar *get_load_data_outvar() + { + return this; + } + bool load_data_set_null(THD *thd, const Load_data_param *param) + { + return field->load_data_set_null(thd); + } + bool load_data_set_value(THD *thd, const char *pos, uint length, + const Load_data_param *param) + { + field->load_data_set_value(pos, length, param->charset()); + return false; + } + bool load_data_set_no_data(THD *thd, const Load_data_param *param); + void load_data_print_for_log_event(THD *thd, String *to) const; + bool load_data_add_outvar(THD *thd, Load_data_param *param) const + { + return param->add_outvar_field(thd, field); + } + uint load_data_fixed_length() const + { + return field->field_length; + } void reset_field(Field *f); bool fix_fields(THD *, Item **); void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge); @@ -4754,6 +4793,10 @@ public: void cleanup(); Item_field *field_for_view_update() { return (*ref)->field_for_view_update(); } + Load_data_outvar *get_load_data_outvar() + { + return (*ref)->get_load_data_outvar(); + } virtual Ref_Type ref_type() { return REF; } // Row emulation: forwarding of ROW-related calls to ref diff --git a/sql/item_func.cc b/sql/item_func.cc index 204dc46658a..709ad407bd7 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -5585,7 +5585,9 @@ bool Item_user_var_as_out_param::get_date(MYSQL_TIME *ltime, ulonglong fuzzy) } -void Item_user_var_as_out_param::print_for_load(THD *thd, String *str) const +void Item_user_var_as_out_param::load_data_print_for_log_event(THD *thd, + String *str) + const { str->append('@'); append_identifier(thd, str, &org_name); diff --git a/sql/item_func.h b/sql/item_func.h index 1c3302388aa..fb775b36ca4 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -2486,7 +2486,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_outvar { LEX_CSTRING org_name; user_var_entry *entry; @@ -2498,6 +2499,35 @@ public: org_name= *a; set_name(thd, a->str, a->length, system_charset_info); } + Load_data_outvar *get_load_data_outvar() + { + return this; + } + bool load_data_set_null(THD *thd, const Load_data_param *param) + { + set_null_value(param->charset()); + return false; + } + bool load_data_set_no_data(THD *thd, const Load_data_param *param) + { + set_null_value(param->charset()); + return false; + } + bool load_data_set_value(THD *thd, const char *pos, uint length, + const Load_data_param *param) + { + set_value(pos, length, param->charset()); + return false; + } + void load_data_print_for_log_event(THD *thd, String *to) const; + bool load_data_add_outvar(THD *thd, Load_data_param *param) const + { + return param->add_outvar_user_var(thd); + } + uint load_data_fixed_length() const + { + return 0; + } /* We should return something different from FIELD_ITEM here */ enum Type type() const { return STRING_ITEM;} double val_real(); @@ -2507,7 +2537,6 @@ 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) const; void set_null_value(CHARSET_INFO* cs); void set_value(const char *str, uint length, CHARSET_INFO* cs); const Type_handler *type_handler() const { return &type_handler_double; } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index f7498f920e4..cb062361651 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -138,10 +138,10 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table, #define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */ #endif /* WITH_WSREP */ -class READ_INFO { +class READ_INFO: public Load_data_param +{ File file; String data; /* Read buffer */ - uint fixed_length; /* Length of the fixed length record */ Term_string m_field_term; /* FIELDS TERMINATED BY 'string' */ Term_string m_line_term; /* LINES TERMINATED BY 'string' */ Term_string m_line_start; /* LINES STARTING BY 'string' */ @@ -193,7 +193,7 @@ class READ_INFO { bool read_mbtail(String *str) { int chlen; - if ((chlen= my_charlen(read_charset, str->end() - 1, str->end())) == 1) + if ((chlen= my_charlen(charset(), str->end() - 1, str->end())) == 1) return false; // Single byte character found for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); ) { @@ -204,7 +204,7 @@ class READ_INFO { return true; // EOF } str->append(chr); - chlen= my_charlen(read_charset, str->ptr() + length0, str->end()); + chlen= my_charlen(charset(), str->ptr() + length0, str->end()); if (chlen == MY_CS_ILSEQ) { /** @@ -226,10 +226,9 @@ public: bool error,line_cuted,found_null,enclosed; uchar *row_start, /* Found row starts here */ *row_end; /* Found row ends here */ - CHARSET_INFO *read_charset; LOAD_FILE_IO_CACHE cache; - READ_INFO(THD *thd, File file, uint tot_length, CHARSET_INFO *cs, + READ_INFO(THD *thd, File file, const Load_data_param ¶m, String &field_term,String &line_start,String &line_term, String &enclosed,int escape,bool get_it_from_net, bool is_fifo); ~READ_INFO(); @@ -284,6 +283,31 @@ static bool write_execute_load_query_log_event(THD *, const sql_exchange*, const char*, const char*, bool, enum enum_duplicates, bool, bool, int); #endif /* EMBEDDED_LIBRARY */ + +bool Load_data_param::add_outvar_field(THD *thd, const Field *field) +{ + if (field->flags & BLOB_FLAG) + { + m_use_blobs= true; + m_fixed_length+= 256; // Will be extended if needed + } + else + m_fixed_length+= field->field_length; + return false; +} + + +bool Load_data_param::add_outvar_user_var(THD *thd) +{ + if (m_is_fixed_length) + { + my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0)); + return true; + } + return false; +} + + /* Execute LOAD DATA query @@ -315,8 +339,6 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, File file; TABLE *table= NULL; int error= 0; - String *field_term=ex->field_term,*escaped=ex->escaped; - String *enclosed=ex->enclosed; bool is_fifo=0; #ifndef EMBEDDED_LIBRARY killed_state killed_status; @@ -345,7 +367,7 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, read_file_from_client = 0; //server is always in the same process #endif - if (escaped->length() > 1 || enclosed->length() > 1) + if (ex->escaped->length() > 1 || ex->enclosed->length() > 1) { my_message(ER_WRONG_FIELD_TERMINATORS, ER_THD(thd, ER_WRONG_FIELD_TERMINATORS), @@ -354,8 +376,8 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, } /* Report problems with non-ascii separators */ - if (!escaped->is_ascii() || !enclosed->is_ascii() || - !field_term->is_ascii() || + if (!ex->escaped->is_ascii() || !ex->enclosed->is_ascii() || + !ex->field_term->is_ascii() || !ex->line_term->is_ascii() || !ex->line_start->is_ascii()) { push_warning(thd, Sql_condition::WARN_LEVEL_WARN, @@ -459,39 +481,21 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, table->prepare_triggers_for_insert_stmt_or_event(); table->mark_columns_needed_for_insert(); - uint tot_length=0; - bool use_blobs= 0, use_vars= 0; + Load_data_param param(ex->cs ? ex->cs : thd->variables.collation_database, + !ex->field_term->length() && !ex->enclosed->length()); List_iterator_fast<Item> it(fields_vars); Item *item; while ((item= it++)) { - Item *real_item= item->real_item(); - - if (real_item->type() == Item::FIELD_ITEM) - { - Field *field= ((Item_field*)real_item)->field; - if (field->flags & BLOB_FLAG) - { - use_blobs= 1; - tot_length+= 256; // Will be extended if needed - } - else - tot_length+= field->field_length; - } - else if (item->type() == Item::STRING_ITEM) - use_vars= 1; + const Load_data_outvar *var= item->get_load_data_outvar_or_error(); + if (!var || var->load_data_add_outvar(thd, ¶m)) + DBUG_RETURN(true); } - if (use_blobs && !ex->line_term->length() && !field_term->length()) + if (param.use_blobs() && !ex->line_term->length() && !ex->field_term->length()) { my_message(ER_BLOBS_AND_NO_TERMINATED, - ER_THD(thd, ER_BLOBS_AND_NO_TERMINATED), - MYF(0)); - DBUG_RETURN(TRUE); - } - if (use_vars && !field_term->length() && !enclosed->length()) - { - my_error(ER_LOAD_FROM_FIXED_SIZE_ROWS_TO_VAR, MYF(0)); + ER_THD(thd, ER_BLOBS_AND_NO_TERMINATED), MYF(0)); DBUG_RETURN(TRUE); } @@ -581,13 +585,13 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, bzero((char*) &info,sizeof(info)); info.ignore= ignore; info.handle_duplicates=handle_duplicates; - info.escape_char= (escaped->length() && (ex->escaped_given() || + info.escape_char= (ex->escaped->length() && (ex->escaped_given() || !(thd->variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES))) - ? (*escaped)[0] : INT_MAX; + ? (*ex->escaped)[0] : INT_MAX; - READ_INFO read_info(thd, file, tot_length, - ex->cs ? ex->cs : thd->variables.collation_database, - *field_term,*ex->line_start, *ex->line_term, *enclosed, + READ_INFO read_info(thd, file, param, + *ex->field_term, *ex->line_start, + *ex->line_term, *ex->enclosed, info.escape_char, read_file_from_client, is_fifo); if (read_info.error) { @@ -648,14 +652,14 @@ int mysql_load(THD *thd, const sql_exchange *ex, TABLE_LIST *table_list, error= read_xml_field(thd, info, table_list, fields_vars, set_fields, set_values, read_info, *(ex->line_term), skip_lines, ignore); - else if (!field_term->length() && !enclosed->length()) + else if (read_info.is_fixed_length()) error= read_fixed_length(thd, info, table_list, fields_vars, set_fields, set_values, read_info, skip_lines, ignore); else error= read_sep_field(thd, info, table_list, fields_vars, set_fields, set_values, read_info, - *enclosed, skip_lines, ignore); + *ex->enclosed, skip_lines, ignore); thd_proc_info(thd, "End bulk insert"); if (!error) @@ -860,14 +864,9 @@ static bool write_execute_load_query_log_event(THD *thd, const sql_exchange* ex, { if (n++) query_str.append(", "); - if (item->real_type() == Item::FIELD_ITEM) - append_identifier(thd, &query_str, &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); - } + const Load_data_outvar *var= item->get_load_data_outvar(); + DBUG_ASSERT(var); + var->load_data_print_for_log_event(thd, &query_str); } query_str.append(")"); } @@ -915,9 +914,9 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, ulong skip_lines, bool ignore_check_option_errors) { List_iterator_fast<Item> it(fields_vars); - Item_field *sql_field; + Item *item; TABLE *table= table_list->table; - bool err, progress_reports, auto_increment_field_not_null=false; + bool err, progress_reports; ulonglong counter, time_to_report_progress; DBUG_ENTER("read_fixed_length"); @@ -927,12 +926,6 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, if ((thd->progress.max_counter= read_info.file_length()) == ~(my_off_t) 0) progress_reports= 0; - while ((sql_field= (Item_field*) it++)) - { - if (sql_field->field == table->next_number_field) - auto_increment_field_not_null= true; - } - while (!read_info.read_fixed_length()) { if (thd->killed) @@ -968,36 +961,27 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, #endif restore_record(table, s->default_values); - /* - There is no variables in fields_vars list in this format so - this conversion is safe. - */ - while ((sql_field= (Item_field*) it++)) + + while ((item= it++)) { - Field *field= sql_field->field; - table->auto_increment_field_not_null= auto_increment_field_not_null; + Load_data_outvar *dst= item->get_load_data_outvar(); + DBUG_ASSERT(dst); if (pos == read_info.row_end) { - if (field->load_data_set_no_data(thd, true)) + if (dst->load_data_set_no_data(thd, &read_info)) DBUG_RETURN(1); - thd->cuted_fields++; /* Not enough fields */ - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_WARN_TOO_FEW_RECORDS, - ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), - thd->get_stmt_da()->current_row_for_warning()); } else { - uint length; - uchar save_chr; - if ((length=(uint) (read_info.row_end-pos)) > - field->field_length) - length=field->field_length; - save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc - field->load_data_set_value((char*) pos,length,read_info.read_charset); - pos[length]=save_chr; - if ((pos+=length) > read_info.row_end) - pos= read_info.row_end; /* Fills rest with space */ + uint length, fixed_length= dst->load_data_fixed_length(); + uchar save_chr; + if ((length=(uint) (read_info.row_end - pos)) > fixed_length) + length= fixed_length; + save_chr= pos[length]; pos[length]= '\0'; // Safeguard aganst malloc + dst->load_data_set_value(thd, (const char *) pos, length, &read_info); + pos[length]= save_chr; + if ((pos+= length) > read_info.row_end) + pos= read_info.row_end; // Fills rest with space } } if (pos != read_info.row_end) @@ -1097,8 +1081,6 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, { uint length; uchar *pos; - Item_field *real_item; - if (read_info.read_field()) break; @@ -1109,48 +1091,22 @@ 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->field_for_view_update(); + Load_data_outvar *dst= item->get_load_data_outvar_or_error(); + DBUG_ASSERT(dst); if ((!read_info.enclosed && (enclosed_length && length == 4 && !memcmp(pos, STRING_WITH_LEN("NULL")))) || (length == 1 && read_info.found_null)) { - if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_null_value( - read_info.read_charset); - } - else if (!real_item) - { - my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + if (dst->load_data_set_null(thd, &read_info)) DBUG_RETURN(1); - } - else - { - DBUG_ASSERT(real_item->field->table == table); - if (real_item->field->load_data_set_null(thd)) - DBUG_RETURN(1); - } - - continue; - } - - if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_value((char*) pos, length, - read_info.read_charset); - } - else if (!real_item) - { - my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); - DBUG_RETURN(1); } else { - Field *field= real_item->field; - read_info.row_end[0]=0; // Safe to change end marker - field->load_data_set_value((char*) pos, length, read_info.read_charset); + read_info.row_end[0]= 0; // Safe to change end marker + if (dst->load_data_set_value(thd, (const char *) pos, length, &read_info)) + DBUG_RETURN(1); } } @@ -1171,34 +1127,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, break; for (; item ; item= it++) { - Item_field *real_item= item->field_for_view_update(); - if (item->type() == Item::STRING_ITEM) - { - ((Item_user_var_as_out_param *)item)->set_null_value( - read_info.read_charset); - } - else if (!real_item) - { - my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + Load_data_outvar *dst= item->get_load_data_outvar_or_error(); + DBUG_ASSERT(dst); + if (dst->load_data_set_no_data(thd, &read_info)) DBUG_RETURN(1); - } - else - { - Field *field= real_item->field; - if (field->load_data_set_no_data(thd, false)) - DBUG_RETURN(1); - /* - TODO: We probably should not throw warning for each field. - But how about intention to always have the same number - of warnings in THD::cuted_fields (and get rid of cuted_fields - in the end ?) - */ - thd->cuted_fields++; - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_WARN_TOO_FEW_RECORDS, - ER_THD(thd, ER_WARN_TOO_FEW_RECORDS), - thd->get_stmt_da()->current_row_for_warning()); - } } } @@ -1260,7 +1192,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, Item *item; TABLE *table= table_list->table; bool no_trans_update_stmt; - CHARSET_INFO *cs= read_info.read_charset; DBUG_ENTER("read_xml_field"); no_trans_update_stmt= !table->file->has_transactions(); @@ -1306,41 +1237,14 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list, while(tag && strcmp(tag->field.c_ptr(), item->name.str) != 0) tag= xmlit++; - - Item_field *real_item= item->field_for_view_update(); - if (!tag) // found null - { - if (item->type() == Item::STRING_ITEM) - ((Item_user_var_as_out_param *) item)->set_null_value(cs); - else if (!real_item) - { - my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); - DBUG_RETURN(1); - } - else - { - DBUG_ASSERT(real_item->field->table == table); - if (real_item->field->load_data_set_null(thd)) - DBUG_RETURN(1); - } - continue; - } - if (item->type() == Item::STRING_ITEM) - ((Item_user_var_as_out_param *) item)->set_value( - (char *) tag->value.ptr(), - tag->value.length(), cs); - else if (!real_item) - { - my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name.str); + Load_data_outvar *dst= item->get_load_data_outvar_or_error(); + DBUG_ASSERT(dst); + if (!tag ? dst->load_data_set_null(thd, &read_info) : + dst->load_data_set_value(thd, tag->value.ptr(), + tag->value.length(), + &read_info)) DBUG_RETURN(1); - } - else - { - - Field *field= ((Item_field *)item)->field; - field->load_data_set_value(tag->value.ptr(), tag->value.length(), cs); - } } if (read_info.error) @@ -1414,14 +1318,16 @@ READ_INFO::unescape(char chr) */ -READ_INFO::READ_INFO(THD *thd, File file_par, uint tot_length, CHARSET_INFO *cs, +READ_INFO::READ_INFO(THD *thd, File file_par, + const Load_data_param ¶m, String &field_term, String &line_start, String &line_term, String &enclosed_par, int escape, bool get_it_from_net, bool is_fifo) - :file(file_par), fixed_length(tot_length), + :Load_data_param(param), + file(file_par), m_field_term(field_term), m_line_term(line_term), m_line_start(line_start), escape_char(escape), found_end_of_line(false), eof(false), - error(false), line_cuted(false), found_null(false), read_charset(cs) + error(false), line_cuted(false), found_null(false) { data.set_thread_specific(); /* @@ -1438,12 +1344,12 @@ READ_INFO::READ_INFO(THD *thd, File file_par, uint tot_length, CHARSET_INFO *cs, enclosed_char= enclosed_par.length() ? (uchar) enclosed_par[0] : INT_MAX; /* Set of a stack for unget if long terminators */ - uint length= MY_MAX(cs->mbmaxlen, MY_MAX(m_field_term.length(), - m_line_term.length())) + 1; + uint length= MY_MAX(charset()->mbmaxlen, MY_MAX(m_field_term.length(), + m_line_term.length())) + 1; set_if_bigger(length,line_start.length()); stack= stack_pos= (int*) thd->alloc(sizeof(int) * length); - if (data.reserve(tot_length)) + if (data.reserve(m_fixed_length)) error=1; /* purecov: inspected */ else { @@ -1585,7 +1491,7 @@ int READ_INFO::read_field() for (;;) { // Make sure we have enough space for the longest multi-byte character. - while (data.length() + read_charset->mbmaxlen <= data.alloced_length()) + while (data.length() + charset()->mbmaxlen <= data.alloced_length()) { chr = GET; if (chr == my_b_EOF) @@ -1671,7 +1577,7 @@ int READ_INFO::read_field() } } data.append(chr); - if (use_mb(read_charset) && read_mbtail(&data)) + if (use_mb(charset()) && read_mbtail(&data)) goto found_eof; } /* @@ -1717,7 +1623,7 @@ int READ_INFO::read_fixed_length() return 1; } - for (data.length(0); data.length() < fixed_length ; ) + for (data.length(0); data.length() < m_fixed_length ; ) { if ((chr=GET) == my_b_EOF) goto found_eof; @@ -1770,8 +1676,8 @@ int READ_INFO::next_line() if (getbyte(&buf[0])) return 1; // EOF - if (use_mb(read_charset) && - (chlen= my_charlen(read_charset, buf, buf + 1)) != 1) + if (use_mb(charset()) && + (chlen= my_charlen(charset(), buf, buf + 1)) != 1) { uint i; for (i= 1; MY_CS_IS_TOOSMALL(chlen); ) @@ -1780,7 +1686,7 @@ int READ_INFO::next_line() DBUG_ASSERT(chlen != 1); if (getbyte(&buf[i++])) return 1; // EOF - chlen= my_charlen(read_charset, buf, buf + i); + chlen= my_charlen(charset(), buf, buf + i); } /* @@ -1951,7 +1857,7 @@ int READ_INFO::read_value(int delim, String *val) else { val->append(chr); - if (use_mb(read_charset) && read_mbtail(val)) + if (use_mb(charset()) && read_mbtail(val)) return my_b_EOF; } } diff --git a/sql/structs.h b/sql/structs.h index 4d05a2433cc..9bcbd1ba0df 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -729,4 +729,40 @@ struct Lex_string_with_pos_st: public LEX_CSTRING }; +class Load_data_param +{ +protected: + CHARSET_INFO *m_charset; // Character set of the file + ulonglong m_fixed_length; // Sum of target field lengths for fixed format + bool m_is_fixed_length; + bool m_use_blobs; +public: + Load_data_param(CHARSET_INFO *cs, bool is_fixed_length): + m_charset(cs), + m_fixed_length(0), + m_is_fixed_length(is_fixed_length), + m_use_blobs(false) + { } + bool add_outvar_field(THD *thd, const Field *field); + bool add_outvar_user_var(THD *thd); + CHARSET_INFO *charset() const { return m_charset; } + bool is_fixed_length() const { return m_is_fixed_length; } + bool use_blobs() const { return m_use_blobs; } +}; + + +class Load_data_outvar +{ +public: + virtual ~Load_data_outvar() {} + virtual bool load_data_set_null(THD *thd, const Load_data_param *param)= 0; + virtual bool load_data_set_value(THD *thd, const char *pos, uint length, + const Load_data_param *param)= 0; + virtual bool load_data_set_no_data(THD *thd, const Load_data_param *param)= 0; + virtual void load_data_print_for_log_event(THD *thd, class String *to) const= 0; + virtual bool load_data_add_outvar(THD *thd, Load_data_param *param) const= 0; + virtual uint load_data_fixed_length() const= 0; +}; + + #endif /* STRUCTS_INCLUDED */ |