From c0a9df1aaedc4a44299398b858021d49ccbfd2ea Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Mar 2004 14:43:24 +0100 Subject: [PATCH] correct support for a mix of UNION/UNION ALL in the same query. Bug#1428 --- mysql-test/r/union.result | 10 +++++----- mysql-test/t/union.test | 3 ++- sql/mysql_priv.h | 3 --- sql/sql_derived.cc | 2 +- sql/sql_lex.cc | 4 ++-- sql/sql_lex.h | 2 +- sql/sql_union.cc | 6 +++++- sql/sql_yacc.yy | 16 ++++++++++------ 8 files changed, 26 insertions(+), 20 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 5eb447ab223..c00b2732bd1 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -36,8 +36,6 @@ a b 1 a 2 b 3 c -3 c -3 c 4 d 5 f 6 e @@ -48,8 +46,6 @@ select 0,'#' union select a,b from t1 union all select a,b from t2 union select 1 a 2 b 3 c -3 c -3 c 4 d 5 f 6 e @@ -920,5 +916,9 @@ select * from t1 UNION select * from t1 UNION ALL select * from t1; i 1 1 -1 drop table t1; +select 1 as a union all select 1 union all select 2 union select 1 union all select 2; +a +1 +2 +2 diff --git a/mysql-test/t/union.test b/mysql-test/t/union.test index 06110474992..b744610ce3d 100644 --- a/mysql-test/t/union.test +++ b/mysql-test/t/union.test @@ -493,6 +493,7 @@ create table t1 (i int); insert into t1 values (1); select * from t1 UNION select * from t1; select * from t1 UNION ALL select * from t1; -# The following should return 2 lines select * from t1 UNION select * from t1 UNION ALL select * from t1; drop table t1; +select 1 as a union all select 1 union all select 2 union select 1 union all select 2; + diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 126675a6e46..499739d8d80 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -210,9 +210,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_RELAXED_UNIQUE_CHECKS (1L << 27) #define SELECT_NO_UNLOCK (1L << 28) -/* options for UNION set by the yacc parser (stored in unit->union_option) */ -#define UNION_ALL 1 - /* Bits for different SQL modes modes (including ANSI mode) */ #define MODE_REAL_AS_FLOAT 1 #define MODE_PIPES_AS_CONCAT 2 diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 4bfb8cdfe3c..ea47ca9f71d 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -138,7 +138,7 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, */ if (!(table= create_tmp_table(thd, &derived_result->tmp_table_param, unit->types, (ORDER*) 0, - is_union && !unit->union_option, 1, + is_union && unit->union_distinct, 1, (first_select->options | thd->options | TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 757eb4fdc7d..914834a75bc 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -997,7 +997,7 @@ void st_select_lex_unit::init_query() global_parameters= first_select(); select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; - union_option= 0; + union_distinct= 0; prepared= optimized= executed= 0; item= 0; union_result= 0; @@ -1572,7 +1572,7 @@ void st_select_lex_unit::print(String *str) if (sl != first_select()) { str->append(" union ", 7); - if (union_option & UNION_ALL) + if (!union_distinct) str->append("all ", 4); } if (sl->braces) diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ba8fe0d8792..b9d85a23011 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -335,7 +335,7 @@ public: /* fake SELECT_LEX for union processing */ st_select_lex *fake_select_lex; - uint union_option; + st_select_lex *union_distinct; /* pointer to the last UNION DISTINCT */ void init_query(); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 87f70bcbd3a..3a27e606cff 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -210,7 +210,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, union_result->tmp_table_param.field_count= types.elements; if (!(table= create_tmp_table(thd_arg, &union_result->tmp_table_param, types, - (ORDER*) 0, !union_option, 1, + (ORDER*) 0, union_distinct, 1, (first_select_in_union()->options | thd_arg->options | TMP_TABLE_ALL_COLUMNS), @@ -267,6 +267,8 @@ int st_select_lex_unit::exec() item->reset(); table->file->delete_all_rows(); } + if (union_distinct) // for subselects + table->file->extra(HA_EXTRA_CHANGE_KEY_TO_UNIQUE); for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { ha_rows records_at_start= 0; @@ -317,6 +319,8 @@ int st_select_lex_unit::exec() { records_at_start= table->file->records; sl->join->exec(); + if (sl == union_distinct) + table->file->extra(HA_EXTRA_CHANGE_KEY_TO_DUP); res= sl->join->error; offset_limit_cnt= sl->offset_limit; if (!res && union_result->flush()) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 1fc063a60ee..5987a69819e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -611,7 +611,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); udf_type if_exists opt_local opt_table_options table_options table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct - opt_ignore_leaves fulltext_options spatial_type + opt_ignore_leaves fulltext_options spatial_type union_option %type ULONG_NUM raid_types merge_insert_types @@ -718,7 +718,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan single_multi table_wild_list table_wild_one opt_wild - union_clause union_list union_option + union_clause union_list precision subselect_start opt_and charset subselect_end select_var_list select_var_list_init help opt_len opt_extended_describe @@ -5571,7 +5571,7 @@ union_clause: ; union_list: - UNION_SYM union_option + UNION_SYM union_option { LEX *lex=Lex; if (lex->exchange) @@ -5589,6 +5589,9 @@ union_list: YYABORT; mysql_init_select(lex); lex->current_select->linkage=UNION_TYPE; + if ($2) /* UNION DISTINCT - remember position */ + lex->current_select->master_unit()->union_distinct= + lex->current_select; } select_init {} ; @@ -5630,9 +5633,10 @@ order_or_limit: ; union_option: - /* empty */ {} - | DISTINCT {} - | ALL {Select->master_unit()->union_option|= UNION_ALL;}; + /* empty */ { $$=1; } + | DISTINCT { $$=1; } + | ALL { $$=0; } + ; singlerow_subselect: subselect_start singlerow_subselect_init