Commit 80c3fd18 authored by Alexander Barkov's avatar Alexander Barkov

Backporting MDEV-15597 Add class Load_data_outvar and avoid using...

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"
parent 8036ad54
......@@ -614,3 +614,24 @@ SELECT * FROM t1;
a b
1
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;
......@@ -700,3 +700,19 @@ TRUNCATE TABLE t1;
LOAD DATA INFILE '../../std_data/loaddata/mdev-15497.txt' INTO TABLE t1 FIELDS TERMINATED BY '';
SELECT * FROM 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;
......@@ -1375,7 +1375,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;
}
......
......@@ -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)
{
Field_enumerator *fe= (Field_enumerator*)arg;
......
......@@ -1866,6 +1866,20 @@ class Item: public Value_source,
{
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
optimization to avoid computing expensive expressions during this
......@@ -2538,7 +2552,8 @@ class Item_ident_for_show :public Item
};
class Item_field :public Item_ident
class Item_field :public Item_ident,
public Load_data_outvar
{
protected:
void set_field(Field *field);
......@@ -2585,6 +2600,30 @@ class Item_field :public Item_ident
bool val_bool_result();
bool is_null_result();
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);
bool fix_fields(THD *, Item **);
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge);
......@@ -4379,6 +4418,10 @@ class Item_ref :public Item_ident
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
......
......@@ -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('@');
append_identifier(thd, str, name.str, name.length);
......
......@@ -2038,13 +2038,43 @@ class Item_func_get_user_var :public Item_func_user_var,
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_STRING name;
user_var_entry *entry;
public:
Item_user_var_as_out_param(THD *thd, LEX_STRING a): Item(thd), name(a)
{ 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 */
enum Type type() const { return STRING_ITEM;}
double val_real();
......@@ -2053,7 +2083,6 @@ class Item_user_var_as_out_param :public Item
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);
enum_field_types field_type() const { return MYSQL_TYPE_DOUBLE; }
......
This diff is collapsed.
......@@ -629,4 +629,40 @@ struct Lex_dyncol_type_st: public Lex_length_and_dec_st
};
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 */
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