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.cc162
1 files changed, 79 insertions, 83 deletions
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 1f1b449e9a7..d992b4d69d0 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -24,6 +24,32 @@
#include "mysql_priv.h"
#include <m_ctype.h>
+static Item_result item_store_type(Item_result a,Item_result b)
+{
+ if (a == STRING_RESULT || b == STRING_RESULT)
+ return STRING_RESULT;
+ else if (a == REAL_RESULT || b == REAL_RESULT)
+ return REAL_RESULT;
+ else
+ return INT_RESULT;
+}
+
+static void agg_result_type(Item_result *type, Item **items, uint nitems)
+{
+ uint i;
+ type[0]= items[0]->result_type();
+ for (i=1 ; i < nitems ; i++)
+ type[0]= item_store_type(type[0], items[i]->result_type());
+}
+
+static void agg_cmp_type(Item_result *type, Item **items, uint nitems)
+{
+ uint i;
+ type[0]= items[0]->result_type();
+ for (i=1 ; i < nitems ; i++)
+ type[0]= item_cmp_type(type[0], items[i]->result_type());
+}
+
static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
@@ -223,7 +249,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
We must set cmp_charset here as we may be called from for an automatic
generated item, like in natural join
*/
- if (cmp_collation.set((*a)->collation, (*b)->collation))
+ if (cmp_collation.set((*a)->collation, (*b)->collation) ||
+ cmp_collation.derivation == DERIVATION_NONE)
{
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return 1;
@@ -556,10 +583,7 @@ void Item_func_between::fix_length_and_dec()
*/
if (!args[0] || !args[1] || !args[2])
return;
- cmp_type=item_cmp_type(args[0]->result_type(),
- item_cmp_type(args[1]->result_type(),
- args[2]->result_type()));
-
+ agg_cmp_type(&cmp_type, args, 3);
if (cmp_type == STRING_RESULT &&
agg_arg_collations_for_comparison(cmp_collation, args, 3))
return;
@@ -650,28 +674,17 @@ longlong Item_func_between::val_int()
return 0;
}
-static Item_result item_store_type(Item_result a,Item_result b)
-{
- if (a == STRING_RESULT || b == STRING_RESULT)
- return STRING_RESULT;
- else if (a == REAL_RESULT || b == REAL_RESULT)
- return REAL_RESULT;
- else
- return INT_RESULT;
-}
-
void
Item_func_ifnull::fix_length_and_dec()
{
maybe_null=args[1]->maybe_null;
max_length=max(args[0]->max_length,args[1]->max_length);
decimals=max(args[0]->decimals,args[1]->decimals);
- if ((cached_result_type=item_store_type(args[0]->result_type(),
- args[1]->result_type())) !=
- REAL_RESULT)
- decimals= 0;
+ agg_result_type(&cached_result_type, args, 2);
if (cached_result_type == STRING_RESULT)
agg_arg_collations(collation, args, arg_count);
+ else if (cached_result_type != REAL_RESULT)
+ decimals= 0;
}
@@ -744,19 +757,18 @@ Item_func_if::fix_length_and_dec()
cached_result_type= arg1_type;
set_charset(args[1]->charset());
}
- else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT)
- {
- cached_result_type = STRING_RESULT;
- if (agg_arg_collations(collation, args+1, 2))
- return;
- }
else
{
- set_charset(&my_charset_bin); // Number
- if (arg1_type == REAL_RESULT || arg2_type == REAL_RESULT)
- cached_result_type = REAL_RESULT;
+ agg_result_type(&cached_result_type, args+1, 2);
+ if (cached_result_type == STRING_RESULT)
+ {
+ if (agg_arg_collations(collation, args+1, 2))
+ return;
+ }
else
- cached_result_type=arg1_type; // Should be INT_RESULT
+ {
+ set_charset(&my_charset_bin); // Number
+ }
}
}
@@ -800,7 +812,7 @@ Item_func_nullif::fix_length_and_dec()
{
max_length=args[0]->max_length;
decimals=args[0]->decimals;
- cached_result_type=args[0]->result_type();
+ agg_result_type(&cached_result_type, args, 2);
}
}
@@ -863,58 +875,60 @@ Item *Item_func_case::find_item(String *str)
String *first_expr_str,*tmp;
longlong first_expr_int;
double first_expr_real;
- bool int_used, real_used,str_used;
- int_used=real_used=str_used=0;
-
+
/* These will be initialized later */
LINT_INIT(first_expr_str);
LINT_INIT(first_expr_int);
LINT_INIT(first_expr_real);
+ if (first_expr_num != -1)
+ {
+ switch (cmp_type)
+ {
+ case STRING_RESULT:
+ // We can't use 'str' here as this may be overwritten
+ if (!(first_expr_str= args[first_expr_num]->val_str(&str_value)))
+ 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();
+ 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 choosen
+ 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 first WHEN
+ // No expression between CASE and the first WHEN
if (args[i]->val_int())
return args[i+1];
continue;
}
- switch (args[i]->result_type()) {
+ switch (cmp_type) {
case STRING_RESULT:
- if (!str_used)
- {
- str_used=1;
- // We can't use 'str' here as this may be overwritten
- if (!(first_expr_str= args[first_expr_num]->val_str(&str_value)))
- return else_expr_num != -1 ? args[else_expr_num] : 0; // Impossible
- }
if ((tmp=args[i]->val_str(str))) // If not null
- {
- if (sortcmp(tmp,first_expr_str,&my_charset_bin)==0)
+ if (sortcmp(tmp,first_expr_str,cmp_collation.collation)==0)
return args[i+1];
- }
break;
case INT_RESULT:
- if (!int_used)
- {
- int_used=1;
- 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;
- }
if (args[i]->val_int()==first_expr_int && !args[i]->null_value)
return args[i+1];
break;
case REAL_RESULT:
- if (!real_used)
- {
- real_used=1;
- first_expr_real= args[first_expr_num]->val();
- if (args[first_expr_num]->null_value)
- return else_expr_num != -1 ? args[else_expr_num] : 0;
- }
if (args[i]->val()==first_expr_real && !args[i]->null_value)
return args[i+1];
break;
@@ -982,22 +996,6 @@ double Item_func_case::val()
return res;
}
-static void agg_result_type(Item_result *type, Item **items, uint nitems)
-{
- uint i;
- type[0]= items[0]->result_type();
- for (i=1 ; i < nitems ; i++)
- type[0]= item_store_type(type[0], items[i]->result_type());
-}
-
-static void agg_cmp_type(Item_result *type, Item **items, uint nitems)
-{
- uint i;
- type[0]= items[0]->result_type();
- for (i=1 ; i < nitems ; i++)
- type[0]= item_cmp_type(type[0], items[i]->result_type());
-}
-
void Item_func_case::fix_length_and_dec()
{
Item **agg;
@@ -1027,7 +1025,7 @@ void Item_func_case::fix_length_and_dec()
{
agg[0]= args[first_expr_num];
for (nagg= 0; nagg < ncases/2 ; nagg++)
- agg[nagg+1]= args[nagg];
+ agg[nagg+1]= args[nagg*2];
nagg++;
agg_cmp_type(&cmp_type, agg, nagg);
if ((cmp_type == STRING_RESULT) &&
@@ -1040,7 +1038,6 @@ void Item_func_case::fix_length_and_dec()
max_length=0;
decimals=0;
- cached_result_type = args[1]->result_type();
for (uint i=0 ; i < ncases ; i+=2)
{
set_if_bigger(max_length,args[i+1]->max_length);
@@ -1108,13 +1105,11 @@ void Item_func_coalesce::fix_length_and_dec()
{
max_length= 0;
decimals= 0;
- cached_result_type = args[0]->result_type();
+ agg_result_type(&cached_result_type, args, arg_count);
for (uint i=0 ; i < arg_count ; i++)
{
set_if_bigger(max_length,args[i]->max_length);
set_if_bigger(decimals,args[i]->decimals);
- cached_result_type=item_store_type(cached_result_type,
- args[i]->result_type());
}
if (cached_result_type == STRING_RESULT)
agg_arg_collations(collation, args, arg_count);
@@ -1404,7 +1399,8 @@ void Item_func_in::fix_length_and_dec()
Item **arg, **arg_end;
uint const_itm= 1;
- if ((args[0]->result_type() == STRING_RESULT) &&
+ agg_cmp_type(&cmp_type, args, arg_count);
+ if ((cmp_type == STRING_RESULT) &&
(agg_arg_collations_for_comparison(cmp_collation, args, arg_count)))
return;
@@ -1417,7 +1413,7 @@ void Item_func_in::fix_length_and_dec()
*/
if (const_itm && !nulls_in_row())
{
- switch (args[0]->result_type()) {
+ switch (cmp_type) {
case STRING_RESULT:
uint i;
array=new in_string(arg_count-1,(qsort2_cmp) srtcmp_in,
@@ -1451,7 +1447,7 @@ void Item_func_in::fix_length_and_dec()
else
{
in_item= cmp_item::get_comparator(args[0]);
- if (args[0]->result_type() == STRING_RESULT)
+ if (cmp_type == STRING_RESULT)
in_item->cmp_charset= cmp_collation.collation;
}
maybe_null= args[0]->maybe_null;