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 secur...@mariadb.org >
commit adf6bb91e349e8983b146cbfcaaa002edff54fe5 Author: Alexander Barkov <b...@mariadb.org> 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); } }
_______________________________________________ Mailing list: https://launchpad.net/~maria-developers Post to : maria-developers@lists.launchpad.net Unsubscribe : https://launchpad.net/~maria-developers More help : https://help.launchpad.net/ListHelp