summaryrefslogtreecommitdiff
path: root/sql/item_cmpfunc.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/item_cmpfunc.cc')
-rw-r--r--sql/item_cmpfunc.cc285
1 files changed, 240 insertions, 45 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 4046a4d6414..ae6658c8e35 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -103,6 +103,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();
null_value=args[0]->null_value;
return !null_value && value == 0 ? 1 : 0;
@@ -113,7 +114,8 @@ longlong Item_func_not::val_int()
*/
longlong Item_func_not_all::val_int()
-{
+{
+ DBUG_ASSERT(fixed == 1);
double value= args[0]->val();
if (abort_on_null)
{
@@ -225,6 +227,13 @@ void Item_bool_func2::fix_length_and_dec()
}
// Make a special case of compare with fields to get nicer DATE comparisons
+
+ if (functype() == LIKE_FUNC) // Disable conversion in case of LIKE function.
+ {
+ set_cmp_func();
+ return;
+ }
+
if (args[0]->type() == FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
@@ -293,6 +302,17 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return 1;
}
+ if (my_binary_compare(cmp_collation.collation))
+ {
+ /*
+ We are using binary collation, change to compare byte by byte,
+ without removing end space
+ */
+ if (func == &Arg_comparator::compare_string)
+ func= &Arg_comparator::compare_binary_string;
+ else if (func == &Arg_comparator::compare_e_string)
+ func= &Arg_comparator::compare_e_binary_string;
+ }
}
return 0;
}
@@ -313,6 +333,39 @@ int Arg_comparator::compare_string()
return -1;
}
+
+/*
+ Compare strings byte by byte. End spaces are also compared.
+
+ RETURN
+ < 0 *a < *b
+ 0 *b == *b
+ > 0 *a > *b
+*/
+
+int Arg_comparator::compare_binary_string()
+{
+ String *res1,*res2;
+ if ((res1= (*a)->val_str(&owner->tmp_value1)))
+ {
+ if ((res2= (*b)->val_str(&owner->tmp_value2)))
+ {
+ owner->null_value= 0;
+ uint res1_length= res1->length();
+ uint res2_length= res2->length();
+ int cmp= memcmp(res1->ptr(), res2->ptr(), min(res1_length,res2_length));
+ return cmp ? cmp : (int) (res1_length - res2_length);
+ }
+ }
+ owner->null_value= 1;
+ return -1;
+}
+
+
+/*
+ Compare strings, but take into account that NULL == NULL
+*/
+
int Arg_comparator::compare_e_string()
{
String *res1,*res2;
@@ -324,6 +377,17 @@ int Arg_comparator::compare_e_string()
}
+int Arg_comparator::compare_e_binary_string()
+{
+ String *res1,*res2;
+ res1= (*a)->val_str(&owner->tmp_value1);
+ res2= (*b)->val_str(&owner->tmp_value2);
+ if (!res1 || !res2)
+ return test(res1 == res2);
+ return test(stringcmp(res1, res2) == 0);
+}
+
+
int Arg_comparator::compare_real()
{
double val1= (*a)->val();
@@ -440,16 +504,15 @@ bool Item_in_optimizer::fix_left(THD *thd,
not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func;
const_item_cache= args[0]->const_item();
- fixed= 1;
return 0;
}
-
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
- if (fix_left(thd, tables, ref))
+ DBUG_ASSERT(fixed == 0);
+ if (!args[0]->fixed && fix_left(thd, tables, ref))
return 1;
if (args[0]->maybe_null)
maybe_null=1;
@@ -468,11 +531,14 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
used_tables_cache|= args[1]->used_tables();
not_null_tables_cache|= args[1]->not_null_tables();
const_item_cache&= args[1]->const_item();
+ fixed= 1;
return 0;
}
+
longlong Item_in_optimizer::val_int()
{
+ DBUG_ASSERT(fixed == 1);
cache->store(args[0]);
if (cache->null_value)
{
@@ -484,18 +550,39 @@ longlong Item_in_optimizer::val_int()
return tmp;
}
+
+void Item_in_optimizer::keep_top_level_cache()
+{
+ cache->keep_array();
+ save_cache= 1;
+}
+
+
+void Item_in_optimizer::cleanup()
+{
+ DBUG_ENTER("Item_in_optimizer::cleanup");
+ Item_bool_func::cleanup();
+ if (!save_cache)
+ cache= 0;
+ DBUG_VOID_RETURN;
+}
+
+
bool Item_in_optimizer::is_null()
{
cache->store(args[0]);
return (null_value= (cache->null_value || args[1]->is_null()));
}
+
longlong Item_func_eq::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value == 0 ? 1 : 0;
}
+
/* Same as Item_func_eq, but NULL = NULL */
void Item_func_equal::fix_length_and_dec()
@@ -506,11 +593,13 @@ void Item_func_equal::fix_length_and_dec()
longlong Item_func_equal::val_int()
{
+ DBUG_ASSERT(fixed == 1);
return cmp.compare();
}
longlong Item_func_ne::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value != 0 && !null_value ? 1 : 0;
}
@@ -518,6 +607,7 @@ longlong Item_func_ne::val_int()
longlong Item_func_ge::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value >= 0 ? 1 : 0;
}
@@ -525,12 +615,14 @@ longlong Item_func_ge::val_int()
longlong Item_func_gt::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value > 0 ? 1 : 0;
}
longlong Item_func_le::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value <= 0 && !null_value ? 1 : 0;
}
@@ -538,6 +630,7 @@ longlong Item_func_le::val_int()
longlong Item_func_lt::val_int()
{
+ DBUG_ASSERT(fixed == 1);
int value= cmp.compare();
return value < 0 && !null_value ? 1 : 0;
}
@@ -545,6 +638,7 @@ longlong Item_func_lt::val_int()
longlong Item_func_strcmp::val_int()
{
+ DBUG_ASSERT(fixed == 1);
String *a=args[0]->val_str(&tmp_value1);
String *b=args[1]->val_str(&tmp_value2);
if (!a || !b)
@@ -594,6 +688,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();
uint i;
@@ -659,6 +754,7 @@ void Item_func_between::fix_length_and_dec()
longlong Item_func_between::val_int()
{ // ANSI BETWEEN
+ DBUG_ASSERT(fixed == 1);
if (cmp_type == STRING_RESULT)
{
String *value,*a,*b;
@@ -674,11 +770,13 @@ longlong Item_func_between::val_int()
null_value=1;
else if (args[1]->null_value)
{
- null_value= sortcmp(value,b,cmp_collation.collation) <= 0; // not null if false range.
+ // Set to not null if false range.
+ null_value= sortcmp(value,b,cmp_collation.collation) <= 0;
}
else
{
- null_value= sortcmp(value,a,cmp_collation.collation) >= 0; // not null if false range.
+ // Set to not null if false range.
+ null_value= sortcmp(value,a,cmp_collation.collation) >= 0;
}
}
else if (cmp_type == INT_RESULT)
@@ -766,6 +864,7 @@ Field *Item_func_ifnull::tmp_table_field(TABLE *table)
double
Item_func_ifnull::val()
{
+ DBUG_ASSERT(fixed == 1);
double value=args[0]->val();
if (!args[0]->null_value)
{
@@ -781,6 +880,7 @@ Item_func_ifnull::val()
longlong
Item_func_ifnull::val_int()
{
+ DBUG_ASSERT(fixed == 1);
longlong value=args[0]->val_int();
if (!args[0]->null_value)
{
@@ -796,6 +896,7 @@ Item_func_ifnull::val_int()
String *
Item_func_ifnull::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
String *res =args[0]->val_str(str);
if (!args[0]->null_value)
{
@@ -851,6 +952,7 @@ Item_func_if::fix_length_and_dec()
double
Item_func_if::val()
{
+ DBUG_ASSERT(fixed == 1);
Item *arg= args[0]->val_int() ? args[1] : args[2];
double value=arg->val();
null_value=arg->null_value;
@@ -860,6 +962,7 @@ Item_func_if::val()
longlong
Item_func_if::val_int()
{
+ DBUG_ASSERT(fixed == 1);
Item *arg= args[0]->val_int() ? args[1] : args[2];
longlong value=arg->val_int();
null_value=arg->null_value;
@@ -869,6 +972,7 @@ Item_func_if::val_int()
String *
Item_func_if::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
Item *arg= args[0]->val_int() ? args[1] : args[2];
String *res=arg->val_str(str);
if (res)
@@ -901,8 +1005,9 @@ Item_func_nullif::fix_length_and_dec()
double
Item_func_nullif::val()
{
+ DBUG_ASSERT(fixed == 1);
double value;
- if (!cmp.compare() || null_value)
+ if (!cmp.compare())
{
null_value=1;
return 0.0;
@@ -915,8 +1020,9 @@ Item_func_nullif::val()
longlong
Item_func_nullif::val_int()
{
+ DBUG_ASSERT(fixed == 1);
longlong value;
- if (!cmp.compare() || null_value)
+ if (!cmp.compare())
{
null_value=1;
return 0;
@@ -929,8 +1035,9 @@ Item_func_nullif::val_int()
String *
Item_func_nullif::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
String *res;
- if (!cmp.compare() || null_value)
+ if (!cmp.compare())
{
null_value=1;
return 0;
@@ -1022,6 +1129,7 @@ Item *Item_func_case::find_item(String *str)
String *Item_func_case::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
String *res;
Item *item=find_item(str);
@@ -1039,6 +1147,7 @@ String *Item_func_case::val_str(String *str)
longlong Item_func_case::val_int()
{
+ DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff,sizeof(buff),default_charset());
Item *item=find_item(&dummy_str);
@@ -1056,6 +1165,7 @@ longlong Item_func_case::val_int()
double Item_func_case::val()
{
+ DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff,sizeof(buff),default_charset());
Item *item=find_item(&dummy_str);
@@ -1161,6 +1271,7 @@ void Item_func_case::print(String *str)
String *Item_func_coalesce::val_str(String *str)
{
+ DBUG_ASSERT(fixed == 1);
null_value=0;
for (uint i=0 ; i < arg_count ; i++)
{
@@ -1174,6 +1285,7 @@ String *Item_func_coalesce::val_str(String *str)
longlong Item_func_coalesce::val_int()
{
+ DBUG_ASSERT(fixed == 1);
null_value=0;
for (uint i=0 ; i < arg_count ; i++)
{
@@ -1187,6 +1299,7 @@ longlong Item_func_coalesce::val_int()
double Item_func_coalesce::val()
{
+ DBUG_ASSERT(fixed == 1);
null_value=0;
for (uint i=0 ; i < arg_count ; i++)
{
@@ -1359,16 +1472,12 @@ cmp_item* cmp_item::get_comparator(Item *item)
switch (item->result_type()) {
case STRING_RESULT:
return new cmp_item_sort_string(item->collation.collation);
- break;
case INT_RESULT:
return new cmp_item_int;
- break;
case REAL_RESULT:
return new cmp_item_real;
- break;
case ROW_RESULT:
return new cmp_item_row;
- break;
default:
DBUG_ASSERT(0);
break;
@@ -1593,6 +1702,7 @@ void Item_func_in::print(String *str)
longlong Item_func_in::val_int()
{
+ DBUG_ASSERT(fixed == 1);
if (array)
{
int tmp=array->find(args[0]);
@@ -1616,6 +1726,7 @@ longlong Item_func_in::val_int()
longlong Item_func_bit_or::val_int()
{
+ DBUG_ASSERT(fixed == 1);
ulonglong arg1= (ulonglong) args[0]->val_int();
if (args[0]->null_value)
{
@@ -1635,6 +1746,7 @@ longlong Item_func_bit_or::val_int()
longlong Item_func_bit_and::val_int()
{
+ DBUG_ASSERT(fixed == 1);
ulonglong arg1= (ulonglong) args[0]->val_int();
if (args[0]->null_value)
{
@@ -1673,6 +1785,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
bool
Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ DBUG_ASSERT(fixed == 0);
List_iterator<Item> li(list);
Item *item;
#ifndef EMBEDDED_LIBRARY
@@ -1700,8 +1813,11 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
if (abort_on_null)
item->top_level_item();
+
+ // item can be substituted in fix_fields
if ((!item->fixed &&
- item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
+ item->fix_fields(thd, tables, li.ref())) ||
+ (item= *li.ref())->check_cols(1))
return 1; /* purecov: inspected */
used_tables_cache|= item->used_tables();
tmp_table_map= item->not_null_tables();
@@ -1793,14 +1909,28 @@ void Item_cond::print(String *str)
}
-void Item_cond::neg_arguments()
+void Item_cond::neg_arguments(THD *thd)
{
List_iterator<Item> li(list);
Item *item;
while ((item= li++)) /* Apply not transformation to the arguments */
{
- Item *new_item= item->neg_transformer();
- VOID(li.replace(new_item ? new_item : new Item_func_not(item)));
+ Item *new_item= item->neg_transformer(thd);
+ if (!new_item)
+ {
+ if (!(new_item= new Item_func_not(item)))
+ return; // Fatal OEM error
+ /*
+ We can use 0 as tables list because Item_func_not do not use it
+ on fix_fields and its arguments are already fixed.
+
+ We do not check results of fix_fields, because there are not way
+ to return error in this functions interface, thd->net.report_error
+ will be checked on upper level call.
+ */
+ new_item->fix_fields(thd, 0, &new_item);
+ }
+ VOID(li.replace(new_item));
}
}
@@ -1825,6 +1955,7 @@ void Item_cond::neg_arguments()
longlong Item_cond_and::val_int()
{
+ DBUG_ASSERT(fixed == 1);
List_iterator_fast<Item> li(list);
Item *item;
null_value= 0;
@@ -1842,6 +1973,7 @@ longlong Item_cond_and::val_int()
longlong Item_cond_or::val_int()
{
+ DBUG_ASSERT(fixed == 1);
List_iterator_fast<Item> li(list);
Item *item;
null_value=0;
@@ -1903,6 +2035,7 @@ Item *and_expressions(Item *a, Item *b, Item **org_item)
longlong Item_func_isnull::val_int()
{
+ DBUG_ASSERT(fixed == 1);
/*
Handle optimization if the argument can't be null
This has to be here because of the test in update_used_tables().
@@ -1914,6 +2047,7 @@ longlong Item_func_isnull::val_int()
longlong Item_is_not_null_test::val_int()
{
+ DBUG_ASSERT(fixed == 1);
DBUG_ENTER("Item_is_not_null_test::val_int");
if (!used_tables_cache)
{
@@ -1953,6 +2087,7 @@ void Item_is_not_null_test::update_used_tables()
longlong Item_func_isnotnull::val_int()
{
+ DBUG_ASSERT(fixed == 1);
return args[0]->is_null() ? 0 : 1;
}
@@ -1967,6 +2102,7 @@ void Item_func_isnotnull::print(String *str)
longlong Item_func_like::val_int()
{
+ DBUG_ASSERT(fixed == 1);
String* res = args[0]->val_str(&tmp_value1);
if (args[0]->null_value)
{
@@ -2012,6 +2148,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const
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))
return 1;
@@ -2065,6 +2202,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
bool
Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
+ DBUG_ASSERT(fixed == 0);
if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1) ||
args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1))
return 1; /* purecov: inspected */
@@ -2112,6 +2250,7 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
longlong Item_func_regex::val_int()
{
+ DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String *res, tmp(buff,sizeof(buff),&my_charset_bin);
@@ -2132,7 +2271,7 @@ longlong Item_func_regex::val_int()
null_value=1;
return 0;
}
- if (!regex_compiled || sortcmp(res2,&prev_regexp,&my_charset_bin))
+ if (!regex_compiled || stringcmp(res2,&prev_regexp))
{
prev_regexp.copy(*res2);
if (regex_compiled)
@@ -2412,6 +2551,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
longlong Item_cond_xor::val_int()
{
+ DBUG_ASSERT(fixed == 1);
List_iterator<Item> li(list);
Item *item;
int result=0;
@@ -2433,6 +2573,7 @@ longlong Item_cond_xor::val_int()
SYNPOSIS
neg_transformer()
+ thd thread handler
DESCRIPTION
Transform the item using next rules:
@@ -2456,62 +2597,116 @@ longlong Item_cond_xor::val_int()
NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
*/
-Item *Item_func_not::neg_transformer() /* NOT(x) -> x */
+Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
{
- /* We should apply negation elimination to the argument of the NOT function */
- return eliminate_not_funcs(args[0]);
+ // We should apply negation elimination to the argument of the NOT function
+ return eliminate_not_funcs(thd, args[0]);
}
-Item *Item_func_eq::neg_transformer() /* a = b -> a != b */
+
+Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
{
- return new Item_func_ne(args[0], args[1]);
+ Item *item= negated_item();
+ if (item)
+ {
+ /*
+ We can use 0 as tables list because Item_func* family do not use it
+ on fix_fields and its arguments are already fixed.
+
+ We do not check results of fix_fields, because there are not way
+ to return error in this functions interface, thd->net.report_error
+ will be checked on upper level call.
+ */
+ item->fix_fields(thd, 0, &item);
+ }
+ return item;
}
-Item *Item_func_ne::neg_transformer() /* a != b -> a = b */
+
+/* a IS NULL -> a IS NOT NULL */
+Item *Item_func_isnull::neg_transformer(THD *thd)
{
- return new Item_func_eq(args[0], args[1]);
+ Item *item= new Item_func_isnotnull(args[0]);
+ // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
+ if (item)
+ item->fix_fields(thd, 0, &item);
+ return item;
}
-Item *Item_func_lt::neg_transformer() /* a < b -> a >= b */
+
+/* a IS NOT NULL -> a IS NULL */
+Item *Item_func_isnotnull::neg_transformer(THD *thd)
{
- return new Item_func_ge(args[0], args[1]);
+ Item *item= new Item_func_isnull(args[0]);
+ // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
+ if (item)
+ item->fix_fields(thd, 0, &item);
+ return item;
}
-Item *Item_func_ge::neg_transformer() /* a >= b -> a < b */
+
+Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
+ /* NOT a OR NOT b OR ... */
{
- return new Item_func_lt(args[0], args[1]);
+ neg_arguments(thd);
+ Item *item= new Item_cond_or(list);
+ // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
+ if (item)
+ item->fix_fields(thd, 0, &item);
+ return item;
}
-Item *Item_func_gt::neg_transformer() /* a > b -> a <= b */
+
+Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
+ /* NOT a AND NOT b AND ... */
{
- return new Item_func_le(args[0], args[1]);
+ neg_arguments(thd);
+ Item *item= new Item_cond_and(list);
+ // see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
+ if (item)
+ item->fix_fields(thd, 0, &item);
+ return item;
}
-Item *Item_func_le::neg_transformer() /* a <= b -> a > b */
+
+Item *Item_func_eq::negated_item() /* a = b -> a != b */
{
- return new Item_func_gt(args[0], args[1]);
+ return new Item_func_ne(args[0], args[1]);
}
-Item *Item_func_isnull::neg_transformer() /* a IS NULL -> a IS NOT NULL */
+
+Item *Item_func_ne::negated_item() /* a != b -> a = b */
{
- return new Item_func_isnotnull(args[0]);
+ return new Item_func_eq(args[0], args[1]);
}
-Item *Item_func_isnotnull::neg_transformer() /* a IS NOT NULL -> a IS NULL */
+
+Item *Item_func_lt::negated_item() /* a < b -> a >= b */
{
- return new Item_func_isnull(args[0]);
+ return new Item_func_ge(args[0], args[1]);
}
-Item *Item_cond_and::neg_transformer() /* NOT(a AND b AND ...) -> */
- /* NOT a OR NOT b OR ... */
+
+Item *Item_func_ge::negated_item() /* a >= b -> a < b */
+{
+ return new Item_func_lt(args[0], args[1]);
+}
+
+
+Item *Item_func_gt::negated_item() /* a > b -> a <= b */
{
- neg_arguments();
- return new Item_cond_or(list);
+ return new Item_func_le(args[0], args[1]);
}
-Item *Item_cond_or::neg_transformer() /* NOT(a OR b OR ...) -> */
- /* NOT a AND NOT b AND ... */
+
+Item *Item_func_le::negated_item() /* a <= b -> a > b */
+{
+ return new Item_func_gt(args[0], args[1]);
+}
+
+// just fake method, should never be called
+Item *Item_bool_rowready_func2::negated_item()
{
- neg_arguments();
- return new Item_cond_and(list);
+ DBUG_ASSERT(0);
+ return 0;
}