diff options
author | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2012-03-09 15:04:49 +0200 |
---|---|---|
committer | Georgi Kodinov <Georgi.Kodinov@Oracle.com> | 2012-03-09 15:04:49 +0200 |
commit | 35d865f2fe497fb5bf15810cf31f717d5d9c4e46 (patch) | |
tree | a990125f7d3483f930365a582a79772c487d7362 | |
parent | 2a3aa3f9023f5f07517c9f9539a1eda34c884178 (diff) | |
download | mariadb-git-35d865f2fe497fb5bf15810cf31f717d5d9c4e46.tar.gz |
Bug #12408412: GROUP_CONCAT + ORDER BY + INPUT/OUTPUT SAME
USER VARIABLE = CRASH
Moved the preparation of the variables that receive the output from
SELECT INTO from execution time (JOIN:execute) to compile time
(JOIN::prepare). This ensures that if the same variable is used in the
SELECT part of SELECT INTO it will be properly marked as non-const
for this query.
Test case added.
Used proper fast iterator.
-rw-r--r-- | mysql-test/r/user_var.result | 6 | ||||
-rw-r--r-- | mysql-test/t/user_var.test | 9 | ||||
-rw-r--r-- | sql/sql_class.cc | 43 | ||||
-rw-r--r-- | sql/sql_class.h | 1 |
4 files changed, 52 insertions, 7 deletions
diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 589186184c3..b0859658077 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -485,4 +485,10 @@ f1 f2 1 4 DROP TRIGGER trg1; DROP TABLE t1; +# +# Bug #12408412: GROUP_CONCAT + ORDER BY + INPUT/OUTPUT +# SAME USER VARIABLE = CRASH +# +SET @bug12408412=1; +SELECT GROUP_CONCAT(@bug12408412 ORDER BY 1) INTO @bug12408412; End of 5.5 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 6a64343b609..fa23d118634 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -404,4 +404,13 @@ SELECT f1, f2 FROM t1 ORDER BY f2; DROP TRIGGER trg1; DROP TABLE t1; + +--echo # +--echo # Bug #12408412: GROUP_CONCAT + ORDER BY + INPUT/OUTPUT +--echo # SAME USER VARIABLE = CRASH +--echo # + +SET @bug12408412=1; +SELECT GROUP_CONCAT(@bug12408412 ORDER BY 1) INTO @bug12408412; + --echo End of 5.5 tests diff --git a/sql/sql_class.cc b/sql/sql_class.cc index b68726c2920..20ab1b71542 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2855,13 +2855,42 @@ bool select_exists_subselect::send_data(List<Item> &items) int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { unit= u; + List_iterator_fast<my_var> var_li(var_list); + List_iterator_fast<Item> it(list); + Item *item; + my_var *mv; + Item_func_set_user_var **suv; if (var_list.elements != list.elements) { my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0)); return 1; - } + } + + /* + Iterate over the destination variables and mark them as being + updated in this query. + We need to do this at JOIN::prepare time to ensure proper + const detection of Item_func_get_user_var that is determined + by the presence of Item_func_set_user_vars + */ + + suv= set_var_items= (Item_func_set_user_var **) + sql_alloc(sizeof(Item_func_set_user_var *) * list.elements); + + while ((mv= var_li++) && (item= it++)) + { + if (!mv->local) + { + *suv= new Item_func_set_user_var(mv->s, item); + (*suv)->fix_fields(thd, 0); + } + else + *suv= NULL; + suv++; + } + return 0; } @@ -3178,6 +3207,7 @@ bool select_dumpvar::send_data(List<Item> &items) List_iterator<Item> it(items); Item *item; my_var *mv; + Item_func_set_user_var **suv; DBUG_ENTER("select_dumpvar::send_data"); if (unit->offset_limit_cnt) @@ -3190,20 +3220,19 @@ bool select_dumpvar::send_data(List<Item> &items) my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0)); DBUG_RETURN(1); } - while ((mv= var_li++) && (item= it++)) + for (suv= set_var_items; ((mv= var_li++) && (item= it++)); suv++) { if (mv->local) { + DBUG_ASSERT(!*suv); if (thd->spcont->set_variable(thd, mv->offset, &item)) DBUG_RETURN(1); } else { - Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); - if (suv->fix_fields(thd, 0)) - DBUG_RETURN (1); - suv->save_item_result(item); - if (suv->update()) + DBUG_ASSERT(*suv); + (*suv)->save_item_result(item); + if ((*suv)->update()) DBUG_RETURN (1); } } diff --git a/sql/sql_class.h b/sql/sql_class.h index 36091546ff4..5434d5ae325 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3531,6 +3531,7 @@ public: class select_dumpvar :public select_result_interceptor { ha_rows row_count; + Item_func_set_user_var **set_var_items; public: List<my_var> var_list; select_dumpvar() { var_list.empty(); row_count= 0;} |