diff options
author | unknown <bell@sanja.is.com.ua> | 2002-05-07 00:04:16 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2002-05-07 00:04:16 +0300 |
commit | 2c62a868a60058a8664dcf3e45cdd86b41635ddd (patch) | |
tree | 28f6bf8b6eba7559f3589a4655aa64349d0b84cc | |
parent | 234dc3a35e8ae7f63aa6d3b7891b72e735728639 (diff) | |
download | mariadb-git-2c62a868a60058a8664dcf3e45cdd86b41635ddd.tar.gz |
new SELECT_LEX structure
mysql-test/r/derived.result:
derived table bug test
mysql-test/t/derived.test:
derived table bug test
sql/mysql_priv.h:
new mysql_new_select call & layout fixing
sql/sql_class.h:
passing unit as parameter of Table_ident constructor
sql/sql_lex.cc:
new SELECT_LEX structure methods
sql/sql_lex.h:
new SELECT_LEX structure definition
sql/table.h:
fixed layout
-rw-r--r-- | mysql-test/r/derived.result | 10 | ||||
-rw-r--r-- | mysql-test/t/derived.test | 7 | ||||
-rw-r--r-- | sql/mysql_priv.h | 6 | ||||
-rw-r--r-- | sql/sql_class.h | 21 | ||||
-rw-r--r-- | sql/sql_derived.cc | 19 | ||||
-rw-r--r-- | sql/sql_lex.cc | 115 | ||||
-rw-r--r-- | sql/sql_lex.h | 149 | ||||
-rw-r--r-- | sql/sql_parse.cc | 88 | ||||
-rw-r--r-- | sql/sql_union.cc | 28 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 24 | ||||
-rw-r--r-- | sql/table.h | 16 |
11 files changed, 372 insertions, 111 deletions
diff --git a/mysql-test/r/derived.result b/mysql-test/r/derived.result index 5a41a51463e..822993a7bf2 100644 --- a/mysql-test/r/derived.result +++ b/mysql-test/r/derived.result @@ -1,4 +1,4 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); @@ -7,4 +7,10 @@ select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a a y 3 3 3 3 -drop table if exists t1.t2; +CREATE TABLE t3 (a int not null, b char (10) not null); +insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); +select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; +a y +3 3 +3 3 +drop table if exists t1.t2,t3; diff --git a/mysql-test/t/derived.test b/mysql-test/t/derived.test index 4a3e8e86d4a..c5f57007e54 100644 --- a/mysql-test/t/derived.test +++ b/mysql-test/t/derived.test @@ -1,7 +1,10 @@ -drop table if exists t1,t2; +drop table if exists t1,t2,t3; CREATE TABLE t1 (a int not null, b char (10) not null); insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c'); CREATE TABLE t2 (a int not null, b char (10) not null); insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e'); select t1.a,t3.y from t1,(select a as y from t2 where b='c') as t3 where t1.a = t3.y; -drop table if exists t1.t2;
\ No newline at end of file +CREATE TABLE t3 (a int not null, b char (10) not null); +insert into t3 values (3,'f'),(4,'y'),(5,'z'),(6,'c'); +select t1.a,t4.y from t1,(select t2.a as y from t2,(select t3.b from t3 where t3.a>3) as t5 where t2.b=t5.b) as t4 where t1.a = t4.y; +drop table if exists t1.t2,t3; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 4c71e845207..a0dad53b4e2 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); @@ -360,8 +360,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result); int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &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); +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.h b/sql/sql_class.h index 3ffac72c1db..56a0d6a44df 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -706,19 +706,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 diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index f1b60dd9b84..79343ef4ae0 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 *s, 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*)s->slave; List<Item> 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); } } @@ -103,9 +107,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_lex.cc b/sql/sql_lex.cc index 31ec6d1cecc..3b17c8d498a 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -879,3 +879,118 @@ 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= 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; +} + +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<List_item> expr_list; - List<List_item> when_list; - SQL_LIST order_list,table_list,group_list; - List<Item> item_list; - List<String> interval_list,use_index, *use_index_ptr, + List<List_item> when_list; /* WHEN clause */ + SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ + List<Item> item_list; /* list of fields & expressions */ + List<String> interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; List<Item_func_match> 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..4d03701e4f8 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1240,8 +1240,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)) || @@ -2664,18 +2666,19 @@ 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.select_lex.init_query(); + thd->lex.unit.slave= &thd->lex.select_lex; + 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 +2686,52 @@ 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->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 +3161,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<String> *) thd->memdup((gptr) use_index, sizeof(*use_index)); @@ -3204,8 +3206,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_union.cc b/sql/sql_union.cc index c8237f3ae9b..7178b857bbc 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -43,8 +43,8 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) /* 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) + sl && sl->linkage != GLOBAL_OPTIONS_TYPE; + last_sl= sl, sl= (SELECT_LEX *) sl->next) { for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; cursor; @@ -133,7 +133,7 @@ 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; @@ -143,15 +143,19 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) if (thd->select_limit == 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); if (res) goto exit; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 6317b21a603..f9d075b75b3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2155,21 +2155,22 @@ join_table: | '(' SELECT_SYM select_part3 ')' opt_table_alias { LEX *lex=Lex; - lex->select=lex->select->prev; - if (!($$=add_table_to_list(new Table_ident(Lex->last_select),$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 @@ -3809,7 +3810,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; } @@ -3824,10 +3826,10 @@ optional_order_or_limit: | { LEX *lex=Lex; - if (!lex->select->braces || mysql_new_select(lex)) + if (!lex->select->braces || mysql_new_select(lex, 0)) YYABORT; mysql_init_select(lex); - lex->select->linkage=NOT_A_SELECT; + lex->select->linkage= GLOBAL_OPTIONS_TYPE; 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<String> *use_index,*ignore_index; + List<String> *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 { |