From bd414485de627818a8fd28fc00887d919d4e0ae1 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Tue, 24 Feb 2009 18:47:12 +0400 Subject: [PATCH] Fix for bug#42009: SELECT into variable gives different results to direct SELECT Problem: storing "SELECT ... INTO @var ..." results in variables we used val_xxx() methods which returned results of the current row. So, in some cases (e.g. SELECT DISTINCT, GROUP BY or HAVING) we got data from the first row of a new group (where we evaluate a clause) instead of data from the last row of the previous group. Fix: use val_xxx_result() counterparts to get proper results. mysql-test/r/distinct.result: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - results adjusted. mysql-test/r/user_var.result: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - test result. mysql-test/t/user_var.test: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - test case. sql/item_func.cc: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - Item_func_set_user_var::save_item_result() added to evaluate and store an item's result into a user variable. sql/item_func.h: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - Item_func_set_user_var::save_item_result() added to evaluate and store an item's result into a user variable. sql/sql_class.cc: Fix for bug#42009: SELECT into variable gives different results to direct SELECT - use Item_func_set_user_var::save_item_result() to store results into user variables. --- mysql-test/r/distinct.result | 8 ++++---- mysql-test/r/user_var.result | 11 +++++++++++ mysql-test/t/user_var.test | 12 ++++++++++++ sql/item_func.cc | 35 +++++++++++++++++++++++++++++++++++ sql/item_func.h | 1 + sql/sql_class.cc | 2 +- 6 files changed, 64 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index 114d3088fe8..ddbee3ec79c 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -629,21 +629,21 @@ SELECT DISTINCT @v5:= fruit_id, @v6:= fruit_name INTO @v7, @v8 FROM t1 WHERE fruit_name = 'APPLE'; SELECT @v5, @v6, @v7, @v8; @v5 @v6 @v7 @v8 -3 PEAR 3 PEAR +2 APPLE 2 APPLE SELECT DISTINCT @v5 + fruit_id, CONCAT(@v6, fruit_name) INTO @v9, @v10 FROM t1 WHERE fruit_name = 'APPLE'; SELECT @v5, @v6, @v7, @v8, @v9, @v10; @v5 @v6 @v7 @v8 @v9 @v10 -3 PEAR 3 PEAR 5 PEARAPPLE +2 APPLE 2 APPLE 4 APPLEAPPLE SELECT DISTINCT @v11:= @v5 + fruit_id, @v12:= CONCAT(@v6, fruit_name) INTO @v13, @v14 FROM t1 WHERE fruit_name = 'APPLE'; SELECT @v11, @v12, @v13, @v14; @v11 @v12 @v13 @v14 -6 PEARPEAR 6 PEARPEAR +4 APPLEAPPLE 4 APPLEAPPLE SELECT DISTINCT @v13, @v14 INTO @v15, @v16 FROM t1 WHERE fruit_name = 'APPLE'; SELECT @v15, @v16; @v15 @v16 -6 PEARPEAR +4 APPLEAPPLE SELECT DISTINCT 2 + 2, 'Bob' INTO @v17, @v18 FROM t1 WHERE fruit_name = 'APPLE'; SELECT @v17, @v18; diff --git a/mysql-test/r/user_var.result b/mysql-test/r/user_var.result index 80b5dccc198..bfa95d8f92b 100644 --- a/mysql-test/r/user_var.result +++ b/mysql-test/r/user_var.result @@ -353,3 +353,14 @@ select @a:=f4, count(f4) from t1 group by 1 desc; 2.6 1 1.6 4 drop table t1; +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (0, 0), (2, 1), (2, 3), (1, 1), (30, 20); +SELECT a, b INTO @a, @b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; +SELECT @a, @b; +@a @b +2 3 +SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; +a b +2 3 +DROP TABLE t1; +End of 5.0 tests diff --git a/mysql-test/t/user_var.test b/mysql-test/t/user_var.test index 3a3e8f88f83..d39b49a0e87 100644 --- a/mysql-test/t/user_var.test +++ b/mysql-test/t/user_var.test @@ -237,3 +237,15 @@ select @a:=f2, count(f2) from t1 group by 1 desc; select @a:=f3, count(f3) from t1 group by 1 desc; select @a:=f4, count(f4) from t1 group by 1 desc; drop table t1; + +# +# Bug#42009: SELECT into variable gives different results to direct SELECT +# +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (0, 0), (2, 1), (2, 3), (1, 1), (30, 20); +SELECT a, b INTO @a, @b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; +SELECT @a, @b; +SELECT a, b FROM t1 WHERE a=2 AND b=3 GROUP BY a, b; +DROP TABLE t1; + +--echo End of 5.0 tests diff --git a/sql/item_func.cc b/sql/item_func.cc index 55324923fe2..519b476ccf8 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -4147,6 +4147,41 @@ Item_func_set_user_var::check(bool use_result_field) } +/** + @brief Evaluate and store item's result. + This function is invoked on "SELECT ... INTO @var ...". + + @param item An item to get value from. +*/ + +void Item_func_set_user_var::save_item_result(Item *item) +{ + DBUG_ENTER("Item_func_set_user_var::save_item_result"); + + switch (cached_result_type) { + case REAL_RESULT: + save_result.vreal= item->val_result(); + break; + case INT_RESULT: + save_result.vint= item->val_int_result(); + unsigned_flag= item->unsigned_flag; + break; + case STRING_RESULT: + save_result.vstr= item->str_result(&value); + break; + case DECIMAL_RESULT: + save_result.vdec= item->val_decimal_result(&decimal_buff); + break; + case ROW_RESULT: + default: + // Should never happen + DBUG_ASSERT(0); + break; + } + DBUG_VOID_RETURN; +} + + /* This functions is invoked on SET @variable or @variable:= expression. diff --git a/sql/item_func.h b/sql/item_func.h index 7e15a536cf2..33aeddfe6e6 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1308,6 +1308,7 @@ public: bool send(Protocol *protocol, String *str_arg); void make_field(Send_field *tmp_field); bool check(bool use_result_field); + void save_item_result(Item *item); bool update(); enum Item_result result_type () const { return cached_result_type; } bool fix_fields(THD *thd, Item **ref); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9ff602bb62e..a95003d440b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -2041,7 +2041,7 @@ bool select_dumpvar::send_data(List &items) { Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); suv->fix_fields(thd, 0); - suv->check(0); + suv->save_item_result(item); suv->update(); } }