← Back to team overview

maria-developers team mailing list archive

Re: Please review MDEV-11134 Assertion `fixed' failed in Item::const_charset_converter(THD*, CHARSET_INFO*, bool, const char*)

 

Hello Sergei,


On 12/29/2016 05:33 PM, Sergei Golubchik wrote:
> Hi, Alexander!
> 
> On Dec 26, Alexander Barkov wrote:
>> Hello Sergei,
>>
>> can you please review a fix for MDEV-11134.
>>
>> I made it the easiest way, just fixed the assert to cover this special
>> case when Item_param::safe_charset_converter() is called from
>> mysql_prepare_create_table().
> 
> I thought that normally basic const items are always fixed. 
> So, Item_param is an exception? It's basic const, but not fixed?
> 
>> But perhaps it can be done in different ways:
>>
>>
>> 1. Do call fix_fields()
>> - Fix mysql_prepare_create_table() to call fix_fields.
>> - Fix Item_param::cleanup() not to set fixed to false.
>>
>> or
>>
>> 2. Sync Item_param::fixed with Item_param::basic_const_item()
>> - Fix Item_param::set_xxx() to set both state=XXX_VALUE and fixed=true.
>> - Fix Item_param::cleanup() not to set fixed to false (like in #1)
> 
> Yes, I think it's reasonable. It'll make Item_param behave as other
> basic constants do.

Please find a new version attached.
It makes sure that Item_param::fixed, Item_param::state and
Item_param::item_type are in sync to each other.

Thanks!

> 
> Regards,
> Sergei
> Chief Architect MariaDB
> and security@xxxxxxxxxxx
> 
commit adf6bb91e349e8983b146cbfcaaa002edff54fe5
Author: Alexander Barkov <bar@xxxxxxxxxxx>
Date:   Wed Jan 11 13:42:52 2017 +0400

    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 is_no_value(), is_long_data_value(), is_int_value(),
      instead of direct access to Item_param::state.

diff --git a/mysql-test/r/default.result b/mysql-test/r/default.result
index dc7a33d..192d782 100644
--- a/mysql-test/r/default.result
+++ b/mysql-test/r/default.result
@@ -3278,6 +3278,44 @@ INSERT INTO t1 VALUES (1),(2),(3);
 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
 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
 set sql_mode=ansi_quotes;
 create table t1 (a int, b int default (a+1));
diff --git a/mysql-test/t/default.test b/mysql-test/t/default.test
index 41ed161..0a3cafd 100644
--- a/mysql-test/t/default.test
+++ b/mysql-test/t/default.test
@@ -2017,6 +2017,36 @@ EXECUTE IMMEDIATE 'EXPLAIN EXTENDED SELECT * FROM t1 WHERE ?+a<=>?+a' USING DEFA
 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
 
 #
diff --git a/sql/item.cc b/sql/item.cc
index 682f883..344e67b 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -3302,9 +3302,9 @@ Item_param::Item_param(THD *thd, uint pos_in_query_arg):
   Rewritable_query_parameter(pos_in_query_arg, 1),
   Type_handler_hybrid_field_type(MYSQL_TYPE_VARCHAR),
   state(NO_VALUE),
-  indicators(0), indicator(STMT_INDICATOR_NONE),
   /* Don't pretend to be a literal unless value for this item is set. */
   item_type(PARAM_ITEM),
+  indicators(0), indicator(STMT_INDICATOR_NONE),
   set_param_func(default_set_param_func),
   m_out_param_info(NULL)
 {
@@ -3332,6 +3332,7 @@ void Item_param::set_null()
   decimals= 0;
   state= NULL_VALUE;
   item_type= Item::NULL_ITEM;
+  fixed= true;
   DBUG_VOID_RETURN;
 }
 
@@ -3343,6 +3344,8 @@ void Item_param::set_int(longlong i, uint32 max_length_arg)
   max_length= max_length_arg;
   decimals= 0;
   maybe_null= 0;
+  item_type= Item::INT_ITEM;
+  fixed= true;
   DBUG_VOID_RETURN;
 }
 
@@ -3354,6 +3357,8 @@ void Item_param::set_double(double d)
   max_length= DBL_DIG + 8;
   decimals= NOT_FIXED_DEC;
   maybe_null= 0;
+  item_type= Item::REAL_ITEM;
+  fixed= true;
   DBUG_VOID_RETURN;
 }
 
@@ -3383,21 +3388,44 @@ void Item_param::set_decimal(const char *str, ulong length)
     my_decimal_precision_to_length_no_truncation(decimal_value.precision(),
                                                  decimals, unsigned_flag);
   maybe_null= 0;
+  item_type= Item::DECIMAL_ITEM;
+  fixed= true;
   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;
 
   my_decimal2decimal(dv, &decimal_value);
 
   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,
                                              decimals, unsigned_flag);
+  item_type= Item::DECIMAL_ITEM;
+  fixed= true;
+}
+
+
+void Item_param::fix_temporal(uint32 max_length_arg, uint decimals_arg)
+{
+  state= TIME_VALUE;
+  max_length= max_length_arg;
+  decimals= decimals_arg;
+  item_type= Item::DATE_ITEM;
+  fixed= true;
 }
 
+
+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.
 
@@ -3426,11 +3454,9 @@ void Item_param::set_time(MYSQL_TIME *tm, timestamp_type time_type,
                                  &str, time_type, 0);
     set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
   }
-
-  state= TIME_VALUE;
   maybe_null= 0;
-  max_length= max_length_arg;
-  decimals= tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0;
+  fix_temporal(max_length_arg,
+               tm->second_part > 0 ? TIME_SECOND_PART_DIGITS : 0);
   DBUG_VOID_RETURN;
 }
 
@@ -3451,6 +3477,8 @@ bool Item_param::set_str(const char *str, ulong length)
   maybe_null= 0;
   /* max_length and decimals are set after charset conversion */
   /* sic: str may be not null-terminated, don't add DBUG_PRINT here */
+  item_type= Item::STRING_ITEM;
+  fixed= true;
   DBUG_RETURN(FALSE);
 }
 
@@ -3482,6 +3510,8 @@ bool Item_param::set_longdata(const char *str, ulong length)
     DBUG_RETURN(TRUE);
   state= LONG_DATA_VALUE;
   maybe_null= 0;
+  item_type= Item::STRING_ITEM;
+  fixed= true;
 
   DBUG_RETURN(FALSE);
 }
@@ -3540,7 +3570,6 @@ bool Item_param::set_from_item(THD *thd, Item *item)
     {
       unsigned_flag= item->unsigned_flag;
       set_int(val, MY_INT64_NUM_DECIMAL_DIGITS);
-      item_type= Item::INT_ITEM;
       set_handler_by_result_type(item->result_type());
       DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
     }
@@ -3552,12 +3581,10 @@ bool Item_param::set_from_item(THD *thd, Item *item)
     switch (item->cmp_type()) {
     case REAL_RESULT:
       set_double(tmp.value.m_double);
-      item_type= Item::REAL_ITEM;
       set_handler_by_field_type(MYSQL_TYPE_DOUBLE);
       break;
     case INT_RESULT:
       set_int(tmp.value.m_longlong, MY_INT64_NUM_DECIMAL_DIGITS);
-      item_type= Item::INT_ITEM;
       set_handler_by_field_type(MYSQL_TYPE_LONGLONG);
       break;
     case STRING_RESULT:
@@ -3567,7 +3594,6 @@ bool Item_param::set_from_item(THD *thd, Item *item)
         Exact value of max_length is not known unless data is converted to
         charset of connection, so we have to set it later.
       */
-      item_type= Item::STRING_ITEM;
       set_handler_by_field_type(MYSQL_TYPE_VARCHAR);
 
       if (set_str(tmp.m_string.ptr(), tmp.m_string.length()))
@@ -3576,24 +3602,13 @@ bool Item_param::set_from_item(THD *thd, Item *item)
     }
     case DECIMAL_RESULT:
     {
-      const my_decimal *ent_value= &tmp.m_decimal;
-      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_decimal(&tmp.m_decimal, unsigned_flag);
       set_handler_by_field_type(MYSQL_TYPE_NEWDECIMAL);
       break;
     }
     case TIME_RESULT:
     {
-      value.time= tmp.value.m_time;
-      state= TIME_VALUE;
-      max_length= item->max_length;
-      decimals= item->decimals;
-      item_type= Item::DATE_ITEM;
+      set_time(&tmp.value.m_time, item->max_length, item->decimals);
       set_handler(item->type_handler());
       break;
     }
@@ -3634,6 +3649,7 @@ void Item_param::reset()
   state= NO_VALUE;
   maybe_null= 1;
   null_value= 0;
+  fixed= false;
   /*
     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
@@ -3971,6 +3987,7 @@ bool Item_param::convert_str_value(THD *thd)
 
 bool Item_param::basic_const_item() const
 {
+  DBUG_ASSERT(fixed || state == NO_VALUE);
   if (state == NO_VALUE || state == TIME_VALUE)
     return FALSE;
   return TRUE;
@@ -4105,6 +4122,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
   maybe_null= src->maybe_null;
   null_value= src->null_value;
   state= src->state;
+  fixed= src->fixed;
   value= src->value;
 
   decimal_value.swap(src->decimal_value);
@@ -4116,6 +4134,7 @@ Item_param::set_param_type_and_swap_value(Item_param *src)
 void Item_param::set_default()
 {
   state= DEFAULT_VALUE;
+  fixed= true;
   /*
     When Item_param is set to DEFAULT_VALUE:
     - its val_str() and val_decimal() return NULL
@@ -4130,6 +4149,7 @@ void Item_param::set_default()
 void Item_param::set_ignore()
 {
   state= IGNORE_VALUE;
+  fixed= true;
   null_value= true;
 }
 
@@ -4175,18 +4195,15 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
                       str_value.charset());
     collation.set(str_value.charset(), DERIVATION_COERCIBLE);
     decimals= 0;
-    item_type= Item::STRING_ITEM;
     break;
   }
 
   case REAL_RESULT:
     set_double(arg->val_real());
-    item_type= Item::REAL_ITEM;
     break;
 
   case INT_RESULT:
     set_int(arg->val_int(), arg->max_length);
-    item_type= Item::INT_ITEM;
     break;
 
   case DECIMAL_RESULT:
@@ -4197,8 +4214,7 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
     if (!dv)
       return TRUE;
 
-    set_decimal(dv);
-    item_type= Item::DECIMAL_ITEM;
+    set_decimal(dv, !dv->sign());
     break;
   }
 
@@ -4208,7 +4224,6 @@ Item_param::set_value(THD *thd, sp_rcontext *ctx, Item **it)
     DBUG_ASSERT(TRUE);  // Abort in debug mode.
 
     set_null();         // Set to NULL in release mode.
-    item_type= Item::NULL_ITEM;
     return FALSE;
   }
 
diff --git a/sql/item.h b/sql/item.h
index 1f3e0f0..893f8de 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -2762,7 +2762,47 @@ class Item_param :public Item_basic_value,
                   public Rewritable_query_parameter,
                   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
   {
     NO_VALUE, NULL_VALUE, INT_VALUE, REAL_VALUE,
@@ -2770,6 +2810,11 @@ class Item_param :public Item_basic_value,
     DECIMAL_VALUE, DEFAULT_VALUE, IGNORE_VALUE
   } state;
 
+  enum Type item_type;
+
+  void fix_temporal(uint32 max_length_arg, uint decimals_arg);
+
+public:
   struct CONVERSION_INFO
   {
     /*
@@ -2838,8 +2883,6 @@ class Item_param :public Item_basic_value,
     MYSQL_TIME     time;
   } value;
 
-  enum Type item_type;
-
   enum_field_types field_type() const
   { return Type_handler_hybrid_field_type::field_type(); }
   enum Item_result result_type () const
@@ -2849,7 +2892,11 @@ class Item_param :public Item_basic_value,
 
   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();
   longlong val_int();
@@ -2864,10 +2911,11 @@ class Item_param :public Item_basic_value,
   void set_int(longlong i, uint32 max_length_arg);
   void set_double(double i);
   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_longdata(const char *str, ulong length);
   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);
   void reset();
   /*
@@ -2893,6 +2941,18 @@ class Item_param :public Item_basic_value,
   bool is_null()
   { DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
   bool basic_const_item() const;
+  bool is_no_value() const
+  {
+    return state == NO_VALUE;
+  }
+  bool is_long_data_value() const
+  {
+    return state == LONG_DATA_VALUE;
+  }
+  bool is_int_value() const
+  {
+    return state == INT_VALUE;
+  }
   /*
     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
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index d7a23a4..f592ba0 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -742,45 +742,35 @@ static void setup_one_conversion_function(THD *thd, Item_param *param,
   switch (param_type) {
   case MYSQL_TYPE_TINY:
     param->set_param_func= set_param_tiny;
-    param->item_type= Item::INT_ITEM;
     break;
   case MYSQL_TYPE_SHORT:
     param->set_param_func= set_param_short;
-    param->item_type= Item::INT_ITEM;
     break;
   case MYSQL_TYPE_LONG:
     param->set_param_func= set_param_int32;
-    param->item_type= Item::INT_ITEM;
     break;
   case MYSQL_TYPE_LONGLONG:
     param->set_param_func= set_param_int64;
-    param->item_type= Item::INT_ITEM;
     break;
   case MYSQL_TYPE_FLOAT:
     param->set_param_func= set_param_float;
-    param->item_type= Item::REAL_ITEM;
     break;
   case MYSQL_TYPE_DOUBLE:
     param->set_param_func= set_param_double;
-    param->item_type= Item::REAL_ITEM;
     break;
   case MYSQL_TYPE_DECIMAL:
   case MYSQL_TYPE_NEWDECIMAL:
     param->set_param_func= set_param_decimal;
-    param->item_type= Item::DECIMAL_ITEM;
     break;
   case MYSQL_TYPE_TIME:
     param->set_param_func= set_param_time;
-    param->item_type= Item::STRING_ITEM;
     break;
   case MYSQL_TYPE_DATE:
     param->set_param_func= set_param_date;
-    param->item_type= Item::STRING_ITEM;
     break;
   case MYSQL_TYPE_DATETIME:
   case MYSQL_TYPE_TIMESTAMP:
     param->set_param_func= set_param_datetime;
-    param->item_type= Item::STRING_ITEM;
     break;
   case MYSQL_TYPE_TINY_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;
     DBUG_ASSERT(thd->variables.character_set_client);
     param->value.cs_info.final_character_set_of_str_value= &my_charset_bin;
-    param->item_type= Item::STRING_ITEM;
     break;
   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
         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);
@@ -892,7 +880,7 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
   for (Item_param **it= begin; it < end; ++it)
   {
     Item_param *param= *it;
-    if (param->state != Item_param::LONG_DATA_VALUE)
+    if (!param->is_long_data_value())
     {
       if (is_param_null(null_array, (uint) (it - begin)))
         param->set_null();
@@ -901,13 +889,12 @@ static bool insert_params_with_log(Prepared_statement *stmt, uchar *null_array,
         if (read_pos >= data_end)
           DBUG_RETURN(1);
         param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
-        if (param->state == Item_param::NO_VALUE)
+        if (param->is_no_value())
           DBUG_RETURN(1);
 
-        if (param->limit_clause_param && param->state != Item_param::INT_VALUE)
+        if (param->limit_clause_param && !param->is_int_value())
         {
           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)
             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)
   {
     Item_param *param= *it;
-    if (param->state != Item_param::LONG_DATA_VALUE)
+    if (!param->is_long_data_value())
     {
       if (is_param_null(null_array, (uint) (it - begin)))
         param->set_null();
@@ -956,7 +943,7 @@ static bool insert_params(Prepared_statement *stmt, uchar *null_array,
         if (read_pos >= data_end)
           DBUG_RETURN(1);
         param->set_param_func(param, &read_pos, (uint) (data_end - read_pos));
-        if (param->state == Item_param::NO_VALUE)
+        if (param->is_no_value())
           DBUG_RETURN(1);
       }
     }
@@ -989,7 +976,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
     Item_param *param= *it;
     if (reset)
       param->reset();
-    if (param->state != Item_param::LONG_DATA_VALUE)
+    if (!param->is_long_data_value())
     {
       if (param->indicators)
         param->indicator= (enum_indicator_type) *((*read_pos)++);
@@ -1003,7 +990,7 @@ static bool insert_bulk_params(Prepared_statement *stmt,
         if ((*read_pos) >= data_end)
           DBUG_RETURN(1);
         param->set_param_func(param, read_pos, (uint) (data_end - (*read_pos)));
-        if (param->state == Item_param::NO_VALUE)
+        if (param->is_no_value())
           DBUG_RETURN(1);
         break;
       case STMT_INDICATOR_NULL:
@@ -1093,7 +1080,7 @@ static bool emb_insert_params(Prepared_statement *stmt, String *expanded_query)
   {
     Item_param *param= *it;
     setup_one_conversion_function(thd, param, client_param->buffer_type);
-    if (param->state != Item_param::LONG_DATA_VALUE)
+    if (!param->is_long_data_value())
     {
       if (*client_param->is_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->buffer_length);
-        if (param->state == Item_param::NO_VALUE)
+        if (param->is_no_value())
           DBUG_RETURN(1);
       }
     }
@@ -1129,7 +1116,7 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt, String *query)
   {
     Item_param *param= *it;
     setup_one_conversion_function(thd, param, client_param->buffer_type);
-    if (param->state != Item_param::LONG_DATA_VALUE)
+    if (!param->is_long_data_value())
     {
       if (*client_param->is_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->buffer_length);
-        if (param->state == Item_param::NO_VALUE)
+        if (param->is_no_value())
           DBUG_RETURN(1);
       }
     }

Follow ups

References