Commit de5029a4 authored by Georgi Kodinov's avatar Georgi Kodinov

Bug #55188: GROUP BY, GROUP_CONCAT and TEXT - inconsistent results

In order to be able to check if the set of the grouping fields in a 
GROUP BY has changed (and thus to start a new group) the optimizer
caches the current values of these fields in a set of Cached_item 
derived objects.
The Cached_item_str, used for caching varchar and TEXT columns,
is limited in length by the max_sort_length variable.
A String buffer to store the value with an alloced length of either
the max length of the string or the value of max_sort_length 
(whichever is smaller) in Cached_item_str's constructor.
Then, at compare time the value of the string to compare to was 
truncated to the alloced length of the string buffer inside 
Cached_item_str.
This is all fine and valid, but only if you're not assigning 
values near or equal to the alloced length of this buffer.
Because when assigning values like this the alloced length is 
rounded up and as a result the next set of data will not match the
group buffer, thus leading to wrong results because of the changed
alloced_length.
Fixed by preserving the original maximum length in the 
Cached_item_str's constructor and using this instead of the 
alloced_length to limit the string to compare to.
Test case added.
parent 415fea54
...@@ -1810,4 +1810,39 @@ MAX(t2.a) ...@@ -1810,4 +1810,39 @@ MAX(t2.a)
2 2
DROP TABLE t1, t2; DROP TABLE t1, t2;
# #
# Bug#55188: GROUP BY, GROUP_CONCAT and TEXT - inconsistent results
#
CREATE TABLE t1 (a text, b varchar(10));
INSERT INTO t1 VALUES (repeat('1', 1300),'one'), (repeat('1', 1300),'two');
EXPLAIN
SELECT SUBSTRING(a,1,10), LENGTH(a), GROUP_CONCAT(b) FROM t1 GROUP BY a;
id 1
select_type SIMPLE
table t1
type ALL
possible_keys NULL
key NULL
key_len NULL
ref NULL
rows 2
Extra Using filesort
SELECT SUBSTRING(a,1,10), LENGTH(a), GROUP_CONCAT(b) FROM t1 GROUP BY a;
SUBSTRING(a,1,10) LENGTH(a) GROUP_CONCAT(b)
1111111111 1300 one,two
EXPLAIN
SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a;
id 1
select_type SIMPLE
table t1
type ALL
possible_keys NULL
key NULL
key_len NULL
ref NULL
rows 2
Extra Using temporary; Using filesort
SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a;
SUBSTRING(a,1,10) LENGTH(a)
1111111111 1300
DROP TABLE t1;
# End of 5.1 tests # End of 5.1 tests
...@@ -1221,5 +1221,19 @@ DROP TABLE t1, t2; ...@@ -1221,5 +1221,19 @@ DROP TABLE t1, t2;
--echo # --echo #
--echo # Bug#55188: GROUP BY, GROUP_CONCAT and TEXT - inconsistent results
--echo #
CREATE TABLE t1 (a text, b varchar(10));
INSERT INTO t1 VALUES (repeat('1', 1300),'one'), (repeat('1', 1300),'two');
query_vertical EXPLAIN
SELECT SUBSTRING(a,1,10), LENGTH(a), GROUP_CONCAT(b) FROM t1 GROUP BY a;
SELECT SUBSTRING(a,1,10), LENGTH(a), GROUP_CONCAT(b) FROM t1 GROUP BY a;
query_vertical EXPLAIN
SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a;
SELECT SUBSTRING(a,1,10), LENGTH(a) FROM t1 GROUP BY a;
DROP TABLE t1;
--echo # End of 5.1 tests --echo # End of 5.1 tests
...@@ -2740,6 +2740,7 @@ public: ...@@ -2740,6 +2740,7 @@ public:
class Cached_item_str :public Cached_item class Cached_item_str :public Cached_item
{ {
Item *item; Item *item;
uint32 value_max_length;
String value,tmp_value; String value,tmp_value;
public: public:
Cached_item_str(THD *thd, Item *arg); Cached_item_str(THD *thd, Item *arg);
......
...@@ -58,7 +58,9 @@ Cached_item::~Cached_item() {} ...@@ -58,7 +58,9 @@ Cached_item::~Cached_item() {}
*/ */
Cached_item_str::Cached_item_str(THD *thd, Item *arg) Cached_item_str::Cached_item_str(THD *thd, Item *arg)
:item(arg), value(min(arg->max_length, thd->variables.max_sort_length)) :item(arg),
value_max_length(min(arg->max_length, thd->variables.max_sort_length)),
value(value_max_length)
{} {}
bool Cached_item_str::cmp(void) bool Cached_item_str::cmp(void)
...@@ -67,7 +69,7 @@ bool Cached_item_str::cmp(void) ...@@ -67,7 +69,7 @@ bool Cached_item_str::cmp(void)
bool tmp; bool tmp;
if ((res=item->val_str(&tmp_value))) if ((res=item->val_str(&tmp_value)))
res->length(min(res->length(), value.alloced_length())); res->length(min(res->length(), value_max_length));
if (null_value != item->null_value) if (null_value != item->null_value)
{ {
if ((null_value= item->null_value)) if ((null_value= item->null_value))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment