MDEV-11134 Assertion `fixed' failed in Item::const_charset_converter(THD*, CHARSET_INFO*, bool, const char*)
Problem: Item_param::basic_const_item() returned true when fixed==false. This unexpected combination made Item::const_charset_converter() crash on asserts. Fix: - Changing all Item_param::set_xxx() to set "fixed" to true. This fixes the problem. - Additionally, changing all Item_param::set_xxx() to set Item_param::item_type, to avoid duplicate code, and for consistency, to make the code symmetric between different constant types. Before this patch only set_null() set item_type. - Moving Item_param::state and Item_param::item_type from public to private, to make sure easier that these members are in sync with "fixed" and to each other. - Adding a new argument "unsigned_arg" to Item::set_decimal(), and reusing it in two places instead of duplicate code. - Adding a new method Item_param::fix_temporal() and reusing it in two places. - Adding methods has_no_value(), has_long_data_value(), has_int_value(), instead of direct access to Item_param::state.
This commit is contained in:
parent
31031a52da
commit
45e40892c5
@ -3278,6 +3278,44 @@ INSERT INTO t1 VALUES (1),(2),(3);
|
|||||||
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
|
EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFAULT,DEFAULT;
|
||||||
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
ERROR HY000: Default/ignore value is not supported for such parameter usage
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# MDEV-11134 Assertion `fixed' failed in Item::const_charset_converter(THD*, CHARSET_INFO*, bool, const char*)
|
||||||
|
#
|
||||||
|
SET NAMES utf8;
|
||||||
|
PREPARE stmt FROM "CREATE OR REPLACE TABLE t1 (c CHAR(8) DEFAULT ?)";
|
||||||
|
SET @a='';
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c` char(8) DEFAULT ''
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a='A';
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c` char(8) DEFAULT 'A'
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a=_utf8 0xC380;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
Table Create Table
|
||||||
|
t1 CREATE TABLE `t1` (
|
||||||
|
`c` char(8) DEFAULT 'À'
|
||||||
|
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a=_utf8 0xD18F;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
ERROR 42000: Invalid default value for 'c'
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
ERROR 42000: Invalid default value for 'c'
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
# end of 10.2 test
|
# end of 10.2 test
|
||||||
set sql_mode=ansi_quotes;
|
set sql_mode=ansi_quotes;
|
||||||
create table t1 (a int, b int default (a+1));
|
create table t1 (a int, b int default (a+1));
|
||||||
|
@ -2013,6 +2013,36 @@ EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFA
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-11134 Assertion `fixed' failed in Item::const_charset_converter(THD*, CHARSET_INFO*, bool, const char*)
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES utf8;
|
||||||
|
PREPARE stmt FROM "CREATE OR REPLACE TABLE t1 (c CHAR(8) DEFAULT ?)";
|
||||||
|
SET @a='';
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a='A';
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a=_utf8 0xC380; # LATIN CAPITAL LETTER A WITH GRAVE
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
SHOW CREATE TABLE t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
SET @a=_utf8 0xD18F; # Cyrillic letter into a latin1 column
|
||||||
|
--error ER_INVALID_DEFAULT
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
--error ER_INVALID_DEFAULT
|
||||||
|
EXECUTE stmt USING @a;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
--echo # end of 10.2 test
|
--echo # end of 10.2 test
|
||||||
|
|
||||||
#
|
#
|
||||||
|
69
sql/item.cc
69
sql/item.cc
@ -3309,9 +3309,9 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
|
|||||||
Rewritable_query_parameter(pos_in_query_arg, 1),
|
Rewritable_query_parameter(pos_in_query_arg, 1),
|
||||||
Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
|
Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
|
||||||
state(NO_VALUE),
|
state(NO_VALUE),
|
||||||
indicators(0), indicator(STMT_INDICATOR_NONE),
|
|
||||||
/* Don't pretend to be a literal unless value for this item is set. */
|
/* Don't pretend to be a literal unless value for this item is set. */
|
||||||
item_type(PARAM_ITEM),
|
item_type(PARAM_ITEM),
|
||||||
|
indicators(0), indicator(STMT_INDICATOR_NONE),
|
||||||
set_param_func(default_set_param_func),
|
set_param_func(default_set_param_func),
|
||||||
m_out_param_info(NULL)
|
m_out_param_info(NULL)
|
||||||
{
|
{
|
||||||
@ -3338,7 +3338,7 @@ void Item_param::set_null()
|
|||||||
max_length= 0;
|
max_length= 0;
|
||||||
decimals= 0;
|
decimals= 0;
|
||||||
state= NULL_VALUE;
|
state= NULL_VALUE;
|
||||||
item_type= Item::NULL_ITEM;
|
fix_type(Item::NULL_ITEM);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3350,6 +3350,7 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
|
|||||||
max_length= max_length_arg;
|
max_length= max_length_arg;
|
||||||
decimals= 0;
|
decimals= 0;
|
||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
|
fix_type(Item::INT_ITEM);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3361,6 +3362,7 @@ void Item_param::set_double(double d)
|
|||||||
max_length= DBL_DIG + 8;
|
max_length= DBL_DIG + 8;
|
||||||
decimals= NOT_FIXED_DEC;
|
decimals= NOT_FIXED_DEC;
|
||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
|
fix_type(Item::REAL_ITEM);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3390,21 +3392,41 @@ void Item_param::set_decimal(const char *str, ulong length)
|
|||||||
my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
|
my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
|
||||||
decimals, unsigned_flag);
|
decimals, unsigned_flag);
|
||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
|
fix_type(Item::DECIMAL_ITEM);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Item_param::set_decimal(const my_decimal *dv)
|
void Item_param::set_decimal(const my_decimal *dv, bool unsigned_arg)
|
||||||
{
|
{
|
||||||
state= DECIMAL_VALUE;
|
state= DECIMAL_VALUE;
|
||||||
|
|
||||||
my_decimal2decimal(dv, &decimal_value);
|
my_decimal2decimal(dv, &decimal_value);
|
||||||
|
|
||||||
decimals= (uint8) decimal_value.frac;
|
decimals= (uint8) decimal_value.frac;
|
||||||
unsigned_flag= !decimal_value.sign();
|
unsigned_flag= unsigned_arg;
|
||||||
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
|
max_length= my_decimal_precision_to_length(decimal_value.intg + decimals,
|
||||||
decimals, unsigned_flag);
|
decimals, unsigned_flag);
|
||||||
|
fix_type(Item::DECIMAL_ITEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
|
||||||
|
{
|
||||||
|
state= TIME_VALUE;
|
||||||
|
max_length= max_length_arg;
|
||||||
|
decimals= decimals_arg;
|
||||||
|
fix_type(Item::DATE_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Item_param::set_time(const MYSQL_TIME *tm,
|
||||||
|
uint32 max_length_arg, uint decimals_arg)
|
||||||
|
{
|
||||||
|
value.time= *tm;
|
||||||
|
fix_temporal(max_length_arg, decimals_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Set parameter value from MYSQL_TIME value.
|
Set parameter value from MYSQL_TIME value.
|
||||||
|
|
||||||
@ -3433,11 +3455,9 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
|
|||||||
&str, time_type, 0);
|
&str, time_type, 0);
|
||||||
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
|
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
state= TIME_VALUE;
|
|
||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
max_length= max_length_arg;
|
fix_temporal(max_length_arg,
|
||||||
decimals= tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0;
|
tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0);
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3458,6 +3478,7 @@ bool Item_param::set_str(const char *str, ulong length)
|
|||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
/* max_length and decimals are set after charset conversion */
|
/* max_length and decimals are set after charset conversion */
|
||||||
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
|
/* sic: str may be not null-terminated, don't add DBUG_PRINT here */
|
||||||
|
fix_type(Item::STRING_ITEM);
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3489,6 +3510,7 @@ bool Item_param::set_longdata(const char *str, ulong length)
|
|||||||
DBUG_RETURN(TRUE);
|
DBUG_RETURN(TRUE);
|
||||||
state= LONG_DATA_VALUE;
|
state= LONG_DATA_VALUE;
|
||||||
maybe_null= 0;
|
maybe_null= 0;
|
||||||
|
fix_type(Item::STRING_ITEM);
|
||||||
|
|
||||||
DBUG_RETURN(FALSE);
|
DBUG_RETURN(FALSE);
|
||||||
}
|
}
|
||||||
@ -3547,7 +3569,6 @@ bool Item_param::set_from_item(THD *thd, Item *item)
|
|||||||
{
|
{
|
||||||
unsigned_flag= item->unsigned_flag;
|
unsigned_flag= item->unsigned_flag;
|
||||||
set_int(val, MY_INT64_NUM_DECIMAL_DIGITS);
|
set_int(val, MY_INT64_NUM_DECIMAL_DIGITS);
|
||||||
item_type= Item::INT_ITEM;
|
|
||||||
set_handler_by_result_type(item->result_type());
|
set_handler_by_result_type(item->result_type());
|
||||||
DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
|
DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
|
||||||
}
|
}
|
||||||
@ -3559,12 +3580,10 @@ bool Item_param::set_from_item(THD *thd, Item *item)
|
|||||||
switch (item->cmp_type()) {
|
switch (item->cmp_type()) {
|
||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
set_double(tmp.value.m_double);
|
set_double(tmp.value.m_double);
|
||||||
item_type= Item::REAL_ITEM;
|
|
||||||
set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
|
set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
|
||||||
break;
|
break;
|
||||||
case INT_RESULT:
|
case INT_RESULT:
|
||||||
set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS);
|
set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS);
|
||||||
item_type= Item::INT_ITEM;
|
|
||||||
set_handler_by_field_type(MYSQL_TYPE_LONGLONG);
|
set_handler_by_field_type(MYSQL_TYPE_LONGLONG);
|
||||||
break;
|
break;
|
||||||
case STRING_RESULT:
|
case STRING_RESULT:
|
||||||
@ -3574,7 +3593,6 @@ bool Item_param::set_from_item(THD *thd, Item *item)
|
|||||||
Exact value of max_length is not known unless data is converted to
|
Exact value of max_length is not known unless data is converted to
|
||||||
charset of connection, so we have to set it later.
|
charset of connection, so we have to set it later.
|
||||||
*/
|
*/
|
||||||
item_type= Item::STRING_ITEM;
|
|
||||||
set_handler_by_field_type(MYSQL_TYPE_VARCHAR);
|
set_handler_by_field_type(MYSQL_TYPE_VARCHAR);
|
||||||
|
|
||||||
if (set_str(tmp.m_string.ptr(), tmp.m_string.length()))
|
if (set_str(tmp.m_string.ptr(), tmp.m_string.length()))
|
||||||
@ -3583,24 +3601,13 @@ bool Item_param::set_from_item(THD *thd, Item *item)
|
|||||||
}
|
}
|
||||||
case DECIMAL_RESULT:
|
case DECIMAL_RESULT:
|
||||||
{
|
{
|
||||||
const my_decimal *ent_value= &tmp.m_decimal;
|
set_decimal(&tmp.m_decimal, unsigned_flag);
|
||||||
my_decimal2decimal(ent_value, &decimal_value);
|
|
||||||
state= DECIMAL_VALUE;
|
|
||||||
decimals= ent_value->frac;
|
|
||||||
max_length=
|
|
||||||
my_decimal_precision_to_length_no_truncation(ent_value->precision(),
|
|
||||||
decimals, unsigned_flag);
|
|
||||||
item_type= Item::DECIMAL_ITEM;
|
|
||||||
set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL);
|
set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TIME_RESULT:
|
case TIME_RESULT:
|
||||||
{
|
{
|
||||||
value.time= tmp.value.m_time;
|
set_time(&tmp.value.m_time, item->max_length, item->decimals);
|
||||||
state= TIME_VALUE;
|
|
||||||
max_length= item->max_length;
|
|
||||||
decimals= item->decimals;
|
|
||||||
item_type= Item::DATE_ITEM;
|
|
||||||
set_handler(item->type_handler());
|
set_handler(item->type_handler());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -3641,6 +3648,7 @@ void Item_param::reset()
|
|||||||
state= NO_VALUE;
|
state= NO_VALUE;
|
||||||
maybe_null= 1;
|
maybe_null= 1;
|
||||||
null_value= 0;
|
null_value= 0;
|
||||||
|
fixed= false;
|
||||||
/*
|
/*
|
||||||
Don't reset item_type to PARAM_ITEM: it's only needed to guard
|
Don't reset item_type to PARAM_ITEM: it's only needed to guard
|
||||||
us from item optimizations at prepare stage, when item doesn't yet
|
us from item optimizations at prepare stage, when item doesn't yet
|
||||||
@ -3978,6 +3986,7 @@ bool Item_param::convert_str_value(THD *thd)
|
|||||||
|
|
||||||
bool Item_param::basic_const_item() const
|
bool Item_param::basic_const_item() const
|
||||||
{
|
{
|
||||||
|
DBUG_ASSERT(fixed || state == NO_VALUE);
|
||||||
if (state == NO_VALUE || state == TIME_VALUE)
|
if (state == NO_VALUE || state == TIME_VALUE)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@ -4112,6 +4121,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
|
|||||||
maybe_null= src->maybe_null;
|
maybe_null= src->maybe_null;
|
||||||
null_value= src->null_value;
|
null_value= src->null_value;
|
||||||
state= src->state;
|
state= src->state;
|
||||||
|
fixed= src->fixed;
|
||||||
value= src->value;
|
value= src->value;
|
||||||
|
|
||||||
decimal_value.swap(src->decimal_value);
|
decimal_value.swap(src->decimal_value);
|
||||||
@ -4123,6 +4133,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
|
|||||||
void Item_param::set_default()
|
void Item_param::set_default()
|
||||||
{
|
{
|
||||||
state= DEFAULT_VALUE;
|
state= DEFAULT_VALUE;
|
||||||
|
fixed= true;
|
||||||
/*
|
/*
|
||||||
When Item_param is set to DEFAULT_VALUE:
|
When Item_param is set to DEFAULT_VALUE:
|
||||||
- its val_str() and val_decimal() return NULL
|
- its val_str() and val_decimal() return NULL
|
||||||
@ -4137,6 +4148,7 @@ void Item_param::set_default()
|
|||||||
void Item_param::set_ignore()
|
void Item_param::set_ignore()
|
||||||
{
|
{
|
||||||
state= IGNORE_VALUE;
|
state= IGNORE_VALUE;
|
||||||
|
fixed= true;
|
||||||
null_value= true;
|
null_value= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4182,18 +4194,15 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
|
|||||||
str_value.charset());
|
str_value.charset());
|
||||||
collation.set(str_value.charset(), DERIVATION_COERCIBLE);
|
collation.set(str_value.charset(), DERIVATION_COERCIBLE);
|
||||||
decimals= 0;
|
decimals= 0;
|
||||||
item_type= Item::STRING_ITEM;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case REAL_RESULT:
|
case REAL_RESULT:
|
||||||
set_double(arg->val_real());
|
set_double(arg->val_real());
|
||||||
item_type= Item::REAL_ITEM;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case INT_RESULT:
|
case INT_RESULT:
|
||||||
set_int(arg->val_int(), arg->max_length);
|
set_int(arg->val_int(), arg->max_length);
|
||||||
item_type= Item::INT_ITEM;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DECIMAL_RESULT:
|
case DECIMAL_RESULT:
|
||||||
@ -4204,8 +4213,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
|
|||||||
if (!dv)
|
if (!dv)
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
set_decimal(dv);
|
set_decimal(dv, !dv->sign());
|
||||||
item_type= Item::DECIMAL_ITEM;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4215,7 +4223,6 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
|
|||||||
DBUG_ASSERT(TRUE); // Abort in debug mode.
|
DBUG_ASSERT(TRUE); // Abort in debug mode.
|
||||||
|
|
||||||
set_null(); // Set to NULL in release mode.
|
set_null(); // Set to NULL in release mode.
|
||||||
item_type= Item::NULL_ITEM;
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
sql/item.h
76
sql/item.h
@ -2762,7 +2762,47 @@ class Item_param :public Item_basic_value,
|
|||||||
public Rewritable_query_parameter,
|
public Rewritable_query_parameter,
|
||||||
public Type_handler_hybrid_field_type
|
public Type_handler_hybrid_field_type
|
||||||
{
|
{
|
||||||
public:
|
/*
|
||||||
|
NO_VALUE is a special value meaning that the parameter has not been
|
||||||
|
assigned yet. Item_param::state is assigned to NO_VALUE in constructor
|
||||||
|
and is used at prepare time.
|
||||||
|
|
||||||
|
1. At prepare time
|
||||||
|
Item_param::fix_fields() sets "fixed" to true,
|
||||||
|
but as Item_param::state is still NO_VALUE,
|
||||||
|
Item_param::basic_const_item() returns false. This prevents various
|
||||||
|
optimizations to happen at prepare time fix_fields().
|
||||||
|
For example, in this query:
|
||||||
|
PREPARE stmt FROM 'SELECT FORMAT(10000,2,?)';
|
||||||
|
Item_param::basic_const_item() is tested from
|
||||||
|
Item_func_format::fix_length_and_dec().
|
||||||
|
|
||||||
|
2. At execute time:
|
||||||
|
When Item_param gets a value
|
||||||
|
(or a pseudo-value like DEFAULT_VALUE or IGNORE_VALUE):
|
||||||
|
- Item_param::state changes from NO_VALUE to something else
|
||||||
|
- Item_param::fixed is changed to true
|
||||||
|
All Item_param::set_xxx() make sure to do so.
|
||||||
|
In the state with an assigned value:
|
||||||
|
- Item_param::basic_const_item() returns true
|
||||||
|
- Item::type() returns NULL_ITEM, INT_ITEM, REAL_ITEM, DECIMAL_ITEM,
|
||||||
|
DATE_ITEM, STRING_ITEM, depending on the value assigned.
|
||||||
|
So in this state Item_param behaves in many cases like a literal.
|
||||||
|
|
||||||
|
When Item_param::cleanup() is called:
|
||||||
|
- Item_param::state does not change
|
||||||
|
- Item_param::fixed changes to false
|
||||||
|
Note, this puts Item_param into an inconsistent state:
|
||||||
|
- Item_param::basic_const_item() still returns "true"
|
||||||
|
- Item_param::type() still pretends to be a basic constant Item
|
||||||
|
Both are not expected in combination with fixed==false.
|
||||||
|
However, these methods are not really called in this state,
|
||||||
|
see asserts in Item_param::basic_const_item() and Item_param::type().
|
||||||
|
|
||||||
|
When Item_param::reset() is called:
|
||||||
|
- Item_param::state changes to NO_VALUE
|
||||||
|
- Item_param::fixed changes to false
|
||||||
|
*/
|
||||||
enum enum_item_param_state
|
enum enum_item_param_state
|
||||||
{
|
{
|
||||||
NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
|
NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
|
||||||
@ -2770,6 +2810,17 @@ public:
|
|||||||
DECIMAL_VALUE, DEFAULT_VALUE, IGNORE_VALUE
|
DECIMAL_VALUE, DEFAULT_VALUE, IGNORE_VALUE
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
|
enum Type item_type;
|
||||||
|
|
||||||
|
void fix_type(Type type)
|
||||||
|
{
|
||||||
|
item_type= type;
|
||||||
|
fixed= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fix_temporal(uint32 max_length_arg, uint decimals_arg);
|
||||||
|
|
||||||
|
public:
|
||||||
struct CONVERSION_INFO
|
struct CONVERSION_INFO
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -2838,8 +2889,6 @@ public:
|
|||||||
MYSQL_TIME time;
|
MYSQL_TIME time;
|
||||||
} value;
|
} value;
|
||||||
|
|
||||||
enum Type item_type;
|
|
||||||
|
|
||||||
enum_field_types field_type() const
|
enum_field_types field_type() const
|
||||||
{ return Type_handler_hybrid_field_type::field_type(); }
|
{ return Type_handler_hybrid_field_type::field_type(); }
|
||||||
enum Item_result result_type () const
|
enum Item_result result_type () const
|
||||||
@ -2849,7 +2898,11 @@ public:
|
|||||||
|
|
||||||
Item_param(THD *thd, uint pos_in_query_arg);
|
Item_param(THD *thd, uint pos_in_query_arg);
|
||||||
|
|
||||||
enum Type type() const { return item_type; }
|
enum Type type() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(fixed || state == NO_VALUE);
|
||||||
|
return item_type;
|
||||||
|
}
|
||||||
|
|
||||||
double val_real();
|
double val_real();
|
||||||
longlong val_int();
|
longlong val_int();
|
||||||
@ -2864,10 +2917,11 @@ public:
|
|||||||
void set_int(longlong i, uint32 max_length_arg);
|
void set_int(longlong i, uint32 max_length_arg);
|
||||||
void set_double(double i);
|
void set_double(double i);
|
||||||
void set_decimal(const char *str, ulong length);
|
void set_decimal(const char *str, ulong length);
|
||||||
void set_decimal(const my_decimal *dv);
|
void set_decimal(const my_decimal *dv, bool unsigned_arg);
|
||||||
bool set_str(const char *str, ulong length);
|
bool set_str(const char *str, ulong length);
|
||||||
bool set_longdata(const char *str, ulong length);
|
bool set_longdata(const char *str, ulong length);
|
||||||
void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
|
void set_time(MYSQL_TIME *tm, timestamp_type type, uint32 max_length_arg);
|
||||||
|
void set_time(const MYSQL_TIME *tm, uint32 max_length_arg, uint decimals_arg);
|
||||||
bool set_from_item(THD *thd, Item *item);
|
bool set_from_item(THD *thd, Item *item);
|
||||||
void reset();
|
void reset();
|
||||||
/*
|
/*
|
||||||
@ -2893,6 +2947,18 @@ public:
|
|||||||
bool is_null()
|
bool is_null()
|
||||||
{ DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
|
{ DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
|
||||||
bool basic_const_item() const;
|
bool basic_const_item() const;
|
||||||
|
bool has_no_value() const
|
||||||
|
{
|
||||||
|
return state == NO_VALUE;
|
||||||
|
}
|
||||||
|
bool has_long_data_value() const
|
||||||
|
{
|
||||||
|
return state == LONG_DATA_VALUE;
|
||||||
|
}
|
||||||
|
bool has_int_value() const
|
||||||
|
{
|
||||||
|
return state == INT_VALUE;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
This method is used to make a copy of a basic constant item when
|
This method is used to make a copy of a basic constant item when
|
||||||
propagating constants in the optimizer. The reason to create a new
|
propagating constants in the optimizer. The reason to create a new
|
||||||
|
@ -742,45 +742,35 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
|||||||
switch (param_type) {
|
switch (param_type) {
|
||||||
case MYSQL_TYPE_TINY:
|
case MYSQL_TYPE_TINY:
|
||||||
param->set_param_func= set_param_tiny;
|
param->set_param_func= set_param_tiny;
|
||||||
param->item_type= Item::INT_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_SHORT:
|
case MYSQL_TYPE_SHORT:
|
||||||
param->set_param_func= set_param_short;
|
param->set_param_func= set_param_short;
|
||||||
param->item_type= Item::INT_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONG:
|
case MYSQL_TYPE_LONG:
|
||||||
param->set_param_func= set_param_int32;
|
param->set_param_func= set_param_int32;
|
||||||
param->item_type= Item::INT_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONGLONG:
|
case MYSQL_TYPE_LONGLONG:
|
||||||
param->set_param_func= set_param_int64;
|
param->set_param_func= set_param_int64;
|
||||||
param->item_type= Item::INT_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_FLOAT:
|
case MYSQL_TYPE_FLOAT:
|
||||||
param->set_param_func= set_param_float;
|
param->set_param_func= set_param_float;
|
||||||
param->item_type= Item::REAL_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_DOUBLE:
|
case MYSQL_TYPE_DOUBLE:
|
||||||
param->set_param_func= set_param_double;
|
param->set_param_func= set_param_double;
|
||||||
param->item_type= Item::REAL_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_DECIMAL:
|
case MYSQL_TYPE_DECIMAL:
|
||||||
case MYSQL_TYPE_NEWDECIMAL:
|
case MYSQL_TYPE_NEWDECIMAL:
|
||||||
param->set_param_func= set_param_decimal;
|
param->set_param_func= set_param_decimal;
|
||||||
param->item_type= Item::DECIMAL_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_TIME:
|
case MYSQL_TYPE_TIME:
|
||||||
param->set_param_func= set_param_time;
|
param->set_param_func= set_param_time;
|
||||||
param->item_type= Item::STRING_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_DATE:
|
case MYSQL_TYPE_DATE:
|
||||||
param->set_param_func= set_param_date;
|
param->set_param_func= set_param_date;
|
||||||
param->item_type= Item::STRING_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_DATETIME:
|
case MYSQL_TYPE_DATETIME:
|
||||||
case MYSQL_TYPE_TIMESTAMP:
|
case MYSQL_TYPE_TIMESTAMP:
|
||||||
param->set_param_func= set_param_datetime;
|
param->set_param_func= set_param_datetime;
|
||||||
param->item_type= Item::STRING_ITEM;
|
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_TINY_BLOB:
|
case MYSQL_TYPE_TINY_BLOB:
|
||||||
case MYSQL_TYPE_MEDIUM_BLOB:
|
case MYSQL_TYPE_MEDIUM_BLOB:
|
||||||
@ -792,7 +782,6 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
|||||||
thd->variables.character_set_client;
|
thd->variables.character_set_client;
|
||||||
DBUG_ASSERT(thd->variables.character_set_client);
|
DBUG_ASSERT(thd->variables.character_set_client);
|
||||||
param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
|
param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
|
||||||
param->item_type= Item::STRING_ITEM;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/*
|
/*
|
||||||
@ -821,7 +810,6 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
|
|||||||
Exact value of max_length is not known unless data is converted to
|
Exact value of max_length is not known unless data is converted to
|
||||||
charset of connection, so we have to set it later.
|
charset of connection, so we have to set it later.
|
||||||
*/
|
*/
|
||||||
param->item_type= Item::STRING_ITEM;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
param->set_handler_by_field_type((enum enum_field_types) param_type);
|
param->set_handler_by_field_type((enum enum_field_types) param_type);
|
||||||
@ -892,7 +880,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
|
|||||||
for (Item_param **it= begin; it < end; ++it)
|
for (Item_param **it= begin; it < end; ++it)
|
||||||
{
|
{
|
||||||
Item_param *param= *it;
|
Item_param *param= *it;
|
||||||
if (param->state != Item_param::LONG_DATA_VALUE)
|
if (!param->has_long_data_value())
|
||||||
{
|
{
|
||||||
if (is_param_null(null_array, (uint) (it - begin)))
|
if (is_param_null(null_array, (uint) (it - begin)))
|
||||||
param->set_null();
|
param->set_null();
|
||||||
@ -901,13 +889,12 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
|
|||||||
if (read_pos >= data_end)
|
if (read_pos >= data_end)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
|
param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
|
||||||
if (param->state == Item_param::NO_VALUE)
|
if (param->has_no_value())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
if (param->limit_clause_param && param->state != Item_param::INT_VALUE)
|
if (param->limit_clause_param && !param->has_int_value())
|
||||||
{
|
{
|
||||||
param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS);
|
param->set_int(param->val_int(), MY_INT64_NUM_DECIMAL_DIGITS);
|
||||||
param->item_type= Item::INT_ITEM;
|
|
||||||
if (!param->unsigned_flag && param->value.integer < 0)
|
if (!param->unsigned_flag && param->value.integer < 0)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
@ -947,7 +934,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
|
|||||||
for (Item_param **it= begin; it < end; ++it)
|
for (Item_param **it= begin; it < end; ++it)
|
||||||
{
|
{
|
||||||
Item_param *param= *it;
|
Item_param *param= *it;
|
||||||
if (param->state != Item_param::LONG_DATA_VALUE)
|
if (!param->has_long_data_value())
|
||||||
{
|
{
|
||||||
if (is_param_null(null_array, (uint) (it - begin)))
|
if (is_param_null(null_array, (uint) (it - begin)))
|
||||||
param->set_null();
|
param->set_null();
|
||||||
@ -956,7 +943,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
|
|||||||
if (read_pos >= data_end)
|
if (read_pos >= data_end)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
|
param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
|
||||||
if (param->state == Item_param::NO_VALUE)
|
if (param->has_no_value())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -989,7 +976,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
|
|||||||
Item_param *param= *it;
|
Item_param *param= *it;
|
||||||
if (reset)
|
if (reset)
|
||||||
param->reset();
|
param->reset();
|
||||||
if (param->state != Item_param::LONG_DATA_VALUE)
|
if (!param->has_long_data_value())
|
||||||
{
|
{
|
||||||
if (param->indicators)
|
if (param->indicators)
|
||||||
param->indicator= (enum_indicator_type) *((*read_pos)++);
|
param->indicator= (enum_indicator_type) *((*read_pos)++);
|
||||||
@ -1003,7 +990,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
|
|||||||
if ((*read_pos) >= data_end)
|
if ((*read_pos) >= data_end)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
param->set_param_func(param, read_pos, (uint) (data_end - (*read_pos)));
|
param->set_param_func(param, read_pos, (uint) (data_end - (*read_pos)));
|
||||||
if (param->state == Item_param::NO_VALUE)
|
if (param->has_no_value())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
break;
|
break;
|
||||||
case STMT_INDICATOR_NULL:
|
case STMT_INDICATOR_NULL:
|
||||||
@ -1093,7 +1080,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
|
|||||||
{
|
{
|
||||||
Item_param *param= *it;
|
Item_param *param= *it;
|
||||||
setup_one_conversion_function(thd, param, client_param->buffer_type);
|
setup_one_conversion_function(thd, param, client_param->buffer_type);
|
||||||
if (param->state != Item_param::LONG_DATA_VALUE)
|
if (!param->has_long_data_value())
|
||||||
{
|
{
|
||||||
if (*client_param->is_null)
|
if (*client_param->is_null)
|
||||||
param->set_null();
|
param->set_null();
|
||||||
@ -1105,7 +1092,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
|
|||||||
client_param->length ?
|
client_param->length ?
|
||||||
*client_param->length :
|
*client_param->length :
|
||||||
client_param->buffer_length);
|
client_param->buffer_length);
|
||||||
if (param->state == Item_param::NO_VALUE)
|
if (param->has_no_value())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1129,7 +1116,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
|
|||||||
{
|
{
|
||||||
Item_param *param= *it;
|
Item_param *param= *it;
|
||||||
setup_one_conversion_function(thd, param, client_param->buffer_type);
|
setup_one_conversion_function(thd, param, client_param->buffer_type);
|
||||||
if (param->state != Item_param::LONG_DATA_VALUE)
|
if (!param->has_long_data_value())
|
||||||
{
|
{
|
||||||
if (*client_param->is_null)
|
if (*client_param->is_null)
|
||||||
param->set_null();
|
param->set_null();
|
||||||
@ -1141,7 +1128,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
|
|||||||
client_param->length ?
|
client_param->length ?
|
||||||
*client_param->length :
|
*client_param->length :
|
||||||
client_param->buffer_length);
|
client_param->buffer_length);
|
||||||
if (param->state == Item_param::NO_VALUE)
|
if (param->has_no_value())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user