List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:April 12 2012 3:33pm
Subject:bzr push into mysql-trunk branch (alexander.barkov:3871 to 3872) Bug#12537203
View as plain text  
 3872 Alexander Barkov	2012-04-12
      BUG#12537203 post-fix
                  
      1. Splitting NameString into three classes:
      - low level SimpleCString without any code specific to identifier handling,
        for easier iteraction with basic classes like String, and for possible
        future use in other parts of the code.
      - NameString, a base class with identifier specific allocation,
        copying, comparison methods. It's a base class for all identifiers
        (column, table, db, function names, etc)
        It's also used in Item_xxx constructors, to pass column name.
        Item_splocal, Item_get_user_var, Item_set_user_var,
        Item_user_var_as_out_param already use it.
      - ItemNameString, for column name handling, with warnings and
        "autogenerated" flag handling.
      - Changing argument types of methods from "NameString *" to "NameString".
        The data type is very small, it's easier to put it on the stack as a whole
        instead of putting a pointer and dereferences the pointer later.
      
      2. Renaming eq() to eq_safe(). Introducing a new quick eq() method,
         which assumes non-NULL pointers.
      
      3. Fixing to create good m_str and m_length values.
         strlen(m_ptr) is now always equal to m_length.
         Adding DBUG_ASSERT to prevent out of sync values
         to be passed to copy().
      
      
      Per-file comments:
      
       @ item.cc
         - Moving warning code from NameString into ItemNameString
         - Fixing NameString::copy() to create a good value:
             strlen(m_ptr) is now always equal to m_length.
       @ item.h
         - Splitting NameString and ItemNameString
      
       @ item_func.h
       @ item_func.h
         - Using new data types and methods
         - Removing get_name() as it's never used.
      
       @ item_xmlfunc.h
         - Making sure to create an Item with a good NameString name.
           Earlier m_ptr did not point to a null-terminated string.
           Revealed by DBUG_ASSERT in SimpleCString::SimpeCString.
      
       @ log_event.cc
         - Fixing that Item_func_set_user_var was created with 
           non null-terminated name string.
      
       @ sp_head.cc
         - Using new append() method
         - Fixing to use a proper constructor.
           Revealed by DBUG_ASSERT in SimpleCString contructor.
      
       @ sql_base.cc
         - Renaming eq() to eq_safe()
      
       @ sql_string.cc
         - Introducing the low level class SimpleCString
         - Adding String::append(), for easier String and SimpleCString interaction
      
       @ sql_view.cc
         - Changing data type from pointer to the structure itself.
      
       @ sql_yacc.yy
         - Removing my_name(). Using m_name directly.
      
       @ sql_show.h
         - Adding helper function append_identifier(), to pass SimpleCString easier

    modified:
      sql/item.cc
      sql/item.h
      sql/item_func.cc
      sql/item_func.h
      sql/item_timefunc.h
      sql/item_xmlfunc.cc
      sql/log_event.cc
      sql/sp_head.cc
      sql/sql_analyse.cc
      sql/sql_base.cc
      sql/sql_executor.cc
      sql/sql_show.h
      sql/sql_string.h
      sql/sql_view.cc
      sql/sql_yacc.yy
 3871 Tor Didriksen	2012-04-12
      Bug#13871079 RQG_MYISAM_DML_ALTER_VALGRIND FAILS ON VALGRIND PN PB2
      
      The class Copy_field contains a String tmp, 
      which may allocate memory on the heap.
      That means that all instances of Copy_field
      must be properly destroyed. Alas they are not.
      
      Solution: don't use Copy_field::tmp for copying
      from_field => tmp => to_field
      in do_field_string()
     @ sql/field.cc
        In Field_set::val_str
        return empty string (of appropriate character set) for an empty set.
     @ sql/field.h
        New private member in Field_enum: empty_set_string.
     @ sql/field_conv.cc
        In do_field_string, use an auto variable for copying
        from_field => tmp => to_field
        rather than copy->tmp.
     @ sql/sql_class.h
        Verifies that these objects are never destroyed....
     @ unittest/gunit/alignment-t.cc
        Add copyright notice.
     @ unittest/gunit/fake_table.h
        More initializations, to avoid valgrind warnings.
     @ unittest/gunit/field-t.cc
        New unit test.
     @ unittest/gunit/field_timestamp-t.cc
        Remove obsolete note about min/max macros.

    modified:
      sql/field.cc
      sql/field.h
      sql/field_conv.cc
      sql/sql_class.h
      unittest/gunit/alignment-t.cc
      unittest/gunit/fake_table.h
      unittest/gunit/field-t.cc
      unittest/gunit/field_timestamp-t.cc
=== modified file 'sql/item.cc'
--- a/sql/item.cc	2012-03-30 15:38:01 +0000
+++ b/sql/item.cc	2012-04-12 15:31:01 +0000
@@ -670,11 +670,11 @@ void Item::print_item_w_name(String *str
 {
   print(str, query_type);
 
-  if (item_name.ptr())
+  if (item_name.is_set())
   {
     THD *thd= current_thd;
     str->append(STRING_WITH_LEN(" AS "));
-    append_identifier(thd, str, item_name.ptr(), item_name.length());
+    append_identifier(thd, str, item_name);
   }
 }
 
@@ -696,9 +696,9 @@ void Item::print_for_order(String *str,
 {
   if (used_alias)
   {
-    DBUG_ASSERT(item_name.ptr() != NULL);
+    DBUG_ASSERT(item_name.is_set());
     // In the clause, user has referenced expression using an alias; we use it
-    append_identifier(current_thd, str, item_name.ptr(), item_name.length());
+    append_identifier(current_thd, str, item_name);
   }
   else
     print(str,query_type);
@@ -710,7 +710,7 @@ void Item::cleanup()
   DBUG_ENTER("Item::cleanup");
   fixed=0;
   marker= 0;
-  if (orig_name.ptr())
+  if (orig_name.is_set())
     item_name= orig_name;
   DBUG_VOID_RETURN;
 }
@@ -742,7 +742,7 @@ void Item::rename(char *new_name)
     we can compare pointers to names here, because if name was not changed,
     pointer will be same
   */
-  if (!orig_name.ptr() && new_name != item_name.ptr())
+  if (!orig_name.is_set() && new_name != item_name.ptr())
     orig_name= item_name;
   item_name.set(new_name);
 }
@@ -958,18 +958,19 @@ bool Item::check_cols(uint c)
 }
 
 
+NameString null_name_string(NULL, 0);
+
+
 void NameString::copy(const char *str, uint length, const CHARSET_INFO *cs)
 {
   if (!length)
   {
     /* Empty string, used by AS or internal function like last_insert_id() */
-    m_str= (char*) str;
-    m_length= 0;
+    set(str ? "" : NULL, 0);
     return;
   }
   if (cs->ctype)
   {
-    uint orig_len= length;
     /*
       This will probably need a better implementation in the future:
       a function in CHARSET_INFO structure.
@@ -979,27 +980,41 @@ void NameString::copy(const char *str, u
       length--;
       str++;
     }
-    if (orig_len != length && !is_autogenerated())
-    {
-      if (length == 0)
-        push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
-                            ER_NAME_BECOMES_EMPTY, ER(ER_NAME_BECOMES_EMPTY),
-                            str + length - orig_len);
-      else
-        push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
-                            ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
-                            str + length - orig_len);
-    }
   }
   if (!my_charset_same(cs, system_charset_info))
   {
     size_t res_length;
-    m_str= sql_strmake_with_convert(str, length, cs, MAX_ALIAS_NAME,
-                                    system_charset_info, &res_length);
-    m_length= res_length;
+    char *tmp= sql_strmake_with_convert(str, length, cs, MAX_ALIAS_NAME,
+                                        system_charset_info, &res_length);
+    set(tmp, tmp ? res_length : 0);
   }
   else
-    m_str= sql_strmake(str, (m_length= min<size_t>(length, MAX_ALIAS_NAME)));
+  {
+    size_t len= min<size_t>(length, MAX_ALIAS_NAME);
+    char *tmp= sql_strmake(str, len);
+    set(tmp, tmp ? len : 0);
+  }
+}
+
+
+void ItemNameString::copy(const char *str_arg, uint length_arg,
+                          const CHARSET_INFO *cs_arg,
+                          bool is_autogenerated_arg)
+{
+  m_is_autogenerated= is_autogenerated_arg;
+  copy(str_arg, length_arg, cs_arg);
+  if (length_arg > length() && !is_autogenerated())
+  {
+    ErrConvString tmp(str_arg, length_arg, cs_arg);
+    if (length() == 0)
+      push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+                          ER_NAME_BECOMES_EMPTY, ER(ER_NAME_BECOMES_EMPTY),
+                          tmp.ptr());
+    else
+      push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
+                          ER_REMOVED_SPACES, ER(ER_REMOVED_SPACES),
+                          tmp.ptr());
+  }
 }
 
 
@@ -1017,7 +1032,7 @@ bool Item::eq(const Item *item, bool bin
     for all basic constants we have special checks, and Item_param's
     type() can be only among basic constant types.
   */
-  return type() == item->type() && item_name.eq(&item->item_name);
+  return type() == item->type() && item_name.eq_safe(item->item_name);
 }
 
 
@@ -1493,15 +1508,12 @@ bool Item::is_blob_field() const
   Item_sp_variable methods
 *****************************************************************************/
 
-Item_sp_variable::Item_sp_variable(char *sp_var_name_str,
-                                   uint sp_var_name_length)
-  :m_thd(0)
+Item_sp_variable::Item_sp_variable(const NameString sp_var_name)
+  :m_thd(0), m_name(sp_var_name)
 #ifndef DBUG_OFF
    , m_sp(0)
 #endif
 {
-  m_name.str= sp_var_name_str;
-  m_name.length= sp_var_name_length;
 }
 
 
@@ -1616,11 +1628,11 @@ bool Item_sp_variable::is_null()
   Item_splocal methods
 *****************************************************************************/
 
-Item_splocal::Item_splocal(const LEX_STRING &sp_var_name,
+Item_splocal::Item_splocal(const NameString sp_var_name,
                            uint sp_var_idx,
                            enum_field_types sp_var_type,
                            uint pos_in_q, uint len_in_q)
-  :Item_sp_variable(sp_var_name.str, sp_var_name.length),
+  :Item_sp_variable(sp_var_name),
    m_var_idx(sp_var_idx),
    limit_clause_param(FALSE),
    pos_in_query(pos_in_q), len_in_query(len_in_q)
@@ -1662,8 +1674,8 @@ Item_splocal::this_item_addr(THD *thd, I
 
 void Item_splocal::print(String *str, enum_query_type)
 {
-  str->reserve(m_name.length+8);
-  str->append(m_name.str, m_name.length);
+  str->reserve(m_name.length() + 8);
+  str->append(m_name);
   str->append('@');
   str->qs_append(m_var_idx);
 }
@@ -1680,7 +1692,7 @@ bool Item_splocal::set_value(THD *thd, s
 *****************************************************************************/
 
 Item_case_expr::Item_case_expr(uint case_expr_id)
-  :Item_sp_variable( C_STRING_WITH_LEN("case_expr")),
+  :Item_sp_variable(NameString(C_STRING_WITH_LEN("case_expr"))),
    m_case_expr_id(case_expr_id)
 {
 }
@@ -2559,7 +2571,7 @@ const char *Item_ident::full_name() cons
 {
   char *tmp;
   if (!table_name || !field_name)
-    return field_name ? field_name : item_name.ptr() ? item_name.ptr() : "tmp_field";
+    return field_name ? field_name : item_name.is_set() ? item_name.ptr() : "tmp_field";
   if (db_name && db_name[0])
   {
     tmp=(char*) sql_alloc((uint) strlen(db_name)+(uint) strlen(table_name)+
@@ -2605,7 +2617,7 @@ void Item_ident::print(String *str, enum
   if (!table_name || !field_name || !field_name[0])
   {
     const char *nm= (field_name && field_name[0]) ?
-                      field_name : item_name.ptr() ? item_name.ptr() : "tmp_field";
+                      field_name : item_name.is_set() ? item_name.ptr() : "tmp_field";
     append_identifier(thd, str, nm, (uint) strlen(nm));
     return;
   }
@@ -2829,7 +2841,7 @@ bool Item_field::eq(const Item *item, bo
     (In cases where we would choose wrong we would have to generate a
     ER_NON_UNIQ_ERROR).
   */
-  return (item_field->item_name.eq(field_name) &&
+  return (item_field->item_name.eq_safe(field_name) &&
 	  (!item_field->table_name || !table_name ||
 	   (!my_strcasecmp(table_alias_charset, item_field->table_name,
 			   table_name) &&
@@ -3993,7 +4005,7 @@ Item_param::clone_item()
     return new Item_float(item_name.ptr(), value.real, decimals, max_length);
   case STRING_VALUE:
   case LONG_DATA_VALUE:
-    return new Item_string(item_name.ptr(), str_value.c_ptr_quick(), str_value.length(),
+    return new Item_string(item_name, str_value.c_ptr_quick(), str_value.length(),
                            str_value.charset());
   case TIME_VALUE:
     break;
@@ -6007,7 +6019,7 @@ void Item_field::make_field(Send_field *
 {
   field->make_field(tmp_field);
   DBUG_ASSERT(tmp_field->table_name != 0);
-  if (item_name.ptr())
+  if (item_name.is_set())
     tmp_field->col_name= item_name.ptr();  // Use user supplied name
   if (table_name)
     tmp_field->table_name= table_name;
@@ -7315,8 +7327,7 @@ void Item_ref::print(String *str, enum_q
         !table_name && item_name.ptr() && alias_name_used)
     {
       THD *thd= current_thd;
-      append_identifier(thd, str, (*ref)->real_item()->item_name.ptr(),
-                        (*ref)->real_item()->item_name.length());
+      append_identifier(thd, str, (*ref)->real_item()->item_name);
     }
     else
       (*ref)->print(str, query_type);
@@ -7531,7 +7542,7 @@ void Item_ref::make_field(Send_field *fi
 {
   (*ref)->make_field(field);
   /* Non-zero in case of a view */
-  if (item_name.ptr())
+  if (item_name.is_set())
     field->col_name= item_name.ptr();
   if (table_name)
     field->table_name= table_name;
@@ -8152,7 +8163,7 @@ void resolve_const_item(THD *thd, Item *
     return;                                     // Can't be better
   Item_result res_type=item_cmp_type(comp_item->result_type(),
 				     item->result_type());
-  char *name= item->item_name.ptr();	// Alloced by sql_alloc
+  const char *name= item->item_name.ptr(); // Alloced by sql_alloc
 
   switch (res_type) {
   case STRING_RESULT:
@@ -8173,7 +8184,7 @@ void resolve_const_item(THD *thd, Item *
     {
       uint length= result->length();
       char *tmp_str= sql_strmake(result->ptr(), length);
-      new_item= new Item_string(name, tmp_str, length, result->charset());
+      new_item= new Item_string(item->item_name, tmp_str, length, result->charset());
     }
     break;
   }
@@ -9085,7 +9096,7 @@ bool Item_type_holder::join_types(THD *t
   DBUG_ENTER("Item_type_holder::join_types");
   DBUG_PRINT("info:", ("was type %d len %d, dec %d name %s",
                        fld_type, max_length, decimals,
-                       (item_name.ptr() ? item_name.ptr() : "<NULL>")));
+                       (item_name.is_set() ? item_name.ptr() : "<NULL>")));
   DBUG_PRINT("info:", ("in type %d len %d, dec %d",
                        get_real_type(item),
                        item->max_length, item->decimals));

=== modified file 'sql/item.h'
--- a/sql/item.h	2012-03-30 15:38:01 +0000
+++ b/sql/item.h	2012-04-12 15:31:01 +0000
@@ -143,6 +143,130 @@ public:
 };
 
 /*************************************************************************/
+
+/**
+  Storage for name strings.
+  Enpowers SimpleCString with allocation routines from the sql_strmake family.
+*/
+class NameString: public SimpleCString
+{
+private:
+  void set_or_copy(const char *str, uint length, bool is_null_terminated)
+  {
+    if (is_null_terminated)
+      set(str, length);
+    else
+      copy(str, length);  
+  }
+public:
+  NameString(): SimpleCString() {}
+  NameString(const char *str, uint length):
+    SimpleCString(str, length) {}
+  NameString(const LEX_STRING str): SimpleCString(str) {}
+  NameString(const char *str, uint length, bool is_null_terminated):
+    SimpleCString()
+  {
+    set_or_copy(str, length, is_null_terminated);
+  }
+  NameString(const LEX_STRING str, bool is_null_terminated):
+    SimpleCString()
+  {
+    set_or_copy(str.str, str.length, is_null_terminated);
+  }
+  /**
+    Allocate space using sql_strmake() or sql_strmake_with_convert().
+  */
+  void copy(const char *str, uint length, const CHARSET_INFO *cs);
+  /**
+    Variants for copy(), for various argument combinations.
+  */
+  void copy(const char *str, uint length)
+  {
+    copy(str, length, system_charset_info);
+  }
+  void copy(const char *str)
+  {
+    copy(str, (uint) (str ? strlen(str) : 0), system_charset_info);
+  }
+  void copy(const LEX_STRING lex)
+  {
+    copy(lex.str, lex.length);
+  }
+  void copy(const LEX_STRING *lex)
+  {
+    copy(lex->str, lex->length);
+  }
+  void copy(const NameString str)
+  {
+    copy(str.ptr(), str.length());
+  }
+  /**
+    Compare name to another name in C string, case insensitively.
+  */
+  bool eq(const char *str) const
+  {
+    DBUG_ASSERT(str && ptr());
+    return my_strcasecmp(system_charset_info, ptr(), str) == 0;
+  }
+  bool eq_safe(const char *str) const
+  {
+    return is_set() && str && eq(str);
+  }
+  /**
+    Compare name to another name in NameString, case insensitively.
+  */
+  bool eq(const NameString name) const
+  {
+    return eq(name.ptr());
+  }
+  bool eq_safe(const NameString name) const
+  {
+    return is_set() && name.is_set() && eq(name);
+  }
+};
+
+
+extern NameString null_name_string;
+
+
+/**
+  Storage for Item names.
+  Adds "autogenerated" flag and warning functionality to NameString.
+*/
+class ItemNameString: public NameString
+{
+private:
+  bool m_is_autogenerated; /* indicates if name of this Item
+                              was autogenerated or set by user */
+public:
+  ItemNameString(): NameString(), m_is_autogenerated(true)
+  { }
+  ItemNameString(const NameString name)
+    :NameString(name), m_is_autogenerated(true)
+  { }
+  /**
+    Set m_is_autogenerated flag to the given value.
+  */
+  void set_autogenerated(bool is_autogenerated)
+  {
+    m_is_autogenerated= is_autogenerated;
+  }
+  /**
+    Return the auto-generated flag.
+  */
+  bool is_autogenerated() const { return m_is_autogenerated; }
+  using NameString::copy;
+  /**
+    Copy name together with autogenerated flag.
+    Produce a warning if name was cut.
+  */
+  void copy(const char *str_arg, uint length_arg, const CHARSET_INFO *cs_arg,
+           bool is_autogenerated_arg);
+};
+
+
+
+/*************************************************************************/
 /*
   A framework to easily handle different return types for hybrid items
   (hybrid item is an item whose operand can be of any type, e.g. integer,
@@ -504,87 +628,6 @@ typedef Item* (Item::*Item_transformer)
 typedef void (*Cond_traverser) (const Item *item, void *arg);
 
 
-class NameString
-{
-private:
-  char *m_str;
-  uint m_length;
-  bool m_is_autogenerated; /* indicates if name of this Item
-                              was autogenerated or set by user */
-public:
-  NameString()
-  {
-    m_str= 0;
-    m_length= 0;
-    m_is_autogenerated= true;
-  }
-  /**
-    Set m_is_autogenerated flag to the given value.
-  */
-  void set_autogenerated(bool is_autogenerated)
-  {
-    m_is_autogenerated= is_autogenerated;
-  }
-  /**
-    Allocate space using sql_strmake() or sql_strmake_with_convert().
-  */
-  void copy(const char *str, uint length, const CHARSET_INFO *cs);
-  /**
-    Variants for copy(), for various argument combinations.
-  */
-  void copy(const char *str, uint length, const CHARSET_INFO *cs,
-           bool is_autogenerated)
-  {
-    m_is_autogenerated= is_autogenerated; // Must be done before set/copy
-    copy(str, length, cs);
-  }
-  void copy(const char *str, uint length)
-  {
-    copy(str, length, system_charset_info);
-  }
-  void copy(const char *str)
-  {
-    copy(str, (uint) (str ? strlen(str) : 0), system_charset_info);
-  }
-  /**
-    Set name to the existing memory. No allocation happens.
-  */
-  void set(const char *str)
-  {
-    m_str= (char *) str;
-    m_length= str ? strlen(str) : 0;
-  }
-  /**
-    Return name buffer.
-  */
-  char *ptr() const { return m_str; }
-  /**
-    Return name length.
-  */
-  uint length() const { return m_length; }
-  /**
-    Return if name was auto-generated.
-  */
-  bool is_autogenerated() const { return m_is_autogenerated; }
-  /**
-    Compare name to another name in NameString.
-  */
-  bool eq(const NameString *name) const
-  {
-    return ptr() && name->ptr() &&
-           my_strcasecmp(system_charset_info, ptr(), name->ptr()) == 0;
-  }
-  /**
-    Compare name to another name in C string.
-  */
-  bool eq(const char *str) const
-  {
-    return ptr() && str &&
-           my_strcasecmp(system_charset_info, ptr(), str) == 0;
-  }
-};
-
-
 class Item
 {
   Item(const Item &);			/* Prevent use of these */
@@ -624,8 +667,8 @@ public:
   */
   String str_value;
 
-  NameString item_name;      /* Name from select */
-  NameString orig_name;      /* Original item name (if it was renamed)*/
+  ItemNameString item_name;  /* Name from select */
+  ItemNameString orig_name;  /* Original item name (if it was renamed)*/
 
   /**
      Intrusive list pointer for free list. If not null, points to the next
@@ -1085,7 +1128,7 @@ public:
   virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
   virtual const char *full_name() const
   {
-    return item_name.ptr() ? item_name.ptr() : "???";
+    return item_name.is_set() ? item_name.ptr() : "???";
   }
 
   /*
@@ -1610,7 +1653,7 @@ public:
       in the statement memory. If the name is auto generated, it must be
       done again between subsequent executions of a prepared statement.
     */
-    if (orig_name.ptr())
+    if (orig_name.is_set())
       item_name= orig_name;
   }
 };
@@ -1633,7 +1676,7 @@ protected:
   THD *m_thd;
 
 public:
-  LEX_STRING m_name;
+  NameString m_name;
 
 public:
 #ifndef DBUG_OFF
@@ -1645,7 +1688,7 @@ public:
 #endif
 
 public:
-  Item_sp_variable(char *sp_var_name_str, uint sp_var_name_length);
+  Item_sp_variable(const NameString sp_var_name);
 
 public:
   bool fix_fields(THD *thd, Item **);
@@ -1671,11 +1714,7 @@ public:
 inline void Item_sp_variable::make_field(Send_field *field)
 {
   Item *it= this_item();
-
-  if (item_name.ptr())
-    it->item_name.copy(item_name.ptr(), (uint) item_name.length());
-  else
-    it->item_name.copy(m_name.str, (uint) m_name.length);
+  it->item_name.copy(item_name.is_set() ? item_name : m_name);
   it->make_field(field);
 }
 
@@ -1731,7 +1770,7 @@ public:
   */
   uint len_in_query;
 
-  Item_splocal(const LEX_STRING &sp_var_name, uint sp_var_idx,
+  Item_splocal(const NameString sp_var_name, uint sp_var_idx,
                enum_field_types sp_var_type,
                uint pos_in_q= 0, uint len_in_q= 0);
 
@@ -1744,8 +1783,6 @@ public:
   virtual void print(String *str, enum_query_type query_type);
 
 public:
-  inline const LEX_STRING *my_name() const;
-
   inline uint get_var_idx() const;
 
   inline enum Type type() const;
@@ -1766,11 +1803,6 @@ public:
   Item_splocal inline implementation.
 *****************************************************************************/
 
-inline const LEX_STRING *Item_splocal::my_name() const
-{
-  return &m_name;
-}
-
 inline uint Item_splocal::get_var_idx() const
 {
   return m_var_idx;
@@ -2180,7 +2212,7 @@ public:
 class Item_null :public Item_basic_constant
 {
 public:
-  Item_null(char *name_par=0)
+  Item_null(const char *name_par=0)
   {
     maybe_null= null_value= TRUE;
     max_length= 0;
@@ -2646,6 +2678,7 @@ public:
 class Item_string :public Item_basic_constant
 {
 public:
+  /* Create from a string, set name from the string itself. */
   Item_string(const char *str,uint length,
               const CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
               uint repertoire= MY_REPERTOIRE_UNICODE30)
@@ -2672,11 +2705,11 @@ public:
   {
     collation.set(cs, dv);
     max_length= 0;
-    item_name.copy(NULL, 0, cs);
     decimals= NOT_FIXED_DEC;
     fixed= 1;
   }
-  Item_string(const char *name_par, const char *str, uint length,
+  /* Create from the given name and string. */
+  Item_string(const NameString name_par, const char *str, uint length,
               const CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
               uint repertoire= MY_REPERTOIRE_UNICODE30)
     : m_cs_specified(FALSE)
@@ -2684,7 +2717,7 @@ public:
     str_value.set_or_copy_aligned(str, length, cs);
     collation.set(cs, dv, repertoire);
     max_length= str_value.numchars()*cs->mbmaxlen;
-    item_name.copy(name_par, 0, cs);
+    item_name= name_par;
     decimals=NOT_FIXED_DEC;
     // it is constant => can be used without fix_fields (and frequently used)
     fixed= 1;
@@ -2728,7 +2761,7 @@ public:
   bool eq(const Item *item, bool binary_cmp) const;
   Item *clone_item() 
   {
-    return new Item_string(item_name.ptr(), str_value.ptr(), 
+    return new Item_string((NameString) item_name, str_value.ptr(), 
     			   str_value.length(), collation.collation);
   }
   Item *safe_charset_converter(const CHARSET_INFO *tocs);
@@ -2799,7 +2832,7 @@ public:
   Item_static_string_func(const char *name_par, const char *str, uint length,
                           const CHARSET_INFO *cs,
                           Derivation dv= DERIVATION_COERCIBLE)
-    :Item_string(NullS, str, length, cs, dv), func_name(name_par)
+    :Item_string(null_name_string, str, length, cs, dv), func_name(name_par)
   {}
   Item *safe_charset_converter(const CHARSET_INFO *tocs);
 
@@ -2816,10 +2849,12 @@ public:
 class Item_partition_func_safe_string: public Item_string
 {
 public:
-  Item_partition_func_safe_string(const char *name, uint length,
+  Item_partition_func_safe_string(const NameString name, uint length,
                                   const CHARSET_INFO *cs= NULL):
-    Item_string(name, length, cs)
-  {}
+    Item_string(name, NullS, 0, cs)
+  {
+    max_length= length;
+  }
 };
 
 
@@ -2828,7 +2863,8 @@ class Item_return_date_time :public Item
   enum_field_types date_time_field_type;
 public:
   Item_return_date_time(const char *name_arg, enum_field_types field_type_arg)
-    :Item_partition_func_safe_string(name_arg, 0, &my_charset_bin),
+    :Item_partition_func_safe_string(NameString((char *) name_arg, strlen(name_arg)),
+                                     0, &my_charset_bin),
      date_time_field_type(field_type_arg)
   { decimals= 0; }
   enum_field_types field_type() const { return date_time_field_type; }
@@ -2839,8 +2875,9 @@ class Item_blob :public Item_partition_f
 {
 public:
   Item_blob(const char *name, uint length) :
-    Item_partition_func_safe_string(name, length, &my_charset_bin)
-  { max_length= length; }
+    Item_partition_func_safe_string(NameString((char *) name, strlen(name)),
+                                    length, &my_charset_bin)
+  { }
   enum Type type() const { return TYPE_HOLDER; }
   enum_field_types field_type() const { return MYSQL_TYPE_BLOB; }
 };
@@ -2857,9 +2894,9 @@ class Item_empty_string :public Item_par
 public:
   Item_empty_string(const char *header, uint length,
                     const CHARSET_INFO *cs= NULL) :
-    Item_partition_func_safe_string("",0, cs ? cs : &my_charset_utf8_general_ci)
+    Item_partition_func_safe_string(NameString((char *)header, strlen(header)),
+                                    0, cs ? cs : &my_charset_utf8_general_ci)
     {
-      item_name.set(header);
       max_length= length * collation.collation->mbmaxlen;
     }
   void make_field(Send_field *field);

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2012-03-30 15:38:01 +0000
+++ b/sql/item_func.cc	2012-04-12 15:31:01 +0000
@@ -3584,7 +3584,7 @@ udf_handler::fix_fields(THD *thd, Item_r
 
       f_args.lengths[i]= arguments[i]->max_length;
       f_args.maybe_null[i]= (char) arguments[i]->maybe_null;
-      f_args.attributes[i]= arguments[i]->item_name.ptr();
+      f_args.attributes[i]= (char*) arguments[i]->item_name.ptr();
       f_args.attribute_lengths[i]= arguments[i]->item_name.length();
 
       if (arguments[i]->const_item())
@@ -4546,23 +4546,23 @@ longlong Item_func_sleep::val_int()
 
 #define extra_size sizeof(double)
 
-static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
+static user_var_entry *get_variable(HASH *hash, NameString &name,
 				    bool create_if_not_exists)
 {
   user_var_entry *entry;
 
-  if (!(entry = (user_var_entry*) my_hash_search(hash, (uchar*) name.str,
-                                                 name.length)) &&
+  if (!(entry = (user_var_entry*) my_hash_search(hash, (uchar*) name.ptr(),
+                                                 name.length())) &&
       create_if_not_exists)
   {
-    uint size=ALIGN_SIZE(sizeof(user_var_entry))+name.length+1+extra_size;
+    uint size=ALIGN_SIZE(sizeof(user_var_entry))+name.length()+1+extra_size;
     if (!my_hash_inited(hash))
       return 0;
     if (!(entry = (user_var_entry*) my_malloc(size,MYF(MY_WME | ME_FATALERROR))))
       return 0;
     entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+
       extra_size;
-    entry->name.length=name.length;
+    entry->name.length= name.length();
     entry->value=0;
     entry->length=0;
     entry->update_query_id=0;
@@ -4580,7 +4580,7 @@ static user_var_entry *get_variable(HASH
     */
     entry->used_query_id=current_thd->query_id;
     entry->type=STRING_RESULT;
-    memcpy(entry->name.str, name.str, name.length+1);
+    name.strcpy(entry->name.str);
     if (my_hash_insert(hash,(uchar*) entry))
     {
       my_free(entry);
@@ -5162,7 +5162,7 @@ bool Item_func_set_user_var::is_null_res
 void Item_func_set_user_var::print(String *str, enum_query_type query_type)
 {
   str->append(STRING_WITH_LEN("(@"));
-  str->append(name.str, name.length);
+  str->append(name);
   str->append(STRING_WITH_LEN(":="));
   args[0]->print(str, query_type);
   str->append(')');
@@ -5173,7 +5173,7 @@ void Item_func_set_user_var::print_as_st
                                            enum_query_type query_type)
 {
   str->append(STRING_WITH_LEN("set @"));
-  str->append(name.str, name.length);
+  str->append(name);
   str->append(STRING_WITH_LEN(":="));
   args[0]->print(str, query_type);
   str->append(')');
@@ -5196,7 +5196,7 @@ void Item_func_set_user_var::make_field(
   {
     result_field->make_field(tmp_field);
     DBUG_ASSERT(tmp_field->table_name != 0);
-    if (Item::item_name.ptr())
+    if (Item::item_name.is_set())
       tmp_field->col_name=Item::item_name.ptr();    // Use user supplied name
   }
   else
@@ -5365,7 +5365,7 @@ longlong Item_func_get_user_var::val_int
 
 static int
 get_var_with_binlog(THD *thd, enum_sql_command sql_command,
-                    LEX_STRING &name, user_var_entry **out_entry)
+                    NameString &name, user_var_entry **out_entry)
 {
   BINLOG_USER_VAR_EVENT *user_var_event;
   user_var_entry *var_entry;
@@ -5548,7 +5548,7 @@ enum Item_result Item_func_get_user_var:
 void Item_func_get_user_var::print(String *str, enum_query_type query_type)
 {
   str->append(STRING_WITH_LEN("(@"));
-  str->append(name.str,name.length);
+  str->append(name);
   str->append(')');
 }
 
@@ -5563,15 +5563,14 @@ bool Item_func_get_user_var::eq(const It
       ((Item_func*) item)->functype() != functype())
     return 0;
   Item_func_get_user_var *other=(Item_func_get_user_var*) item;
-  return (name.length == other->name.length &&
-	  !memcmp(name.str, other->name.str, name.length));
+  return name.eq_bin(other->name);
 }
 
 
 bool Item_func_get_user_var::set_value(THD *thd,
                                        sp_rcontext * /*ctx*/, Item **it)
 {
-  Item_func_set_user_var *suv= new Item_func_set_user_var(get_name(), *it);
+  Item_func_set_user_var *suv= new Item_func_set_user_var(name, *it);
   /*
     Item_func_set_user_var is not fixed after construction, call
     fix_fields().
@@ -5647,7 +5646,7 @@ my_decimal* Item_user_var_as_out_param::
 void Item_user_var_as_out_param::print(String *str, enum_query_type query_type)
 {
   str->append('@');
-  str->append(name.str,name.length);
+  str->append(name);
 }
 
 
@@ -6805,7 +6804,7 @@ Item_func_sp::make_field(Send_field *tmp
   DBUG_ENTER("Item_func_sp::make_field");
   DBUG_ASSERT(sp_result_field);
   sp_result_field->make_field(tmp_field);
-  if (item_name.ptr())
+  if (item_name.is_set())
     tmp_field->col_name= item_name.ptr();
   DBUG_VOID_RETURN;
 }

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2012-03-30 15:38:01 +0000
+++ b/sql/item_func.h	2012-04-12 15:31:01 +0000
@@ -1634,8 +1634,8 @@ class Item_func_set_user_var :public Ite
   } save_result;
 
 public:
-  LEX_STRING name; // keep it public
-  Item_func_set_user_var(LEX_STRING a,Item *b)
+  NameString name; // keep it public
+  Item_func_set_user_var(NameString a, Item *b)
     :Item_var_func(b), cached_result_type(INT_RESULT),
      entry(NULL), entry_thread_id(0), name(a)
   {}
@@ -1689,11 +1689,10 @@ class Item_func_get_user_var :public Ite
   Item_result m_cached_result_type;
 
 public:
-  LEX_STRING name; // keep it public
-  Item_func_get_user_var(LEX_STRING a):
+  NameString name; // keep it public
+  Item_func_get_user_var(NameString a):
     Item_var_func(), m_cached_result_type(STRING_RESULT), name(a) {}
   enum Functype functype() const { return GUSERVAR_FUNC; }
-  LEX_STRING get_name() { return name; }
   double val_real();
   longlong val_int();
   my_decimal *val_decimal(my_decimal*);
@@ -1732,11 +1731,11 @@ public:
 */
 class Item_user_var_as_out_param :public Item
 {
-  LEX_STRING name;
+  NameString name;
   user_var_entry *entry;
 public:
-  Item_user_var_as_out_param(LEX_STRING a) : name(a)
-  { item_name.copy(a.str, 0); }
+  Item_user_var_as_out_param(NameString a) :name(a)
+  { item_name.copy(a); }
   /* We should return something different from FIELD_ITEM here */
   enum Type type() const { return STRING_ITEM;}
   double val_real();

=== modified file 'sql/item_timefunc.h'
--- a/sql/item_timefunc.h	2012-03-30 15:38:01 +0000
+++ b/sql/item_timefunc.h	2012-04-12 15:31:01 +0000
@@ -899,7 +899,7 @@ public:
   void cleanup()
   {
     // See Item_basic_const::cleanup()
-    if (orig_name.ptr())
+    if (orig_name.is_set())
       item_name= orig_name;
   }
   bool eq(const Item *item, bool binary_cmp) const;
@@ -956,7 +956,7 @@ public:
   void cleanup()
   {
     // See Item_basic_const::cleanup()
-    if (orig_name.ptr())
+    if (orig_name.is_set())
       item_name= orig_name;
   }
   bool eq(const Item *item, bool binary_cmp) const;
@@ -1013,7 +1013,7 @@ public:
   void cleanup()
   {
     // See Item_basic_const::cleanup()
-    if (orig_name.ptr())
+    if (orig_name.is_set())
       item_name= orig_name;
   }
   bool eq(const Item *item, bool binary_cmp) const;

=== modified file 'sql/item_xmlfunc.cc'
--- a/sql/item_xmlfunc.cc	2012-03-13 13:27:02 +0000
+++ b/sql/item_xmlfunc.cc	2012-04-12 15:31:01 +0000
@@ -2485,7 +2485,7 @@ my_xpath_parse_VariableReference(MY_XPAT
   name.str= (char*) xpath->prevtok.beg;
   
   if (user_var)
-    xpath->item= new Item_func_get_user_var(name);
+    xpath->item= new Item_func_get_user_var(NameString(name, false));
   else
   {
     sp_variable *spv;
@@ -2495,7 +2495,8 @@ my_xpath_parse_VariableReference(MY_XPAT
         (spc= lex->get_sp_current_parsing_ctx()) &&
         (spv= spc->find_variable(name, false)))
     {
-      Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0);
+      Item_splocal *splocal= new Item_splocal(NameString(name, false),
+                                              spv->offset, spv->type, 0);
 #ifndef DBUG_OFF
       if (splocal)
         splocal->m_sp= lex->sphead;

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2012-04-12 08:43:18 +0000
+++ b/sql/log_event.cc	2012-04-12 15:31:01 +0000
@@ -7388,9 +7388,6 @@ int User_var_log_event::do_apply_event(R
   CHARSET_INFO *charset;
   if (!(charset= get_charset(charset_number, MYF(MY_WME))))
     return 1;
-  LEX_STRING user_var_name;
-  user_var_name.str= name;
-  user_var_name.length= name_len;
   double real_val;
   longlong int_val;
 
@@ -7436,7 +7433,7 @@ int User_var_log_event::do_apply_event(R
       return 0;
     }
   }
-  Item_func_set_user_var e(user_var_name, it);
+  Item_func_set_user_var e(NameString(name, name_len, false), it);
   /*
     Item_func_set_user_var can't substitute something else on its place =>
     0 can be passed as last argument (reference on item)

=== modified file 'sql/sp_head.cc'
--- a/sql/sp_head.cc	2012-03-31 18:30:05 +0000
+++ b/sql/sp_head.cc	2012-04-12 15:31:01 +0000
@@ -1010,7 +1010,7 @@ subst_spvars(THD *thd, sp_instr *instr,
 
     /* append the spvar substitute */
     res|= qbuf.append(STRING_WITH_LEN(" NAME_CONST('"));
-    res|= qbuf.append((*splocal)->m_name.str, (*splocal)->m_name.length);
+    res|= qbuf.append((*splocal)->m_name);
     res|= qbuf.append(STRING_WITH_LEN("',"));
 
     if (res)
@@ -2814,7 +2814,7 @@ sp_head::show_routine_code(THD *thd)
   if (check_show_routine_access(thd, this, &full_access) || !full_access)
     DBUG_RETURN(1);
 
-  field_list.push_back(new Item_uint("Pos", 9));
+  field_list.push_back(new Item_uint("Pos", 0, 9));
   // 1024 is for not to confuse old clients
   field_list.push_back(new Item_empty_string("Instruction",
                                              max(buffer.length(), 1024U)));

=== modified file 'sql/sql_analyse.cc'
--- a/sql/sql_analyse.cc	2012-03-30 15:38:01 +0000
+++ b/sql/sql_analyse.cc	2012-04-12 15:31:01 +0000
@@ -70,7 +70,7 @@ Procedure *
 proc_analyse_init(THD *thd, ORDER *param, select_result *result,
 		  List<Item> &field_list)
 {
-  char *proc_name = (*param->item)->item_name.ptr();
+  const char *proc_name = (*param->item)->item_name.ptr();
   analyse *pc = new analyse(result);
   field_info **f_info;
   DBUG_ENTER("proc_analyse_init");

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2012-04-03 08:34:25 +0000
+++ b/sql/sql_base.cc	2012-04-12 15:31:01 +0000
@@ -7259,7 +7259,7 @@ find_item_in_list(Item *find, List<Item>
 	(if this field created from expression argument of group_concat()),
 	=> we have to check presence of name before compare
       */ 
-      if (!item_field->item_name.ptr())
+      if (!item_field->item_name.is_set())
         continue;
 
       if (table_name)
@@ -7314,7 +7314,7 @@ find_item_in_list(Item *find, List<Item>
         int fname_cmp= my_strcasecmp(system_charset_info,
                                      item_field->field_name,
                                      field_name);
-        if (item_field->item_name.eq(field_name))
+        if (item_field->item_name.eq_safe(field_name))
         {
           /*
             If table name was not given we should scan through aliases
@@ -7358,7 +7358,7 @@ find_item_in_list(Item *find, List<Item>
     }
     else if (!table_name)
     { 
-      if (is_ref_by_name && item->item_name.eq(&find->item_name))
+      if (is_ref_by_name && item->item_name.eq_safe(find->item_name))
       {
         found= li.ref();
         *counter= i;
@@ -7389,7 +7389,7 @@ find_item_in_list(Item *find, List<Item>
         Item_field for tables.
       */
       Item_ident *item_ref= (Item_ident *) item;
-      if (item_ref->item_name.eq(field_name) &&
+      if (item_ref->item_name.eq_safe(field_name) &&
           item_ref->table_name &&
           !my_strcasecmp(table_alias_charset, item_ref->table_name,
                          table_name) &&

=== modified file 'sql/sql_executor.cc'
--- a/sql/sql_executor.cc	2012-03-30 15:38:01 +0000
+++ b/sql/sql_executor.cc	2012-04-12 15:31:01 +0000
@@ -4839,7 +4839,7 @@ change_to_use_tmp_fields(THD *thd, Ref_p
         ifield->db_name= iref->db_name;
       }
 #ifndef DBUG_OFF
-      if (!item_field->item_name.ptr())
+      if (!item_field->item_name.is_set())
       {
         char buff[256];
         String str(buff,sizeof(buff),&my_charset_bin);

=== modified file 'sql/sql_show.h'
--- a/sql/sql_show.h	2011-12-09 21:08:37 +0000
+++ b/sql/sql_show.h	2012-04-12 15:31:01 +0000
@@ -166,6 +166,10 @@ int copy_event_to_schema_table(THD *thd,
 
 void append_identifier(THD *thd, String *packet, const char *name,
 		       uint length);
+inline void append_identifier(THD *thd, String *packet, SimpleCString str)
+{
+  append_identifier(thd, packet, str.ptr(), str.length());
+}
 void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild);
 bool mysqld_show_create(THD *thd, TABLE_LIST *table_list);
 bool mysqld_show_create_db(THD *thd, char *dbname, HA_CREATE_INFO *create);

=== modified file 'sql/sql_string.h'
--- a/sql/sql_string.h	2012-03-06 14:29:42 +0000
+++ b/sql/sql_string.h	2012-04-12 15:31:01 +0000
@@ -22,6 +22,85 @@
 #include "my_sys.h"              /* alloc_root, my_free, my_realloc */
 #include "m_string.h"                           /* TRASH */
 
+
+/**
+  A wrapper class for null-terminated constant strings.
+  Constructors make sure that the position of the '\0' terminating byte
+  in m_str is always in sync with m_length.
+*/
+class SimpleCString
+{
+private:
+  const char *m_str;
+  uint m_length;
+protected:
+  /**
+    Initialize from a C string whose length is already known.
+  */
+  void set(const char *str_arg, uint length_arg)
+  {
+    // NULL is allowed only with length==0
+    DBUG_ASSERT(str_arg || length_arg == 0);
+    // For non-NULL, make sure length_arg is in sync with '\0' terminator.
+    DBUG_ASSERT(!str_arg || str_arg[length_arg] == '\0');
+    m_str= str_arg;
+    m_length= length_arg;
+  }
+public:
+  SimpleCString()
+  {
+    set(NULL, 0);
+  }
+  SimpleCString(const char *str_arg, uint length_arg)
+  {
+    set(str_arg, length_arg);
+  }
+  SimpleCString(const LEX_STRING arg)
+  {
+    set(arg.str, arg.length);
+  }
+  void reset()
+  {
+    set(NULL, 0);
+  }
+  /**
+    Set to a null-terminated string.
+  */
+  void set(const char *str)
+  {
+    set(str, str ? strlen(str) : 0);
+  }
+  /**
+    Return string buffer.
+  */
+  const char *ptr() const { return m_str; }
+  /**
+    Check if m_ptr is set.
+  */
+  bool is_set() const { return m_str != NULL; }
+  /**
+    Return name length.
+  */
+  uint length() const { return m_length; }
+  /**
+    Compare to another SimpleCString.
+  */
+  bool eq_bin(const SimpleCString other) const
+  {
+    return m_length == other.m_length &&
+           memcmp(m_str, other.m_str, m_length) == 0;
+  }
+  /**
+    Copy to the given buffer
+  */
+  void strcpy(char *buff) const
+  {
+    memcpy(buff, m_str, m_length);
+    buff[m_length]= '\0';
+  }
+};
+
+
 class String;
 typedef struct charset_info_st CHARSET_INFO;
 typedef struct st_io_cache IO_CACHE;
@@ -290,6 +369,10 @@ public:
   {
     return append(ls->str, ls->length);
   }
+  bool append(SimpleCString str)
+  {
+    return append(str.ptr(), str.length());
+  }
   bool append(const char *s, uint32 arg_length);
   bool append(const char *s, uint32 arg_length, const CHARSET_INFO *cs);
   bool append_ulonglong(ulonglong val);

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2012-03-30 15:38:01 +0000
+++ b/sql/sql_view.cc	2012-04-12 15:31:01 +0000
@@ -61,9 +61,8 @@ static void make_unique_view_field_name(
                                         List<Item> &item_list,
                                         Item *last_element)
 {
-  char *name= (target->orig_name.ptr() ?
-               target->orig_name.ptr() :
-               target->item_name.ptr());
+  const char *name= (target->orig_name.is_set() ?
+                     target->orig_name.ptr() : target->item_name.ptr());
   size_t name_len;
   uint attempt;
   char buff[NAME_LEN+1];
@@ -137,7 +136,7 @@ bool check_duplicate_names(List<Item> &i
     itc.rewind();
     while ((check= itc++) && check != item)
     {
-      if (item->item_name.eq(&check->item_name))
+      if (item->item_name.eq(check->item_name))
       {
         if (!gen_unique_view_name)
           goto err;

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2012-04-12 08:24:17 +0000
+++ b/sql/sql_yacc.yy	2012-04-12 15:31:01 +0000
@@ -8275,7 +8275,7 @@ select_item:
               }
               $2->item_name.copy($4.str, $4.length, system_charset_info, false);
             }
-            else if (!$2->item_name.ptr())
+            else if (!$2->item_name.is_set())
             {
               $2->item_name.copy($1, (uint) ($3 - $1), thd->charset());
             }
@@ -8885,7 +8885,7 @@ simple_expr:
             {
               Item_splocal *il= static_cast<Item_splocal *>($3);
 
-              my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->my_name()->str);
+              my_error(ER_WRONG_COLUMN_NAME, MYF(0), il->m_name.ptr());
               MYSQL_YYABORT;
             }
             $$= new (YYTHD->mem_root) Item_default_value(Lex->current_context(),
@@ -10994,7 +10994,7 @@ procedure_item:
 
             if (add_proc_to_list(thd, $2))
               MYSQL_YYABORT;
-            if (!$2->item_name.ptr())
+            if (!$2->item_name.is_set())
               $2->item_name.copy($1, (uint) ($3 - $1), thd->charset());
           }
         ;
@@ -12781,7 +12781,7 @@ literal:
 
             Item_string *item_str;
             item_str= new (YYTHD->mem_root)
-                        Item_string(NULL, /* name will be set in select_item */
+                        Item_string(null_name_string, /* name will be set in select_item */
                                     str ? str->ptr() : "",
                                     str ? str->length() : 0,
                                     $1);
@@ -12810,7 +12810,7 @@ literal:
 
             Item_string *item_str;
             item_str= new (YYTHD->mem_root)
-                        Item_string(NULL, /* name will be set in select_item */
+                        Item_string(null_name_string, /* name will be set in select_item */
                                     str ? str->ptr() : "",
                                     str ? str->length() : 0,
                                     $1);

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (alexander.barkov:3871 to 3872) Bug#12537203Alexander Barkov13 Apr