MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:kgeorge Date:May 13 2008 3:10pm
Subject:bk commit into 5.1 tree (gkodinov:1.2632) BUG#32858
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of gkodinov.  When gkodinov does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-05-13 18:10:46+03:00, gkodinov@stripped +5 -0
  Bug #32858: Erro: "Incorrect usage of UNION and INTO" does not take 
  subselects into account
    
  It is forbidden to use the SELECT INTO construction inside UNION statements
  unless on the last SELECT of the union. The parser records whether it 
  has seen INTO or not when parsing a UNION statement. But if the INTO was
  legally used in an outer query, an error is thrown if UNION is seen in a
  subquery. Fixed in 5.0 by remembering the nesting level of INTO tokens and 
  mitigate the error unless it collides with the UNION.

  mysql-test/r/union.result@stripped, 2008-05-13 18:10:45+03:00, gkodinov@stripped +42 -0
    Bug#32858: Test result

  mysql-test/t/union.test@stripped, 2008-05-13 18:10:45+03:00, gkodinov@stripped +59 -0
    Bug#32858: Test case

  sql/sql_class.cc@stripped, 2008-05-13 18:10:45+03:00, gkodinov@stripped +1 -0
    Bug#32858: Initializing new member

  sql/sql_class.h@stripped, 2008-05-13 18:10:45+03:00, gkodinov@stripped +34 -0
    Bug#32858: Added property nest_level to select_result class.

  sql/sql_yacc.yy@stripped, 2008-05-13 18:10:45+03:00, gkodinov@stripped +16 -9
    Bug#32858: The fix.

diff -Nrup a/mysql-test/r/union.result b/mysql-test/r/union.result
--- a/mysql-test/r/union.result	2008-01-10 12:46:31 +02:00
+++ b/mysql-test/r/union.result	2008-05-13 18:10:45 +03:00
@@ -153,6 +153,48 @@ ERROR 42S22: Unknown column 'a' in 'fiel
 1	3
 1	3
 2	1
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+SELECT a INTO @v FROM (
+SELECT a FROM t1
+UNION
+SELECT a FROM t1
+) alias;
+SELECT a INTO OUTFILE 'union.out.file' FROM (
+SELECT a FROM t1
+UNION
+SELECT a FROM t1 WHERE 0
+) alias;
+SELECT a INTO DUMPFILE 'union.out.file2' FROM (
+SELECT a FROM t1
+UNION
+SELECT a FROM t1 WHERE 0
+) alias;
+SELECT a FROM (
+SELECT a FROM t1
+UNION
+SELECT a INTO @v FROM t1
+) alias;
+SELECT a FROM (
+SELECT a FROM t1
+UNION
+SELECT a INTO OUTFILE 'union.out.file3' FROM t1
+) alias;
+SELECT a FROM (
+SELECT a FROM t1
+UNION
+SELECT a INTO DUMPFILE 'union.out.file4' FROM t1
+) alias;
+SELECT a FROM t1 UNION SELECT a INTO @v FROM t1;
+SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file5' FROM t1;
+SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file6' FROM t1;
+SELECT a INTO @v FROM t1 UNION SELECT a FROM t1;
+ERROR HY000: Incorrect usage of UNION and INTO
+SELECT a INTO OUTFILE 'union.out.file7' FROM t1 UNION SELECT a FROM t1;
+ERROR HY000: Incorrect usage of UNION and INTO
+SELECT a INTO DUMPFILE 'union.out.file8' FROM t1 UNION SELECT a FROM t1;
+ERROR HY000: Incorrect usage of UNION and INTO
+DROP TABLE t1;
 CREATE TABLE t1 (
 `pseudo` char(35) NOT NULL default '',
 `pseudo1` char(35) NOT NULL default '',
diff -Nrup a/mysql-test/t/union.test b/mysql-test/t/union.test
--- a/mysql-test/t/union.test	2008-01-10 12:46:31 +02:00
+++ b/mysql-test/t/union.test	2008-05-13 18:10:45 +03:00
@@ -91,6 +91,65 @@ SELECT @a:=1 UNION SELECT @a:=@a+1;
 (SELECT 1) UNION (SELECT 2) ORDER BY (SELECT a);
 (SELECT 1,3) UNION (SELECT 2,1) ORDER BY (SELECT 2);
 
+
+#
+# Bug#32858: Erro: "Incorrect usage of UNION and INTO" does not take subselects 
+# into account
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (1);
+
+SELECT a INTO @v FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a FROM t1
+) alias;
+
+SELECT a INTO OUTFILE 'union.out.file' FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a FROM t1 WHERE 0
+) alias;
+
+SELECT a INTO DUMPFILE 'union.out.file2' FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a FROM t1 WHERE 0
+) alias;
+
+#
+# INTO will not be allowed in subqueries in version 5.1 and above.
+#
+SELECT a FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a INTO @v FROM t1
+) alias;
+
+SELECT a FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a INTO OUTFILE 'union.out.file3' FROM t1
+) alias;
+
+SELECT a FROM (
+  SELECT a FROM t1
+  UNION
+  SELECT a INTO DUMPFILE 'union.out.file4' FROM t1
+) alias;
+
+SELECT a FROM t1 UNION SELECT a INTO @v FROM t1;
+SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file5' FROM t1;
+SELECT a FROM t1 UNION SELECT a INTO OUTFILE 'union.out.file6' FROM t1;
+--error ER_WRONG_USAGE
+SELECT a INTO @v FROM t1 UNION SELECT a FROM t1;
+--error ER_WRONG_USAGE
+SELECT a INTO OUTFILE 'union.out.file7' FROM t1 UNION SELECT a FROM t1;
+--error ER_WRONG_USAGE
+SELECT a INTO DUMPFILE 'union.out.file8' FROM t1 UNION SELECT a FROM t1;
+
+DROP TABLE t1;
+
 #
 # Test bug reported by joc@stripped
 #
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc	2008-03-30 14:12:23 +03:00
+++ b/sql/sql_class.cc	2008-05-13 18:10:45 +03:00
@@ -1430,6 +1430,7 @@ void THD::rollback_item_tree_changes()
 select_result::select_result()
 {
   thd=current_thd;
+  nest_level= -1;
 }
 
 void select_result::send_error(uint errcode,const char *err)
diff -Nrup a/sql/sql_class.h b/sql/sql_class.h
--- a/sql/sql_class.h	2008-03-26 15:40:39 +02:00
+++ b/sql/sql_class.h	2008-05-13 18:10:45 +03:00
@@ -2193,6 +2193,7 @@ class select_result :public Sql_alloc {
 protected:
   THD *thd;
   SELECT_LEX_UNIT *unit;
+  uint nest_level;
 public:
   select_result();
   virtual ~select_result() {};
@@ -2229,6 +2230,12 @@ public:
   */
   virtual void cleanup();
   void set_thd(THD *thd_arg) { thd= thd_arg; }
+  /**
+     The nest level, if supported. 
+     @return
+     -1 if nest level is undefined, otherwise a positive integer.
+   */
+  int get_nest_level() { return nest_level; }
 #ifdef EMBEDDED_LIBRARY
   virtual void begin_dataset() {}
 #else
@@ -2322,6 +2329,14 @@ class select_export :public select_to_fi
   bool fixed_row_size;
 public:
   select_export(sql_exchange *ex) :select_to_file(ex) {}
+  /**
+     Creates a select_export to represent INTO OUTFILE <filename> with a
+     defined level of subquery nesting.
+   */
+  select_export(sql_exchange *ex, uint nest_level_arg) :select_to_file(ex) 
+  {
+    nest_level= nest_level_arg;
+  }
   ~select_export();
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
@@ -2331,6 +2346,15 @@ public:
 class select_dump :public select_to_file {
 public:
   select_dump(sql_exchange *ex) :select_to_file(ex) {}
+  /**
+     Creates a select_export to represent INTO DUMPFILE <filename> with a
+     defined level of subquery nesting.
+   */  
+  select_dump(sql_exchange *ex, uint nest_level_arg) : 
+    select_to_file(ex) 
+  {
+    nest_level= nest_level_arg;
+  }
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
 };
@@ -2763,6 +2787,16 @@ class select_dumpvar :public select_resu
 public:
   List<my_var> var_list;
   select_dumpvar()  { var_list.empty(); row_count= 0;}
+  /**
+     Creates a select_dumpvar to represent INTO <variable> with a defined 
+     level of subquery nesting.
+   */
+  select_dumpvar(uint nest_level_arg)
+  {
+    var_list.empty();
+    row_count= 0;
+    nest_level= nest_level_arg;
+  }
   ~select_dumpvar() {}
   int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
   bool send_data(List<Item> &items);
diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
--- a/sql/sql_yacc.yy	2008-05-09 10:43:00 +03:00
+++ b/sql/sql_yacc.yy	2008-05-13 18:10:45 +03:00
@@ -8380,7 +8380,8 @@ procedure_item:
 select_var_list_init:
           {
             LEX *lex=Lex;
-            if (!lex->describe && (!(lex->result= new select_dumpvar())))
+            if (!lex->describe && 
+                  (!(lex->result= new select_dumpvar(lex->nest_level))))
               MYSQL_YYABORT;
           }
           select_var_list
@@ -8454,7 +8455,7 @@ into_destination:
             LEX *lex= Lex;
             lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
             if (!(lex->exchange= new sql_exchange($2.str, 0)) ||
-                !(lex->result= new select_export(lex->exchange)))
+                !(lex->result= new select_export(lex->exchange, lex->nest_level)))
               MYSQL_YYABORT;
           }
           opt_field_term opt_line_term
@@ -8466,7 +8467,7 @@ into_destination:
               lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
               if (!(lex->exchange= new sql_exchange($2.str,1)))
                 MYSQL_YYABORT;
-              if (!(lex->result= new select_dump(lex->exchange)))
+              if (!(lex->result= new select_dump(lex->exchange, lex->nest_level)))
                 MYSQL_YYABORT;
             }
           }
@@ -11804,12 +11805,18 @@ union_list:
           UNION_SYM union_option
           {
             LEX *lex=Lex;
-            if (lex->result)
-            {
-              /* Only the last SELECT can have  INTO...... */
-              my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
-              MYSQL_YYABORT;
-            }
+            if (lex->result && 
+               (lex->result->get_nest_level() == -1 ||
+                lex->result->get_nest_level() == lex->nest_level))
+              {
+                /* 
+                   Only the last SELECT can have INTO unless the INTO and UNION
+                   are at different nest levels. In version 5.1 and above, INTO
+                   will onle be allowed at top level.
+                */
+                my_error(ER_WRONG_USAGE, MYF(0), "UNION", "INTO");
+                MYSQL_YYABORT;
+              }
             if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE)
             {
               my_parse_error(ER(ER_SYNTAX_ERROR));
Thread
bk commit into 5.1 tree (gkodinov:1.2632) BUG#32858kgeorge13 May