diff options
author | unknown <mhansson/martin@linux-st28.site> | 2007-12-15 16:45:21 +0100 |
---|---|---|
committer | unknown <mhansson/martin@linux-st28.site> | 2007-12-15 16:45:21 +0100 |
commit | fe28526ba14cfe5ea073c37eda4d351cf723ef69 (patch) | |
tree | 5b483818e9ae3a28bd145f206839388520d4de23 | |
parent | 4f44d701b88fd67db8e868d0c833ede5b54cd6ea (diff) | |
parent | 30b17b997fa7a096b2644a3260cf1106e69f1ccc (diff) | |
download | mariadb-git-fe28526ba14cfe5ea073c37eda4d351cf723ef69.tar.gz |
Merge mhansson@bk-internal:/home/bk/mysql-5.0-opt
into linux-st28.site:/home/martin/mysql/src/bug32798-united/my50-bug32798-united-push
-rw-r--r-- | mysql-test/r/union.result | 42 | ||||
-rw-r--r-- | mysql-test/t/union.test | 57 | ||||
-rw-r--r-- | sql/sql_class.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 37 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 25 |
5 files changed, 150 insertions, 12 deletions
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index c7a6035aab2..bd0c1f31bd7 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -1440,4 +1440,46 @@ UNION SELECT 1,1; ERROR HY000: Incorrect usage of UNION and ORDER BY DROP TABLE t1,t2; +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; End of 5.0 tests diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 0277b01e21a..3bf8e204333 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -921,4 +921,61 @@ SELECT 1,1; DROP TABLE t1,t2; +# 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; + --echo End of 5.0 tests diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 93f5a34d5c6..e36ed0c425f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -931,6 +931,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 --git a/sql/sql_class.h b/sql/sql_class.h index daeb16de7e0..97f2d07b1d3 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1912,6 +1912,7 @@ class select_result :public Sql_alloc { protected: THD *thd; SELECT_LEX_UNIT *unit; + uint nest_level; public: select_result(); virtual ~select_result() {}; @@ -1948,6 +1949,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 @@ -2034,7 +2041,14 @@ class select_export :public select_to_file { bool is_unsafe_field_sep; 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); @@ -2043,7 +2057,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); }; @@ -2461,7 +2483,16 @@ class select_dumpvar :public select_result_interceptor { ha_rows row_count; 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 --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 170ae1b889b..c4aca1df7ec 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -6350,7 +6350,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 @@ -6424,7 +6425,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 @@ -6436,7 +6437,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; } } @@ -9427,12 +9428,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)); |