From: Alexander Barkov Date: August 15 2012 11:57am Subject: bzr push into mysql-trunk branch (alexander.barkov:4230 to 4231) List-Archive: http://lists.mysql.com/commits/144562 Message-Id: <201208151205.q7FC5a5c010819@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 4231 Alexander Barkov 2012-08-15 [merge] Merging from 5.6. modified: sql/binlog.cc sql/item.cc sql/item_func.cc sql/log_event.h sql/rpl_master.cc sql/sql_class.cc sql/sql_class.h sql/sql_prepare.cc 4230 Martin Hansson 2012-08-15 Bug#13985071: DEPRECATE INSERT DELAYED Follow-up patch. There is now a deprecation message when using system variables that are part of the INSERT DELAYED feature. The variables are also flagged as deprecated when running mysqld --help. modified: mysql-test/r/delayed.result mysql-test/r/mysqld--help-notwin.result mysql-test/r/mysqld--help-win.result mysql-test/r/variables.result mysql-test/suite/rpl/r/rpl_bug31076.result mysql-test/suite/sys_vars/r/delayed_insert_limit_basic_32.result mysql-test/suite/sys_vars/r/delayed_insert_limit_basic_64.result mysql-test/suite/sys_vars/r/delayed_insert_limit_func.result mysql-test/suite/sys_vars/r/delayed_insert_timeout_basic.result mysql-test/suite/sys_vars/r/delayed_queue_size_basic_32.result mysql-test/suite/sys_vars/r/delayed_queue_size_basic_64.result mysql-test/suite/sys_vars/r/max_delayed_threads_basic.result mysql-test/suite/sys_vars/r/max_insert_delayed_threads_basic.result mysql-test/t/delayed.test sql/sys_vars.cc === modified file 'sql/binlog.cc' --- a/sql/binlog.cc 2012-07-24 11:18:33 +0000 +++ b/sql/binlog.cc 2012-08-15 11:04:29 +0000 @@ -4732,8 +4732,9 @@ bool MYSQL_BIN_LOG::write_event(Log_even if (user_var_event->unsigned_flag) flags|= User_var_log_event::UNSIGNED_F; - User_var_log_event e(thd, user_var_event->user_var_event->name.str, - user_var_event->user_var_event->name.length, + User_var_log_event e(thd, + user_var_event->user_var_event->entry_name.ptr(), + user_var_event->user_var_event->entry_name.length(), user_var_event->value, user_var_event->length, user_var_event->type, === modified file 'sql/item.cc' --- a/sql/item.cc 2012-08-09 12:30:01 +0000 +++ b/sql/item.cc 2012-08-15 11:04:29 +0000 @@ -3579,9 +3579,9 @@ bool Item_param::set_longdata(const char bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry) { DBUG_ENTER("Item_param::set_from_user_var"); - if (entry && entry->value) + if (entry && entry->ptr()) { - item_result_type= entry->type; + item_result_type= entry->type(); unsigned_flag= entry->unsigned_flag; if (limit_clause_param) { @@ -3592,11 +3592,11 @@ bool Item_param::set_from_user_var(THD * } switch (item_result_type) { case REAL_RESULT: - set_double(*(double*)entry->value); + set_double(*(double*) entry->ptr()); item_type= Item::REAL_ITEM; break; case INT_RESULT: - set_int(*(longlong*)entry->value, MY_INT64_NUM_DECIMAL_DIGITS); + set_int(*(longlong*) entry->ptr(), MY_INT64_NUM_DECIMAL_DIGITS); item_type= Item::INT_ITEM; break; case STRING_RESULT: @@ -3621,13 +3621,13 @@ bool Item_param::set_from_user_var(THD * */ item_type= Item::STRING_ITEM; - if (set_str((const char *)entry->value, entry->length)) + if (set_str((const char *) entry->ptr(), entry->length())) DBUG_RETURN(1); break; } case DECIMAL_RESULT: { - const my_decimal *ent_value= (const my_decimal *)entry->value; + const my_decimal *ent_value= (const my_decimal *) entry->ptr(); my_decimal2decimal(ent_value, &decimal_value); state= DECIMAL_VALUE; decimals= ent_value->frac; === modified file 'sql/item_func.cc' --- a/sql/item_func.cc 2012-08-07 13:37:23 +0000 +++ b/sql/item_func.cc 2012-08-15 10:38:01 +0000 @@ -4550,9 +4550,7 @@ longlong Item_func_sleep::val_int() } -#define extra_size sizeof(double) - -static user_var_entry *get_variable(HASH *hash, Name_string &name, +static user_var_entry *get_variable(HASH *hash, const Name_string &name, bool create_if_not_exists) { user_var_entry *entry; @@ -4561,32 +4559,10 @@ static user_var_entry *get_variable(HASH name.length())) && create_if_not_exists) { - 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)))) + if (!(entry= user_var_entry::create(name))) return 0; - entry->name.str=(char*) entry+ ALIGN_SIZE(sizeof(user_var_entry))+ - extra_size; - entry->name.length= name.length(); - entry->value=0; - entry->length=0; - entry->update_query_id=0; - entry->collation.set(NULL, DERIVATION_IMPLICIT, 0); - entry->unsigned_flag= 0; - /* - If we are here, we were called from a SET or a query which sets a - variable. Imagine it is this: - INSERT INTO t SELECT @a:=10, @a:=@a+1. - Then when we have a Item_func_get_user_var (because of the @a+1) so we - think we have to write the value of @a to the binlog. But before that, - we have a Item_func_set_user_var to create @a (@a:=10), in this we mark - the variable as "already logged" (line below) so that it won't be logged - by Item_func_get_user_var (because that's not necessary). - */ - entry->used_query_id=current_thd->query_id; - entry->type=STRING_RESULT; - name.strcpy(entry->name.str); if (my_hash_insert(hash,(uchar*) entry)) { my_free(entry); @@ -4699,11 +4675,60 @@ bool Item_func_set_user_var::register_fi } +bool user_var_entry::realloc(uint length) +{ + if (length <= extra_size) + { + /* Enough space to store value in value struct */ + free_value(); + m_ptr= internal_buffer_ptr(); + } + else + { + /* Allocate an external buffer */ + if (m_length != length) + { + if (m_ptr == internal_buffer_ptr()) + m_ptr= 0; + if (!(m_ptr= (char*) my_realloc(m_ptr, length, + MYF(MY_ALLOW_ZERO_PTR | MY_WME | + ME_FATALERROR)))) + return true; + } + } + return false; +} + + +/** + Set value to user variable. + @param ptr pointer to buffer with new value + @param length length of new value + @param type type of new value + + @retval false on success + @retval true on allocation error + +*/ +bool user_var_entry::store(void *from, uint length, Item_result type) +{ + // Store strings with end \0 + if (realloc(length + test(type == STRING_RESULT))) + return true; + if (type == STRING_RESULT) + m_ptr[length]= 0; // Store end \0 + memmove(m_ptr, from, length); + if (type == DECIMAL_RESULT) + ((my_decimal*) m_ptr)->fix_buffer_pointer(); + m_length= length; + m_type= type; + return false; +} + + /** Set value to user variable. - @param entry pointer to structure representing variable - @param set_null should we set NULL value ? @param ptr pointer to buffer with new value @param length length of new value @param type type of new value @@ -4719,63 +4744,15 @@ bool Item_func_set_user_var::register_fi true failure */ -static bool -update_hash(user_var_entry *entry, bool set_null, void *ptr, uint length, - Item_result type, const CHARSET_INFO *cs, Derivation dv, - bool unsigned_arg) -{ - if (set_null) - { - char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); - if (entry->value && entry->value != pos) - my_free(entry->value); - entry->value= 0; - entry->length= 0; - } - else - { - if (type == STRING_RESULT) - length++; // Store strings with end \0 - if (length <= extra_size) - { - /* Save value in value struct */ - char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); - if (entry->value != pos) - { - if (entry->value) - my_free(entry->value); - entry->value=pos; - } - } - else - { - /* Allocate variable */ - if (entry->length != length) - { - char *pos= (char*) entry+ ALIGN_SIZE(sizeof(user_var_entry)); - if (entry->value == pos) - entry->value=0; - entry->value= (char*) my_realloc(entry->value, length, - MYF(MY_ALLOW_ZERO_PTR | MY_WME | - ME_FATALERROR)); - if (!entry->value) - return 1; - } - } - if (type == STRING_RESULT) - { - length--; // Fix length change above - entry->value[length]= 0; // Store end \0 - } - memmove(entry->value, ptr, length); - if (type == DECIMAL_RESULT) - ((my_decimal*)entry->value)->fix_buffer_pointer(); - entry->length= length; - entry->collation.set(cs, dv); - entry->unsigned_flag= unsigned_arg; - } - entry->type=type; - return 0; +bool user_var_entry::store(void *ptr, uint length, Item_result type, + const CHARSET_INFO *cs, Derivation dv, + bool unsigned_arg) +{ + if (store(ptr, length, type)) + return true; + collation.set(cs, dv); + unsigned_flag= unsigned_arg; + return false; } @@ -4795,9 +4772,10 @@ Item_func_set_user_var::update_hash(void else null_value= args[0]->null_value; if (null_value && null_item) - res_type= entry->type; // Don't change type of item - if (::update_hash(entry, null_value, - ptr, length, res_type, cs, dv, unsigned_arg)) + res_type= entry->type(); // Don't change type of item + if (null_value) + entry->set_null_value(res_type); + else if (entry->store(ptr, length, res_type, cs, dv, unsigned_arg)) { null_value= 1; return 1; @@ -4810,22 +4788,22 @@ Item_func_set_user_var::update_hash(void double user_var_entry::val_real(my_bool *null_value) { - if ((*null_value= (value == 0))) + if ((*null_value= (m_ptr == 0))) return 0.0; - switch (type) { + switch (m_type) { case REAL_RESULT: - return *(double*) value; + return *(double*) m_ptr; case INT_RESULT: - return (double) *(longlong*) value; + return (double) *(longlong*) m_ptr; case DECIMAL_RESULT: { double result; - my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *)value, &result); + my_decimal2double(E_DEC_FATAL_ERROR, (my_decimal *) m_ptr, &result); return result; } case STRING_RESULT: - return my_atof(value); // This is null terminated + return my_atof(m_ptr); // This is null terminated case ROW_RESULT: DBUG_ASSERT(1); // Impossible break; @@ -4838,24 +4816,24 @@ double user_var_entry::val_real(my_bool longlong user_var_entry::val_int(my_bool *null_value) const { - if ((*null_value= (value == 0))) + if ((*null_value= (m_ptr == 0))) return LL(0); - switch (type) { + switch (m_type) { case REAL_RESULT: - return (longlong) *(double*) value; + return (longlong) *(double*) m_ptr; case INT_RESULT: - return *(longlong*) value; + return *(longlong*) m_ptr; case DECIMAL_RESULT: { longlong result; - my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *)value, 0, &result); + my_decimal2int(E_DEC_FATAL_ERROR, (my_decimal *) m_ptr, 0, &result); return result; } case STRING_RESULT: { int error; - return my_strtoll10(value, (char**) 0, &error);// String is null terminated + return my_strtoll10(m_ptr, (char**) 0, &error);// String is null terminated } case ROW_RESULT: DBUG_ASSERT(1); // Impossible @@ -4870,24 +4848,24 @@ longlong user_var_entry::val_int(my_bool String *user_var_entry::val_str(my_bool *null_value, String *str, uint decimals) { - if ((*null_value= (value == 0))) + if ((*null_value= (m_ptr == 0))) return (String*) 0; - switch (type) { + switch (m_type) { case REAL_RESULT: - str->set_real(*(double*) value, decimals, collation.collation); + str->set_real(*(double*) m_ptr, decimals, collation.collation); break; case INT_RESULT: if (!unsigned_flag) - str->set(*(longlong*) value, collation.collation); + str->set(*(longlong*) m_ptr, collation.collation); else - str->set(*(ulonglong*) value, collation.collation); + str->set(*(ulonglong*) m_ptr, collation.collation); break; case DECIMAL_RESULT: - str_set_decimal((my_decimal *) value, str, collation.collation); + str_set_decimal((my_decimal *) m_ptr, str, collation.collation); break; case STRING_RESULT: - if (str->copy(value, length, collation.collation)) + if (str->copy(m_ptr, m_length, collation.collation)) str= 0; // EOM error case ROW_RESULT: DBUG_ASSERT(1); // Impossible @@ -4900,21 +4878,22 @@ String *user_var_entry::val_str(my_bool my_decimal *user_var_entry::val_decimal(my_bool *null_value, my_decimal *val) { - if ((*null_value= (value == 0))) + if ((*null_value= (m_ptr == 0))) return 0; - switch (type) { + switch (m_type) { case REAL_RESULT: - double2my_decimal(E_DEC_FATAL_ERROR, *(double*) value, val); + double2my_decimal(E_DEC_FATAL_ERROR, *(double*) m_ptr, val); break; case INT_RESULT: - int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) value, 0, val); + int2my_decimal(E_DEC_FATAL_ERROR, *(longlong*) m_ptr, 0, val); break; case DECIMAL_RESULT: - my_decimal2decimal((my_decimal *) value, val); + my_decimal2decimal((my_decimal *) m_ptr, val); break; case STRING_RESULT: - str2my_decimal(E_DEC_FATAL_ERROR, value, length, collation.collation, val); + str2my_decimal(E_DEC_FATAL_ERROR, m_ptr, m_length, + collation.collation, val); break; case ROW_RESULT: DBUG_ASSERT(1); // Impossible @@ -5453,7 +5432,7 @@ get_var_with_binlog(THD *thd, enum_sql_c may need to be valid after current [SP] statement execution pool is destroyed. */ - size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length; + size= ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)) + var_entry->length(); if (!(user_var_event= (BINLOG_USER_VAR_EVENT *) alloc_root(thd->user_var_events_alloc, size))) goto err; @@ -5461,10 +5440,10 @@ get_var_with_binlog(THD *thd, enum_sql_c user_var_event->value= (char*) user_var_event + ALIGN_SIZE(sizeof(BINLOG_USER_VAR_EVENT)); user_var_event->user_var_event= var_entry; - user_var_event->type= var_entry->type; + user_var_event->type= var_entry->type(); user_var_event->charset_number= var_entry->collation.collation->number; user_var_event->unsigned_flag= var_entry->unsigned_flag; - if (!var_entry->value) + if (!var_entry->ptr()) { /* NULL value*/ user_var_event->length= 0; @@ -5472,9 +5451,9 @@ get_var_with_binlog(THD *thd, enum_sql_c } else { - user_var_event->length= var_entry->length; - memcpy(user_var_event->value, var_entry->value, - var_entry->length); + user_var_event->length= var_entry->length(); + memcpy(user_var_event->value, var_entry->ptr(), + var_entry->length()); } /* Mark that this variable has been used by this query */ var_entry->used_query_id= thd->query_id; @@ -5506,9 +5485,9 @@ void Item_func_get_user_var::fix_length_ */ if (!error && var_entry) { - m_cached_result_type= var_entry->type; + m_cached_result_type= var_entry->type(); unsigned_flag= var_entry->unsigned_flag; - max_length= var_entry->length; + max_length= var_entry->length(); collation.set(var_entry->collation); switch(m_cached_result_type) { @@ -5595,7 +5574,7 @@ bool Item_user_var_as_out_param::fix_fie if (Item::fix_fields(thd, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return TRUE; - entry->type= STRING_RESULT; + entry->set_type(STRING_RESULT); /* Let us set the same collation which is used for loading of fields in LOAD DATA INFILE. @@ -5611,16 +5590,15 @@ bool Item_user_var_as_out_param::fix_fie void Item_user_var_as_out_param::set_null_value(const CHARSET_INFO* cs) { - ::update_hash(entry, TRUE, 0, 0, STRING_RESULT, cs, - DERIVATION_IMPLICIT, 0 /* unsigned_arg */); + entry->set_null_value(STRING_RESULT); } void Item_user_var_as_out_param::set_value(const char *str, uint length, const CHARSET_INFO* cs) { - ::update_hash(entry, FALSE, (void*)str, length, STRING_RESULT, cs, - DERIVATION_IMPLICIT, 0 /* unsigned_arg */); + entry->store((void*) str, length, STRING_RESULT, cs, + DERIVATION_IMPLICIT, 0 /* unsigned_arg */); } === modified file 'sql/log_event.h' --- a/sql/log_event.h 2012-08-14 08:57:19 +0000 +++ b/sql/log_event.h 2012-08-15 10:38:01 +0000 @@ -2882,7 +2882,7 @@ public: UNDEF_F= 0, UNSIGNED_F= 1 }; - char *name; + const char *name; uint name_len; char *val; ulong val_len; @@ -2892,7 +2892,7 @@ public: uchar flags; #ifdef MYSQL_SERVER bool deferred; - User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg, + User_var_log_event(THD* thd_arg, const char *name_arg, uint name_len_arg, char *val_arg, ulong val_len_arg, Item_result type_arg, uint charset_number_arg, uchar flags_arg, enum_event_cache_type cache_type_arg, === modified file 'sql/rpl_master.cc' --- a/sql/rpl_master.cc 2012-06-25 09:28:20 +0000 +++ b/sql/rpl_master.cc 2012-08-15 10:38:01 +0000 @@ -313,10 +313,10 @@ static uint8 get_binlog_checksum_value_a } else { - DBUG_ASSERT(entry->type == STRING_RESULT); + DBUG_ASSERT(entry->type() == STRING_RESULT); String str; uint dummy_errors; - str.copy(entry->value, entry->length, &my_charset_bin, &my_charset_bin, + str.copy(entry->ptr(), entry->length(), &my_charset_bin, &my_charset_bin, &dummy_errors); ret= (uint8) find_type ((char*) str.ptr(), &binlog_checksum_typelib, 1) - 1; DBUG_ASSERT(ret <= BINLOG_CHECKSUM_ALG_CRC32); // while it's just on CRC32 alg @@ -1611,9 +1611,9 @@ String *get_slave_uuid(THD *thd, String return NULL; user_var_entry *entry= (user_var_entry*) my_hash_search(&thd->user_vars, name, sizeof(name)-1); - if (entry && entry->length > 0) + if (entry && entry->length() > 0) { - value->copy(entry->value, entry->length, NULL); + value->copy(entry->ptr(), entry->length(), NULL); return value; } else === modified file 'sql/sql_class.cc' --- a/sql/sql_class.cc 2012-08-02 08:15:19 +0000 +++ b/sql/sql_class.cc 2012-08-15 11:04:29 +0000 @@ -85,16 +85,13 @@ const char * const THD::DEFAULT_WHERE= " extern "C" uchar *get_var_key(user_var_entry *entry, size_t *length, my_bool not_used __attribute__((unused))) { - *length= entry->name.length; - return (uchar*) entry->name.str; + *length= entry->entry_name.length(); + return (uchar*) entry->entry_name.ptr(); } extern "C" void free_user_var(user_var_entry *entry) { - char *pos= (char*) entry+ALIGN_SIZE(sizeof(*entry)); - if (entry->value && entry->value != pos) - my_free(entry->value); - my_free(entry); + entry->destroy(); } bool Key_part_spec::operator==(const Key_part_spec& other) const === modified file 'sql/sql_class.h' --- a/sql/sql_class.h 2012-08-09 07:55:37 +0000 +++ b/sql/sql_class.h 2012-08-15 11:04:29 +0000 @@ -4572,20 +4572,181 @@ public: // this is needed for user_vars hash class user_var_entry { - public: + static const size_t extra_size= sizeof(double); + char *m_ptr; // Value + ulong m_length; // Value length + Item_result m_type; // Value type + + void reset_value() + { m_ptr= NULL; m_length= 0; } + void set_value(char *value, ulong length) + { m_ptr= value; m_length= length; } + + /** + Position inside a user_var_entry where small values are stored: + double values, longlong values and string values with length + up to extra_size (should be 8 bytes on all platforms). + String values with length longer than 8 are stored in a separate + memory buffer, which is allocated when needed using the method realloc(). + */ + char *internal_buffer_ptr() const + { return (char *) this + ALIGN_SIZE(sizeof(user_var_entry)); } + + /** + Position inside a user_var_entry where a null-terminates array + of characters representing the variable name is stored. + */ + char *name_ptr() const + { return internal_buffer_ptr() + extra_size; } + + /** + Initialize m_ptr to the internal buffer (if the value is small enough), + or allocate a separate buffer. + @param length - length of the value to be stored. + */ + bool realloc(uint length); + + /** + Check if m_ptr point to an external buffer previously alloced by realloc(). + @retval true - an external buffer is alloced. + @retval false - m_ptr is null, or points to the internal buffer. + */ + bool alloced() + { return m_ptr && m_ptr != internal_buffer_ptr(); } + + /** + Free the external value buffer, if it's allocated. + */ + void free_value() + { + if (alloced()) + my_free(m_ptr); + } + + /** + Copy the array of characters from the given name into the internal + name buffer and initialize entry_name to point to it. + */ + void copy_name(const Simple_cstring &name) + { + name.strcpy(name_ptr()); + entry_name= Name_string(name_ptr(), name.length()); + } + + /** + Initialize all members + @param name - Name of the user_var_entry instance. + */ + void init(const Simple_cstring &name) + { + copy_name(name); + reset_value(); + update_query_id= 0; + collation.set(NULL, DERIVATION_IMPLICIT, 0); + unsigned_flag= 0; + /* + If we are here, we were called from a SET or a query which sets a + variable. Imagine it is this: + INSERT INTO t SELECT @a:=10, @a:=@a+1. + Then when we have a Item_func_get_user_var (because of the @a+1) so we + think we have to write the value of @a to the binlog. But before that, + we have a Item_func_set_user_var to create @a (@a:=10), in this we mark + the variable as "already logged" (line below) so that it won't be logged + by Item_func_get_user_var (because that's not necessary). + */ + used_query_id= current_thd->query_id; + set_type(STRING_RESULT); + } + + /** + Store a value of the given type into a user_var_entry instance. + @param from Value + @param length Size of the value + @param type type + @return + @retval false on success + @retval true on memory allocation error + */ + bool store(void *from, uint length, Item_result type); + +public: user_var_entry() {} /* Remove gcc warning */ - LEX_STRING name; - char *value; - ulong length; + + Simple_cstring entry_name; // Variable name + DTCollation collation; // Collation with attributes query_id_t update_query_id, used_query_id; - Item_result type; - bool unsigned_flag; + bool unsigned_flag; // true if unsigned, false if signed + + /** + Store a value of the given type and attributes (collation, sign) + into a user_var_entry instance. + @param from Value + @param length Size of the value + @param type type + @param cs Character set and collation of the value + @param dv Collationd erivation of the value + @param unsigned_arg Signess of the value + @return + @retval false on success + @retval true on memory allocation error + */ + bool store(void *from, uint length, Item_result type, + const CHARSET_INFO *cs, Derivation dv, bool unsigned_arg); + /** + Set type of to the given value. + @param type Data type. + */ + void set_type(Item_result type) { m_type= type; } + /** + Set value to NULL + @param type Data type. + */ + + void set_null_value(Item_result type) + { + free_value(); + reset_value(); + set_type(type); + } + + /** + Allocate and initialize a user variable instance. + @param namec Name of the variable. + @return + @retval Address of the allocated and initialized user_var_entry instance. + @retval NULL on allocation error. + */ + static user_var_entry *create(const Name_string &name) + { + user_var_entry *entry; + uint size= ALIGN_SIZE(sizeof(user_var_entry)) + + (name.length() + 1) + extra_size; + if (!(entry= (user_var_entry*) my_malloc(size, MYF(MY_WME | + ME_FATALERROR)))) + return NULL; + entry->init(name); + return entry; + } + + /** + Free all memory used by a user_var_entry instance + previously created by create(). + */ + void destroy() + { + free_value(); // Free the external value buffer + my_free(this); // Free the instance itself + } + /* Routines to access the value and its type */ + const char *ptr() const { return m_ptr; } + ulong length() const { return m_length; } + Item_result type() const { return m_type; } + /* Item-alike routines to access the value */ double val_real(my_bool *null_value); longlong val_int(my_bool *null_value) const; String *val_str(my_bool *null_value, String *str, uint decimals); my_decimal *val_decimal(my_bool *null_value, my_decimal *result); - DTCollation collation; }; /* === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2012-07-26 18:46:34 +0000 +++ b/sql/sql_prepare.cc 2012-08-15 10:38:01 +0000 @@ -2321,7 +2321,7 @@ static const char *get_dynamic_sql_strin (user_var_entry*)my_hash_search(&thd->user_vars, (uchar*)lex->prepared_stmt_code.str, lex->prepared_stmt_code.length)) - && entry->value) + && entry->ptr()) { my_bool is_var_null; var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC); No bundle (reason: useless for push emails).