Loading mysql-test/r/func_in.result +68 −0 Original line number Diff line number Diff line Loading @@ -343,3 +343,71 @@ some_id 1 2 drop table t1; create table t1(f1 char(1)); insert into t1 values ('a'),('b'),('1'); select f1 from t1 where f1 in ('a',1); f1 a 1 select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; f1 case f1 when 'a' then '+' when 1 then '-' end a + b NULL 1 - create index t1f1_idx on t1(f1); select f1 from t1 where f1 in ('a',1); f1 1 a explain select f1 from t1 where f1 in ('a',1); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL t1f1_idx 2 NULL 3 Using where; Using index select f1 from t1 where f1 in ('a','b'); f1 a b explain select f1 from t1 where f1 in ('a','b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index select f1 from t1 where f1 in (2,1); f1 1 explain select f1 from t1 where f1 in (2,1); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index create table t2(f2 int, index t2f2(f2)); insert into t2 values(0),(1),(2); select f2 from t2 where f2 in ('a',2); f2 0 2 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'a' explain select f2 from t2 where f2 in ('a',2); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index select f2 from t2 where f2 in ('a','b'); f2 0 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'b' explain select f2 from t2 where f2 in ('a','b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'b' select f2 from t2 where f2 in (1,'b'); f2 0 1 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'b' Warning 1292 Truncated incorrect DOUBLE value: 'b' explain select f2 from t2 where f2 in (1,'b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index drop table t1, t2; mysql-test/t/func_in.test +24 −0 Original line number Diff line number Diff line Loading @@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1); select some_id from t1 where some_id not in(-4,-1,-4); select some_id from t1 where some_id not in(-4,-1,3423534,2342342); drop table t1; # # Bug#18360: Type aggregation for IN and CASE may lead to a wrong result # create table t1(f1 char(1)); insert into t1 values ('a'),('b'),('1'); select f1 from t1 where f1 in ('a',1); select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; create index t1f1_idx on t1(f1); select f1 from t1 where f1 in ('a',1); explain select f1 from t1 where f1 in ('a',1); select f1 from t1 where f1 in ('a','b'); explain select f1 from t1 where f1 in ('a','b'); select f1 from t1 where f1 in (2,1); explain select f1 from t1 where f1 in (2,1); create table t2(f2 int, index t2f2(f2)); insert into t2 values(0),(1),(2); select f2 from t2 where f2 in ('a',2); explain select f2 from t2 where f2 in ('a',2); select f2 from t2 where f2 in ('a','b'); explain select f2 from t2 where f2 in ('a','b'); select f2 from t2 where f2 in (1,'b'); explain select f2 from t2 where f2 in (1,'b'); drop table t1, t2; mysql-test/t/view.test +1 −1 Original line number Diff line number Diff line Loading @@ -2443,7 +2443,7 @@ DROP TABLE t1, t2; # # Bug #16069: VIEW does return the same results as underlying SELECT # with WHERE condition containing BETWEEN over dates # Dates as strings should be casted to date type CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, td date DEFAULT NULL, KEY idx(td)); Loading sql/item.cc +0 −5 Original line number Diff line number Diff line Loading @@ -5711,11 +5711,6 @@ void Item_trigger_field::cleanup() } /* If item is a const function, calculate it and return a const item The original item is freed if not returned */ Item_result item_cmp_type(Item_result a,Item_result b) { if (a == STRING_RESULT && b == STRING_RESULT) Loading sql/item_cmpfunc.cc +184 −112 Original line number Diff line number Diff line Loading @@ -66,10 +66,8 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) /* Aggregates result types from the array of items. SYNOPSIS: SYNOPSIS agg_cmp_type() thd thread handle type [out] the aggregated type items array of items to aggregate the type from nitems number of items in the array Loading @@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) Aggregation itself is performed by the item_cmp_type() function. */ static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) static Item_result agg_cmp_type(Item **items, uint nitems) { uint i; Item_result type= items[0]->result_type(); for (i= 1 ; i < nitems ; i++) type= item_cmp_type(type, items[i]->result_type()); return type; } /* Collects different types for comparison of first item with each other items SYNOPSIS collect_cmp_types() items Array of items to collect types from nitems Number of items in the array DESCRIPTION This function collects different result types for comparison of the first item in the list with each of the remaining items in the 'items' array. RETURN Bitmap of collected types */ static uint collect_cmp_types(Item **items, uint nitems) { uint i; type[0]= items[0]->result_type(); uint found_types; Item_result left_result= items[0]->result_type(); DBUG_ASSERT(nitems > 1); found_types= 0; for (i= 1; i < nitems ; i++) type[0]= item_cmp_type(type[0], items[i]->result_type()); found_types|= 1<< (uint)item_cmp_type(left_result, items[i]->result_type()); return found_types; } Loading Loading @@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; agg_cmp_type(thd, &cmp_type, args, 3); cmp_type= agg_cmp_type(args, 3); if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1)) return; Loading Loading @@ -1597,94 +1626,65 @@ Item_func_nullif::is_null() return (null_value= (!cmp.compare() ? 1 : args[0]->null_value)); } /* CASE expression Return the matching ITEM or NULL if all compares (including else) failed SYNOPSIS find_item() str Buffer string DESCRIPTION Find and return matching items for CASE or ELSE item if all compares are failed or NULL if ELSE item isn't defined. IMPLEMENTATION In order to do correct comparisons of the CASE expression (the expression between CASE and the first WHEN) with each WHEN expression several comparators are used. One for each result type. CASE expression can be evaluated up to # of different result types are used. To check whether the CASE expression already was evaluated for a particular result type a bit mapped variable value_added_map is used. Result types are mapped to it according to their int values i.e. STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. RETURN NULL - Nothing found and there is no ELSE expression defined item - Found item or ELSE item if defined and all comparisons are failed */ Item *Item_func_case::find_item(String *str) { String *first_expr_str, *tmp; my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; char buff[MAX_FIELD_WIDTH]; String buff_str(buff,sizeof(buff),default_charset()); uint value_added_map= 0; /* These will be initialized later */ LINT_INIT(first_expr_str); LINT_INIT(first_expr_int); LINT_INIT(first_expr_real); LINT_INIT(first_expr_dec); if (first_expr_num != -1) { switch (cmp_type) if (first_expr_num == -1) { case STRING_RESULT: // We can't use 'str' here as this may be overwritten if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str))) return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible break; case INT_RESULT: first_expr_int= args[first_expr_num]->val_int(); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case REAL_RESULT: first_expr_real= args[first_expr_num]->val_real(); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case DECIMAL_RESULT: first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case ROW_RESULT: default: // This case should never be chosen DBUG_ASSERT(0); break; } } // Compare every WHEN argument with it and return the first match for (uint i=0 ; i < ncases ; i+=2) { if (first_expr_num == -1) { // No expression between CASE and the first WHEN if (args[i]->val_bool()) return args[i+1]; continue; } switch (cmp_type) { case STRING_RESULT: if ((tmp=args[i]->val_str(str))) // If not null if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0) return args[i+1]; break; case INT_RESULT: if (args[i]->val_int()==first_expr_int && !args[i]->null_value) return args[i+1]; break; case REAL_RESULT: if (args[i]->val_real() == first_expr_real && !args[i]->null_value) return args[i+1]; break; case DECIMAL_RESULT: } else { my_decimal value; if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) return args[i+1]; break; /* Compare every WHEN argument with it and return the first match */ for (uint i=0 ; i < ncases ; i+=2) { cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); DBUG_ASSERT(cmp_type != ROW_RESULT); DBUG_ASSERT(cmp_items[(uint)cmp_type]); if (!(value_added_map & (1<<(uint)cmp_type))) { cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]); if ((null_value=args[first_expr_num]->null_value)) return else_expr_num != -1 ? args[else_expr_num] : 0; value_added_map|= 1<<(uint)cmp_type; } case ROW_RESULT: default: // This case should never be chosen DBUG_ASSERT(0); break; if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value) return args[i + 1]; } } // No, WHEN clauses all missed, return ELSE expression Loading Loading @@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec() Item **agg; uint nagg; THD *thd= current_thd; uint found_types= 0; if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; Loading @@ -1818,14 +1818,29 @@ void Item_func_case::fix_length_and_dec() */ if (first_expr_num != -1) { uint i; agg[0]= args[first_expr_num]; left_result_type= agg[0]->result_type(); for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; agg_cmp_type(thd, &cmp_type, agg, nagg); if ((cmp_type == STRING_RESULT) && found_types= collect_cmp_types(agg, nagg); for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) { DBUG_ASSERT((Item_result)i != ROW_RESULT); if ((Item_result)i == STRING_RESULT && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1)) return; if (!(cmp_items[i]= cmp_item::get_comparator((Item_result)i, cmp_collation.collation))) return; } } } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) Loading Loading @@ -2412,14 +2427,12 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; uint const_itm= 1; bool const_itm= 1; THD *thd= current_thd; agg_cmp_type(thd, &cmp_type, args, arg_count); if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; uint found_types= 0; uint type_cnt= 0, i; left_result_type= args[0]->result_type(); found_types= collect_cmp_types(args, arg_count); for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) { Loading @@ -2429,15 +2442,28 @@ void Item_func_in::fix_length_and_dec() break; } } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & 1 << i) (type_cnt)++; } /* Row item with NULLs inside can return NULL or FALSE => they can't be processed as static */ if (const_itm && !nulls_in_row()) if (type_cnt == 1 && const_itm && !nulls_in_row()) { uint tmp_type; Item_result cmp_type; /* Only one cmp type was found. Extract it here */ for (tmp_type= 0; found_types - 1; found_types>>= 1) tmp_type++; cmp_type= (Item_result)tmp_type; switch (cmp_type) { case STRING_RESULT: if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in, cmp_collation.collation); break; Loading Loading @@ -2474,9 +2500,19 @@ void Item_func_in::fix_length_and_dec() } else { in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; for (i= 0; i <= (uint) DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) { if ((Item_result)i == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; if (!(cmp_items[i]= cmp_item::get_comparator((Item_result)i, cmp_collation.collation))) return; } } } maybe_null= args[0]->maybe_null; max_length= 1; Loading @@ -2495,25 +2531,61 @@ void Item_func_in::print(String *str) } /* Evaluate the function and return its value. SYNOPSIS val_int() DESCRIPTION Evaluate the function and return its value. IMPLEMENTATION If the array object is defined then the value of the function is calculated by means of this array. Otherwise several cmp_item objects are used in order to do correct comparison of left expression and an expression from the values list. One cmp_item object correspond to one used comparison type. Left expression can be evaluated up to number of different used comparison types. A bit mapped variable value_added_map is used to check whether the left expression already was evaluated for a particular result type. Result types are mapped to it according to their integer values i.e. STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. RETURN Value of the function */ longlong Item_func_in::val_int() { cmp_item *in_item; DBUG_ASSERT(fixed == 1); uint value_added_map= 0; if (array) { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); return (longlong) (!null_value && tmp != negated); } for (uint i= 1 ; i < arg_count ; i++) { Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); in_item= cmp_items[(uint)cmp_type]; DBUG_ASSERT(in_item); if (!(value_added_map & (1 << (uint)cmp_type))) { in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) return 0; have_null= 0; for (uint i=1 ; i < arg_count ; i++) { value_added_map|= 1 << (uint)cmp_type; } if (!in_item->cmp(args[i]) && !args[i]->null_value) return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; return (longlong) (!null_value && negated); } Loading Loading
mysql-test/r/func_in.result +68 −0 Original line number Diff line number Diff line Loading @@ -343,3 +343,71 @@ some_id 1 2 drop table t1; create table t1(f1 char(1)); insert into t1 values ('a'),('b'),('1'); select f1 from t1 where f1 in ('a',1); f1 a 1 select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; f1 case f1 when 'a' then '+' when 1 then '-' end a + b NULL 1 - create index t1f1_idx on t1(f1); select f1 from t1 where f1 in ('a',1); f1 1 a explain select f1 from t1 where f1 in ('a',1); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL t1f1_idx 2 NULL 3 Using where; Using index select f1 from t1 where f1 in ('a','b'); f1 a b explain select f1 from t1 where f1 in ('a','b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index select f1 from t1 where f1 in (2,1); f1 1 explain select f1 from t1 where f1 in (2,1); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index t1f1_idx t1f1_idx 2 NULL 3 Using where; Using index create table t2(f2 int, index t2f2(f2)); insert into t2 values(0),(1),(2); select f2 from t2 where f2 in ('a',2); f2 0 2 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'a' explain select f2 from t2 where f2 in ('a',2); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index select f2 from t2 where f2 in ('a','b'); f2 0 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'b' explain select f2 from t2 where f2 in ('a','b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index t2f2 t2f2 5 NULL 3 Using where; Using index Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'a' Warning 1292 Truncated incorrect DOUBLE value: 'b' select f2 from t2 where f2 in (1,'b'); f2 0 1 Warnings: Warning 1292 Truncated incorrect DOUBLE value: 'b' Warning 1292 Truncated incorrect DOUBLE value: 'b' explain select f2 from t2 where f2 in (1,'b'); id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 index NULL t2f2 5 NULL 3 Using where; Using index drop table t1, t2;
mysql-test/t/func_in.test +24 −0 Original line number Diff line number Diff line Loading @@ -232,3 +232,27 @@ select some_id from t1 where some_id not in(2,-1); select some_id from t1 where some_id not in(-4,-1,-4); select some_id from t1 where some_id not in(-4,-1,3423534,2342342); drop table t1; # # Bug#18360: Type aggregation for IN and CASE may lead to a wrong result # create table t1(f1 char(1)); insert into t1 values ('a'),('b'),('1'); select f1 from t1 where f1 in ('a',1); select f1, case f1 when 'a' then '+' when 1 then '-' end from t1; create index t1f1_idx on t1(f1); select f1 from t1 where f1 in ('a',1); explain select f1 from t1 where f1 in ('a',1); select f1 from t1 where f1 in ('a','b'); explain select f1 from t1 where f1 in ('a','b'); select f1 from t1 where f1 in (2,1); explain select f1 from t1 where f1 in (2,1); create table t2(f2 int, index t2f2(f2)); insert into t2 values(0),(1),(2); select f2 from t2 where f2 in ('a',2); explain select f2 from t2 where f2 in ('a',2); select f2 from t2 where f2 in ('a','b'); explain select f2 from t2 where f2 in ('a','b'); select f2 from t2 where f2 in (1,'b'); explain select f2 from t2 where f2 in (1,'b'); drop table t1, t2;
mysql-test/t/view.test +1 −1 Original line number Diff line number Diff line Loading @@ -2443,7 +2443,7 @@ DROP TABLE t1, t2; # # Bug #16069: VIEW does return the same results as underlying SELECT # with WHERE condition containing BETWEEN over dates # Dates as strings should be casted to date type CREATE TABLE t1 (id int NOT NULL PRIMARY KEY, td date DEFAULT NULL, KEY idx(td)); Loading
sql/item.cc +0 −5 Original line number Diff line number Diff line Loading @@ -5711,11 +5711,6 @@ void Item_trigger_field::cleanup() } /* If item is a const function, calculate it and return a const item The original item is freed if not returned */ Item_result item_cmp_type(Item_result a,Item_result b) { if (a == STRING_RESULT && b == STRING_RESULT) Loading
sql/item_cmpfunc.cc +184 −112 Original line number Diff line number Diff line Loading @@ -66,10 +66,8 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) /* Aggregates result types from the array of items. SYNOPSIS: SYNOPSIS agg_cmp_type() thd thread handle type [out] the aggregated type items array of items to aggregate the type from nitems number of items in the array Loading @@ -79,12 +77,43 @@ static void agg_result_type(Item_result *type, Item **items, uint nitems) Aggregation itself is performed by the item_cmp_type() function. */ static void agg_cmp_type(THD *thd, Item_result *type, Item **items, uint nitems) static Item_result agg_cmp_type(Item **items, uint nitems) { uint i; Item_result type= items[0]->result_type(); for (i= 1 ; i < nitems ; i++) type= item_cmp_type(type, items[i]->result_type()); return type; } /* Collects different types for comparison of first item with each other items SYNOPSIS collect_cmp_types() items Array of items to collect types from nitems Number of items in the array DESCRIPTION This function collects different result types for comparison of the first item in the list with each of the remaining items in the 'items' array. RETURN Bitmap of collected types */ static uint collect_cmp_types(Item **items, uint nitems) { uint i; type[0]= items[0]->result_type(); uint found_types; Item_result left_result= items[0]->result_type(); DBUG_ASSERT(nitems > 1); found_types= 0; for (i= 1; i < nitems ; i++) type[0]= item_cmp_type(type[0], items[i]->result_type()); found_types|= 1<< (uint)item_cmp_type(left_result, items[i]->result_type()); return found_types; } Loading Loading @@ -1117,7 +1146,7 @@ void Item_func_between::fix_length_and_dec() */ if (!args[0] || !args[1] || !args[2]) return; agg_cmp_type(thd, &cmp_type, args, 3); cmp_type= agg_cmp_type(args, 3); if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, 3, MY_COLL_CMP_CONV, 1)) return; Loading Loading @@ -1597,94 +1626,65 @@ Item_func_nullif::is_null() return (null_value= (!cmp.compare() ? 1 : args[0]->null_value)); } /* CASE expression Return the matching ITEM or NULL if all compares (including else) failed SYNOPSIS find_item() str Buffer string DESCRIPTION Find and return matching items for CASE or ELSE item if all compares are failed or NULL if ELSE item isn't defined. IMPLEMENTATION In order to do correct comparisons of the CASE expression (the expression between CASE and the first WHEN) with each WHEN expression several comparators are used. One for each result type. CASE expression can be evaluated up to # of different result types are used. To check whether the CASE expression already was evaluated for a particular result type a bit mapped variable value_added_map is used. Result types are mapped to it according to their int values i.e. STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. RETURN NULL - Nothing found and there is no ELSE expression defined item - Found item or ELSE item if defined and all comparisons are failed */ Item *Item_func_case::find_item(String *str) { String *first_expr_str, *tmp; my_decimal *first_expr_dec, first_expr_dec_val; longlong first_expr_int; double first_expr_real; char buff[MAX_FIELD_WIDTH]; String buff_str(buff,sizeof(buff),default_charset()); uint value_added_map= 0; /* These will be initialized later */ LINT_INIT(first_expr_str); LINT_INIT(first_expr_int); LINT_INIT(first_expr_real); LINT_INIT(first_expr_dec); if (first_expr_num != -1) { switch (cmp_type) if (first_expr_num == -1) { case STRING_RESULT: // We can't use 'str' here as this may be overwritten if (!(first_expr_str= args[first_expr_num]->val_str(&buff_str))) return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible break; case INT_RESULT: first_expr_int= args[first_expr_num]->val_int(); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case REAL_RESULT: first_expr_real= args[first_expr_num]->val_real(); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case DECIMAL_RESULT: first_expr_dec= args[first_expr_num]->val_decimal(&first_expr_dec_val); if (args[first_expr_num]->null_value) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case ROW_RESULT: default: // This case should never be chosen DBUG_ASSERT(0); break; } } // Compare every WHEN argument with it and return the first match for (uint i=0 ; i < ncases ; i+=2) { if (first_expr_num == -1) { // No expression between CASE and the first WHEN if (args[i]->val_bool()) return args[i+1]; continue; } switch (cmp_type) { case STRING_RESULT: if ((tmp=args[i]->val_str(str))) // If not null if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0) return args[i+1]; break; case INT_RESULT: if (args[i]->val_int()==first_expr_int && !args[i]->null_value) return args[i+1]; break; case REAL_RESULT: if (args[i]->val_real() == first_expr_real && !args[i]->null_value) return args[i+1]; break; case DECIMAL_RESULT: } else { my_decimal value; if (my_decimal_cmp(args[i]->val_decimal(&value), first_expr_dec) == 0) return args[i+1]; break; /* Compare every WHEN argument with it and return the first match */ for (uint i=0 ; i < ncases ; i+=2) { cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); DBUG_ASSERT(cmp_type != ROW_RESULT); DBUG_ASSERT(cmp_items[(uint)cmp_type]); if (!(value_added_map & (1<<(uint)cmp_type))) { cmp_items[(uint)cmp_type]->store_value(args[first_expr_num]); if ((null_value=args[first_expr_num]->null_value)) return else_expr_num != -1 ? args[else_expr_num] : 0; value_added_map|= 1<<(uint)cmp_type; } case ROW_RESULT: default: // This case should never be chosen DBUG_ASSERT(0); break; if (!cmp_items[(uint)cmp_type]->cmp(args[i]) && !args[i]->null_value) return args[i + 1]; } } // No, WHEN clauses all missed, return ELSE expression Loading Loading @@ -1791,7 +1791,7 @@ void Item_func_case::fix_length_and_dec() Item **agg; uint nagg; THD *thd= current_thd; uint found_types= 0; if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; Loading @@ -1818,14 +1818,29 @@ void Item_func_case::fix_length_and_dec() */ if (first_expr_num != -1) { uint i; agg[0]= args[first_expr_num]; left_result_type= agg[0]->result_type(); for (nagg= 0; nagg < ncases/2 ; nagg++) agg[nagg+1]= args[nagg*2]; nagg++; agg_cmp_type(thd, &cmp_type, agg, nagg); if ((cmp_type == STRING_RESULT) && found_types= collect_cmp_types(agg, nagg); for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) { DBUG_ASSERT((Item_result)i != ROW_RESULT); if ((Item_result)i == STRING_RESULT && agg_arg_charsets(cmp_collation, agg, nagg, MY_COLL_CMP_CONV, 1)) return; if (!(cmp_items[i]= cmp_item::get_comparator((Item_result)i, cmp_collation.collation))) return; } } } if (else_expr_num == -1 || args[else_expr_num]->maybe_null) Loading Loading @@ -2412,14 +2427,12 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) void Item_func_in::fix_length_and_dec() { Item **arg, **arg_end; uint const_itm= 1; bool const_itm= 1; THD *thd= current_thd; agg_cmp_type(thd, &cmp_type, args, arg_count); if (cmp_type == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; uint found_types= 0; uint type_cnt= 0, i; left_result_type= args[0]->result_type(); found_types= collect_cmp_types(args, arg_count); for (arg= args + 1, arg_end= args + arg_count; arg != arg_end ; arg++) { Loading @@ -2429,15 +2442,28 @@ void Item_func_in::fix_length_and_dec() break; } } for (i= 0; i <= (uint)DECIMAL_RESULT; i++) { if (found_types & 1 << i) (type_cnt)++; } /* Row item with NULLs inside can return NULL or FALSE => they can't be processed as static */ if (const_itm && !nulls_in_row()) if (type_cnt == 1 && const_itm && !nulls_in_row()) { uint tmp_type; Item_result cmp_type; /* Only one cmp type was found. Extract it here */ for (tmp_type= 0; found_types - 1; found_types>>= 1) tmp_type++; cmp_type= (Item_result)tmp_type; switch (cmp_type) { case STRING_RESULT: if (agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; array=new in_string(arg_count - 1,(qsort2_cmp) srtcmp_in, cmp_collation.collation); break; Loading Loading @@ -2474,9 +2500,19 @@ void Item_func_in::fix_length_and_dec() } else { in_item= cmp_item::get_comparator(cmp_type, cmp_collation.collation); if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; for (i= 0; i <= (uint) DECIMAL_RESULT; i++) { if (found_types & (1 << i) && !cmp_items[i]) { if ((Item_result)i == STRING_RESULT && agg_arg_charsets(cmp_collation, args, arg_count, MY_COLL_CMP_CONV, 1)) return; if (!(cmp_items[i]= cmp_item::get_comparator((Item_result)i, cmp_collation.collation))) return; } } } maybe_null= args[0]->maybe_null; max_length= 1; Loading @@ -2495,25 +2531,61 @@ void Item_func_in::print(String *str) } /* Evaluate the function and return its value. SYNOPSIS val_int() DESCRIPTION Evaluate the function and return its value. IMPLEMENTATION If the array object is defined then the value of the function is calculated by means of this array. Otherwise several cmp_item objects are used in order to do correct comparison of left expression and an expression from the values list. One cmp_item object correspond to one used comparison type. Left expression can be evaluated up to number of different used comparison types. A bit mapped variable value_added_map is used to check whether the left expression already was evaluated for a particular result type. Result types are mapped to it according to their integer values i.e. STRING_RESULT is mapped to bit 0, REAL_RESULT to bit 1, so on. RETURN Value of the function */ longlong Item_func_in::val_int() { cmp_item *in_item; DBUG_ASSERT(fixed == 1); uint value_added_map= 0; if (array) { int tmp=array->find(args[0]); null_value=args[0]->null_value || (!tmp && have_null); return (longlong) (!null_value && tmp != negated); } for (uint i= 1 ; i < arg_count ; i++) { Item_result cmp_type= item_cmp_type(left_result_type, args[i]->result_type()); in_item= cmp_items[(uint)cmp_type]; DBUG_ASSERT(in_item); if (!(value_added_map & (1 << (uint)cmp_type))) { in_item->store_value(args[0]); if ((null_value=args[0]->null_value)) return 0; have_null= 0; for (uint i=1 ; i < arg_count ; i++) { value_added_map|= 1 << (uint)cmp_type; } if (!in_item->cmp(args[i]) && !args[i]->null_value) return (longlong) (!negated); have_null|= args[i]->null_value; } null_value= have_null; return (longlong) (!null_value && negated); } Loading