diff options
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r-- | sql/item_cmpfunc.cc | 476 |
1 files changed, 414 insertions, 62 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 3d79c16b5d0..aa98f1860b6 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -53,10 +53,10 @@ static void agg_cmp_type(Item_result *type, Item **items, uint nitems) static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname) { - my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0), - c1.collation->name,c1.derivation_name(), - c2.collation->name,c2.derivation_name(), - fname); + my_error(ER_CANT_AGGREGATE_2COLLATIONS, MYF(0), + c1.collation->name,c1.derivation_name(), + c2.collation->name,c2.derivation_name(), + fname); } @@ -104,7 +104,7 @@ Item_bool_func2* Le_creator::create(Item *a, Item *b) const longlong Item_func_not::val_int() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); null_value=args[0]->null_value; return ((!null_value && value == 0) ? 1 : 0); } @@ -116,7 +116,7 @@ longlong Item_func_not::val_int() longlong Item_func_not_all::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val(); + double value= args[0]->val_real(); /* return TRUE if there was records in underlaying select in max/min @@ -154,7 +154,7 @@ void Item_func_not_all::print(String *str) longlong Item_func_nop_all::val_int() { DBUG_ASSERT(fixed == 1); - double value= args[0]->val(); + longlong value= args[0]->val_int(); /* return FALSE if there was records in underlaying select in max/min @@ -207,12 +207,26 @@ void Item_bool_func2::fix_length_and_dec() if (!args[0] || !args[1]) return; + /* + We allow to convert to Unicode character sets in some cases. + The conditions when conversion is possible are: + - arguments A and B have different charsets + - A wins according to coercibility rules + - character set of A is superset for character set of B + + If all of the above is true, then it's possible to convert + B into the character set of A, and then compare according + to the collation of A. + */ + + DTCollation coll; if (args[0]->result_type() == STRING_RESULT && args[1]->result_type() == STRING_RESULT && agg_arg_charsets(coll, args, 2, MY_COLL_CMP_CONV)) return; - + + // Make a special case of compare with fields to get nicer DATE comparisons if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function. @@ -234,7 +248,7 @@ void Item_bool_func2::fix_length_and_dec() } } } - if (args[1]->type() == FIELD_ITEM) + if (args[1]->type() == FIELD_ITEM /* && !args[1]->const_item() */) { Field *field=((Item_field*) args[1])->field; if (field->can_be_compared_as_longlong()) @@ -299,6 +313,17 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type) func= &Arg_comparator::compare_binary_string; else if (func == &Arg_comparator::compare_e_string) func= &Arg_comparator::compare_e_binary_string; + + /* + As this is binary comparsion, mark all fields that they can't be + transformed. Otherwise we would get into trouble with comparisons + like: + WHERE col= 'j' AND col LIKE BINARY 'j' + which would be transformed to: + WHERE col= 'j' + */ + (*a)->transform(&Item::set_no_const_sub, (byte*) 0); + (*b)->transform(&Item::set_no_const_sub, (byte*) 0); } } else if (type == INT_RESULT) @@ -393,10 +418,10 @@ int Arg_comparator::compare_e_binary_string() int Arg_comparator::compare_real() { - double val1= (*a)->val(); + double val1= (*a)->val_real(); if (!(*a)->null_value) { - double val2= (*b)->val(); + double val2= (*b)->val_real(); if (!(*b)->null_value) { owner->null_value= 0; @@ -411,8 +436,8 @@ int Arg_comparator::compare_real() int Arg_comparator::compare_e_real() { - double val1= (*a)->val(); - double val2= (*b)->val(); + double val1= (*a)->val_real(); + double val2= (*b)->val_real(); if ((*a)->null_value || (*b)->null_value) return test((*a)->null_value && (*b)->null_value); return test(val1 == val2); @@ -576,7 +601,7 @@ bool Item_in_optimizer::fix_left(THD *thd, If it is preparation PS only then we do not know values of parameters => cant't get there values and do not need that values. */ - if (! thd->current_arena->is_stmt_prepare()) + if (!thd->only_prepare()) cache->store(args[0]); if (cache->cols() == 1) { @@ -609,17 +634,17 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, { DBUG_ASSERT(fixed == 0); if (fix_left(thd, tables, ref)) - return 1; + return TRUE; if (args[0]->maybe_null) maybe_null=1; if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1)) - return 1; + return TRUE; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) { my_error(ER_OPERAND_COLUMNS, MYF(0), args[0]->cols()); - return 1; + return TRUE; } if (args[1]->maybe_null) maybe_null=1; @@ -628,7 +653,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, not_null_tables_cache|= args[1]->not_null_tables(); const_item_cache&= args[1]->const_item(); fixed= 1; - return 0; + return FALSE; } @@ -764,7 +789,7 @@ void Item_func_interval::fix_length_and_dec() (intervals=(double*) sql_alloc(sizeof(double)*(row->cols()-1)))) { for (uint i=1 ; i < row->cols(); i++) - intervals[i-1]=row->el(i)->val(); + intervals[i-1]= row->el(i)->val_real(); } } maybe_null= 0; @@ -786,7 +811,7 @@ void Item_func_interval::fix_length_and_dec() longlong Item_func_interval::val_int() { DBUG_ASSERT(fixed == 1); - double value= row->el(0)->val(); + double value= row->el(0)->val_real(); uint i; if (row->el(0)->null_value) @@ -809,7 +834,7 @@ longlong Item_func_interval::val_int() for (i=1 ; i < row->cols() ; i++) { - if (row->el(i)->val() > value) + if (row->el(i)->val_real() > value) return i-1; } return i-1; @@ -883,7 +908,7 @@ longlong Item_func_between::val_int() } else if (cmp_type == INT_RESULT) { - longlong value=args[0]->val_int(),a,b; + longlong value=args[0]->val_int(), a, b; if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ a=args[1]->val_int(); @@ -903,11 +928,11 @@ longlong Item_func_between::val_int() } else { - double value=args[0]->val(),a,b; + double value= args[0]->val_real(),a,b; if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ - a=args[1]->val(); - b=args[2]->val(); + a= args[1]->val_real(); + b= args[2]->val_real(); if (!args[1]->null_value && !args[2]->null_value) return (value >= a && value <= b) ? 1 : 0; if (args[1]->null_value && args[2]->null_value) @@ -964,16 +989,16 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table) } double -Item_func_ifnull::val() +Item_func_ifnull::val_real() { DBUG_ASSERT(fixed == 1); - double value=args[0]->val(); + double value= args[0]->val_real(); if (!args[0]->null_value) { null_value=0; return value; } - value=args[1]->val(); + value= args[1]->val_real(); if ((null_value=args[1]->null_value)) return 0.0; return value; @@ -1041,7 +1066,7 @@ Item_func_if::fix_length_and_dec() if (cached_result_type == STRING_RESULT) { if (agg_arg_charsets(collation, args+1, 2, MY_COLL_ALLOW_CONV)) - return; + return; } else { @@ -1052,11 +1077,11 @@ Item_func_if::fix_length_and_dec() double -Item_func_if::val() +Item_func_if::val_real() { DBUG_ASSERT(fixed == 1); Item *arg= args[0]->val_int() ? args[1] : args[2]; - double value=arg->val(); + double value= arg->val_real(); null_value=arg->null_value; return value; } @@ -1105,7 +1130,7 @@ Item_func_nullif::fix_length_and_dec() */ double -Item_func_nullif::val() +Item_func_nullif::val_real() { DBUG_ASSERT(fixed == 1); double value; @@ -1114,7 +1139,7 @@ Item_func_nullif::val() null_value=1; return 0.0; } - value=args[0]->val(); + value= args[0]->val_real(); null_value=args[0]->null_value; return value; } @@ -1189,7 +1214,7 @@ Item *Item_func_case::find_item(String *str) return else_expr_num != -1 ? args[else_expr_num] : 0; break; case REAL_RESULT: - first_expr_real= args[first_expr_num]->val(); + 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; @@ -1222,7 +1247,7 @@ Item *Item_func_case::find_item(String *str) return args[i+1]; break; case REAL_RESULT: - if (args[i]->val()==first_expr_real && !args[i]->null_value) + if (args[i]->val_real() == first_expr_real && !args[i]->null_value) return args[i+1]; break; case ROW_RESULT: @@ -1274,7 +1299,7 @@ longlong Item_func_case::val_int() return res; } -double Item_func_case::val() +double Item_func_case::val_real() { DBUG_ASSERT(fixed == 1); char buff[MAX_FIELD_WIDTH]; @@ -1287,7 +1312,7 @@ double Item_func_case::val() null_value=1; return 0; } - res=item->val(); + res= item->val_real(); null_value=item->null_value; return res; } @@ -1300,8 +1325,10 @@ void Item_func_case::fix_length_and_dec() if (!(agg= (Item**) sql_alloc(sizeof(Item*)*(ncases+1)))) return; - // Aggregate all THEN and ELSE expression types - // and collations when string result + /* + Aggregate all THEN and ELSE expression types + and collations when string result + */ for (nagg= 0 ; nagg < ncases/2 ; nagg++) agg[nagg]= args[nagg*2+1]; @@ -1408,13 +1435,13 @@ longlong Item_func_coalesce::val_int() return 0; } -double Item_func_coalesce::val() +double Item_func_coalesce::val_real() { DBUG_ASSERT(fixed == 1); null_value=0; for (uint i=0 ; i < arg_count ; i++) { - double res=args[i]->val(); + double res= args[i]->val_real(); if (!args[i]->null_value) return res; } @@ -1567,12 +1594,12 @@ in_double::in_double(uint elements) void in_double::set(uint pos,Item *item) { - ((double*) base)[pos]=item->val(); + ((double*) base)[pos]= item->val_real(); } byte *in_double::get_value(Item *item) { - tmp= item->val(); + tmp= item->val_real(); if (item->null_value) return 0; /* purecov: inspected */ return (byte*) &tmp; @@ -1621,7 +1648,7 @@ cmp_item* cmp_item_row::make_same() cmp_item_row::~cmp_item_row() { DBUG_ENTER("~cmp_item_row"); - DBUG_PRINT("enter",("this: %lx", this)); + DBUG_PRINT("enter",("this: 0x%lx", this)); if (comparators) { for (uint i= 0; i < n; i++) @@ -1734,7 +1761,7 @@ static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y) { return cs->coll->strnncollsp(cs, (uchar *) x->ptr(),x->length(), - (uchar *) y->ptr(),y->length()); + (uchar *) y->ptr(),y->length(), 0); } @@ -1956,7 +1983,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) char buff[sizeof(char*)]; // Max local vars in function #endif not_null_tables_cache= used_tables_cache= 0; - const_item_cache= 0; + const_item_cache= 1; /* and_table_cache is the value that Item_cond_or() returns for not_null_tables() @@ -1964,7 +1991,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) and_tables_cache= ~(table_map) 0; if (check_stack_overrun(thd, buff)) - return 1; // Fatal error flag is set! + return TRUE; // Fatal error flag is set! while ((item=li++)) { table_map tmp_table_map; @@ -1982,12 +2009,12 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if ((!item->fixed && item->fix_fields(thd, tables, li.ref())) || (item= *li.ref())->check_cols(1)) - return 1; /* purecov: inspected */ + return TRUE; /* purecov: inspected */ used_tables_cache|= item->used_tables(); tmp_table_map= item->not_null_tables(); not_null_tables_cache|= tmp_table_map; and_tables_cache&= tmp_table_map; - const_item_cache&= item->const_item(); + const_item_cache&= item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; if (item->maybe_null) maybe_null=1; @@ -1995,7 +2022,7 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) thd->lex->current_select->cond_count+= list.elements; fix_length_and_dec(); fixed= 1; - return 0; + return FALSE; } bool Item_cond::walk(Item_processor processor, byte *arg) @@ -2008,13 +2035,51 @@ bool Item_cond::walk(Item_processor processor, byte *arg) return Item_func::walk(processor, arg); } + +/* + Transform an Item_cond object with a transformer callback function + + SYNOPSIS + transform() + transformer the transformer callback function to be applied to the nodes + of the tree of the object + arg parameter to be passed to the transformer + + DESCRIPTION + The function recursively applies the transform method with the + same transformer to each member item of the codition list. + If the call of the method for a member item returns a new item + the old item is substituted for a new one. + After this the transform method is applied to the root node + of the Item_cond object. + + RETURN VALUES + Item returned as the result of transformation of the root node +*/ + +Item *Item_cond::transform(Item_transformer transformer, byte *arg) +{ + List_iterator<Item> li(list); + Item *item; + while ((item= li++)) + { + Item *new_item= item->transform(transformer, arg); + if (!new_item) + return 0; + if (new_item != item) + li.replace(new_item); + } + return Item_func::transform(transformer, arg); +} + + void Item_cond::split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields) { List_iterator<Item> li(list); Item *item; used_tables_cache=0; - const_item_cache=0; + const_item_cache=1; while ((item=li++)) { if (item->with_sum_func && item->type() != SUM_FUNC_ITEM) @@ -2054,7 +2119,7 @@ void Item_cond::update_used_tables() { item->update_used_tables(); used_tables_cache|= item->used_tables(); - const_item_cache&= item->const_item(); + const_item_cache&= item->const_item(); } } @@ -2310,12 +2375,12 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) DBUG_ASSERT(fixed == 0); if (Item_bool_func2::fix_fields(thd, tlist, ref) || escape_item->fix_fields(thd, tlist, &escape_item)) - return 1; + return TRUE; if (!escape_item->const_during_execution()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"ESCAPE"); - return 1; + return TRUE; } if (escape_item->const_item()) @@ -2333,7 +2398,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { String* res2 = args[1]->val_str(&tmp_value2); if (!res2) - return 0; // Null argument + return FALSE; // Null argument const size_t len = res2->length(); const char* first = res2->ptr(); @@ -2366,7 +2431,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) } } } - return 0; + return FALSE; } #ifdef USE_REGEX @@ -2379,13 +2444,13 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) args[0]->fix_fields(thd, tables, args)) || args[0]->check_cols(1) || (!args[1]->fixed && args[1]->fix_fields(thd,tables, args + 1)) || args[1]->check_cols(1)) - return 1; /* purecov: inspected */ + return TRUE; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length= 1; decimals= 0; if (agg_arg_charsets(cmp_collation, args, 2, MY_COLL_CMP_CONV)) - return 1; + return TRUE; used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); not_null_tables_cache= (args[0]->not_null_tables() | @@ -2399,7 +2464,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (args[1]->null_value) { // Will always return NULL maybe_null=1; - return 0; + return FALSE; } int error; if ((error= regcomp(&preg,res->c_ptr(), @@ -2410,8 +2475,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) cmp_collation.collation))) { (void) regerror(error,&preg,buff,sizeof(buff)); - my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff); - return 1; + my_error(ER_REGEXP_ERROR, MYF(0), buff); + return TRUE; } regex_compiled=regex_is_const=1; maybe_null=args[0]->maybe_null; @@ -2419,7 +2484,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) else maybe_null=1; fixed= 1; - return 0; + return FALSE; } @@ -2862,3 +2927,290 @@ Item *Item_bool_rowready_func2::negated_item() DBUG_ASSERT(0); return 0; } + +Item_equal::Item_equal(Item_field *f1, Item_field *f2) + : Item_bool_func(), const_item(0), eval_item(0), cond_false(0) +{ + const_item_cache= 0; + fields.push_back(f1); + fields.push_back(f2); +} + +Item_equal::Item_equal(Item *c, Item_field *f) + : Item_bool_func(), eval_item(0), cond_false(0) +{ + const_item_cache= 0; + fields.push_back(f); + const_item= c; +} + +Item_equal::Item_equal(Item_equal *item_equal) + : Item_bool_func(), eval_item(0), cond_false(0) +{ + const_item_cache= 0; + List_iterator_fast<Item_field> li(item_equal->fields); + Item_field *item; + while ((item= li++)) + { + fields.push_back(item); + } + const_item= item_equal->const_item; + cond_false= item_equal->cond_false; +} + +void Item_equal::add(Item *c) +{ + if (cond_false) + return; + if (!const_item) + { + const_item= c; + return; + } + Item_func_eq *func= new Item_func_eq(c, const_item); + func->set_cmp_func(); + func->quick_fix_field(); + cond_false = !(func->val_int()); +} + +void Item_equal::add(Item_field *f) +{ + fields.push_back(f); +} + +uint Item_equal::members() +{ + uint count= 0; + List_iterator_fast<Item_field> li(fields); + Item_field *item; + while ((item= li++)) + count++; + return count; +} + + +/* + Check whether a field is referred in the multiple equality + + SYNOPSIS + contains() + field field whose occurence is to be checked + + DESCRIPTION + The function checks whether field is occured in the Item_equal object + + RETURN VALUES + 1 if nultiple equality contains a reference to field + 0 otherwise +*/ + +bool Item_equal::contains(Field *field) +{ + List_iterator_fast<Item_field> it(fields); + Item_field *item; + while ((item= it++)) + { + if (field->eq(item->field)) + return 1; + } + return 0; +} + + +/* + Join members of another Item_equal object + + SYNOPSIS + merge() + item multiple equality whose members are to be joined + + DESCRIPTION + The function actually merges two multiple equalitis. + After this operation the Item_equal object additionally contains + the field items of another item of the type Item_equal. + If the optional constant items are not equal the cond_false flag is + set to 1. + + RETURN VALUES + none +*/ + +void Item_equal::merge(Item_equal *item) +{ + fields.concat(&item->fields); + Item *c= item->const_item; + if (c) + { + /* + The flag cond_false will be set to 1 after this, if + the multiple equality already contains a constant and its + value is not equal to the value of c. + */ + add(const_item); + } + cond_false|= item->cond_false; +} + + +/* + Order field items in multiple equality according to a sorting criteria + + SYNOPSIS + sort() + cmp function to compare field item + arg context extra parameter for the cmp function + + DESCRIPTION + The function perform ordering of the field items in the Item_equal + object according to the criteria determined by the cmp callback parameter. + If cmp(item_field1,item_field2,arg)<0 than item_field1 must be + placed after item_fiel2. + + IMPLEMENTATION + The function sorts field items by the exchange sort algorithm. + The list of field items is looked through and whenever two neighboring + members follow in a wrong order they are swapped. This is performed + again and again until we get all members in a right order. + + RETURN VALUES + None +*/ + +void Item_equal::sort(Item_field_cmpfunc cmp, void *arg) +{ + bool swap; + List_iterator<Item_field> it(fields); + do + { + Item_field *item1= it++; + Item_field **ref1= it.ref(); + Item_field *item2; + + swap= FALSE; + while ((item2= it++)) + { + Item_field **ref2= it.ref(); + if (cmp(item1, item2, arg) < 0) + { + Item_field *item= *ref1; + *ref1= *ref2; + *ref2= item; + swap= TRUE; + } + else + { + item1= item2; + ref1= ref2; + } + } + it.rewind(); + } while (swap); +} + +bool Item_equal::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + List_iterator_fast<Item_field> li(fields); + Item *item; + not_null_tables_cache= used_tables_cache= 0; + const_item_cache= 0; + while ((item=li++)) + { + table_map tmp_table_map; + used_tables_cache|= item->used_tables(); + tmp_table_map= item->not_null_tables(); + not_null_tables_cache|= tmp_table_map; + if (item->maybe_null) + maybe_null=1; + } + fix_length_and_dec(); + fixed= 1; + return 0; +} + +void Item_equal::update_used_tables() +{ + List_iterator_fast<Item_field> li(fields); + Item *item; + not_null_tables_cache= used_tables_cache= 0; + if ((const_item_cache= cond_false)) + return; + while ((item=li++)) + { + item->update_used_tables(); + used_tables_cache|= item->used_tables(); + const_item_cache&= item->const_item(); + } +} + +longlong Item_equal::val_int() +{ + if (cond_false) + return 0; + List_iterator_fast<Item_field> it(fields); + Item *item= const_item ? const_item : it++; + if ((null_value= item->null_value)) + return 0; + eval_item->store_value(item); + while ((item= it++)) + { + if ((null_value= item->null_value) || eval_item->cmp(item)) + return 0; + } + return 1; +} + +void Item_equal::fix_length_and_dec() +{ + Item *item= const_item ? const_item : get_first(); + eval_item= cmp_item::get_comparator(item); + if (item->result_type() == STRING_RESULT) + eval_item->cmp_charset= cmp_collation.collation; +} + +bool Item_equal::walk(Item_processor processor, byte *arg) +{ + List_iterator_fast<Item_field> it(fields); + Item *item; + while ((item= it++)) + if (item->walk(processor, arg)) + return 1; + return Item_func::walk(processor, arg); +} + +Item *Item_equal::transform(Item_transformer transformer, byte *arg) +{ + List_iterator<Item_field> it(fields); + Item *item; + while ((item= it++)) + { + Item *new_item= item->transform(transformer, arg); + if (!new_item) + return 0; + if (new_item != item) + it.replace((Item_field *) new_item); + } + return Item_func::transform(transformer, arg); +} + +void Item_equal::print(String *str) +{ + str->append(func_name()); + str->append('('); + List_iterator_fast<Item_field> it(fields); + Item *item; + if (const_item) + const_item->print(str); + else + { + item= it++; + item->print(str); + } + while ((item= it++)) + { + str->append(','); + str->append(' '); + item->print(str); + } + str->append(')'); +} + |