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 4c71e845207..1719fe69b17 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -291,7 +291,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); void mysql_init_select(LEX *lex); -bool mysql_new_select(LEX *lex); +bool mysql_new_select(LEX *lex, bool move_down); void mysql_init_multi_delete(LEX *lex); void init_max_user_conn(void); void free_max_user_conn(void); @@ -359,9 +359,10 @@ 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); -int mysql_union(THD *thd,LEX *lex,select_result *result); -int mysql_derived(THD *thd,LEX *lex,SELECT_LEX *s, TABLE_LIST *t); + 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, Item_result_field ***copy_func, Field **from_field, bool group,bool modify_item); 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 3ffac72c1db..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); @@ -706,19 +711,28 @@ class Table_ident :public Sql_alloc { public: LEX_STRING db; LEX_STRING table; - SELECT_LEX *sel; - inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force) - :table(table_arg), sel((SELECT_LEX *)0) + SELECT_LEX_UNIT *sel; + inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force) + :table(table_arg), sel((SELECT_LEX_UNIT *)0) { if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA)) db.str=0; else db= db_arg; } - inline Table_ident(LEX_STRING table_arg) :table(table_arg), sel((SELECT_LEX *)0) {db.str=0;} - inline Table_ident(SELECT_LEX *s) : sel(s) {db.str=0; table.str=(char *)""; table.length=0;} + inline Table_ident(LEX_STRING table_arg) + :table(table_arg), sel((SELECT_LEX_UNIT *)0) + { + db.str=0; + } + inline Table_ident(SELECT_LEX_UNIT *s) : sel(s) + { + db.str=0; table.str=(char *)""; table.length=0; + } inline void change_db(char *db_name) - { db.str= db_name; db.length=(uint) strlen(db_name); } + { + db.str= db_name; db.length= (uint) strlen(db_name); + } }; // this is needed for user_vars hash @@ -778,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); @@ -807,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 f1b60dd9b84..41f166c6ad0 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -28,21 +28,25 @@ static const char *any_db="*any*"; // Special symbol for check_access -int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t) +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) { - SELECT_LEX *sl=s; + /* + TODO: make derived tables with union inside (now only 1 SELECT may be + procesed) + */ + SELECT_LEX *sl= (SELECT_LEX*)unit->slave; List item_list; TABLE *table; int res; select_union *derived_result; - TABLE_LIST *tables=(TABLE_LIST *)sl->table_list.first; + TABLE_LIST *tables= (TABLE_LIST *)sl->table_list.first; TMP_TABLE_PARAM tmp_table_param; DBUG_ENTER("mysql_derived"); if (tables) - res=check_table_access(thd,SELECT_ACL, tables); + res= check_table_access(thd,SELECT_ACL, tables); else - res=check_access(thd, SELECT_ACL, any_db); + res= check_access(thd, SELECT_ACL, any_db); if (res) DBUG_RETURN(-1); @@ -52,7 +56,7 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t) { if (cursor->derived) { - res=mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor); + res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, cursor); if (res) DBUG_RETURN(res); } } @@ -71,9 +75,11 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *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; @@ -81,11 +87,11 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *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, @@ -93,7 +99,7 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *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 @@ -103,9 +109,8 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t) { t->real_name=table->real_name; t->table=table; - sl->prev->next=sl->next; + sl->exclude(); t->derived=(SELECT_LEX *)0; // just in case ... - if (!sl->next) lex->last_select = sl; } } delete derived_result; 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 31ec6d1cecc..bfa06353e30 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -879,3 +879,120 @@ int yylex(void *arg) } } } + +/* + st_select_lex structures initialisations +*/ + +void st_select_lex_node::init_query() +{ + next= master= slave= link_next= 0; + prev= link_prev= 0; +} + +void st_select_lex_node::init_select() +{ + order_list.elements= 0; + order_list.first= 0; + order_list.next= (byte**) &order_list.first; + 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= HA_POS_ERROR; + offset_limit_cnt= 0; +} + +void st_select_lex::init_query() +{ + st_select_lex_node::init_query(); + table_list.elements= 0; + table_list.first= 0; + table_list.next= (byte**) &table_list.first; + item_list.empty(); +} + +void st_select_lex::init_select() +{ + st_select_lex_node::init_select(); + group_list.elements= 0; + group_list.first= 0; + group_list.next= (byte**) &group_list.first; + options= 0; + where= having= 0; + when_list.empty(); + expr_list.empty(); + interval_list.empty(); + use_index.empty(); + ftfunc_list.empty(); + linkage=UNSPECIFIED_TYPE; +} + +/* + st_select_lex structures linking +*/ + +/* include on level down */ +void st_select_lex_node::include_down(st_select_lex_node *upper) +{ + if ((next= upper->slave)) + next->prev= &next; + prev= &upper->slave; + upper->slave= this; + master= upper; +} + +/* include neighbour (on same level) */ +void st_select_lex_node::include_neighbour(st_select_lex_node *before) +{ + if ((next= before->next)) + next->prev= &next; + prev= &before->next; + before->next= this; + master= before->master; +} + +/* including in global SELECT_LEX list */ +void st_select_lex_node::include_global(st_select_lex_node **plink) +{ + if ((link_next= *plink)) + link_next->link_prev= &link_next; + link_prev= plink; + *plink= this; +} + +//excluding from global list (internal function) +void st_select_lex_node::fast_exclude() +{ + if(link_prev) + { + if ((*link_prev= link_next)) + link_next->link_prev= link_prev; + // Remove slave structure + for (; slave; slave= slave->next) + slave->fast_exclude(); + } +} + +/* + excluding select_lex structure (except first (first select can't be + deleted, because it is most upper select)) +*/ +void st_select_lex_node::exclude() +{ + //exclude from global list + fast_exclude(); + //exclude from other structures + if ((*prev= next)) + next->prev= prev; + /* + We do not need following statements, because prev pointer of first + list element point to master->slave + if (master->slave == this) + master->slave= next; + */ +} diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 53422b050a3..7603157f66d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -103,28 +103,143 @@ typedef struct st_lex_master_info } LEX_MASTER_INFO; -enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT, DERIVED_TABLE_TYPE}; +enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, + EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE}; -/* The state of the lex parsing for selects */ +/* + The state of the lex parsing for selects + + All select describing structures linked with following pointers: + - list of neighbors (next/prev) (prev of first element point to slave + pointer of upper structure) + - one level units for unit (union) structure + - member of one union(unit) for ordinary select_lex + - pointer to master + - outer select_lex for unit (union) + - unit structure for ordinary select_lex + - pointer to slave + - first list element of select_lex belonged to this unit for unit + - first unit in list of units that belong to this select_lex (as + subselects or derived tables) for ordinary select_lex + - list of all select_lex (for group operation like correcting list of opened + tables) + for example for following query: -typedef struct st_select_lex { + select * + from table1 + where table1.field IN (select * from table1_1_1 union + select * from table1_1_2) + union + select * + from table2 + where table2.field=(select (select f1 from table2_1_1_1_1 + where table2_1_1_1_1.f2=table2_1_1.f3) + from table2_1_1 + where table2_1_1.f1=table2.f2) + union + select * from table3; + + we will have following structure: + + + main unit + select1 select2 select3 + |^^ |^ + s||| ||master + l||| |+---------------------------------+ + a||| +---------------------------------+| + v|||master slave || + e||+-------------------------+ || + V| neighbor | V| + unit 1.1<==================>unit1.2 unit2.1 + select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2 + |^ + || + V| + unit2.1.1.1 + select2.1.1.1.1 + + + relation in main unit will be following: + + main unit + |^^^ + |||| + |||+------------------------------+ + ||+--------------+ | + slave||master | | + V| neighbor | neighbor | + select1<========>select2<========>select3 + + list of all select_lex will be following (as it will be constructed by + parser): + + select1->select2->select3->select2.1.1->select 2.1.2->select2.1.1.1.1-+ + | + +---------------------------------------------------------------------+ + | + +->select1.1.1->select1.1.2 + +*/ + +/* + Base class for st_select_lex (SELECT_LEX) & + st_select_lex_unit (SELECT_LEX_UNIT) +*/ +struct st_select_lex_node { enum sub_select_type linkage; - char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */ - Item *where,*having; - ha_rows select_limit,offset_limit; + st_select_lex_node *next, **prev, /* neighbor list */ + *master, *slave, /* vertical links */ + *link_next, **link_prev; /* list of whole SELECT_LEX */ + SQL_LIST order_list; /* ORDER clause */ + ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ + void init_query(); + void init_select(); + void include_down(st_select_lex_node *upper); + void include_neighbour(st_select_lex_node *before); + void include_global(st_select_lex_node **plink); + void exclude(); +private: + void fast_exclude(); +}; + +/* + SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group + SELECT_LEXs +*/ +struct st_select_lex_unit: public st_select_lex_node { + /* + Pointer to 'last' select or pointer to unit where stored + global parameters for union + */ + st_select_lex_node *global_parameters; + /* LIMIT clause runtime counters */ + ha_rows select_limit_cnt, offset_limit_cnt; + void init_query(); +}; +typedef struct st_select_lex_unit SELECT_LEX_UNIT; + +/* + SELECT_LEX - store information of parsed SELECT_LEX statment +*/ +struct st_select_lex: public st_select_lex_node { + char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ + Item *where, *having; /* WHERE & HAVING clauses */ ulong options; List expr_list; - List when_list; - SQL_LIST order_list,table_list,group_list; - List item_list; - List interval_list,use_index, *use_index_ptr, + List when_list; /* WHEN clause */ + SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ + List item_list; /* list of fields & expressions */ + List interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; List ftfunc_list; uint in_sum_expr, sort_default; - bool create_refs, braces; - st_select_lex *next, *prev; -} SELECT_LEX; - + bool create_refs, + braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ + void init_query(); + void init_select(); +}; +typedef struct st_select_lex SELECT_LEX; class Set_option :public Sql_alloc { public: @@ -137,13 +252,15 @@ public: :name(par_name), item(par_item), name_length(length), type(par_type) {} }; - /* The state of the lex parsing. This is saved in the THD struct */ typedef struct st_lex { uint yylineno,yytoklen; /* Simulate lex */ LEX_YYSTYPE yylval; - SELECT_LEX select_lex, *select, *last_select; + SELECT_LEX_UNIT unit; /* most upper unit */ + SELECT_LEX select_lex, /* first SELECT_LEX */ + /* current SELECT_LEX in parsing */ + *select; uchar *ptr,*tok_start,*tok_end,*end_of_query; char *length,*dec,*change,*name; char *backup_dir; /* For RESTORE/BACKUP */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 06431124356..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) @@ -1240,8 +1241,10 @@ mysql_execute_command(void) { for (TABLE_LIST *cursor= tables; cursor; - cursor=cursor->next) - if (cursor->derived && mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor)) + cursor= cursor->next) + if (cursor->derived && mysql_derived(thd, lex, + (SELECT_LEX_UNIT *)cursor->derived, + cursor)) DBUG_VOID_RETURN; } if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) || @@ -1272,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) @@ -1501,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= @@ -1786,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 @@ -1842,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)) { @@ -1961,7 +1965,7 @@ mysql_execute_command(void) (ORDER *)NULL, select_lex->options | thd->options | SELECT_NO_JOIN_CACHE, - result); + result, unit); delete result; } else @@ -2664,18 +2668,21 @@ static void mysql_init_query(THD *thd) { DBUG_ENTER("mysql_init_query"); - thd->lex.select_lex.item_list.empty(); + 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(); - thd->lex.select_lex.table_list.elements=0; - thd->free_list=0; thd->lex.union_option=0; - thd->lex.select = thd->lex.last_select = &thd->lex.select_lex; - thd->lex.select_lex.table_list.first=0; - thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first; - thd->lex.select_lex.next=0; - thd->fatal_error=0; // Safety - thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; - thd->sent_row_count=thd->examined_row_count=0; - thd->safe_to_cache_query=1; + thd->free_list= 0; + thd->lex.union_option= 0; + thd->lex.select= &thd->lex.select_lex; + thd->fatal_error= 0; // Safety + thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; + thd->sent_row_count= thd->examined_row_count= 0; + thd->safe_to_cache_query= 1; DBUG_VOID_RETURN; } @@ -2683,53 +2690,53 @@ void mysql_init_select(LEX *lex) { SELECT_LEX *select_lex = lex->select; - select_lex->where=select_lex->having=0; + select_lex->init_select(); select_lex->select_limit=lex->thd->default_select_limit; select_lex->offset_limit=0; - select_lex->options=0; - select_lex->linkage=UNSPECIFIED_TYPE; lex->exchange = 0; lex->proc_list.first=0; - select_lex->order_list.elements=select_lex->group_list.elements=0; - select_lex->order_list.first=0; - select_lex->order_list.next= (byte**) &select_lex->order_list.first; - select_lex->group_list.first=0; - select_lex->group_list.next= (byte**) &select_lex->group_list.first; - select_lex->next = select_lex->prev = (SELECT_LEX *)NULL; } bool -mysql_new_select(LEX *lex) +mysql_new_select(LEX *lex, bool move_down) { SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX)); if (!select_lex) return 1; - lex->select=lex->last_select; - lex->select->next=select_lex; - lex->select=lex->last_select=select_lex; - select_lex->table_list.next= (byte**) &select_lex->table_list.first; - select_lex->item_list.empty(); - select_lex->when_list.empty(); - select_lex->expr_list.empty(); - select_lex->interval_list.empty(); - select_lex->use_index.empty(); - select_lex->ftfunc_list.empty(); + select_lex->init_query(); + select_lex->init_select(); + if (move_down) + { + /* first select_lex of subselect or derived table */ + SELECT_LEX_UNIT *unit= + (SELECT_LEX_UNIT *) lex->thd->calloc(sizeof(SELECT_LEX_UNIT)); + if (!unit) + return 1; + unit->init_query(); + unit->init_select(); + unit->include_down(lex->select); + select_lex->include_down(unit); + } + 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; } void mysql_init_multi_delete(LEX *lex) { - lex->sql_command = SQLCOM_DELETE_MULTI; + lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); - lex->select->select_limit=HA_POS_ERROR; - lex->auxilliary_table_list=lex->select_lex.table_list; - lex->select->table_list.elements=0; - lex->select->table_list.first=0; - lex->select->table_list.next= (byte**) &(lex->select->table_list.first); + lex->select->select_limit= HA_POS_ERROR; + lex->auxilliary_table_list= lex->select_lex.table_list; + lex->select->init_query(); } void -mysql_parse(THD *thd,char *inBuf,uint length) +mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); @@ -3159,7 +3166,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, ptr->real_name_length=table->table.length; ptr->lock_type=flags; ptr->updating=updating; - ptr->derived=(SELECT_LEX *)table->sel; + ptr->derived= (SELECT_LEX_UNIT *) table->sel; if (use_index) ptr->use_index=(List *) thd->memdup((gptr) use_index, sizeof(*use_index)); @@ -3204,8 +3211,8 @@ static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result) SELECT_LEX *sl; TABLE_LIST **new_table_list= result, *aux; - *new_table_list=0; // end result list - for (sl= &lex->select_lex; sl; sl=sl->next) + *new_table_list= 0; // end result list + for (sl= &lex->select_lex; sl; sl= (SELECT_LEX *) sl->next) { if (sl->order_list.first && sl->next && !sl->braces) { 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 c8237f3ae9b..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 != NOT_A_SELECT; - last_sl=sl, sl=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); @@ -133,25 +116,29 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) } union_result->save_time_stamp=!describe; - for (sl= &lex->select_lex; sl; sl=sl->next) + 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, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first, - sl->item_list, - sl->where, - (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), - union_result); + res= mysql_select(thd, + (describe && sl->linkage==GLOBAL_OPTIONS_TYPE) ? + first_table : (TABLE_LIST*) sl->table_list.first, + sl->item_list, + sl->where, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl->options | thd->options | + SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), + union_result, unit); if (res) goto exit; } @@ -183,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; } @@ -226,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() @@ -234,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, @@ -247,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 24321dbdb53..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: @@ -2155,23 +2162,22 @@ join_table: | '(' SELECT_SYM select_part3 ')' opt_table_alias { LEX *lex=Lex; - SELECT_LEX *select_to_execute= lex->select; - lex->select=lex->select->prev; - if (!($$=add_table_to_list(new Table_ident(select_to_execute), - $5,0,TL_UNLOCK))) + SELECT_LEX_UNIT *unit= (SELECT_LEX_UNIT*) lex->select->master; + lex->select= (SELECT_LEX*) unit->master; + if (!($$= add_table_to_list(new Table_ident(unit), + $5,0,TL_UNLOCK))) YYABORT; } select_part3: { - LEX *lex=Lex; - lex->derived_tables=true; - SELECT_LEX *tmp=lex->select; - if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex)) + LEX *lex= Lex; + lex->derived_tables= true; + if (lex->select->linkage == GLOBAL_OPTIONS_TYPE || + mysql_new_select(lex, 1)) YYABORT; mysql_init_select(lex); - lex->select->linkage=DERIVED_TABLE_TYPE; - lex->select->prev=tmp; + lex->select->linkage= DERIVED_TABLE_TYPE; } select_options select_item_list select_intoto @@ -3811,7 +3817,8 @@ union_list: net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO"); YYABORT; } - if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex)) + if (lex->select->linkage == GLOBAL_OPTIONS_TYPE || + mysql_new_select(lex, 0)) YYABORT; lex->select->linkage=UNION_TYPE; } @@ -3826,10 +3833,15 @@ optional_order_or_limit: | { LEX *lex=Lex; - if (!lex->select->braces || mysql_new_select(lex)) + if (!lex->select->braces) YYABORT; - mysql_init_select(lex); - lex->select->linkage=NOT_A_SELECT; + ((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 diff --git a/sql/table.h b/sql/table.h index 59cb28038bf..e30e29ddd3f 100644 --- a/sql/table.h +++ b/sql/table.h @@ -139,18 +139,18 @@ typedef struct st_table_list { struct st_table_list *next; char *db,*name,*real_name; uint32 db_length, real_name_length; - Item *on_expr; /* Used with outer join */ - struct st_table_list *natural_join; /* natural join on this table*/ + Item *on_expr; /* Used with outer join */ + struct st_table_list *natural_join; /* natural join on this table*/ /* ... join ... USE INDEX ... IGNORE INDEX */ - List *use_index,*ignore_index; + List *use_index, *ignore_index; TABLE *table; GRANT_INFO grant; thr_lock_type lock_type; - uint outer_join; /* Which join type */ - bool straight; /* optimize with prev table */ - bool updating; /* for replicate-do/ignore table */ - bool shared; /* Used twice in union */ - void *derived; + uint outer_join; /* Which join type */ + bool straight; /* optimize with prev table */ + bool updating; /* for replicate-do/ignore table */ + bool shared; /* Used twice in union */ + void *derived; /* SELECT_LEX_UNIT of derived table */ } TABLE_LIST; typedef struct st_changed_table_list {