summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/func_str.result6
-rw-r--r--mysql-test/t/func_str.test8
-rw-r--r--sql/item_func.cc55
-rw-r--r--sql/item_func.h3
-rw-r--r--sql/item_strfunc.cc75
5 files changed, 90 insertions, 57 deletions
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index 42b96956cef..c2a921e1a54 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -278,6 +278,12 @@ row('A','b','c') = row('a' COLLATE latin1_bin,'b','c')
0
select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c');
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation '='
+select concat(_latin1'a',_latin2'a');
+ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat'
+select concat(_latin1'a',_latin2'a',_latin5'a');
+ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin5_turkish_ci,COERCIBLE) for operation 'concat'
+select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a');
+ERROR HY000: Illegal mix of collations for operation 'concat'
select FIELD('b','A','B');
FIELD('b','A','B')
2
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 79d2b082d01..c9e7b1a529d 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -152,6 +152,14 @@ select row('A','b','c') = row('a' COLLATE latin1_bin,'b','c');
--error 1265
select row('A' COLLATE latin1_general_ci,'b','c') = row('a' COLLATE latin1_bin,'b','c');
+--error 1265
+select concat(_latin1'a',_latin2'a');
+--error 1268
+select concat(_latin1'a',_latin2'a',_latin5'a');
+--error 1269
+select concat(_latin1'a',_latin2'a',_latin5'a',_latin7'a');
+
+
#
# Test FIELD() and collations
#
diff --git a/sql/item_func.cc b/sql/item_func.cc
index eba6a2cc8d1..df1bce37581 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -39,6 +39,61 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam
fname);
}
+static void my_coll_agg_error(DTCollation &c1,
+ DTCollation &c2,
+ DTCollation &c3,
+ const char *fname)
+{
+ my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
+ c1.collation->name,c1.derivation_name(),
+ c2.collation->name,c2.derivation_name(),
+ c3.collation->name,c3.derivation_name(),
+ fname);
+}
+
+static void my_coll_agg_error(Item** args, uint ac, const char *fname)
+{
+ if (2 == ac)
+ my_coll_agg_error(args[0]->collation, args[1]->collation, fname);
+ else if (3 == ac)
+ my_coll_agg_error(args[0]->collation,
+ args[1]->collation,
+ args[2]->collation,
+ fname);
+ else
+ my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
+}
+
+bool Item_func::agg_arg_collations(DTCollation &c, uint from, uint argc)
+{
+ uint i;
+ c.set(args[from]->collation);
+ for (i= from+1; i < argc; i++)
+ {
+ if (c.aggregate(args[i]->collation))
+ {
+ my_coll_agg_error(args+from, argc-from, func_name());
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
+ uint from, uint argc)
+{
+ if (agg_arg_collations(c, from, argc))
+ return FALSE;
+
+ if (c.derivation == DERIVATION_NONE)
+ {
+ my_coll_agg_error(args+from, argc-from, func_name());
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
/* return TRUE if item is a constant */
bool
diff --git a/sql/item_func.h b/sql/item_func.h
index 6a08d961bc3..c7f227051f3 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -135,6 +135,9 @@ public:
Field *tmp_table_field(TABLE *t_arg);
void set_outer_resolving();
Item *get_tmp_table_item(THD *thd);
+
+ bool agg_arg_collations(DTCollation &c, uint from, uint argc);
+ bool agg_arg_collations_for_comparison(DTCollation &c, uint from, uint argc);
};
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index cbfe98bfd21..8c3784a5d4e 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -44,18 +44,6 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam
fname);
}
-static void my_coll_agg3_error(DTCollation &c1,
- DTCollation &c2,
- DTCollation &c3,
- const char *fname)
-{
- my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
- c1.collation->name,c1.derivation_name(),
- c2.collation->name,c2.derivation_name(),
- c3.collation->name,c3.derivation_name(),
- fname);
-}
-
uint nr_of_decimals(const char *str)
{
if ((str=strchr(str,'.')))
@@ -336,16 +324,11 @@ void Item_func_concat::fix_length_and_dec()
bool first_coll= 1;
max_length=0;
- collation.set(args[0]->collation);
+ if (agg_arg_collations(collation, 0, arg_count))
+ return;
+
for (uint i=0 ; i < arg_count ; i++)
- {
max_length+=args[i]->max_length;
- if (collation.aggregate(args[i]->collation))
- {
- my_coll_agg_error(collation, args[i]->collation, func_name());
- break;
- }
- }
if (max_length > MAX_BLOB_WIDTH)
{
@@ -840,13 +823,8 @@ void Item_func_replace::fix_length_and_dec()
maybe_null=1;
}
- collation.set(args[0]->collation);
- if (!collation.aggregate(args[1]->collation))
- collation.aggregate(args[2]->collation);
-
- if (collation.derivation == DERIVATION_NONE)
- my_coll_agg3_error(args[0]->collation, args[1]->collation,
- args[2]->collation, func_name());
+ if (agg_arg_collations_for_comparison(collation, 0, 3))
+ return;
}
@@ -1050,9 +1028,9 @@ void Item_func_substr::fix_length_and_dec()
void Item_func_substr_index::fix_length_and_dec()
{
max_length= args[0]->max_length;
- if (collation.set(args[0]->collation, args[1]->collation) ||
- (collation.derivation == DERIVATION_NONE))
- my_coll_agg_error(args[0]->collation, args[1]->collation, func_name());
+
+ if (agg_arg_collations_for_comparison(collation, 0, 2))
+ return;
}
@@ -1680,20 +1658,13 @@ void Item_func_elt::fix_length_and_dec()
max_length=0;
decimals=0;
+ if (agg_arg_collations(collation, 0, arg_count))
+ return;
+
for (uint i=0 ; i < arg_count ; i++)
{
set_if_bigger(max_length,args[i]->max_length);
set_if_bigger(decimals,args[i]->decimals);
- if (i == 0)
- collation.set(args[0]->collation);
- else
- {
- if (collation.aggregate(args[i]->collation))
- {
- my_coll_agg_error(collation, args[i]->collation, func_name());
- break;
- }
- }
}
maybe_null=1; // NULL if wrong first arg
with_sum_func= with_sum_func || item->with_sum_func;
@@ -1786,16 +1757,13 @@ void Item_func_make_set::split_sum_func(Item **ref_pointer_array,
void Item_func_make_set::fix_length_and_dec()
{
max_length=arg_count-1;
- collation.set(args[0]->collation);
+
+ if (agg_arg_collations(collation, 0, arg_count))
+ return;
+
for (uint i=0 ; i < arg_count ; i++)
- {
max_length+=args[i]->max_length;
- if (collation.aggregate(args[i]->collation))
- {
- my_coll_agg_error(collation, args[i]->collation, func_name());
- break;
- }
- }
+
used_tables_cache|=item->used_tables();
const_item_cache&=item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
@@ -2463,15 +2431,8 @@ void Item_func_export_set::fix_length_and_dec()
uint sep_length=(arg_count > 3 ? args[3]->max_length : 1);
max_length=length*64+sep_length*63;
- collation.set(args[1]->collation);
- for (i=2 ; i < 4 && i < arg_count ; i++)
- {
- if (collation.aggregate(args[i]->collation))
- {
- my_coll_agg_error(collation, args[i]->collation, func_name());
- break;
- }
- }
+ if (agg_arg_collations(collation,1, min(4,arg_count)))
+ return;
}
String* Item_func_inet_ntoa::val_str(String* str)