summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <mhansson/martin@linux-st28.site>2007-12-15 16:45:21 +0100
committerunknown <mhansson/martin@linux-st28.site>2007-12-15 16:45:21 +0100
commitfe28526ba14cfe5ea073c37eda4d351cf723ef69 (patch)
tree5b483818e9ae3a28bd145f206839388520d4de23
parent4f44d701b88fd67db8e868d0c833ede5b54cd6ea (diff)
parent30b17b997fa7a096b2644a3260cf1106e69f1ccc (diff)
downloadmariadb-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.result42
-rw-r--r--mysql-test/t/union.test57
-rw-r--r--sql/sql_class.cc1
-rw-r--r--sql/sql_class.h37
-rw-r--r--sql/sql_yacc.yy25
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));