Backporting MDEV-15597 Add class Load_data_outvar and avoid using Item::STRING_ITEM for Item_user_var_as_out_param detection
This is a part of "MDEV-18045 Backporting the MDEV-15497 changes to 10.2 branch"
This commit is contained in:
parent
8036ad541e
commit
80c3fd184d
@ -614,3 +614,24 @@ SELECT * FROM t1;
|
|||||||
a b
|
a b
|
||||||
1
|
1
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-15597 Add class Load_data_outvar and avoid using Item::STRING_ITEM for Item_user_var_as_out_param detection
|
||||||
|
#
|
||||||
|
SET sql_mode=NO_AUTO_VALUE_ON_ZERO;
|
||||||
|
CREATE TABLE t1 (id integer not null auto_increment primary key);
|
||||||
|
LOAD DATA INFILE '../../std_data/loaddata/nl.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
||||||
|
Warnings:
|
||||||
|
Warning 1261 Row 1 doesn't contain data for all columns
|
||||||
|
SELECT * FROM t1;
|
||||||
|
id
|
||||||
|
0
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET sql_mode='';
|
||||||
|
CREATE TABLE t1 (id integer not null auto_increment primary key);
|
||||||
|
LOAD DATA INFILE '../../std_data/loaddata/nl.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
||||||
|
Warnings:
|
||||||
|
Warning 1261 Row 1 doesn't contain data for all columns
|
||||||
|
SELECT * FROM t1;
|
||||||
|
id
|
||||||
|
1
|
||||||
|
DROP TABLE t1;
|
||||||
|
1
mysql-test/std_data/loaddata/nl.txt
Normal file
1
mysql-test/std_data/loaddata/nl.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
|
@ -700,3 +700,19 @@ TRUNCATE TABLE t1;
|
|||||||
LOAD DATA INFILE '../../std_data/loaddata/mdev-15497.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
LOAD DATA INFILE '../../std_data/loaddata/mdev-15497.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
||||||
SELECT * FROM t1;
|
SELECT * FROM t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-15597 Add class Load_data_outvar and avoid using Item::STRING_ITEM for Item_user_var_as_out_param detection
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET sql_mode=NO_AUTO_VALUE_ON_ZERO;
|
||||||
|
CREATE TABLE t1 (id integer not null auto_increment primary key);
|
||||||
|
LOAD DATA INFILE '../../std_data/loaddata/nl.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
SET sql_mode='';
|
||||||
|
CREATE TABLE t1 (id integer not null auto_increment primary key);
|
||||||
|
LOAD DATA INFILE '../../std_data/loaddata/nl.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
18
sql/field.cc
18
sql/field.cc
@ -1375,7 +1375,25 @@ bool Field::load_data_set_no_data(THD *thd, bool fixed_format)
|
|||||||
{
|
{
|
||||||
reset(); // Do not use the DEFAULT value
|
reset(); // Do not use the DEFAULT value
|
||||||
if (fixed_format)
|
if (fixed_format)
|
||||||
|
{
|
||||||
set_notnull();
|
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
|
set_has_explicit_value(); // Do not auto-update this field
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
25
sql/item.cc
25
sql/item.cc
@ -2645,6 +2645,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, (uint) strlen(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
bool Item_field::enumerate_field_refs_processor(void *arg)
|
||||||
{
|
{
|
||||||
Field_enumerator *fe= (Field_enumerator*)arg;
|
Field_enumerator *fe= (Field_enumerator*)arg;
|
||||||
|
45
sql/item.h
45
sql/item.h
@ -1866,6 +1866,20 @@ public:
|
|||||||
{
|
{
|
||||||
return 0;
|
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);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Test whether an expression is expensive to compute. Used during
|
Test whether an expression is expensive to compute. Used during
|
||||||
optimization to avoid computing expensive expressions during this
|
optimization to avoid computing expensive expressions during this
|
||||||
@ -2538,7 +2552,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Item_field :public Item_ident
|
class Item_field :public Item_ident,
|
||||||
|
public Load_data_outvar
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
void set_field(Field *field);
|
void set_field(Field *field);
|
||||||
@ -2585,6 +2600,30 @@ public:
|
|||||||
bool val_bool_result();
|
bool val_bool_result();
|
||||||
bool is_null_result();
|
bool is_null_result();
|
||||||
bool send(Protocol *protocol, String *str_arg);
|
bool send(Protocol *protocol, String *str_arg);
|
||||||
|
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);
|
void reset_field(Field *f);
|
||||||
bool fix_fields(THD *, Item **);
|
bool fix_fields(THD *, Item **);
|
||||||
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
|
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
|
||||||
@ -4379,6 +4418,10 @@ public:
|
|||||||
void cleanup();
|
void cleanup();
|
||||||
Item_field *field_for_view_update()
|
Item_field *field_for_view_update()
|
||||||
{ return (*ref)->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; }
|
virtual Ref_Type ref_type() { return REF; }
|
||||||
|
|
||||||
// Row emulation: forwarding of ROW-related calls to ref
|
// Row emulation: forwarding of ROW-related calls to ref
|
||||||
|
@ -5751,7 +5751,9 @@ 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_for_log_event(THD *thd,
|
||||||
|
String *str)
|
||||||
|
const
|
||||||
{
|
{
|
||||||
str->append('@');
|
str->append('@');
|
||||||
append_identifier(thd, str, name.str, name.length);
|
append_identifier(thd, str, name.str, name.length);
|
||||||
|
@ -2038,13 +2038,43 @@ public:
|
|||||||
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_outvar
|
||||||
{
|
{
|
||||||
LEX_STRING name;
|
LEX_STRING name;
|
||||||
user_var_entry *entry;
|
user_var_entry *entry;
|
||||||
public:
|
public:
|
||||||
Item_user_var_as_out_param(THD *thd, LEX_STRING a): Item(thd), name(a)
|
Item_user_var_as_out_param(THD *thd, LEX_STRING a): Item(thd), name(a)
|
||||||
{ set_name(thd, a.str, 0, system_charset_info); }
|
{ set_name(thd, a.str, 0, 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 */
|
/* We should return something different from FIELD_ITEM here */
|
||||||
enum Type type() const { return STRING_ITEM;}
|
enum Type type() const { return STRING_ITEM;}
|
||||||
double val_real();
|
double val_real();
|
||||||
@ -2053,7 +2083,6 @@ public:
|
|||||||
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);
|
|
||||||
void set_null_value(CHARSET_INFO* cs);
|
void set_null_value(CHARSET_INFO* cs);
|
||||||
void set_value(const char *str, uint length, CHARSET_INFO* cs);
|
void 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; }
|
||||||
|
321
sql/sql_load.cc
321
sql/sql_load.cc
@ -134,11 +134,10 @@ static bool wsrep_load_data_split(THD *thd, const TABLE *table,
|
|||||||
#define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */
|
#define WSREP_LOAD_DATA_SPLIT(thd,table,info) /* empty */
|
||||||
#endif /* WITH_WSREP */
|
#endif /* WITH_WSREP */
|
||||||
|
|
||||||
class READ_INFO {
|
class READ_INFO: public Load_data_param
|
||||||
|
{
|
||||||
File file;
|
File file;
|
||||||
String data; /* Read buffer */
|
String data; /* Read buffer */
|
||||||
uint fixed_length; /* Length of the fixed length record */
|
|
||||||
uint max_length; /* Max length of row */
|
|
||||||
Term_string m_field_term; /* FIELDS TERMINATED BY 'string' */
|
Term_string m_field_term; /* FIELDS TERMINATED BY 'string' */
|
||||||
Term_string m_line_term; /* LINES TERMINATED BY 'string' */
|
Term_string m_line_term; /* LINES TERMINATED BY 'string' */
|
||||||
Term_string m_line_start; /* LINES STARTING BY 'string' */
|
Term_string m_line_start; /* LINES STARTING BY 'string' */
|
||||||
@ -191,7 +190,7 @@ class READ_INFO {
|
|||||||
bool read_mbtail(String *str)
|
bool read_mbtail(String *str)
|
||||||
{
|
{
|
||||||
int chlen;
|
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
|
return false; // Single byte character found
|
||||||
for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); )
|
for (uint32 length0= str->length() - 1 ; MY_CS_IS_TOOSMALL(chlen); )
|
||||||
{
|
{
|
||||||
@ -202,7 +201,7 @@ class READ_INFO {
|
|||||||
return true; // EOF
|
return true; // EOF
|
||||||
}
|
}
|
||||||
str->append(chr);
|
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)
|
if (chlen == MY_CS_ILSEQ)
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -224,10 +223,9 @@ public:
|
|||||||
bool error,line_cuted,found_null,enclosed;
|
bool error,line_cuted,found_null,enclosed;
|
||||||
uchar *row_start, /* Found row starts here */
|
uchar *row_start, /* Found row starts here */
|
||||||
*row_end; /* Found row ends here */
|
*row_end; /* Found row ends here */
|
||||||
CHARSET_INFO *read_charset;
|
|
||||||
LOAD_FILE_IO_CACHE cache;
|
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 &field_term,String &line_start,String &line_term,
|
||||||
String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
|
String &enclosed,int escape,bool get_it_from_net, bool is_fifo);
|
||||||
~READ_INFO();
|
~READ_INFO();
|
||||||
@ -282,6 +280,31 @@ static bool write_execute_load_query_log_event(THD *, sql_exchange*, const
|
|||||||
char*, const char*, bool, enum enum_duplicates, bool, bool, int);
|
char*, const char*, bool, enum enum_duplicates, bool, bool, int);
|
||||||
#endif /* EMBEDDED_LIBRARY */
|
#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
|
Execute LOAD DATA query
|
||||||
|
|
||||||
@ -313,8 +336,6 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
File file;
|
File file;
|
||||||
TABLE *table= NULL;
|
TABLE *table= NULL;
|
||||||
int error= 0;
|
int error= 0;
|
||||||
String *field_term=ex->field_term,*escaped=ex->escaped;
|
|
||||||
String *enclosed=ex->enclosed;
|
|
||||||
bool is_fifo=0;
|
bool is_fifo=0;
|
||||||
#ifndef EMBEDDED_LIBRARY
|
#ifndef EMBEDDED_LIBRARY
|
||||||
killed_state killed_status;
|
killed_state killed_status;
|
||||||
@ -343,7 +364,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
read_file_from_client = 0; //server is always in the same process
|
read_file_from_client = 0; //server is always in the same process
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (escaped->length() > 1 || enclosed->length() > 1)
|
if (ex->escaped->length() > 1 || ex->enclosed->length() > 1)
|
||||||
{
|
{
|
||||||
my_message(ER_WRONG_FIELD_TERMINATORS,
|
my_message(ER_WRONG_FIELD_TERMINATORS,
|
||||||
ER_THD(thd, ER_WRONG_FIELD_TERMINATORS),
|
ER_THD(thd, ER_WRONG_FIELD_TERMINATORS),
|
||||||
@ -352,8 +373,8 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Report problems with non-ascii separators */
|
/* Report problems with non-ascii separators */
|
||||||
if (!escaped->is_ascii() || !enclosed->is_ascii() ||
|
if (!ex->escaped->is_ascii() || !ex->enclosed->is_ascii() ||
|
||||||
!field_term->is_ascii() ||
|
!ex->field_term->is_ascii() ||
|
||||||
!ex->line_term->is_ascii() || !ex->line_start->is_ascii())
|
!ex->line_term->is_ascii() || !ex->line_start->is_ascii())
|
||||||
{
|
{
|
||||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||||
@ -450,39 +471,21 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
table->prepare_triggers_for_insert_stmt_or_event();
|
table->prepare_triggers_for_insert_stmt_or_event();
|
||||||
table->mark_columns_needed_for_insert();
|
table->mark_columns_needed_for_insert();
|
||||||
|
|
||||||
uint tot_length=0;
|
Load_data_param param(ex->cs ? ex->cs : thd->variables.collation_database,
|
||||||
bool use_blobs= 0, use_vars= 0;
|
!ex->field_term->length() && !ex->enclosed->length());
|
||||||
List_iterator_fast<Item> it(fields_vars);
|
List_iterator_fast<Item> it(fields_vars);
|
||||||
Item *item;
|
Item *item;
|
||||||
|
|
||||||
while ((item= it++))
|
while ((item= it++))
|
||||||
{
|
{
|
||||||
Item *real_item= item->real_item();
|
const Load_data_outvar *var= item->get_load_data_outvar_or_error();
|
||||||
|
if (!var || var->load_data_add_outvar(thd, ¶m))
|
||||||
if (real_item->type() == Item::FIELD_ITEM)
|
DBUG_RETURN(true);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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,
|
my_message(ER_BLOBS_AND_NO_TERMINATED,
|
||||||
ER_THD(thd, ER_BLOBS_AND_NO_TERMINATED),
|
ER_THD(thd, ER_BLOBS_AND_NO_TERMINATED), MYF(0));
|
||||||
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));
|
|
||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,13 +575,13 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
bzero((char*) &info,sizeof(info));
|
bzero((char*) &info,sizeof(info));
|
||||||
info.ignore= ignore;
|
info.ignore= ignore;
|
||||||
info.handle_duplicates=handle_duplicates;
|
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)))
|
!(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,
|
READ_INFO read_info(thd, file, param,
|
||||||
ex->cs ? ex->cs : thd->variables.collation_database,
|
*ex->field_term, *ex->line_start,
|
||||||
*field_term,*ex->line_start, *ex->line_term, *enclosed,
|
*ex->line_term, *ex->enclosed,
|
||||||
info.escape_char, read_file_from_client, is_fifo);
|
info.escape_char, read_file_from_client, is_fifo);
|
||||||
if (read_info.error)
|
if (read_info.error)
|
||||||
{
|
{
|
||||||
@ -639,14 +642,14 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
|||||||
error= read_xml_field(thd, info, table_list, fields_vars,
|
error= read_xml_field(thd, info, table_list, fields_vars,
|
||||||
set_fields, set_values, read_info,
|
set_fields, set_values, read_info,
|
||||||
*(ex->line_term), skip_lines, ignore);
|
*(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,
|
error= read_fixed_length(thd, info, table_list, fields_vars,
|
||||||
set_fields, set_values, read_info,
|
set_fields, set_values, read_info,
|
||||||
skip_lines, ignore);
|
skip_lines, ignore);
|
||||||
else
|
else
|
||||||
error= read_sep_field(thd, info, table_list, fields_vars,
|
error= read_sep_field(thd, info, table_list, fields_vars,
|
||||||
set_fields, set_values, read_info,
|
set_fields, set_values, read_info,
|
||||||
*enclosed, skip_lines, ignore);
|
*ex->enclosed, skip_lines, ignore);
|
||||||
|
|
||||||
thd_proc_info(thd, "End bulk insert");
|
thd_proc_info(thd, "End bulk insert");
|
||||||
if (!error)
|
if (!error)
|
||||||
@ -850,14 +853,9 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
|
|||||||
{
|
{
|
||||||
if (n++)
|
if (n++)
|
||||||
query_str.append(", ");
|
query_str.append(", ");
|
||||||
if (item->real_type() == Item::FIELD_ITEM)
|
const Load_data_outvar *var= item->get_load_data_outvar();
|
||||||
append_identifier(thd, &query_str, item->name, strlen(item->name));
|
DBUG_ASSERT(var);
|
||||||
else
|
var->load_data_print_for_log_event(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(")");
|
||||||
}
|
}
|
||||||
@ -905,9 +903,9 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
ulong skip_lines, bool ignore_check_option_errors)
|
ulong skip_lines, bool ignore_check_option_errors)
|
||||||
{
|
{
|
||||||
List_iterator_fast<Item> it(fields_vars);
|
List_iterator_fast<Item> it(fields_vars);
|
||||||
Item_field *sql_field;
|
Item *item;
|
||||||
TABLE *table= table_list->table;
|
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;
|
ulonglong counter, time_to_report_progress;
|
||||||
DBUG_ENTER("read_fixed_length");
|
DBUG_ENTER("read_fixed_length");
|
||||||
|
|
||||||
@ -917,12 +915,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)
|
if ((thd->progress.max_counter= read_info.file_length()) == ~(my_off_t) 0)
|
||||||
progress_reports= 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())
|
while (!read_info.read_fixed_length())
|
||||||
{
|
{
|
||||||
if (thd->killed)
|
if (thd->killed)
|
||||||
@ -958,36 +950,27 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
restore_record(table, s->default_values);
|
restore_record(table, s->default_values);
|
||||||
/*
|
|
||||||
There is no variables in fields_vars list in this format so
|
while ((item= it++))
|
||||||
this conversion is safe.
|
|
||||||
*/
|
|
||||||
while ((sql_field= (Item_field*) it++))
|
|
||||||
{
|
{
|
||||||
Field *field= sql_field->field;
|
Load_data_outvar *dst= item->get_load_data_outvar();
|
||||||
table->auto_increment_field_not_null= auto_increment_field_not_null;
|
DBUG_ASSERT(dst);
|
||||||
if (pos == read_info.row_end)
|
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
uint length;
|
uint length, fixed_length= dst->load_data_fixed_length();
|
||||||
uchar save_chr;
|
uchar save_chr;
|
||||||
if ((length=(uint) (read_info.row_end-pos)) >
|
if ((length=(uint) (read_info.row_end - pos)) > fixed_length)
|
||||||
field->field_length)
|
length= fixed_length;
|
||||||
length=field->field_length;
|
save_chr= pos[length]; pos[length]= '\0'; // Safeguard aganst malloc
|
||||||
save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc
|
dst->load_data_set_value(thd, (const char *) pos, length, &read_info);
|
||||||
field->load_data_set_value((char*) pos,length,read_info.read_charset);
|
pos[length]= save_chr;
|
||||||
pos[length]=save_chr;
|
if ((pos+= length) > read_info.row_end)
|
||||||
if ((pos+=length) > read_info.row_end)
|
pos= read_info.row_end; // Fills rest with space
|
||||||
pos= read_info.row_end; /* Fills rest with space */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pos != read_info.row_end)
|
if (pos != read_info.row_end)
|
||||||
@ -1087,8 +1070,6 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
{
|
{
|
||||||
uint length;
|
uint length;
|
||||||
uchar *pos;
|
uchar *pos;
|
||||||
Item_field *real_item;
|
|
||||||
|
|
||||||
if (read_info.read_field())
|
if (read_info.read_field())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1099,48 +1080,22 @@ 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->field_for_view_update();
|
Load_data_outvar *dst= item->get_load_data_outvar_or_error();
|
||||||
|
DBUG_ASSERT(dst);
|
||||||
|
|
||||||
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::STRING_ITEM)
|
if (dst->load_data_set_null(thd, &read_info))
|
||||||
{
|
|
||||||
((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);
|
|
||||||
DBUG_RETURN(1);
|
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);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Field *field= real_item->field;
|
read_info.row_end[0]= 0; // Safe to change end marker
|
||||||
read_info.row_end[0]=0; // Safe to change end marker
|
if (dst->load_data_set_value(thd, (const char *) pos, length, &read_info))
|
||||||
field->load_data_set_value((char*) pos, length, read_info.read_charset);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1161,34 +1116,10 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
break;
|
break;
|
||||||
for (; item ; item= it++)
|
for (; item ; item= it++)
|
||||||
{
|
{
|
||||||
Item_field *real_item= item->field_for_view_update();
|
Load_data_outvar *dst= item->get_load_data_outvar_or_error();
|
||||||
if (item->type() == Item::STRING_ITEM)
|
DBUG_ASSERT(dst);
|
||||||
{
|
if (dst->load_data_set_no_data(thd, &read_info))
|
||||||
((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);
|
|
||||||
DBUG_RETURN(1);
|
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1250,7 +1181,6 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
Item *item;
|
Item *item;
|
||||||
TABLE *table= table_list->table;
|
TABLE *table= table_list->table;
|
||||||
bool no_trans_update_stmt;
|
bool no_trans_update_stmt;
|
||||||
CHARSET_INFO *cs= read_info.read_charset;
|
|
||||||
DBUG_ENTER("read_xml_field");
|
DBUG_ENTER("read_xml_field");
|
||||||
|
|
||||||
no_trans_update_stmt= !table->file->has_transactions();
|
no_trans_update_stmt= !table->file->has_transactions();
|
||||||
@ -1297,40 +1227,13 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
|
while(tag && strcmp(tag->field.c_ptr(), item->name) != 0)
|
||||||
tag= xmlit++;
|
tag= xmlit++;
|
||||||
|
|
||||||
Item_field *real_item= item->field_for_view_update();
|
Load_data_outvar *dst= item->get_load_data_outvar_or_error();
|
||||||
if (!tag) // found null
|
DBUG_ASSERT(dst);
|
||||||
{
|
if (!tag ? dst->load_data_set_null(thd, &read_info) :
|
||||||
if (item->type() == Item::STRING_ITEM)
|
dst->load_data_set_value(thd, tag->value.ptr(),
|
||||||
((Item_user_var_as_out_param *) item)->set_null_value(cs);
|
tag->value.length(),
|
||||||
else if (!real_item)
|
&read_info))
|
||||||
{
|
|
||||||
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
|
|
||||||
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);
|
|
||||||
DBUG_RETURN(1);
|
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)
|
if (read_info.error)
|
||||||
@ -1342,38 +1245,7 @@ read_xml_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item)
|
DBUG_ASSERT(!item);
|
||||||
{
|
|
||||||
/* Have not read any field, thus input file is simply ended */
|
|
||||||
if (item == fields_vars.head())
|
|
||||||
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(cs);
|
|
||||||
else if (!real_item)
|
|
||||||
{
|
|
||||||
my_error(ER_NONUPDATEABLE_COLUMN, MYF(0), item->name);
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
QQ: 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());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thd->killed ||
|
if (thd->killed ||
|
||||||
fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
|
fill_record_n_invoke_before_triggers(thd, table, set_fields, set_values,
|
||||||
@ -1435,14 +1307,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 &field_term, String &line_start, String &line_term,
|
||||||
String &enclosed_par, int escape, bool get_it_from_net,
|
String &enclosed_par, int escape, bool get_it_from_net,
|
||||||
bool is_fifo)
|
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),
|
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),
|
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();
|
data.set_thread_specific();
|
||||||
/*
|
/*
|
||||||
@ -1459,12 +1333,13 @@ 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;
|
enclosed_char= enclosed_par.length() ? (uchar) enclosed_par[0] : INT_MAX;
|
||||||
|
|
||||||
/* Set of a stack for unget if long terminators */
|
/* Set of a stack for unget if long terminators */
|
||||||
uint length= MY_MAX(cs->mbmaxlen, MY_MAX(m_field_term.length(),
|
uint length= MY_MAX(charset()->mbmaxlen, MY_MAX(m_field_term.length(),
|
||||||
m_line_term.length())) + 1;
|
m_line_term.length())) + 1;
|
||||||
set_if_bigger(length,line_start.length());
|
set_if_bigger(length,line_start.length());
|
||||||
stack= stack_pos= (int*) thd->alloc(sizeof(int) * length);
|
stack= stack_pos= (int*) thd->alloc(sizeof(int) * length);
|
||||||
|
|
||||||
if (data.reserve(tot_length))
|
DBUG_ASSERT(m_fixed_length < UINT_MAX32);
|
||||||
|
if (data.reserve((size_t) m_fixed_length))
|
||||||
error=1; /* purecov: inspected */
|
error=1; /* purecov: inspected */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1606,7 +1481,7 @@ int READ_INFO::read_field()
|
|||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
// Make sure we have enough space for the longest multi-byte character.
|
// 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;
|
chr = GET;
|
||||||
if (chr == my_b_EOF)
|
if (chr == my_b_EOF)
|
||||||
@ -1692,7 +1567,7 @@ int READ_INFO::read_field()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
data.append(chr);
|
data.append(chr);
|
||||||
if (use_mb(read_charset) && read_mbtail(&data))
|
if (use_mb(charset()) && read_mbtail(&data))
|
||||||
goto found_eof;
|
goto found_eof;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -1738,7 +1613,7 @@ int READ_INFO::read_fixed_length()
|
|||||||
return 1;
|
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)
|
if ((chr=GET) == my_b_EOF)
|
||||||
goto found_eof;
|
goto found_eof;
|
||||||
@ -1791,8 +1666,8 @@ int READ_INFO::next_line()
|
|||||||
if (getbyte(&buf[0]))
|
if (getbyte(&buf[0]))
|
||||||
return 1; // EOF
|
return 1; // EOF
|
||||||
|
|
||||||
if (use_mb(read_charset) &&
|
if (use_mb(charset()) &&
|
||||||
(chlen= my_charlen(read_charset, buf, buf + 1)) != 1)
|
(chlen= my_charlen(charset(), buf, buf + 1)) != 1)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
for (i= 1; MY_CS_IS_TOOSMALL(chlen); )
|
for (i= 1; MY_CS_IS_TOOSMALL(chlen); )
|
||||||
@ -1801,7 +1676,7 @@ int READ_INFO::next_line()
|
|||||||
DBUG_ASSERT(chlen != 1);
|
DBUG_ASSERT(chlen != 1);
|
||||||
if (getbyte(&buf[i++]))
|
if (getbyte(&buf[i++]))
|
||||||
return 1; // EOF
|
return 1; // EOF
|
||||||
chlen= my_charlen(read_charset, buf, buf + i);
|
chlen= my_charlen(charset(), buf, buf + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1972,7 +1847,7 @@ int READ_INFO::read_value(int delim, String *val)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
val->append(chr);
|
val->append(chr);
|
||||||
if (use_mb(read_charset) && read_mbtail(val))
|
if (use_mb(charset()) && read_mbtail(val))
|
||||||
return my_b_EOF;
|
return my_b_EOF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,4 +629,40 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
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 */
|
#endif /* STRUCTS_INCLUDED */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user