From 6ff06df2333d90021cb10a27f9285586908ee542 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 8 May 2002 23:14:40 +0300 Subject: [PATCH] new SELECT_LEX structures used for storing global ORDER BY, global LIMIT & limit counters mysql-test/r/union.result: correct result of union explain command --- mysql-test/r/union.result | 1 - sql/item_sum.cc | 8 +-- sql/mysql_priv.h | 3 +- sql/sql_class.cc | 19 ++++--- sql/sql_class.h | 23 +++++---- sql/sql_delete.cc | 3 +- sql/sql_derived.cc | 24 +++++---- sql/sql_insert.cc | 14 +++--- sql/sql_lex.cc | 6 ++- sql/sql_parse.cc | 55 ++++++++++---------- sql/sql_select.cc | 93 ++++++++++++++++++---------------- sql/sql_select.h | 5 +- sql/sql_union.cc | 102 +++++++++++++++----------------------- sql/sql_update.cc | 13 +++-- sql/sql_yacc.yy | 20 ++++++-- 15 files changed, 208 insertions(+), 181 deletions(-) diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result index 7d914d029af..29b925b6746 100644 --- a/mysql-test/r/union.result +++ b/mysql-test/r/union.result @@ -88,7 +88,6 @@ explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a l table type possible_keys key key_len ref rows Extra t1 ALL NULL NULL NULL NULL 4 t2 ALL NULL NULL NULL NULL 4 Using filesort -t1 ALL NULL NULL NULL NULL 4 (select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2; a b 1 a diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 83bc2272515..ecb908a797b 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -940,6 +940,7 @@ bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables) bool Item_sum_count_distinct::setup(THD *thd) { List list; + SELECT_LEX *select_lex= current_lex->select; /* Create a table with an unique key over all parameters */ for (uint i=0; i < arg_count ; i++) { @@ -961,9 +962,10 @@ bool Item_sum_count_distinct::setup(THD *thd) free_tmp_table(thd, table); tmp_table_param->cleanup(); } - if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, 0, - current_lex->select->options | thd->options))) + if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, + 0, 0, + select_lex->options | thd->options, + (SELECT_LEX_UNIT*) select_lex->master))) return 1; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows table->no_rows=1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a0dad53b4e2..1719fe69b17 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -359,7 +359,8 @@ int setup_order(THD *thd,TABLE_LIST *tables, List &fields, int handle_select(THD *thd, LEX *lex, select_result *result); int mysql_select(THD *thd,TABLE_LIST *tables,List &list,COND *conds, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - ulong select_type,select_result *result); + ulong select_type,select_result *result, + SELECT_LEX_UNIT *unit); int mysql_union(THD *thd, LEX *lex,select_result *result); int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 29cdaa676d6..6be0e46679b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -389,9 +389,9 @@ bool select_send::send_data(List &items) String *packet= &thd->packet; DBUG_ENTER("send_data"); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } packet->length(0); // Reset packet @@ -439,11 +439,12 @@ select_export::~select_export() } int -select_export::prepare(List &list) +select_export::prepare(List &list, SELECT_LEX_UNIT *u) { char path[FN_REFLEN]; uint option=4; bool blob_flag=0; + unit= u; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS option|=1; // Force use of db directory #endif @@ -510,9 +511,9 @@ bool select_export::send_data(List &items) String tmp(buff,sizeof(buff)),*res; tmp.length(0); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } row_count++; @@ -678,9 +679,11 @@ select_dump::~select_dump() } int -select_dump::prepare(List &list __attribute__((unused))) +select_dump::prepare(List &list __attribute__((unused)), + SELECT_LEX_UNIT *u) { uint option=4; + unit= u; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS option|=1; // Force use of db directory #endif @@ -719,9 +722,9 @@ bool select_dump::send_data(List &items) Item *item; DBUG_ENTER("send_data"); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } if (row_count++ > 1) diff --git a/sql/sql_class.h b/sql/sql_class.h index 56a0d6a44df..d4bd65674f1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -382,7 +382,7 @@ public: #endif ulonglong next_insert_id,last_insert_id,current_insert_id, limit_found_rows; - ha_rows select_limit,offset_limit,default_select_limit,cuted_fields, + ha_rows default_select_limit,cuted_fields, max_join_size, sent_row_count, examined_row_count; table_map used_tables; UC *user_connect; @@ -551,10 +551,15 @@ void send_error(NET *net,uint sql_errno=0, const char *err=0); class select_result :public Sql_alloc { protected: THD *thd; + SELECT_LEX_UNIT *unit; public: select_result(); virtual ~select_result() {}; - virtual int prepare(List &list) { return 0; } + virtual int prepare(List &list, SELECT_LEX_UNIT *u) + { + unit= u; + return 0; + } virtual bool send_fields(List &list,uint flag)=0; virtual bool send_data(List &items)=0; virtual void initialize_tables (JOIN *join=0) {} @@ -587,7 +592,7 @@ class select_export :public select_result { public: select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {} ~select_export(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); @@ -606,7 +611,7 @@ public: select_dump(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) { path[0]=0; } ~select_dump(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); @@ -629,7 +634,7 @@ class select_insert :public select_result { info.handle_duplicates=duplic; } ~select_insert(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); @@ -658,7 +663,7 @@ public: create_info(create_info_par), lock(0) {} - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_data(List &values); bool send_eof(); void abort(); @@ -672,7 +677,7 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); @@ -787,7 +792,7 @@ public: multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg, uint num_of_tables); ~multi_delete(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); @@ -816,7 +821,7 @@ public: enum enum_duplicates handle_duplicates, thr_lock_type lock_option_arg, uint num); ~multi_update(); - int prepare(List &list); + int prepare(List &list, SELECT_LEX_UNIT *u); bool send_fields(List &list, uint flag) { return 0; } bool send_data(List &items); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index f5a5a684fc0..2e565a59ca0 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -232,9 +232,10 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, int -multi_delete::prepare(List &values) +multi_delete::prepare(List &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("multi_delete::prepare"); + unit= u; do_delete = true; thd->proc_info="deleting from main table"; diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 79343ef4ae0..41f166c6ad0 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -28,13 +28,13 @@ static const char *any_db="*any*"; // Special symbol for check_access -int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t) +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) { /* TODO: make derived tables with union inside (now only 1 SELECT may be procesed) */ - SELECT_LEX *sl= (SELECT_LEX*)s->slave; + SELECT_LEX *sl= (SELECT_LEX*)unit->slave; List item_list; TABLE *table; int res; @@ -75,9 +75,11 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t) } bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; - if (!(table=create_tmp_table(thd, &tmp_table_param, sl->item_list, - (ORDER*) 0, 0, 1, 0, - (sl->options | thd->options | TMP_TABLE_ALL_COLUMNS)))) + if (!(table= create_tmp_table(thd, &tmp_table_param, sl->item_list, + (ORDER*) 0, 0, 1, 0, + (sl->options | thd->options | + TMP_TABLE_ALL_COLUMNS), + unit))) { res=-1; goto exit; @@ -85,11 +87,11 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t) if ((derived_result=new select_union(table))) { - thd->offset_limit=sl->offset_limit; - thd->select_limit=sl->select_limit+sl->offset_limit; - if (thd->select_limit < sl->select_limit) - thd->select_limit= HA_POS_ERROR; - if (thd->select_limit == HA_POS_ERROR) + unit->offset_limit_cnt= sl->offset_limit; + unit->select_limit_cnt= sl->select_limit+sl->offset_limit; + if (unit->select_limit_cnt < sl->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; + if (unit->select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; res=mysql_select(thd, tables, sl->item_list, @@ -97,7 +99,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t) (ORDER*) sl->group_list.first, sl->having, (ORDER*) NULL, sl->options | thd->options | SELECT_NO_UNLOCK, - derived_result); + derived_result, unit); if (!res) { // Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 69fc7c00955..2e6c009741e 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1266,10 +1266,11 @@ bool delayed_insert::handle_inserts(void) ***************************************************************************/ int -select_insert::prepare(List &values) +select_insert::prepare(List &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("select_insert::prepare"); + unit= u; save_time_stamp=table->time_stamp; if (check_insert_fields(thd,table,*fields,values,1)) DBUG_RETURN(1); @@ -1302,9 +1303,9 @@ select_insert::~select_insert() bool select_insert::send_data(List &values) { - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; return 0; } if (fields->elements) @@ -1380,10 +1381,11 @@ bool select_insert::send_eof() ***************************************************************************/ int -select_create::prepare(List &values) +select_create::prepare(List &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("select_create::prepare"); + unit= u; table=create_table_from_items(thd, create_info, db, name, extra_fields, keys, &values, &lock); if (!table) @@ -1413,9 +1415,9 @@ select_create::prepare(List &values) bool select_create::send_data(List &values) { - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; return 0; } fill_record(field,values); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 3b17c8d498a..bfa06353e30 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -895,14 +895,16 @@ void st_select_lex_node::init_select() order_list.elements= 0; order_list.first= 0; order_list.next= (byte**) &order_list.first; - select_limit= offset_limit= 0; + select_limit= HA_POS_ERROR; + offset_limit= 0; } void st_select_lex_unit::init_query() { st_select_lex_node::init_query(); global_parameters= this; - select_limit_cnt= offset_limit_cnt= 0; + select_limit_cnt= HA_POS_ERROR; + offset_limit_cnt= 0; } void st_select_lex::init_query() diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4d03701e4f8..4313259aaf3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1203,11 +1203,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, void mysql_execute_command(void) { - int res=0; - THD *thd=current_thd; + int res= 0; + THD *thd= current_thd; LEX *lex= &thd->lex; - TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first; - SELECT_LEX *select_lex = lex->select; + TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first; + SELECT_LEX *select_lex= lex->select; + SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_execute_command"); if (thd->slave_thread) @@ -1274,11 +1275,11 @@ mysql_execute_command(void) break; // Error message is given } - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // no limit - if (thd->select_limit == HA_POS_ERROR) + unit->offset_limit_cnt =select_lex->offset_limit; + unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) select_lex->options&= ~OPTION_FOUND_ROWS; if (lex->exchange) @@ -1503,10 +1504,11 @@ mysql_execute_command(void) for (table = tables->next ; table ; table=table->next) table->lock_type= lex->lock_option; } - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // No limit + unit->offset_limit_cnt= select_lex->offset_limit; + unit->select_limit_cnt= select_lex->select_limit+ + select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // No limit /* Skip first table, which is the table we are creating */ lex->select_lex.table_list.first= @@ -1788,13 +1790,13 @@ mysql_execute_command(void) while ((item=value_list++)) total_list.push_back(item); - res=mysql_select(thd,tables,total_list, - select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, - (ORDER *)NULL, - select_lex->options | thd->options | - SELECT_NO_JOIN_CACHE, - result); + res= mysql_select(thd, tables, total_list, + select_lex->where, + (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, + (ORDER *)NULL, + select_lex->options | thd->options | + SELECT_NO_JOIN_CACHE, + result, unit); delete result; } else @@ -1844,10 +1846,10 @@ mysql_execute_command(void) } select_result *result; - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // No limit + unit->offset_limit_cnt= select_lex->offset_limit; + unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // No limit if (check_dup(tables->db, tables->real_name, tables->next)) { @@ -1963,7 +1965,7 @@ mysql_execute_command(void) (ORDER *)NULL, select_lex->options | thd->options | SELECT_NO_JOIN_CACHE, - result); + result, unit); delete result; } else @@ -2667,8 +2669,10 @@ mysql_init_query(THD *thd) { DBUG_ENTER("mysql_init_query"); thd->lex.unit.init_query(); + thd->lex.unit.init_select(); thd->lex.select_lex.init_query(); thd->lex.unit.slave= &thd->lex.select_lex; + thd->lex.unit.select_limit= thd->default_select_limit; //Global limit thd->lex.select_lex.master= &thd->lex.unit; thd->lex.select_lex.prev= &thd->lex.unit.slave; thd->lex.value_list.empty(); @@ -2716,6 +2720,7 @@ mysql_new_select(LEX *lex, bool move_down) else select_lex->include_neighbour(lex->select); + ((SELECT_LEX_UNIT*)select_lex->master)->global_parameters= select_lex; select_lex->include_global(&lex->select->link_next); lex->select= select_lex; return 0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 2599fe216c5..d8d9c854652 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -65,7 +65,8 @@ static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond, static int return_zero_rows(select_result *res,TABLE_LIST *tables, List &fields, bool send_row, uint select_options, const char *info, - Item *having, Procedure *proc); + Item *having, Procedure *proc, + SELECT_LEX_UNIT *unit); static COND *optimize_cond(COND *conds,Item::cond_result *cond_value); static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); @@ -166,7 +167,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result) select_lex->having, (ORDER*) lex->proc_list.first, select_lex->options | thd->options, - result); + result, &(lex->unit)); if (res && result) result->abort(); delete result; @@ -182,7 +183,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result) int mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - ulong select_options,select_result *result) + ulong select_options,select_result *result, + SELECT_LEX_UNIT *unit) { TABLE *tmp_table; int error, tmp_error; @@ -195,8 +197,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, Procedure *procedure; List all_fields(fields); bool select_distinct; - SELECT_LEX *select_lex = &(thd->lex.select_lex); - SELECT_LEX *cur_sel = thd->lex.select; + SELECT_LEX *select_lex= &(thd->lex.select_lex); + SELECT_LEX *cur_sel= thd->lex.select; DBUG_ENTER("mysql_select"); /* Check that all tables, fields, conds and order are ok */ @@ -312,7 +314,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, join.do_send_rows = 1; join.group= group != 0; join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR : - thd->select_limit); + unit->select_limit_cnt); + join.unit= unit; #ifdef RESTRICTED_GROUP if (join.sum_func_count && !group && (join.func_count || join.field_count)) @@ -322,7 +325,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, DBUG_RETURN(-1); } #endif - if (!procedure && result->prepare(fields)) + if (!procedure && result->prepare(fields, unit)) { /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */ } @@ -351,7 +354,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, delete procedure; DBUG_RETURN(0); } - if (cond_value == Item::COND_FALSE || !thd->select_limit) + if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt) { /* Impossible cond */ if (select_options & SELECT_DESCRIBE && select_lex->next) select_describe(&join,false,false,false,"Impossible WHERE"); @@ -359,7 +362,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, error=return_zero_rows(result, tables, fields, join.tmp_table_param.sum_func_count != 0 && !group, select_options,"Impossible WHERE",having, - procedure); + procedure, unit); delete procedure; DBUG_RETURN(error); } @@ -376,8 +379,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, select_describe(&join,false,false,false,"No matching min/max row"); else error=return_zero_rows(result, tables, fields, !group, - select_options,"No matching min/max row", - having,procedure); + select_options, "No matching min/max row", + having, procedure, unit); delete procedure; DBUG_RETURN(error); } @@ -435,9 +438,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (join.const_table_map != join.found_const_table_map && !(select_options & SELECT_DESCRIBE)) { - error=return_zero_rows(result,tables,fields, - join.tmp_table_param.sum_func_count != 0 && - !group,0,"",having,procedure); + error= return_zero_rows(result, tables, fields, + join.tmp_table_param.sum_func_count != 0 && + !group, 0, "", having, procedure, unit); goto err; } if (!(thd->options & OPTION_BIG_SELECTS) && @@ -483,11 +486,12 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (select_options & SELECT_DESCRIBE && select_lex->next) select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables"); else - error=return_zero_rows(result,tables,fields, - join.tmp_table_param.sum_func_count != 0 && !group, - select_options, - "Impossible WHERE noticed after reading const tables", - having,procedure); + error= return_zero_rows(result,tables,fields, + join.tmp_table_param.sum_func_count != 0 && + !group, + select_options, + "Impossible WHERE noticed after reading const tables", + having, procedure, unit); goto err; } @@ -501,12 +505,12 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, select_distinct=0; } else if (select_distinct && join.tables - join.const_tables == 1 && - (thd->select_limit == HA_POS_ERROR || + (unit->select_limit_cnt == HA_POS_ERROR || (join.select_options & OPTION_FOUND_ROWS) || order && !(skip_sort_order= test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,1)))) + order, unit->select_limit_cnt,1)))) { if ((group=create_distinct_group(order,fields))) { @@ -593,7 +597,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, ((group && join.const_tables != join.tables && (!simple_group || !test_if_skip_sort_order(&join.join_tab[join.const_tables], group, - thd->select_limit,0))) || + unit->select_limit_cnt, 0))) || select_distinct) && join.tmp_table_param.quick_group && !procedure) { @@ -610,7 +614,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, test_if_skip_sort_order(&join.join_tab[join.const_tables], order, (join.const_tables != join.tables - 1 || (join.select_options & OPTION_FOUND_ROWS)) ? - HA_POS_ERROR : thd->select_limit,0)))) + HA_POS_ERROR : unit->select_limit_cnt, 0)))) order=0; select_describe(&join,need_tmp, order != 0 && !skip_sort_order, @@ -637,7 +641,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, group && simple_group, (order == 0 || skip_sort_order) && !(join.select_options & OPTION_FOUND_ROWS), - join.select_options))) + join.select_options, unit))) goto err; /* purecov: inspected */ if (having && (join.sort_and_group || (tmp_table->distinct && !group))) @@ -690,7 +694,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (order && skip_sort_order) { (void) test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,0); + order, unit->select_limit_cnt, 0); order=0; } } @@ -760,7 +764,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, (ORDER*) 0, select_distinct && !group, 1, 0, - join.select_options))) + join.select_options, unit))) goto err; /* purecov: inspected */ if (group) { @@ -817,9 +821,9 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, if (procedure) { if (procedure->change_columns(fields) || - result->prepare(fields)) + result->prepare(fields, unit)) goto err; - count_field_types(&join.tmp_table_param,all_fields,0); + count_field_types(&join.tmp_table_param, all_fields, 0); } if (join.group || join.tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) @@ -864,7 +868,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List &fields,COND *conds, (having || group || join.const_tables != join.tables - 1 || (join.select_options & OPTION_FOUND_ROWS)) ? - HA_POS_ERROR : thd->select_limit)) + HA_POS_ERROR : unit->select_limit_cnt)) goto err; /* purecov: inspected */ } join.having=having; // Actually a parameter @@ -2480,7 +2484,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if ((tab->keys & ~ tab->const_keys && i > 0) || (tab->const_keys && i == join->const_tables && - join->thd->select_limit < join->best_positions[i].records_read && + join->unit->select_limit_cnt < + join->best_positions[i].records_read && !(join->select_options & OPTION_FOUND_ROWS))) { /* Join with outer join condition */ @@ -2491,7 +2496,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) (join->select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : - join->thd->select_limit)) < 0) + join->unit->select_limit_cnt)) < 0) DBUG_RETURN(1); // Impossible range sel->cond=orig_cond; } @@ -2929,7 +2934,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order) static int return_zero_rows(select_result *result,TABLE_LIST *tables,List &fields, bool send_row, uint select_options,const char *info, - Item *having, Procedure *procedure) + Item *having, Procedure *procedure, SELECT_LEX_UNIT *unit) { DBUG_ENTER("return_zero_rows"); @@ -2940,7 +2945,7 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List &fields, } if (procedure) { - if (result->prepare(fields)) // This hasn't been done yet + if (result->prepare(fields, unit)) // This hasn't been done yet DBUG_RETURN(-1); } if (send_row) @@ -3475,7 +3480,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options) + bool allow_distinct_limit, ulong select_options, + SELECT_LEX_UNIT *unit) { TABLE *table; uint i,field_count,reclength,null_count,null_pack_length, @@ -3846,8 +3852,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, test(null_pack_length)); if (allow_distinct_limit) { - set_if_smaller(table->max_rows,thd->select_limit); - param->end_write_records=thd->select_limit; + set_if_smaller(table->max_rows, unit->select_limit_cnt); + param->end_write_records= unit->select_limit_cnt; } else param->end_write_records= HA_POS_ERROR; @@ -4892,7 +4898,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), error=join->result->send_data(*join->fields); if (error) DBUG_RETURN(-1); /* purecov: inspected */ - if (++join->send_records >= join->thd->select_limit && join->do_send_rows) + if (++join->send_records >= join->unit->select_limit_cnt && + join->do_send_rows) { if (join->select_options & OPTION_FOUND_ROWS) { @@ -4907,8 +4914,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } else { - join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->do_send_rows= 0; + join->unit->select_limit= HA_POS_ERROR; DBUG_RETURN(0); } } @@ -4969,13 +4976,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), DBUG_RETURN(-1); /* purecov: inspected */ if (end_of_records) DBUG_RETURN(0); - if (!error && ++join->send_records >= join->thd->select_limit && + if (!error && ++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) DBUG_RETURN(-3); // Abort nicely join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->unit->select_limit_cnt = HA_POS_ERROR; } } } @@ -5056,7 +5063,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!(join->select_options & OPTION_FOUND_ROWS)) DBUG_RETURN(-3); join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->unit->select_limit_cnt = HA_POS_ERROR; DBUG_RETURN(0); } } @@ -5755,7 +5762,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List &fields, Item *having) if (!field_count) { // only const items - join->thd->select_limit=1; // Only send first row + join->unit->select_limit_cnt= 1; // Only send first row DBUG_RETURN(0); } Field **first_field=entry->field+entry->fields - field_count; diff --git a/sql/sql_select.h b/sql/sql_select.h index befa1efde53..5466974f587 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -173,6 +173,8 @@ class JOIN { select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; + // unit structure (with global parameters) for this select + SELECT_LEX_UNIT *unit; }; @@ -187,7 +189,8 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options); + bool allow_distinct_limit, ulong select_options, + SELECT_LEX_UNIT *unit); void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List &fields, bool reset_with_sum_func); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 7178b857bbc..2eae37a70eb 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -27,8 +27,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) { - SELECT_LEX *sl, *last_sl, *lex_sl; - ORDER *order; + SELECT_LEX *sl; + SELECT_LEX_UNIT *unit= &(lex->unit); List item_list; TABLE *table; int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; @@ -39,12 +39,12 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) TMP_TABLE_PARAM tmp_table_param; select_union *union_result; DBUG_ENTER("mysql_union"); + st_select_lex_node * global; /* Fix tables 'to-be-unioned-from' list to point at opened tables */ - last_sl= &lex->select_lex; - for (sl= last_sl; - sl && sl->linkage != GLOBAL_OPTIONS_TYPE; - last_sl= sl, sl= (SELECT_LEX *) sl->next) + for (sl= &lex->select_lex; + sl; + sl= (SELECT_LEX *) sl->next) { for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; cursor; @@ -52,31 +52,13 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) cursor->table= ((TABLE_LIST*) cursor->table)->table; } - /* last_sel now points at the last select where the ORDER BY is stored */ - if (sl) + /* Global option */ + if (((void*)(global= unit->global_parameters)) == ((void*)unit)) { - /* - The found SL is an extra SELECT_LEX argument that contains - the ORDER BY and LIMIT parameter for the whole UNION - */ - lex_sl= sl; - order= (ORDER *) lex_sl->order_list.first; - found_rows_for_union = lex->select_lex.options & OPTION_FOUND_ROWS && !describe && sl->select_limit; + found_rows_for_union = lex->select_lex.options & OPTION_FOUND_ROWS && + !describe && global->select_limit; if (found_rows_for_union) lex->select_lex.options ^= OPTION_FOUND_ROWS; -// This is done to eliminate unnecessary slowing down of the first query - if (!order || !describe) - last_sl->next=0; // Remove this extra element - } - else if (!last_sl->braces) - { - lex_sl= last_sl; // ORDER BY is here - order= (ORDER *) lex_sl->order_list.first; - } - else - { - lex_sl=0; - order=0; } if (describe) @@ -113,11 +95,12 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; - if (!(table=create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, !describe & !lex->union_option, - 1, 0, - (lex->select_lex.options | thd->options | - TMP_TABLE_ALL_COLUMNS)))) + if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, + (ORDER*) 0, !describe & !lex->union_option, + 1, 0, + (lex->select_lex.options | thd->options | + TMP_TABLE_ALL_COLUMNS), + unit))) DBUG_RETURN(-1); table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); @@ -136,11 +119,11 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) for (sl= &lex->select_lex; sl; sl= (SELECT_LEX*) sl->next) { lex->select=sl; - thd->offset_limit=sl->offset_limit; - thd->select_limit=sl->select_limit+sl->offset_limit; - if (thd->select_limit < sl->select_limit) - thd->select_limit= HA_POS_ERROR; // no limit - if (thd->select_limit == HA_POS_ERROR) + unit->offset_limit_cnt= sl->offset_limit; + unit->select_limit_cnt= sl->select_limit+sl->offset_limit; + if (unit->select_limit_cnt < sl->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; res= mysql_select(thd, @@ -155,7 +138,7 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) (ORDER*) NULL, sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), - union_result); + union_result, unit); if (res) goto exit; } @@ -187,26 +170,20 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) } if (!thd->fatal_error) // Check if EOM { - if (lex_sl) - { - thd->offset_limit=lex_sl->offset_limit; - thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit; - if (thd->select_limit < lex_sl->select_limit) - thd->select_limit= HA_POS_ERROR; // no limit - if (thd->select_limit == HA_POS_ERROR) - thd->options&= ~OPTION_FOUND_ROWS; - } - else - { - thd->offset_limit= 0; - thd->select_limit= thd->default_select_limit; - } + st_select_lex_node * global= unit->global_parameters; + unit->offset_limit_cnt= global->offset_limit; + unit->select_limit_cnt= global->select_limit+global->offset_limit; + if (unit->select_limit_cnt < global->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + thd->options&= ~OPTION_FOUND_ROWS; if (describe) - thd->select_limit= HA_POS_ERROR; // no limit - res=mysql_select(thd,&result_table_list, - item_list, NULL, (describe) ? 0 : order, - (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result); + unit->select_limit_cnt= HA_POS_ERROR; // no limit + res= mysql_select(thd,&result_table_list, + item_list, NULL, + (describe) ? 0 : (ORDER*)global->order_list.first, + (ORDER*) NULL, NULL, (ORDER*) NULL, + thd->options, result, unit); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; } @@ -230,7 +207,7 @@ select_union::select_union(TABLE *table_par) We can always use DUP_IGNORE because the temporary table will only contain a unique key if we are using not using UNION ALL */ - info.handle_duplicates=DUP_IGNORE; + info.handle_duplicates= DUP_IGNORE; } select_union::~select_union() @@ -238,8 +215,9 @@ select_union::~select_union() } -int select_union::prepare(List &list) +int select_union::prepare(List &list, SELECT_LEX_UNIT *u) { + unit= u; if (save_time_stamp && list.elements != table->fields) { my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, @@ -251,9 +229,9 @@ int select_union::prepare(List &list) bool select_union::send_data(List &values) { - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; return 0; } fill_record(table->field,values); diff --git a/sql/sql_update.cc b/sql/sql_update.cc index db520af61c1..7e3d10ee202 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -379,9 +379,10 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List &fs, } int -multi_update::prepare(List &values) +multi_update::prepare(List &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("multi_update::prepare"); + unit= u; do_update = true; thd->count_cuted_fields=1; thd->cuted_fields=0L; @@ -466,15 +467,19 @@ multi_update::prepare(List &values) } if (counter) { - Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true); + Field_string offset(table_ref->table->file->ref_length, false, + "offset", table_ref->table, true); temp_fields->push_front(new Item_field(((Field *)&offset))); // Here I make tmp tables int cnt=counter-1; TMP_TABLE_PARAM tmp_table_param; bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=temp_fields->elements; - if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, *temp_fields, - (ORDER*) 0, 1, 0, 0, TMP_TABLE_ALL_COLUMNS))) + if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, + *temp_fields, + (ORDER*) 0, 1, 0, 0, + TMP_TABLE_ALL_COLUMNS, + unit))) { error = 1; // A proper error message is due here DBUG_RETURN(1); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f9d075b75b3..bd7a5ff3b48 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1449,7 +1449,14 @@ select: select_init: SELECT_SYM select_part2 { Select->braces=false; } union | - '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt + '(' SELECT_SYM select_part2 ')' + { + SELECT_LEX * sel=Select; + sel->braces=true; + /* select in braces, can't contain global parameters */ + ((SELECT_LEX_UNIT*)sel->master)->global_parameters= + sel->master; + } union_opt select_part2: @@ -3826,10 +3833,15 @@ optional_order_or_limit: | { LEX *lex=Lex; - if (!lex->select->braces || mysql_new_select(lex, 0)) + if (!lex->select->braces) YYABORT; - mysql_init_select(lex); - lex->select->linkage= GLOBAL_OPTIONS_TYPE; + ((SELECT_LEX_UNIT*)lex->select->master)->global_parameters= + lex->select->master; + /* + Following type conversion looks like hack, but all that need SELECT_LEX + fields always check linkage type. + */ + lex->select= (SELECT_LEX*)lex->select->master; lex->select->select_limit=lex->thd->default_select_limit; } opt_order_clause limit_clause