diff options
-rw-r--r-- | mysql-test/r/func_gconcat.result | 47 | ||||
-rw-r--r-- | mysql-test/t/func_gconcat.test | 32 | ||||
-rw-r--r-- | sql/field.h | 5 | ||||
-rw-r--r-- | sql/field_conv.cc | 14 | ||||
-rw-r--r-- | sql/item_sum.cc | 14 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 |
6 files changed, 111 insertions, 6 deletions
diff --git a/mysql-test/r/func_gconcat.result b/mysql-test/r/func_gconcat.result index 4c7baac051a..3f577c57626 100644 --- a/mysql-test/r/func_gconcat.result +++ b/mysql-test/r/func_gconcat.result @@ -743,4 +743,51 @@ SELECT GROUP_CONCAT(DISTINCT UCASE(b)) FROM t1; GROUP_CONCAT(DISTINCT UCASE(b)) ONE.1,TWO.2,ONE.3 DROP TABLE t1; +SET group_concat_max_len= 65535; +CREATE TABLE t1( a TEXT, b INTEGER ); +INSERT INTO t1 VALUES ( 'a', 0 ), ( 'b', 1 ); +SELECT GROUP_CONCAT( a ORDER BY b ) FROM t1; +GROUP_CONCAT( a ORDER BY b ) +a,b +SELECT GROUP_CONCAT(DISTINCT a ORDER BY b) FROM t1; +GROUP_CONCAT(DISTINCT a ORDER BY b) +a,b +SELECT GROUP_CONCAT(DISTINCT a) FROM t1; +GROUP_CONCAT(DISTINCT a) +a,b +SET group_concat_max_len= 10; +SELECT GROUP_CONCAT(a ORDER BY b) FROM t1; +GROUP_CONCAT(a ORDER BY b) +a,b +SELECT GROUP_CONCAT(DISTINCT a ORDER BY b) FROM t1; +GROUP_CONCAT(DISTINCT a ORDER BY b) +a,b +SELECT GROUP_CONCAT(DISTINCT a) FROM t1; +GROUP_CONCAT(DISTINCT a) +a,b +SET group_concat_max_len= 65535; +CREATE TABLE t2( a TEXT ); +INSERT INTO t2 VALUES( REPEAT( 'a', 5000 ) ); +INSERT INTO t2 VALUES( REPEAT( 'b', 5000 ) ); +INSERT INTO t2 VALUES( REPEAT( 'a', 5000 ) ); +SELECT LENGTH( GROUP_CONCAT( DISTINCT a ) ) FROM t2; +LENGTH( GROUP_CONCAT( DISTINCT a ) ) +10001 +CREATE TABLE t3( a TEXT, b INT ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65534 ), 1 ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65535 ), 2 ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65536 ), 3 ); +Warnings: +Warning 1265 Data truncated for column 'a' at row 1 +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 1; +LENGTH( GROUP_CONCAT( a ) ) +65534 +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 2; +LENGTH( GROUP_CONCAT( a ) ) +65535 +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 3; +LENGTH( GROUP_CONCAT( a ) ) +65535 +SET group_concat_max_len= DEFAULT; +DROP TABLE t1, t2, t3; End of 5.0 tests diff --git a/mysql-test/t/func_gconcat.test b/mysql-test/t/func_gconcat.test index 431d582be50..0c162df02e7 100644 --- a/mysql-test/t/func_gconcat.test +++ b/mysql-test/t/func_gconcat.test @@ -507,4 +507,36 @@ SELECT GROUP_CONCAT(DISTINCT UCASE(a)) FROM t1; SELECT GROUP_CONCAT(DISTINCT UCASE(b)) FROM t1; DROP TABLE t1; +# +# Bug #23856:GROUP_CONCAT and ORDER BY: junk from previous rows for query on I_S +# +SET group_concat_max_len= 65535; +CREATE TABLE t1( a TEXT, b INTEGER ); +INSERT INTO t1 VALUES ( 'a', 0 ), ( 'b', 1 ); +SELECT GROUP_CONCAT( a ORDER BY b ) FROM t1; +SELECT GROUP_CONCAT(DISTINCT a ORDER BY b) FROM t1; +SELECT GROUP_CONCAT(DISTINCT a) FROM t1; +SET group_concat_max_len= 10; +SELECT GROUP_CONCAT(a ORDER BY b) FROM t1; +SELECT GROUP_CONCAT(DISTINCT a ORDER BY b) FROM t1; +SELECT GROUP_CONCAT(DISTINCT a) FROM t1; + +SET group_concat_max_len= 65535; +CREATE TABLE t2( a TEXT ); +INSERT INTO t2 VALUES( REPEAT( 'a', 5000 ) ); +INSERT INTO t2 VALUES( REPEAT( 'b', 5000 ) ); +INSERT INTO t2 VALUES( REPEAT( 'a', 5000 ) ); +SELECT LENGTH( GROUP_CONCAT( DISTINCT a ) ) FROM t2; + +CREATE TABLE t3( a TEXT, b INT ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65534 ), 1 ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65535 ), 2 ); +INSERT INTO t3 VALUES( REPEAT( 'a', 65536 ), 3 ); +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 1; +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 2; +SELECT LENGTH( GROUP_CONCAT( a ) ) FROM t3 WHERE b = 3; + +SET group_concat_max_len= DEFAULT; +DROP TABLE t1, t2, t3; + --echo End of 5.0 tests diff --git a/sql/field.h b/sql/field.h index 2c2640a8262..da7bc690929 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1171,6 +1171,11 @@ public: class Field_varstring :public Field_longstr { public: + /* + The maximum space available in a Field_varstring, in bytes. See + length_bytes. + */ + static const int MAX_SIZE= UINT_MAX16; /* Store number of bytes used to store length (1 or 2) */ uint32 length_bytes; Field_varstring(char *ptr_arg, diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 9771cbc12b1..e042c0ad76d 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -529,7 +529,21 @@ void Copy_field::set(char *to,Field *from) } +/* + To do: + + If 'save\ is set to true and the 'from' is a blob field, do_copy is set to + do_save_blob rather than do_conv_blob. The only differences between them + appears to be: + - do_save_blob allocates and uses an intermediate buffer before calling + Field_blob::store. Is this in order to trigger the call to + well_formed_copy_nchars, by changing the pointer copy->tmp.ptr()? + That call will take place anyway in all known cases. + + - The above causes a truncation to MAX_FIELD_WIDTH. Is this the intended + effect? Truncation is handled by well_formed_copy_nchars anyway. + */ void Copy_field::set(Field *to,Field *from,bool save) { if (to->type() == MYSQL_TYPE_NULL) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 6215aacde64..b79b029df32 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -431,7 +431,7 @@ Field *Item_sum::create_tmp_field(bool group, TABLE *table, break; case STRING_RESULT: if (max_length/collation.collation->mbmaxlen <= 255 || - convert_blob_length >=UINT_MAX16 || + convert_blob_length > Field_varstring::MAX_SIZE || !convert_blob_length) return make_string_field(table); field= new Field_varstring(convert_blob_length, maybe_null, @@ -3290,14 +3290,20 @@ bool Item_func_group_concat::setup(THD *thd) tmp_table_param->force_copy_fields= force_copy_fields; DBUG_ASSERT(table == 0); /* + Currently we have to force conversion of BLOB values to VARCHAR's + if we are to store them in TREE objects used for ORDER BY and + DISTINCT. This leads to truncation if the BLOB's size exceeds + Field_varstring::MAX_SIZE. + */ + if (arg_count_order > 0 || distinct) + set_if_smaller(tmp_table_param->convert_blob_length, + Field_varstring::MAX_SIZE); + /* We have to create a temporary table to get descriptions of fields (types, sizes and so on). Note that in the table, we first have the ORDER BY fields, then the field list. - - We need to set set_sum_field in true for storing value of blob in buffer - of a record instead of a pointer of one. */ if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, (ORDER*) 0, 0, TRUE, diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8de3e041bfc..ffbcc64ede0 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8991,7 +8991,7 @@ Field *create_tmp_field_from_field(THD *thd, Field *org_field, Make sure that the blob fits into a Field_varstring which has 2-byte lenght. */ - if (convert_blob_length && convert_blob_length < UINT_MAX16 && + if (convert_blob_length && convert_blob_length <= Field_varstring::MAX_SIZE && (org_field->flags & BLOB_FLAG)) new_field= new Field_varstring(convert_blob_length, org_field->maybe_null(), @@ -9084,7 +9084,8 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, 2-byte lenght. */ else if (item->max_length/item->collation.collation->mbmaxlen > 255 && - convert_blob_length < UINT_MAX16 && convert_blob_length) + convert_blob_length <= Field_varstring::MAX_SIZE && + convert_blob_length) new_field= new Field_varstring(convert_blob_length, maybe_null, item->name, table->s, item->collation.collation); |