diff options
-rw-r--r-- | mysql-test/r/subselect.result | 55 | ||||
-rw-r--r-- | mysql-test/t/subselect.test | 34 | ||||
-rw-r--r-- | sql/item.cc | 87 | ||||
-rw-r--r-- | sql/item.h | 52 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 31 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 8 | ||||
-rw-r--r-- | sql/item_func.cc | 17 | ||||
-rw-r--r-- | sql/item_func.h | 6 | ||||
-rw-r--r-- | sql/item_row.cc | 12 | ||||
-rw-r--r-- | sql/item_row.h | 3 | ||||
-rw-r--r-- | sql/item_strfunc.h | 13 | ||||
-rw-r--r-- | sql/item_subselect.cc | 473 | ||||
-rw-r--r-- | sql/item_subselect.h | 37 | ||||
-rw-r--r-- | sql/item_sum.cc | 6 | ||||
-rw-r--r-- | sql/mysql_priv.h | 21 | ||||
-rw-r--r-- | sql/sql_base.cc | 13 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_derived.cc | 5 | ||||
-rw-r--r-- | sql/sql_lex.cc | 160 | ||||
-rw-r--r-- | sql/sql_lex.h | 115 | ||||
-rw-r--r-- | sql/sql_olap.cc | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 34 | ||||
-rw-r--r-- | sql/sql_select.cc | 41 | ||||
-rw-r--r-- | sql/sql_select.h | 81 | ||||
-rw-r--r-- | sql/sql_union.cc | 153 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 107 | ||||
-rw-r--r-- | sql/table.h | 11 |
27 files changed, 938 insertions, 642 deletions
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result index 41fba93db5b..38a0e1341c0 100644 --- a/mysql-test/r/subselect.result +++ b/mysql-test/r/subselect.result @@ -46,7 +46,7 @@ SELECT 1 FROM (SELECT 1 as a) as b HAVING (SELECT a)=1; 1 1 SELECT (SELECT 1), a; -ERROR 42S22: Unknown column 'a' in 'field list' +ERROR 42S22: Unknown column 'a' in 'checking transformed subquery' SELECT 1 as a FROM (SELECT 1) as b HAVING (SELECT a)=1; a 1 @@ -677,7 +677,6 @@ id EXPLAIN SELECT * FROM t2 WHERE id IN (SELECT 1+(select 1)); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ref id id 5 const 1 Using where; Using index -3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: Note 1247 Select 3 was reduced during optimisation Note 1247 Select 2 was reduced during optimisation @@ -1025,7 +1024,7 @@ CREATE TABLE t1 SELECT (SELECT 1 as a UNION SELECT 1+1 limit 1,1) as a; SHOW CREATE TABLE t1; Table Create Table t1 CREATE TABLE `t1` ( - `a` bigint(1) NOT NULL default '0' + `a` bigint(17) NOT NULL default '0' ) TYPE=MyISAM CHARSET=latin1 drop table t1; create table t1 (a int); @@ -1213,6 +1212,56 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1.PARENTID='2f6161e879db43c1a5b82c21ddc49089' AND t1.FOLDERNAME = 'Level1') 0 drop table t1; +create table t1 (a int not null, b int, primary key (a)); +create table t2 (a int not null, primary key (a)); +create table t3 (a int not null, b int, primary key (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +a +2 +3 +4 +explain select * from t2 where t2.a in (select a from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index +2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where; Using index +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +a +2 +3 +explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL PRIMARY 4 NULL 4 Using where; Using index +2 DEPENDENT SUBQUERY t1 eq_ref PRIMARY PRIMARY 4 func 1 Using where +2 DEPENDENT SUBQUERY t3 eq_ref PRIMARY PRIMARY 4 test.t1.b 1 Using where; Using index +drop table t1, t2, t3; +create table t1 (a int, b int, index a (a)); +create table t2 (a int, index a (a)); +create table t3 (a int, b int, index a (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +a +2 +3 +4 +explain select * from t2 where t2.a in (select a from t1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index +2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where; Using index +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +a +2 +3 +explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 index NULL a 5 NULL 4 Using where; Using index +2 DEPENDENT SUBQUERY t1 ref a a 5 func 10 Using where +2 DEPENDENT SUBQUERY t3 index a a 5 NULL 3 Using where; Using index +drop table t1, t2, t3; create table t1 (a int, b int); create table t2 (a int, b int); create table t3 (a int, b int); diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test index 1d7da94d455..4c124d431da 100644 --- a/mysql-test/t/subselect.test +++ b/mysql-test/t/subselect.test @@ -809,6 +809,40 @@ SELECT 'c373e9f5ad0791a0dab5444553544200' IN(SELECT t1.FOLDERID FROM t1 WHERE t1 drop table t1; # +# IN subselect optimization test +# +create table t1 (a int not null, b int, primary key (a)); +create table t2 (a int not null, primary key (a)); +create table t3 (a int not null, b int, primary key (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +explain select * from t2 where t2.a in (select a from t1); +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +drop table t1, t2, t3; +create table t1 (a int, b int, index a (a)); +create table t2 (a int, index a (a)); +create table t3 (a int, b int, index a (a)); +insert into t1 values (1,10), (2,20), (3,30), (4,40); +disable_query_log; +# making table large enough +let $1 = 10000; +while ($1) + { + eval insert into t1 values (rand()*100000+200,rand()*100000); + dec $1; + } +enable_query_log; +insert into t2 values (2), (3), (4), (5); +insert into t3 values (10,3), (20,4), (30,5); +select * from t2 where t2.a in (select a from t1); +explain select * from t2 where t2.a in (select a from t1); +select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +explain select * from t2 where t2.a in (select t1.a from t1,t3 where t1.b=t3.a); +drop table t1, t2, t3; +# # alloc_group_fields() working # create table t1 (a int, b int); diff --git a/sql/item.cc b/sql/item.cc index 17b0519b61c..58c47025a6f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -23,8 +23,7 @@ #include <m_ctype.h> #include "my_dir.h" -static void mark_as_dependent(bool outer_resolving, - SELECT_LEX *last, SELECT_LEX_NODE *current, +static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current, Item_ident *item); /***************************************************************************** @@ -95,6 +94,15 @@ Item_ident::Item_ident(THD *thd, Item_ident &item): depended_from(item.depended_from) {} +bool Item_ident::remove_dependence_processor(byte * arg) +{ + DBUG_ENTER("Item_ident::remove_dependence_processor"); + if (depended_from == (st_select_lex *) arg) + depended_from= 0; + DBUG_RETURN(1); +} + + bool Item::check_cols(uint c) { if (c != 1) @@ -810,28 +818,17 @@ bool Item_ref_null_helper::get_date(TIME *ltime, bool fuzzydate) SYNOPSIS mark_as_dependent() - outer_resolving - flag of outer resolving last - select from which current item depend current - current select item - item which should be marked */ -static void mark_as_dependent(bool outer_resolving, - SELECT_LEX *last, SELECT_LEX_NODE *current, +static void mark_as_dependent(SELECT_LEX *last, SELECT_LEX *current, Item_ident *item) { - /* - only last check is need, i.e. - "last != current" - first check added for speed up (check boolean should be faster - then comparing pointers and this condition usually true) - */ - if (!outer_resolving || ((SELECT_LEX_NODE *)last) != current) - { - // store pointer on SELECT_LEX from wich item is dependent - item->depended_from= last; - current->mark_as_dependent(last); - } + // store pointer on SELECT_LEX from wich item is dependent + item->depended_from= last; + current->mark_as_dependent(last); } @@ -841,8 +838,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { TABLE_LIST *where= 0; Field *tmp= (Field *)not_found_field; - if (outer_resolving || - (tmp= find_field_in_tables(thd, this, tables, &where, 0)) == + if ((tmp= find_field_in_tables(thd, this, tables, &where, 0)) == not_found_field) { /* @@ -863,9 +859,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) uint counter; // Prevent using outer fields in subselects, that is not supported now SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select; - if (outer_resolving || - cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE) - for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select()); + if (cursel->master_unit()->first_select()->linkage != DERIVED_TABLE_TYPE) + for (SELECT_LEX *sl= cursel->outer_select(); sl; sl= sl->outer_select()) { @@ -916,12 +911,12 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) if (rf->fix_fields(thd, tables, ref) || rf->check_cols(1)) return 1; - mark_as_dependent(outer_resolving, last, cursel, rf); + mark_as_dependent(last, cursel, rf); return 0; } else { - mark_as_dependent(outer_resolving, last, cursel, this); + mark_as_dependent(last, cursel, this); if (last->having_fix_field) { Item_ref *rf; @@ -930,7 +925,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) (char *)field_name); if (!rf) return 1; - (rf)->outer_resolving= outer_resolving; return rf->fix_fields(thd, tables, ref) || rf->check_cols(1); } } @@ -1325,16 +1319,13 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) if (!ref) { TABLE_LIST *where= 0, *table_list; - SELECT_LEX *sl= (outer_resolving? - thd->lex.current_select->select_lex(): - thd->lex.current_select->outer_select()); + SELECT_LEX *sl= thd->lex.current_select->outer_select(); /* Finding only in current select will be performed for selects that have not outer one and for derived tables (which not support using outer fields for now) */ - if (outer_resolving || - (ref= find_item_in_list(this, + if ((ref= find_item_in_list(this, *(thd->lex.current_select->get_item_list()), &counter, ((sl && @@ -1400,7 +1391,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) Item_field* fld; if (!((*reference)= fld= new Item_field(tmp))) return 1; - mark_as_dependent(outer_resolving, last, thd->lex.current_select, fld); + mark_as_dependent(last, thd->lex.current_select, fld); return 0; } else @@ -1411,7 +1402,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) "forward reference in item list"); return -1; } - mark_as_dependent(outer_resolving, last, thd->lex.current_select, + mark_as_dependent(last, thd->lex.current_select, this); ref= last->ref_pointer_array + counter; } @@ -1430,19 +1421,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) } } -/* - * The following conditional is changed as to correctly identify - * incorrect references in group functions or forward references - * with sub-select's / derived tables, while it prevents this - * check when Item_ref is created in an expression involving - * summing function, which is to be placed in the user variable. - * - */ - + /* + The following conditional is changed as to correctly identify + incorrect references in group functions or forward references + with sub-select's / derived tables, while it prevents this + check when Item_ref is created in an expression involving + summing function, which is to be placed in the user variable. + */ if (((*ref)->with_sum_func && name && - (depended_from || + (depended_from || !(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE && - thd->lex.current_select->select_lex()->having_fix_field))) || + thd->lex.current_select->having_fix_field))) || !(*ref)->fixed) { my_error(ER_ILLEGAL_REFERENCE, MYF(0), name, @@ -1687,11 +1676,11 @@ Item_cache* Item_cache::get_cache(Item_result type) void Item_cache_str::store(Item *item) { - str_value.set(buffer, sizeof(buffer), item->collation.collation); - value= item->str_result(&str_value); + value_buff.set(buffer, sizeof(buffer), item->collation.collation); + value= item->str_result(&value_buff); if ((null_value= item->null_value)) value= 0; - else if (value != &str_value) + else if (value != &value_buff) { /* We copy string value to avoid changing value if 'item' is table field @@ -1701,10 +1690,10 @@ void Item_cache_str::store(Item *item) (select c from t1 where a=t2.a) from t2; */ - str_value.copy(*value); - value= &str_value; + value_buff.copy(*value); + value= &value_buff; } - + set_charset(&item->collation); } double Item_cache_str::val() { diff --git a/sql/item.h b/sql/item.h index 621dc017d25..82c61466200 100644 --- a/sql/item.h +++ b/sql/item.h @@ -82,6 +82,8 @@ public: } }; +typedef bool (Item::*Item_processor)(byte *arg); + class Item { Item(const Item &); /* Prevent use of these */ void operator=(Item &); @@ -158,7 +160,7 @@ public: virtual bool get_time(TIME *ltime); virtual bool get_date_result(TIME *ltime,bool fuzzydate) { return get_date(ltime,fuzzydate); } - virtual bool is_null() { return 0; }; + virtual bool is_null() { return 0; } virtual void top_level_item() {} virtual void set_result_field(Field *field) {} virtual bool is_result_field() { return 0; } @@ -169,8 +171,14 @@ public: virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); } CHARSET_INFO *default_charset() const; - virtual void set_outer_resolving() {} + virtual bool walk(Item_processor processor, byte *arg) + { + return (this->*processor)(arg); + } + + virtual bool remove_dependence_processor(byte * arg) { return 0; } + // Row emulation virtual uint cols() { return 1; } virtual Item* el(uint i) { return this; } @@ -191,16 +199,16 @@ public: const char *table_name; const char *field_name; st_select_lex *depended_from; - bool outer_resolving; /* used for items from reduced subselect */ Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) :db_name(db_name_par), table_name(table_name_par), - field_name(field_name_par), depended_from(0), outer_resolving(0) + field_name(field_name_par), depended_from(0) { name = (char*) field_name_par; } // Constructor used by Item_field & Item_ref (see Item comment) Item_ident(THD *thd, Item_ident &item); const char *full_name() const; - void set_outer_resolving() { outer_resolving= 1; } + + bool remove_dependence_processor(byte * arg); }; @@ -607,6 +615,15 @@ public: longlong val_int(); String* val_str(String* s); bool get_date(TIME *ltime, bool fuzzydate); + void print(String *str) + { + str->append("ref_null_helper("); + if (ref && *ref) + (*ref)->print(str); + else + str->append('?'); + str->append(')'); + } }; @@ -652,6 +669,15 @@ public: {} bool fix_fields(THD *, struct st_table_list *, Item ** ref); Item **storage() {return &item;} + void print(String *str) + { + str->append("ref_null_helper('"); + if (item) + item->print(str); + else + str->append('?'); + str->append(')'); + } }; /* @@ -788,7 +814,6 @@ public: enum Type type() const { return DEFAULT_VALUE_ITEM; } bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, struct st_table_list *, Item **); - void set_outer_resolving() { arg->set_outer_resolving(); } void print(String *str); virtual bool basic_const_item() const { return true; } int save_in_field(Field *field, bool no_conversions) @@ -801,6 +826,12 @@ public: return Item_field::save_in_field(field, no_conversions); } table_map used_tables() const { return (table_map)0L; } + + bool walk(Item_processor processor, byte *args) + { + return arg->walk(processor, args) || + (this->*processor)(args); + } }; class Item_insert_value : public Item_field @@ -811,7 +842,6 @@ public: Item_field((const char *)NULL, (const char *)NULL, (const char *)NULL), arg(a) {} bool eq(const Item *item, bool binary_cmp) const; bool fix_fields(THD *, struct st_table_list *, Item **); - void set_outer_resolving() { arg->set_outer_resolving(); } void print(String *str); virtual bool basic_const_item() const { return true; } int save_in_field(Field *field, bool no_conversions) @@ -819,6 +849,12 @@ public: return Item_field::save_in_field(field, no_conversions); } table_map used_tables() const { return (table_map)0L; } + + bool walk(Item_processor processor, byte *args) + { + return arg->walk(processor, args) || + (this->*processor)(args); + } }; class Item_cache: public Item @@ -883,7 +919,7 @@ public: class Item_cache_str: public Item_cache { char buffer[80]; - String *value; + String *value, value_buff; public: Item_cache_str(): Item_cache() { } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 7d8da16338b..c78e032c943 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -373,16 +373,24 @@ int Arg_comparator::compare_e_row() return 1; } -bool Item_in_optimizer::preallocate_row() + +bool Item_in_optimizer::fix_left(THD *thd, + struct st_table_list *tables, + Item **ref) { - return (!(cache= Item_cache::get_cache(ROW_RESULT))); + if (args[0]->fix_fields(thd, tables, ref) || + (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))) + return 1; + cache->setup(args[0]); + return 0; } + bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, Item ** ref) { - if (args[0]->fix_fields(thd, tables, args)) + if (fix_left(thd, tables, ref)) return 1; if (args[0]->maybe_null) maybe_null=1; @@ -390,9 +398,6 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, with_sum_func= args[0]->with_sum_func; used_tables_cache= args[0]->used_tables(); const_item_cache= args[0]->const_item(); - if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))) - return 1; - cache->setup(args[0]); if (cache->cols() == 1) { if (args[0]->used_tables()) @@ -411,7 +416,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, ((Item_cache *)cache->el(i))->set_used_tables(0); } } - if (args[1]->fix_fields(thd, tables, args)) + if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args)) return 1; Item_in_subselect * sub= (Item_in_subselect *)args[1]; if (args[0]->cols() != sub->engine->cols()) @@ -1554,7 +1559,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) } if (abort_on_null) item->top_level_item(); - if (item->fix_fields(thd, tables, li.ref()) || item->check_cols(1)) + if ((!item->fixed && + item->fix_fields(thd, tables, li.ref())) || item->check_cols(1)) return 1; /* purecov: inspected */ used_tables_cache|=item->used_tables(); with_sum_func= with_sum_func || item->with_sum_func; @@ -1569,13 +1575,14 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; } -void Item_cond::set_outer_resolving() +bool Item_cond::walk(Item_processor processor, byte *arg) { - Item_func::set_outer_resolving(); - List_iterator<Item> li(list); + List_iterator_fast<Item> li(list); Item *item; while ((item= li++)) - item->set_outer_resolving(); + if (item->walk(processor, arg)) + return 1; + return Item_func::walk(processor, arg); } void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields) diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 25cc97d60bf..42ece007a54 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -93,9 +93,8 @@ protected: public: Item_in_optimizer(Item *a, Item_in_subselect *b): Item_bool_func(a, (Item *)b), cache(0) {} - // used by row in transformer - bool preallocate_row(); bool fix_fields(THD *, struct st_table_list *, Item **); + bool fix_left(THD *thd, struct st_table_list *tables, Item **ref); bool is_null(); /* Item_in_optimizer item is special boolean function. On value request @@ -105,7 +104,7 @@ public: Item_in_optimizer return NULL, else it evaluate Item_in_subselect. */ longlong val_int(); - + const char *func_name() const { return "IN_OPTIMIZER"; } Item_cache **get_cache() { return &cache; } }; @@ -790,7 +789,8 @@ public: void split_sum_func(Item **ref_pointer_array, List<Item> &fields); friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); void top_level_item() { abort_on_null=1; } - void set_outer_resolving(); + + bool walk(Item_processor processor, byte *arg); }; diff --git a/sql/item_func.cc b/sql/item_func.cc index a7c5b35b8db..660b623987c 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -198,14 +198,18 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) return 0; } -void Item_func::set_outer_resolving() +bool Item_func::walk (Item_processor processor, byte *argument) { if (arg_count) { Item **arg,**arg_end; for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) - (*arg)->set_outer_resolving(); + { + if ((*arg)->walk(processor, argument)) + return 1; + } } + return (this->*processor)(argument); } void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields) @@ -2524,13 +2528,14 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) return 0; } -void Item_func_match::set_outer_resolving() +bool Item_func_match::walk(Item_processor processor, byte *arg) { - Item_real_func::set_outer_resolving(); - List_iterator<Item> li(fields); + List_iterator_fast<Item> li(fields); Item *item; while ((item= li++)) - item->set_outer_resolving(); + if (item->walk(processor, arg)) + return 1; + return Item_func::walk(processor, arg); } bool Item_func_match::fix_index() diff --git a/sql/item_func.h b/sql/item_func.h index 56ee0379cd5..e55313c6ad0 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -134,11 +134,12 @@ public: friend class udf_handler; Field *tmp_table_field() { return result_field; } Field *tmp_table_field(TABLE *t_arg); - void set_outer_resolving(); Item *get_tmp_table_item(THD *thd); bool agg_arg_collations(DTCollation &c, Item **items, uint nitems); bool agg_arg_collations_for_comparison(DTCollation &c, Item **items, uint nitems); + + bool walk(Item_processor processor, byte *arg); }; @@ -1011,7 +1012,8 @@ public: bool fix_index(); void init_search(bool no_order); - void set_outer_resolving(); + + bool walk(Item_processor processor, byte *arg); }; diff --git a/sql/item_row.cc b/sql/item_row.cc index cf745e21e45..43e38763aa6 100644 --- a/sql/item_row.cc +++ b/sql/item_row.cc @@ -118,14 +118,18 @@ bool Item_row::check_cols(uint c) return 0; } -void Item_row::bring_value() +bool Item_row::walk(Item_processor processor, byte *arg) { for (uint i= 0; i < arg_count; i++) - items[i]->bring_value(); + { + if (items[i]->walk(processor, arg)) + return 1; + } + return (this->*processor)(arg); } -void Item_row::set_outer_resolving() +void Item_row::bring_value() { for (uint i= 0; i < arg_count; i++) - items[i]->set_outer_resolving(); + items[i]->bring_value(); } diff --git a/sql/item_row.h b/sql/item_row.h index 4f674d8a561..6dd955ed426 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -68,7 +68,8 @@ public: bool const_item() const { return const_item_cache; }; enum Item_result result_type() const { return ROW_RESULT; } void update_used_tables(); - void set_outer_resolving(); + + bool walk(Item_processor processor, byte *arg); uint cols() { return arg_count; } Item* el(uint i) { return items[i]; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index dfcc22b3443..f64a145b136 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -107,10 +107,10 @@ public: } void split_sum_func(Item **ref_pointer_array, List<Item> &fields); const char *func_name() const { return "concat_ws"; } - void set_outer_resolving() + bool walk(Item_processor processor, byte *arg) { - separator->set_outer_resolving(); - Item_func::set_outer_resolving(); + return separator->walk(processor, arg) || + Item_str_func::walk(processor, arg); } }; @@ -399,10 +399,11 @@ public: void fix_length_and_dec(); void update_used_tables(); const char *func_name() const { return "make_set"; } - void set_outer_resolving() + + bool walk(Item_processor processor, byte *arg) { - item->set_outer_resolving(); - Item_str_func::set_outer_resolving(); + return item->walk(processor, arg) || + Item_str_func::walk(processor, arg); } }; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 32edaaca0fd..de6ba791a97 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -20,9 +20,6 @@ SUBSELECT TODO: - add function from mysql_select that use JOIN* as parameter to JOIN methods (sql_select.h/sql_select.cc) - - remove double 'having' & 'having_list' from JOIN - (sql_select.h/sql_select.cc) - */ #ifdef __GNUC__ @@ -56,7 +53,6 @@ void Item_subselect::init(THD *thd, st_select_lex *select_lex, DBUG_ENTER("Item_subselect::init"); DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); - select_transformer(thd, select_lex->master_unit()); if (select_lex->next_select()) engine= new subselect_union_engine(thd, select_lex->master_unit(), result, this); @@ -72,10 +68,11 @@ Item_subselect::~Item_subselect() delete engine; } -void Item_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) +Item_subselect::trans_res +Item_subselect::select_transformer(JOIN *join) { DBUG_ENTER("Item_subselect::select_transformer"); - DBUG_VOID_RETURN; + DBUG_RETURN(OK); } @@ -83,27 +80,28 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) { thd= thd_param; - if (substitution) - { - (*ref)= substitution; - substitution->name= name; - if (have_to_be_excluded) - engine->exclude(); - substitution= 0; - int ret= (*ref)->fix_fields(thd, tables, ref); - // We can't substitute aggregate functions (like (SELECT (max(i))) - if ((*ref)->with_sum_func) - { - my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0)); - return 1; - } - return ret; - } - char const *save_where= thd->where; int res= engine->prepare(); if (!res) { + if (substitution) + { + (*ref)= substitution; + substitution->name= name; + if (have_to_be_excluded) + engine->exclude(); + substitution= 0; + fixed= 1; + thd->where= "checking transformed subquery"; + int ret= (*ref)->fix_fields(thd, tables, ref); + // We can't substitute aggregate functions (like (SELECT (max(i))) + if ((*ref)->with_sum_func) + { + my_error(ER_INVALID_GROUP_FUNC_USE, MYF(0)); + return 1; + } + return ret; + } // Is it one field subselect? if (engine->cols() > max_columns) { @@ -166,12 +164,13 @@ void Item_singlerow_subselect::reset() value->null_value= 1; } -void Item_singlerow_subselect::select_transformer(THD *thd, - st_select_lex_unit *unit) +Item_subselect::trans_res +Item_singlerow_subselect::select_transformer(JOIN *join) { - SELECT_LEX *select_lex= unit->first_select(); + SELECT_LEX *select_lex= join->select_lex; - if (!select_lex->next_select() && !select_lex->table_list.elements && + if (!select_lex->master_unit()->first_select()->next_select() && + !select_lex->table_list.elements && select_lex->item_list.elements == 1 && /* We cant change name of Item_field or Item_ref, because it will @@ -186,31 +185,37 @@ void Item_singlerow_subselect::select_transformer(THD *thd, { have_to_be_excluded= 1; - if (thd->lex.describe) + if (join->thd->lex.describe) { char warn_buff[MYSQL_ERRMSG_SIZE]; sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + push_warning(join->thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SELECT_REDUCED, warn_buff); } substitution= select_lex->item_list.head(); - substitution->set_outer_resolving(); - + /* + as far as we moved content to upper leven, field which depend of + 'upper' select is not really dependent => we remove this dependence + */ + substitution->walk(&Item::remove_dependence_processor, + (byte *) select_lex->outer_select()); if (select_lex->where || select_lex->having) { Item *cond; - if (!select_lex->having) - cond= select_lex->where; - else if (!select_lex->where) - cond= select_lex->having; + if (!join->having) + cond= join->conds; + else if (!join->conds) + cond= join->having; else - if (!(cond= new Item_cond_and(select_lex->having, select_lex->where))) - return; + if (!(cond= new Item_cond_and(join->conds, join->having))) + return ERROR; if (!(substitution= new Item_func_if(cond, substitution, new Item_null()))) - return; + return ERROR; } + return REDUCE; } + return OK; } void Item_singlerow_subselect::store(uint i, Item *item) @@ -329,6 +334,21 @@ Item_exists_subselect::Item_exists_subselect(THD *thd, DBUG_VOID_RETURN; } +bool Item_in_subselect::test_limit(SELECT_LEX_UNIT *unit) +{ + if (unit->fake_select_lex && + unit->fake_select_lex->test_limit()) + return(1); + + SELECT_LEX *sl= unit->first_select(); + for (; sl; sl= sl->next_select()) + { + if (sl->test_limit()) + return(1); + } + return(0); +} + Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, st_select_lex *select_lex): Item_exists_subselect() @@ -338,25 +358,27 @@ Item_in_subselect::Item_in_subselect(THD *thd, Item * left_exp, init(thd, select_lex, new select_exists_subselect(this)); max_columns= UINT_MAX; maybe_null= 1; + abort_on_null= 0; reset(); - // We need only 1 row to determinate existence - select_lex->master_unit()->global_parameters->select_limit= 1; + //if test_limit will fail then error will be reported to client + test_limit(select_lex->master_unit()); DBUG_VOID_RETURN; } Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp, - compare_func_creator f, + compare_func_creator fn, st_select_lex *select_lex): Item_in_subselect() { DBUG_ENTER("Item_in_subselect::Item_in_subselect"); left_expr= left_exp; - func= f; + func= fn; init(thd, select_lex, new select_exists_subselect(this)); max_columns= 1; + abort_on_null= 0; reset(); - // We need only 1 row to determinate existence - select_lex->master_unit()->global_parameters->select_limit= 1; + //if test_limit will fail then error will be reported to client + test_limit(select_lex->master_unit()); DBUG_VOID_RETURN; } @@ -446,6 +468,7 @@ Item_in_subselect::Item_in_subselect(Item_in_subselect *item): Item_exists_subselect(item) { left_expr= item->left_expr; + abort_on_null= item->abort_on_null; } Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item): @@ -454,227 +477,257 @@ Item_allany_subselect::Item_allany_subselect(Item_allany_subselect *item): func= item->func; } -void Item_in_subselect::single_value_transformer(THD *thd, - st_select_lex_unit *unit, - Item *left_expr, - compare_func_creator func) +Item_subselect::trans_res +Item_in_subselect::single_value_transformer(JOIN *join, + Item *left_expr, + compare_func_creator func) { DBUG_ENTER("Item_in_subselect::single_value_transformer"); - if (unit->global_parameters->select_limit != HA_POS_ERROR) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "LIMIT & IN/ALL/ANY/SOME subquery"); - DBUG_VOID_RETURN; - } - // no sense in ORDER BY without LIMIT - unit->global_parameters->order_list.empty(); + SELECT_LEX *select_lex= join->select_lex; - Item_in_optimizer *optimizer; - substitution= optimizer= new Item_in_optimizer(left_expr, this); - if (!optimizer) - DBUG_VOID_RETURN; + THD *thd= join->thd; + thd->where= "scalar IN/ALL/ANY subquery"; - /* - As far as Item_ref_in_optimizer do not substitude itself on fix_fields - we can use same item for all selects. - */ - Item *expr= new Item_ref((Item**)optimizer->get_cache(), - (char *)"<no matter>", - (char*)"<left expr>"); - unit->dependent= 1; - for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select()) + if (!substitution) { - if (sl->select_limit != HA_POS_ERROR) - { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "LIMIT & IN/ALL/ANY/SOME subquery"); - DBUG_VOID_RETURN; - } + //first call for this unit + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + substitution= optimizer= new Item_in_optimizer(left_expr, this); - sl->dependent= 1; - Item *item; - if (sl->item_list.elements > 1) + SELECT_LEX *current= thd->lex.current_select, *up; + + thd->lex.current_select= up= current->return_after_parsing(); + //optimizer never use Item **ref => we can pass 0 as parameter + if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { - my_error(ER_CARDINALITY_COL, MYF(0), 1); - DBUG_VOID_RETURN; + thd->lex.current_select= current; + DBUG_RETURN(ERROR); } - else - item= (Item*) sl->item_list.pop(); + thd->lex.current_select= current; - sl->order_list.empty(); // no sense in ORDER BY without LIMIT + /* + As far as Item_ref_in_optimizer do not substitude itself on fix_fields + we can use same item for all selects. + */ + expr= new Item_ref((Item**)optimizer->get_cache(), + (char *)"<no matter>", + (char *)"<left expr>"); + + unit->dependent= 1; + } - if (sl->having || sl->with_sum_func || sl->group_list.elements) + select_lex->dependent= 1; + Item *item; + if (select_lex->item_list.elements > 1) + { + my_error(ER_CARDINALITY_COL, MYF(0), 1); + DBUG_RETURN(ERROR); + } + + item= (Item*) select_lex->item_list.head(); + + if (join->having || select_lex->with_sum_func || + select_lex->group_list.elements) + { + item= (*func)(expr, + new Item_ref_null_helper(this, + select_lex->ref_pointer_array, + (char *)"<ref>", + this->full_name())); + join->having= and_items(join->having, item); + select_lex->having_fix_field= 1; + if (join->having->fix_fields(thd, join->tables_list, &join->having)) { - sl->item_list.push_back(item); - setup_ref_array(thd, &sl->ref_pointer_array, - 1 + sl->select_n_having_items + - sl->order_list.elements + sl->group_list.elements); - // To prevent crash on Item_ref_null_helper destruction in case of error - sl->ref_pointer_array[0]= 0; - item= (*func)(expr, new Item_ref_null_helper(this, - sl->ref_pointer_array, - (char *)"<ref>", - this->full_name())); - sl->having= and_items(sl->having, item); + select_lex->having_fix_field= 0; + DBUG_RETURN(ERROR); } - else + select_lex->having_fix_field= 0; + } + else + { + select_lex->item_list.empty(); + select_lex->item_list.push_back(new Item_int("Not_used", + (longlong) 1, 21)); + select_lex->ref_pointer_array[0]= select_lex->item_list.head(); + if (select_lex->table_list.elements) { - sl->item_list.empty(); - sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21)); - if (sl->table_list.elements) + Item *having= item, *isnull= item; + if (item->type() == Item::FIELD_ITEM && + ((Item_field*) item)->field_name[0] == '*') { - Item *having= item, *isnull= item; - if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field_name[0] == '*') + Item_asterisk_remover *remover; + item= remover= new Item_asterisk_remover(this, item, + (char *)"<no matter>", + (char *)"<result>"); + if (!abort_on_null) { - Item_asterisk_remover *remover; - item= remover= new Item_asterisk_remover(this, item, - (char*)"<no matter>", - (char*)"<result>"); having= new Item_is_not_null_test(this, new Item_ref(remover->storage(), - (char*)"<no matter>", - (char*)"<null test>")); + (char *)"<no matter>", + (char *)"<null test>")); isnull= new Item_is_not_null_test(this, new Item_ref(remover->storage(), - (char*)"<no matter>", - (char*)"<null test>")); + (char *)"<no matter>", + (char *)"<null test>")); } - having= new Item_is_not_null_test(this, having); - sl->having= (sl->having ? - new Item_cond_and(having, sl->having) : - having); - item= new Item_cond_or((*func)(expr, item), - new Item_func_isnull(isnull)); - sl->where= and_items(sl->where, item); } - else + item= (*func)(expr, item); + if (!abort_on_null) { - if (item->type() == Item::FIELD_ITEM && - ((Item_field*) item)->field_name[0] == '*') + having= new Item_is_not_null_test(this, having); + join->having= (join->having ? + new Item_cond_and(having, join->having) : + having); + select_lex->having_fix_field= 1; + if (join->having->fix_fields(thd, join->tables_list, &join->having)) { - my_error(ER_NO_TABLES_USED, MYF(0)); - DBUG_VOID_RETURN; + select_lex->having_fix_field= 0; + DBUG_RETURN(ERROR); } - if (unit->first_select()->next_select()) - { - /* - It is in union => we should perform it. - Item_asterisk_remover used only as wrapper to receine NULL value - */ - sl->having= (*func)(expr, + select_lex->having_fix_field= 0; + item= new Item_cond_or(item, + new Item_func_isnull(isnull)); + } + join->conds= and_items(join->conds, item); + if (join->conds->fix_fields(thd, join->tables_list, &join->conds)) + DBUG_RETURN(ERROR); + } + else + { + if (item->type() == Item::FIELD_ITEM && + ((Item_field*) item)->field_name[0] == '*') + { + my_error(ER_NO_TABLES_USED, MYF(0)); + DBUG_RETURN(ERROR); + } + if (select_lex->master_unit()->first_select()->next_select()) + { + /* + It is in union => we should perform it. + Item_asterisk_remover used only as wrapper to receine NULL value + */ + join->having= (*func)(expr, new Item_asterisk_remover(this, item, (char *)"<no matter>", - (char*)"<result>")); + (char *)"<result>")); + select_lex->having_fix_field= 1; + if (join->having->fix_fields(thd, join->tables_list, &join->having)) + { + select_lex->having_fix_field= 0; + DBUG_RETURN(ERROR); } - else + select_lex->having_fix_field= 0; + } + else + { + // it is single select without tables => possible optimization + item= (*func)(left_expr, item); + // fix_field of item will be done in time of substituting + substitution= item; + have_to_be_excluded= 1; + if (thd->lex.describe) { - // it is single select without tables => possible optimization - item= (*func)(left_expr, item); - substitution= item; - have_to_be_excluded= 1; - if (thd->lex.describe) - { - char warn_buff[MYSQL_ERRMSG_SIZE]; - sprintf(warn_buff, ER(ER_SELECT_REDUCED), sl->select_number); - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, - ER_SELECT_REDUCED, warn_buff); - } + char warn_buff[MYSQL_ERRMSG_SIZE]; + sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, + ER_SELECT_REDUCED, warn_buff); } + DBUG_RETURN(REDUCE); } } } - DBUG_VOID_RETURN; + DBUG_RETURN(OK); } -void Item_in_subselect::row_value_transformer(THD *thd, - st_select_lex_unit *unit, - Item *left_expr) +Item_subselect::trans_res +Item_in_subselect::row_value_transformer(JOIN *join, + Item *left_expr) { DBUG_ENTER("Item_in_subselect::row_value_transformer"); - if (unit->global_parameters->select_limit != - HA_POS_ERROR) - { - /* - Because we do the following (not exactly, following is just explenation) - transformation - SELECT * from t1 WHERE t1.a IN (SELECT t2.a FROM t2) - -> - SELECT * from t1 WHERE EXISTS(SELECT 1 FROM t2 t1.a = t2.a LIMIT 1) - it's impossible to support limit in the sub select. - */ - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "LIMIT & IN/ALL/ANY/SOME subquery"); - DBUG_VOID_RETURN; - } - // no sense in ORDER BY without LIMIT - unit->global_parameters->order_list.empty(); + THD *thd= join->thd; + thd->where= "row IN/ALL/ANY subquery"; - Item_in_optimizer *optimizer; - substitution= optimizer= new Item_in_optimizer(left_expr, this); - if (!optimizer) - DBUG_VOID_RETURN; + SELECT_LEX *select_lex= join->select_lex; - unit->dependent= 1; - uint n= left_expr->cols(); - if (optimizer->preallocate_row() || (*optimizer->get_cache())->allocate(n)) - DBUG_VOID_RETURN; - for (SELECT_LEX * sl= unit->first_select(); sl; sl= sl->next_select()) + if (!substitution) { - if (sl->select_limit != HA_POS_ERROR) + //first call for this unit + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + substitution= optimizer= new Item_in_optimizer(left_expr, this); + + SELECT_LEX *current= thd->lex.current_select, *up; + thd->lex.current_select= up= current->return_after_parsing(); + //optimizer never use Item **ref => we can pass 0 as parameter + if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0)) { - my_error(ER_NOT_SUPPORTED_YET, MYF(0), - "LIMIT & IN/ALL/ANY/SOME subquery"); - DBUG_VOID_RETURN; + thd->lex.current_select= current; + DBUG_RETURN(ERROR); } - sl->order_list.empty(); // no sense in ORDER BY without LIMIT + thd->lex.current_select= current; + + unit->dependent= 1; + } - sl->dependent= 1; + uint n= left_expr->cols(); + + select_lex->dependent= 1; + + Item *item= 0; + List_iterator_fast<Item> li(select_lex->item_list); + for (uint i= 0; i < n; i++) + { + Item *func= + new Item_ref_on_list_position(this, select_lex, i, + (char *) "<no matter>", + (char *) "<list ref>"); + func= + Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())-> + addr(i), + (char *)"<no matter>", + (char *)"<left expr>"), + func); + item= and_items(item, func); + } - Item *item= 0; - List_iterator_fast<Item> li(sl->item_list); - for (uint i= 0; i < n; i++) + if (join->having || select_lex->with_sum_func || + select_lex->group_list.first || + !select_lex->table_list.elements) + { + join->having= and_items(join->having, item); + select_lex->having_fix_field= 1; + if (join->having->fix_fields(thd, join->tables_list, &join->having)) { - Item *func= - new Item_ref_on_list_position(this, sl, i, - (char *) "<no matter>", - (char *) "<list ref>"); - func= - Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())-> - addr(i), - (char *)"<no matter>", - (char *)"<left expr>"), - func); - item= and_items(item, func); + select_lex->having_fix_field= 0; + DBUG_RETURN(ERROR); } - - if (sl->having || sl->with_sum_func || sl->group_list.first || - !sl->table_list.elements) - sl->having= and_items(sl->having, item); - else - sl->where= and_items(sl->where, item); + select_lex->having_fix_field= 0; } - DBUG_VOID_RETURN; + else + { + join->conds= and_items(join->conds, item); + if (join->conds->fix_fields(thd, join->tables_list, &join->having)) + DBUG_RETURN(ERROR); + } + DBUG_RETURN(OK); } - -void Item_in_subselect::select_transformer(THD *thd, st_select_lex_unit *unit) +Item_subselect::trans_res +Item_in_subselect::select_transformer(JOIN *join) { if (left_expr->cols() == 1) - single_value_transformer(thd, unit, left_expr, - &Item_bool_func2::eq_creator); - else - row_value_transformer(thd, unit, left_expr); + return single_value_transformer(join, left_expr, + &Item_bool_func2::eq_creator); + return row_value_transformer(join, left_expr); } -void Item_allany_subselect::select_transformer(THD *thd, - st_select_lex_unit *unit) +Item_subselect::trans_res +Item_allany_subselect::select_transformer(JOIN *join) { - single_value_transformer(thd, unit, left_expr, func); + return single_value_transformer(join, left_expr, func); } subselect_single_select_engine::subselect_single_select_engine(THD *thd, @@ -719,7 +772,7 @@ int subselect_single_select_engine::prepare() if (prepared) return 0; prepared= 1; - SELECT_LEX_NODE *save_select= thd->lex.current_select; + SELECT_LEX *save_select= thd->lex.current_select; thd->lex.current_select= select_lex; if (join->prepare(&select_lex->ref_pointer_array, (TABLE_LIST*) select_lex->table_list.first, @@ -826,7 +879,7 @@ int subselect_single_select_engine::exec() { DBUG_ENTER("subselect_single_select_engine::exec"); char const *save_where= join->thd->where; - SELECT_LEX_NODE *save_select= join->thd->lex.current_select; + SELECT_LEX *save_select= join->thd->lex.current_select; join->thd->lex.current_select= select_lex; if (!optimized) { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 3ed3f2af0e9..bf165289cff 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -48,6 +48,8 @@ protected: bool have_to_be_excluded; public: + enum trans_res {OK, REDUCE, ERROR}; + Item_subselect(); Item_subselect(Item_subselect *item) { @@ -73,7 +75,7 @@ public: { null_value= 1; } - virtual void select_transformer(THD *thd, st_select_lex_unit *unit); + virtual trans_res select_transformer(JOIN *join); bool assigned() { return value_assigned; } void assigned(bool a) { value_assigned= a; } enum Type type() const; @@ -86,6 +88,13 @@ public: bool exec(); virtual void fix_length_and_dec(); table_map used_tables() const; + void print(String *str) + { + if (name) + str->append(name); + else + str->append("-subselect-"); + } friend class select_subselect; friend class Item_in_optimizer; @@ -108,7 +117,7 @@ public: decimals= item->decimals; } void reset(); - void select_transformer(THD *thd, st_select_lex_unit *unit); + trans_res select_transformer(JOIN *join); void store(uint i, Item* item); double val(); longlong val_int (); @@ -164,25 +173,35 @@ class Item_in_subselect :public Item_exists_subselect { protected: Item * left_expr; + /* + expr & optimizer used in subselect rewriting to store Item for + all JOIN in UNION + */ + Item *expr; + Item_in_optimizer *optimizer; bool was_null; + bool abort_on_null; public: Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex); Item_in_subselect(Item_in_subselect *item); - Item_in_subselect(): Item_exists_subselect() {} + Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {} void reset() { value= 0; null_value= 0; was_null= 0; } - virtual void select_transformer(THD *thd, st_select_lex_unit *unit); - void single_value_transformer(THD *thd, st_select_lex_unit *unit, - Item *left_expr, compare_func_creator func); - void row_value_transformer(THD *thd, st_select_lex_unit *unit, - Item *left_expr); + trans_res select_transformer(JOIN *join); + trans_res single_value_transformer(JOIN *join, + Item *left_expr, + compare_func_creator func); + trans_res row_value_transformer(JOIN * join, + Item *left_expr); longlong val_int(); double val(); String *val_str(String*); + void top_level_item() { abort_on_null=1; } + bool test_limit(st_select_lex_unit *unit); friend class Item_asterisk_remover; friend class Item_ref_null_helper; @@ -199,7 +218,7 @@ public: Item_allany_subselect(THD *thd, Item * left_expr, compare_func_creator f, st_select_lex *select_lex); Item_allany_subselect(Item_allany_subselect *item); - virtual void select_transformer(THD *thd, st_select_lex_unit *unit); + trans_res select_transformer(JOIN *join); }; class subselect_engine: public Sql_alloc diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 0da2725f3ab..7ab83c1e7b2 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -1116,7 +1116,7 @@ void Item_sum_count_distinct::make_unique() bool Item_sum_count_distinct::setup(THD *thd) { List<Item> list; - SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select; if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) return 1; @@ -1610,7 +1610,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, quick_group= 0; mark_as_sum_func(); item_thd= current_thd; - SELECT_LEX *select_lex= item_thd->lex.current_select->select_lex(); + SELECT_LEX *select_lex= item_thd->lex.current_select; order= 0; group_concat_max_len= item_thd->variables.group_concat_max_len; @@ -1792,7 +1792,7 @@ bool Item_func_group_concat::setup(THD *thd) { DBUG_ENTER("Item_func_group_concat::setup"); List<Item> list; - SELECT_LEX *select_lex= thd->lex.current_select->select_lex(); + SELECT_LEX *select_lex= thd->lex.current_select; if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) DBUG_RETURN(1); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 2c41d973f2e..05a2cf4c7f8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -952,3 +952,24 @@ compare_func_creator comp_le_creator(bool invert); compare_func_creator comp_lt_creator(bool invert); compare_func_creator comp_ne_creator(bool invert); +/* + clean/setup table fields and map + + SYNOPSYS + setup_table_map() + table - TABLE structure pointer (which should be setup) + table_list TABLE_LIST structure pointer (owner of TABLE) + tablenr - table number +*/ +inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr) +{ + table->used_fields= 0; + table->const_table= 0; + table->outer_join= table->null_row= 0; + table->status= STATUS_NO_RECORD; + table->keys_in_use_for_query= table->keys_in_use; + table->maybe_null= test(table->outer_join= table_list->outer_join); + table->tablenr= tablenr; + table->map= (table_map) 1 << tablenr; + table->force_index= table_list->force_index; +} diff --git a/sql/sql_base.cc b/sql/sql_base.cc index a5807914abd..f33533d9eb7 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -2020,18 +2020,9 @@ bool setup_tables(TABLE_LIST *tables) for (TABLE_LIST *table_list=tables ; table_list ; table_list=table_list->next,tablenr++) { - TABLE *table=table_list->table; - - table->used_fields=0; - table->const_table=0; - table->outer_join=table->null_row=0; - table->status=STATUS_NO_RECORD; - table->keys_in_use_for_query= table->keys_in_use; + TABLE *table= table_list->table; + setup_table_map(table, table_list, tablenr); table->used_keys= table->keys_for_keyread; - table->maybe_null=test(table->outer_join=table_list->outer_join); - table->tablenr=tablenr; - table->map= (table_map) 1 << tablenr; - table->force_index= table_list->force_index; if (table_list->use_index) { key_map map= get_key_map_from_key_list(table, diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ebb09b99df7..876c4f9e670 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -304,7 +304,7 @@ multi_delete::initialize_tables(JOIN *join) table->file->ref_length, MEM_STRIP_BUF_SIZE); } - init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1); + init_ftfuncs(thd, thd->lex.current_select, 1); DBUG_RETURN(thd->is_fatal_error != 0); } diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 81439a19918..d7a88ecd53e 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -74,7 +74,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, bool is_union= select_cursor->next_select() && select_cursor->next_select()->linkage == UNION_TYPE; bool is_subsel= select_cursor->first_inner_unit() ? 1: 0; - SELECT_LEX_NODE *save_current_select= lex->current_select; + SELECT_LEX *save_current_select= lex->current_select; DBUG_ENTER("mysql_derived"); /* @@ -211,7 +211,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, if (tables) { for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) - cursor->table_list->table=cursor->table; + if (cursor->table_list) + cursor->table_list->table=cursor->table; } } else diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 57e39a0dc83..2d1d08aa596 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -948,27 +948,17 @@ void st_select_lex_node::init_query() options= 0; linkage= UNSPECIFIED_TYPE; no_error= no_table_names_allowed= uncacheable= dependent= 0; - ref_pointer_array= 0; - cond_count= 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; - select_n_having_items= 0; - with_sum_func= 0; - parsing_place= SELECT_LEX_NODE::NO_MATTER; } void st_select_lex_unit::init_query() { st_select_lex_node::init_query(); linkage= GLOBAL_OPTIONS_TYPE; - global_parameters= this; + global_parameters= first_select(); select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; union_option= 0; @@ -976,6 +966,7 @@ void st_select_lex_unit::init_query() item= 0; union_result= 0; table= 0; + fake_select_lex= 0; } void st_select_lex::init_query() @@ -988,7 +979,8 @@ void st_select_lex::init_query() olap= UNSPECIFIED_OLAP_TYPE; having_fix_field= 0; resolve_mode= NOMATTER_MODE; - with_wild= 0; + cond_count= with_wild= 0; + ref_pointer_array= 0; } void st_select_lex::init_select() @@ -1010,6 +1002,14 @@ void st_select_lex::init_select() ftfunc_list_alloc.empty(); ftfunc_list= &ftfunc_list_alloc; linkage= UNSPECIFIED_TYPE; + order_list.elements= 0; + order_list.first= 0; + order_list.next= (byte**) &order_list.first; + select_limit= HA_POS_ERROR; + offset_limit= 0; + select_n_having_items= 0; + with_sum_func= 0; + parsing_place= SELECT_LEX_NODE::NO_MATTER; } /* @@ -1027,6 +1027,23 @@ void st_select_lex_node::include_down(st_select_lex_node *upper) slave= 0; } +/* + include on level down (but do not link) + + SYNOPSYS + st_select_lex_node::include_standalone() + upper - reference on node underr which this node should be included + ref - references on reference on this node +*/ +void st_select_lex_node::include_standalone(st_select_lex_node *upper, + st_select_lex_node **ref) +{ + next= 0; + prev= ref; + master= upper; + slave= 0; +} + /* include neighbour (on same level) */ void st_select_lex_node::include_neighbour(st_select_lex_node *before) { @@ -1108,33 +1125,6 @@ void st_select_lex_unit::exclude_level() (*prev)= next; } -st_select_lex* st_select_lex_node::select_lex() -{ - DBUG_ENTER("st_select_lex_node::select_lex (never should be called)"); - DBUG_ASSERT(0); - DBUG_RETURN(0); -} - -bool st_select_lex_node::add_item_to_list(THD *thd, Item *item) -{ - return 1; -} - -bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc) -{ - return 1; -} - -bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc) -{ - return add_to_list(thd, order_list, item, asc); -} - -bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func) -{ - return 1; -} - /* st_select_lex_node::mark_as_dependent mark all st_select_lex struct from this to 'last' as dependent @@ -1148,31 +1138,26 @@ bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func) */ -void st_select_lex_node::mark_as_dependent(SELECT_LEX *last) +void st_select_lex::mark_as_dependent(SELECT_LEX *last) { /* Mark all selects from resolved to 1 before select where was found table as depended (of select where was found table) */ - for (SELECT_LEX_NODE *s= this; + for (SELECT_LEX *s= this; s &&s != last; s= s->outer_select()) if ( !s->dependent ) { // Select is dependent of outer select s->dependent= 1; - if (s->linkage != GLOBAL_OPTIONS_TYPE) - { - //s is st_select_lex* - - s->master_unit()->dependent= 1; - //Tables will be reopened many times - for (TABLE_LIST *tbl= - s->get_table_list(); - tbl; - tbl= tbl->next) - tbl->shared= 1; - } + s->master_unit()->dependent= 1; + //Tables will be reopened many times + for (TABLE_LIST *tbl= + s->get_table_list(); + tbl; + tbl= tbl->next) + tbl->shared= 1; } } @@ -1183,17 +1168,29 @@ TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } List<Item>* st_select_lex_node::get_item_list() { return 0; } List<String>* st_select_lex_node::get_use_index() { return 0; } List<String>* st_select_lex_node::get_ignore_index() { return 0; } -TABLE_LIST *st_select_lex_node::add_table_to_list(THD *thd, Table_ident *table, - LEX_STRING *alias, - ulong table_join_options, - thr_lock_type flags, - List<String> *use_index, - List<String> *ignore_index) + +ulong st_select_lex_node::get_table_join_options() { return 0; } -ulong st_select_lex_node::get_table_join_options() { return 0; } +/* + prohibit using LIMIT clause +*/ +bool st_select_lex::test_limit() +{ + if (select_limit != HA_POS_ERROR) + { + my_error(ER_NOT_SUPPORTED_YET, MYF(0), + "LIMIT & IN/ALL/ANY/SOME subquery"); + return(1); + } + // We need only 1 row to determinate existence + select_limit= 1; + // no sense in ORDER BY without LIMIT + order_list.empty(); + return(0); +} /* Interface method of table list creation for query @@ -1255,22 +1252,39 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first; TABLE_LIST **new_table_list= *result, *aux; SELECT_LEX *sl= (SELECT_LEX*)slave; - for (; sl; sl= sl->next_select()) + + /* + iterate all inner selects + fake_select (if exists), + fake_select->next_select() always is 0 + */ + for (; + sl; + sl= (sl->next_select() ? + sl->next_select() : + (sl == fake_select_lex ? + 0 : + fake_select_lex))) { // check usage of ORDER BY in union - if (sl->order_list.first && sl->next_select() && !sl->braces) + if (sl->order_list.first && sl->next_select() && !sl->braces && + sl->linkage != GLOBAL_OPTIONS_TYPE) { net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY"); return 1; } + if (sl->linkage == DERIVED_TABLE_TYPE && !check_derived) - continue; + goto end; + for (SELECT_LEX_UNIT *inner= sl->first_inner_unit(); inner; inner= inner->next_unit()) + { if (inner->create_total_list_n_last_return(thd, lex, &slave_list_last, 0)) return 1; + } + if ((aux= (TABLE_LIST*) sl->table_list.first)) { TABLE_LIST *next; @@ -1293,15 +1307,18 @@ bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, return 1; } *new_table_list= cursor; + cursor->table_list= aux; //to be able mark this table as shared new_table_list= &cursor->next; *new_table_list= 0; // end result list } else - aux->shared= 1; // Mark that it's used twice + // Mark that it's used twice + cursor->table_list->shared= aux->shared= 1; aux->table_list= cursor; } } } +end: if (slave_list_first) { *new_table_list= slave_list_first; @@ -1321,9 +1338,9 @@ st_select_lex* st_select_lex_unit::outer_select() return (st_select_lex*) master; } -st_select_lex* st_select_lex::select_lex() +bool st_select_lex::add_order_to_list(THD *thd, Item *item, bool asc) { - return this; + return add_to_list(thd, order_list, item, asc); } bool st_select_lex::add_item_to_list(THD *thd, Item *item) @@ -1393,17 +1410,6 @@ ulong st_select_lex::get_table_join_options() return table_join_options; } -st_select_lex::st_select_lex(struct st_lex *lex) -{ - select_number= ++lex->thd->select_number; - init_query(); - init_select(); - include_neighbour(lex->current_select); - include_global((st_select_lex_node**)&lex->all_selects_list); - lex->current_select= this; -} - - /* There are st_select_lex::add_table_to_list & st_select_lex::set_lock_for_tables in sql_parse.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 6b3da620fc1..d310aa5c06f 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -118,6 +118,12 @@ enum olap_type subselects or derived tables) for ordinary select_lex - list of all select_lex (for group operation like correcting list of opened tables) + - if unit contain several selects (union) then it have special + select_lex called fake_select_lex. It used for storing global parameters + and executing union. subqueries of global ORDER BY clause will be + attached to this fake_select_lex, which will allow them correctly + resolve fields of 'upper' union and other more outer selects. + for example for following query: select * @@ -138,6 +144,7 @@ enum olap_type main unit + fake0 select1 select2 select3 |^^ |^ s||| ||master @@ -146,7 +153,8 @@ enum olap_type v|||master slave || e||+-------------------------+ || V| neighbor | V| - unit 1.1<==================>unit1.2 unit2.1 + unit1.1<+==================>unit1.2 unit2.1 + fake1.1 fake2.1 select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2 |^ || @@ -158,13 +166,14 @@ enum olap_type relation in main unit will be following: main unit - |^^^ - |||| - |||+------------------------------+ - ||+--------------+ | - slave||master | | - V| neighbor | neighbor | - select1<========>select2<========>select3 + |^^^^|fake_select_lex + |||||+--------------------------------------------+ + ||||+--------------------------------------------+| + |||+------------------------------+ || + ||+--------------+ | || + slave||master | | || + V| neighbor | neighbor | master|V + select1<========>select2<========>select3 fake0 list of all select_lex will be following (as it will be constructed by parser): @@ -199,21 +208,6 @@ public: ulong options; enum sub_select_type linkage; - SQL_LIST order_list; /* ORDER clause */ - List<List_item> expr_list; - List<List_item> when_list; /* WHEN clause (expression) */ - ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ - // Arrays of pointers to top elements of all_fields list - Item **ref_pointer_array; - /* - number of items in select_list and HAVING clause used to get number - bigger then can be number of entries that will be added to all item - list during split_sum_func - */ - uint select_n_having_items; - uint cond_count; /* number of arguments of and/or/xor in where/having */ - enum_parsing_place parsing_place; /* where we are parsing expression */ - bool with_sum_func; /* sum function indicator */ bool dependent; /* dependent from outer select subselect */ bool uncacheable; /* result of this query can't be cached */ bool no_table_names_allowed; /* used for global order by */ @@ -231,18 +225,13 @@ public: virtual void init_select(); void include_down(st_select_lex_node *upper); void include_neighbour(st_select_lex_node *before); + void include_standalone(st_select_lex_node *sel, st_select_lex_node **ref); void include_global(st_select_lex_node **plink); void exclude(); - virtual st_select_lex* select_lex(); - virtual bool add_item_to_list(THD *thd, Item *item); - bool add_order_to_list(THD *thd, Item *item, bool asc); - virtual bool add_group_to_list(THD *thd, Item *item, bool asc); - virtual bool add_ftfunc_to_list(Item_func_match *func); - virtual st_select_lex_unit* master_unit()= 0; virtual st_select_lex* outer_select()= 0; - virtual st_select_lex_node* return_after_parsing()= 0; + virtual st_select_lex* return_after_parsing()= 0; virtual bool set_braces(bool value); virtual bool inc_in_sum_expr(); @@ -252,14 +241,7 @@ public: virtual List<String>* get_use_index(); virtual List<String>* get_ignore_index(); virtual ulong get_table_join_options(); - virtual TABLE_LIST *add_table_to_list(THD *thd, Table_ident *table, - LEX_STRING *alias, - ulong table_options, - thr_lock_type flags= TL_UNLOCK, - List<String> *use_index= 0, - List<String> *ignore_index= 0); virtual void set_lock_for_tables(thr_lock_type lock_type) {} - void mark_as_dependent(st_select_lex *last); friend class st_select_lex_unit; friend bool mysql_new_select(struct st_lex *lex, bool move_down); @@ -296,14 +278,17 @@ public: Pointer to 'last' select or pointer to unit where stored global parameters for union */ - st_select_lex_node *global_parameters; + st_select_lex *global_parameters; //node on wich we should return current_select pointer after parsing subquery - st_select_lex_node *return_to; + st_select_lex *return_to; /* LIMIT clause runtime counters */ ha_rows select_limit_cnt, offset_limit_cnt; /* not NULL if union used in subselect, point to subselect item */ Item_subselect *item; + /* thread handler */ THD *thd; + /* fake SELECT_LEX for union processing */ + st_select_lex *fake_select_lex; uint union_option; @@ -315,11 +300,10 @@ public: st_select_lex* first_select() { return (st_select_lex*) slave; } st_select_lex* first_select_in_union() { - return (slave && slave->linkage == GLOBAL_OPTIONS_TYPE) ? - (st_select_lex*) slave->next : (st_select_lex*) slave; + return (st_select_lex*) slave; } st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } - st_select_lex_node* return_after_parsing() { return return_to; } + st_select_lex* return_after_parsing() { return return_to; } void exclude_level(); /* UNION methods */ @@ -357,6 +341,24 @@ public: List<Item_func_match> ftfunc_list_alloc; JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */ const char *type; /* type of select for EXPLAIN */ + + SQL_LIST order_list; /* ORDER clause */ + List<List_item> expr_list; + List<List_item> when_list; /* WHEN clause (expression) */ + ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ + // Arrays of pointers to top elements of all_fields list + Item **ref_pointer_array; + + /* + number of items in select_list and HAVING clause used to get number + bigger then can be number of entries that will be added to all item + list during split_sum_func + */ + uint select_n_having_items; + uint cond_count; /* number of arguments of and/or/xor in where/having */ + enum_parsing_place parsing_place; /* where we are parsing expression */ + bool with_sum_func; /* sum function indicator */ + ulong table_join_options; uint in_sum_expr; uint select_number; /* number of select (used for EXPLAIN) */ @@ -403,31 +405,33 @@ public: { return &link_next; } - st_select_lex_node* return_after_parsing() + st_select_lex* return_after_parsing() { return master_unit()->return_after_parsing(); } + void mark_as_dependent(st_select_lex *last); + bool set_braces(bool value); bool inc_in_sum_expr(); uint get_in_sum_expr(); - st_select_lex* select_lex(); bool add_item_to_list(THD *thd, Item *item); bool add_group_to_list(THD *thd, Item *item, bool asc); bool add_ftfunc_to_list(Item_func_match *func); - - TABLE_LIST* get_table_list(); - List<Item>* get_item_list(); - List<String>* get_use_index(); - List<String>* get_ignore_index(); - ulong get_table_join_options(); + bool add_order_to_list(THD *thd, Item *item, bool asc); TABLE_LIST* add_table_to_list(THD *thd, Table_ident *table, LEX_STRING *alias, ulong table_options, thr_lock_type flags= TL_UNLOCK, List<String> *use_index= 0, List<String> *ignore_index= 0); + + TABLE_LIST* get_table_list(); + List<Item>* get_item_list(); + List<String>* get_use_index(); + List<String>* get_ignore_index(); + ulong get_table_join_options(); void set_lock_for_tables(thr_lock_type lock_type); inline void init_order() { @@ -436,15 +440,14 @@ public: order_list.next= (byte**) &order_list.first; } + bool test_limit(); + friend void mysql_init_query(THD *thd); - st_select_lex(struct st_lex *lex); st_select_lex() {} - void make_empty_select(st_select_lex *last_select) + void make_empty_select() { - select_number=INT_MAX; init_query(); init_select(); - include_neighbour(last_select); } }; typedef class st_select_lex SELECT_LEX; @@ -459,7 +462,7 @@ typedef struct st_lex SELECT_LEX_UNIT unit; /* most upper unit */ SELECT_LEX select_lex; /* first SELECT_LEX */ /* current SELECT_LEX in parsing */ - SELECT_LEX_NODE *current_select; + SELECT_LEX *current_select; /* list of all SELECT_LEX */ SELECT_LEX *all_selects_list; uchar *ptr,*tok_start,*tok_end,*end_of_query; @@ -531,7 +534,7 @@ typedef struct st_lex but we should merk all subselects as uncacheable from current till most upper */ - SELECT_LEX_NODE *sl; + SELECT_LEX *sl; SELECT_LEX_UNIT *un; for (sl= current_select, un= sl->master_unit(); un != &unit; diff --git a/sql/sql_olap.cc b/sql/sql_olap.cc index a5f164e1e38..ef7bf013be8 100644 --- a/sql/sql_olap.cc +++ b/sql/sql_olap.cc @@ -150,7 +150,8 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex) { if (cursor->do_redirect) { - cursor->table= ((TABLE_LIST*) cursor->table)->table; + //Sinisa TODO: there are function for this purpose: fix_tables_pointers + cursor->table= cursor->table_list->table; cursor->do_redirect= 0; } } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5880a9d4c8a..f0eba167b90 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3490,10 +3490,10 @@ mysql_init_query(THD *thd) lex->select_lex.init_query(); lex->value_list.empty(); lex->param_list.empty(); - lex->unit.next= lex->unit.master= lex->unit.return_to= - lex->unit.link_next= 0; + lex->unit.next= lex->unit.master= + lex->unit.link_next= lex->unit.return_to=0; lex->unit.prev= lex->unit.link_prev= 0; - lex->unit.global_parameters= lex->unit.slave= lex->current_select= + lex->unit.slave= lex->unit.global_parameters= lex->current_select= lex->all_selects_list= &lex->select_lex; lex->select_lex.master= &lex->unit; lex->select_lex.prev= &lex->unit.slave; @@ -3522,10 +3522,9 @@ mysql_init_query(THD *thd) void mysql_init_select(LEX *lex) { - SELECT_LEX *select_lex= lex->current_select->select_lex(); + SELECT_LEX *select_lex= lex->current_select; select_lex->init_select(); - select_lex->master_unit()->select_limit= select_lex->select_limit= - lex->thd->variables.select_limit; + select_lex->select_limit= lex->thd->variables.select_limit; if (select_lex == &lex->select_lex) { lex->exchange= 0; @@ -3553,10 +3552,7 @@ mysql_new_select(LEX *lex, bool move_down) unit->init_query(); unit->init_select(); unit->thd= lex->thd; - if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) - unit->include_neighbour(lex->current_select); - else - unit->include_down(lex->current_select); + unit->include_down(lex->current_select); unit->link_next= 0; unit->link_prev= 0; unit->return_to= lex->current_select; @@ -3564,7 +3560,25 @@ mysql_new_select(LEX *lex, bool move_down) // TODO: assign resolve_mode for fake subquery after merging with new tree } else + { select_lex->include_neighbour(lex->current_select); + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + SELECT_LEX *fake= unit->fake_select_lex; + if (!fake) + { + /* + as far as we included SELECT_LEX for UNION unit should have + fake SELECT_LEX for UNION processing + */ + fake= unit->fake_select_lex= new SELECT_LEX(); + fake->include_standalone(unit, + (SELECT_LEX_NODE**)&unit->fake_select_lex); + fake->select_number= INT_MAX; + fake->make_empty_select(); + fake->linkage= GLOBAL_OPTIONS_TYPE; + fake->select_limit= lex->thd->variables.select_limit; + } + } select_lex->master_unit()->global_parameters= select_lex; select_lex->include_global((st_select_lex_node**)&lex->all_selects_list); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 71c0d0bdddc..6c92f1f5dcf 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -206,7 +206,8 @@ void relink_tables(SELECT_LEX *select_lex) for (TABLE_LIST *cursor= (TABLE_LIST *) select_lex->table_list.first; cursor; cursor=cursor->next) - cursor->table= cursor->table_list->table; + if (cursor->table_list) + cursor->table= cursor->table_list->table; } @@ -320,6 +321,19 @@ JOIN::prepare(Item ***rref_pointer_array, having->split_sum_func(ref_pointer_array, all_fields); } + // Is it subselect + { + Item_subselect *subselect; + if ((subselect= select_lex->master_unit()->item) && + select_lex->linkage != GLOBAL_OPTIONS_TYPE) + { + Item_subselect::trans_res res; + if ((res= subselect->select_transformer(this)) != + Item_subselect::OK) + DBUG_RETURN((res == Item_subselect::ERROR)); + } + } + if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); @@ -1386,12 +1400,24 @@ mysql_select(THD *thd, Item ***rref_pointer_array, JOIN *join; if (select_lex->join != 0) { - //here is EXPLAIN of subselect or derived table join= select_lex->join; - join->result= result; - if (!join->procedure && result->prepare(join->fields_list, unit)) + if (select_lex->linkage != GLOBAL_OPTIONS_TYPE) { - DBUG_RETURN(-1); + //here is EXPLAIN of subselect or derived table + join->result= result; + if (!join->procedure && result->prepare(join->fields_list, unit)) + { + DBUG_RETURN(-1); + } + } + else + { + if (join->prepare(rref_pointer_array, tables, wild_num, + conds, og_num, order, group, having, proc_param, + select_lex, unit, tables_and_fields_initied)) + { + DBUG_RETURN(-1); + } } join->select_options= select_options; free_join= 0; @@ -1401,7 +1427,6 @@ mysql_select(THD *thd, Item ***rref_pointer_array, join= new JOIN(thd, fields, select_options, result); thd->proc_info="init"; thd->used_tables=0; // Updated by setup_fields - if (join->prepare(rref_pointer_array, tables, wild_num, conds, og_num, order, group, having, proc_param, select_lex, unit, tables_and_fields_initied)) @@ -4297,6 +4322,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, default: // This case should never be choosen DBUG_ASSERT(0); + new_field= 0; // to satisfy compiler (uninitialized variable) break; } if (copy_func && item->is_result_field()) @@ -5797,7 +5823,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), else { join->do_send_rows= 0; - join->unit->select_limit= HA_POS_ERROR; + if (join->unit->fake_select_lex) + join->unit->fake_select_lex->select_limit= HA_POS_ERROR; DBUG_RETURN(0); } } diff --git a/sql/sql_select.h b/sql/sql_select.h index 76960876158..d84a3715707 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -192,45 +192,62 @@ class JOIN :public Sql_alloc bool optimized; // flag to avoid double optimization in EXPLAIN JOIN(THD *thd_arg, List<Item> &fields, ulong select_options_arg, - select_result *result_arg): - join_tab(0), - table(0), - tables(0), const_tables(0), - sort_and_group(0), first_record(0), - do_send_rows(1), - send_records(0), found_records(0), examined_rows(0), - exec_tmp_table1(0), exec_tmp_table2(0), - thd(thd_arg), - sum_funcs(0),sum_funcs2(0), - procedure(0), - having(0), tmp_having(0), - select_options(select_options_arg), - result(result_arg), - lock(thd_arg->lock), - select_lex(0), //for safety - tmp_join(0), - select_distinct(test(select_options & SELECT_DISTINCT)), - no_order(0), simple_order(0), simple_group(0), skip_sort_order(0), - need_tmp(0), - hidden_group_fields (0), /*safety*/ - buffer_result(test(select_options & OPTION_BUFFER_RESULT) && - !test(select_options & OPTION_FOUND_ROWS)), - all_fields(fields), - fields_list(fields), - error(0), - select(0), - ref_pointer_array(0), items0(0), items1(0), items2(0), items3(0), - ref_pointer_array_size(0), - zero_result_cause(0), - optimized(0) + select_result *result_arg) + :fields_list(fields) { + init(thd_arg, fields, select_options_arg, result_arg); + } + + void init(THD *thd_arg, List<Item> &fields, ulong select_options_arg, + select_result *result_arg) + { + join_tab= 0; + table= 0; + tables= 0; + const_tables= 0; + sort_and_group= 0; + first_record= 0; + do_send_rows= 1; + send_records= 0; + found_records= 0; + examined_rows= 0; + exec_tmp_table1= 0; + exec_tmp_table2= 0; + thd= thd_arg; + sum_funcs= sum_funcs2= 0; + procedure= 0; + having= 0; + tmp_having= 0; + select_options= select_options_arg; + result= result_arg; + lock= thd_arg->lock; + select_lex= 0; //for safety + tmp_join= 0; + select_distinct= test(select_options & SELECT_DISTINCT); + no_order= 0; + simple_order= 0; + simple_group= 0; + skip_sort_order= 0; + need_tmp= 0; + hidden_group_fields= 0; /*safety*/ + buffer_result= test(select_options & OPTION_BUFFER_RESULT) && + !test(select_options & OPTION_FOUND_ROWS); + all_fields= fields; + fields_list= fields; + error= 0; + select= 0; + ref_pointer_array= items0= items1= items2= items3= 0; + ref_pointer_array_size= 0; + zero_result_cause= 0; + optimized= 0; + fields_list = fields; bzero((char*) &keyuse,sizeof(keyuse)); tmp_table_param.copy_field=0; tmp_table_param.end_write_records= HA_POS_ERROR; rollup.state= ROLLUP::STATE_NONE; } - + int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num, COND *conds, uint og_num, ORDER *order, ORDER *group, Item *having, ORDER *proc_param, SELECT_LEX *select, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 57044a8370a..0d50348f199 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -115,7 +115,7 @@ bool select_union::flush() int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, bool tables_and_fields_initied) { - SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; + SELECT_LEX *lex_select_save= thd->lex.current_select; SELECT_LEX *select_cursor; DBUG_ENTER("st_select_lex_unit::prepare"); @@ -193,42 +193,33 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result, union_result->not_describe=1; union_result->tmp_table_param=tmp_table_param; - /* - The following piece of code is placed here solely for the purpose of - getting correct results with EXPLAIN when UNION is withing a sub-select - or derived table ... - */ - - if (thd->lex.describe) + for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { - for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) - { - JOIN *join= new JOIN(thd, sl->item_list, - sl->options | thd->options | SELECT_NO_UNLOCK, - union_result); - thd->lex.current_select= sl; - offset_limit_cnt= sl->offset_limit; - select_limit_cnt= sl->select_limit+sl->offset_limit; - if (select_limit_cnt < sl->select_limit) - select_limit_cnt= HA_POS_ERROR; // no limit - if (select_limit_cnt == HA_POS_ERROR) - sl->options&= ~OPTION_FOUND_ROWS; - - res= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, sl->with_wild, - sl->where, - ((sl->braces) ? sl->order_list.elements : 0) + - sl->group_list.elements, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl, this, t_and_f); - t_and_f= 0; - if (res || thd->is_fatal_error) - goto err; - } + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + res= join->prepare(&sl->ref_pointer_array, + (TABLE_LIST*) sl->table_list.first, sl->with_wild, + sl->where, + ((sl->braces) ? sl->order_list.elements : 0) + + sl->group_list.elements, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, t_and_f); + t_and_f= 0; + if (res || thd->is_fatal_error) + goto err; } item_list.empty(); @@ -254,7 +245,7 @@ err: int st_select_lex_unit::exec() { - SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; + SELECT_LEX *lex_select_save= thd->lex.current_select; SELECT_LEX *select_cursor=first_select_in_union(); DBUG_ENTER("st_select_lex_unit::exec"); @@ -272,14 +263,12 @@ int st_select_lex_unit::exec() } for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select()) { + thd->lex.current_select= sl; + if (optimized) res= sl->join->reinit(); else { - JOIN *join= new JOIN(thd, sl->item_list, - sl->options | thd->options | SELECT_NO_UNLOCK, - union_result); - thd->lex.current_select= sl; offset_limit_cnt= sl->offset_limit; select_limit_cnt= sl->select_limit+sl->offset_limit; if (select_limit_cnt < sl->select_limit) @@ -287,22 +276,27 @@ int st_select_lex_unit::exec() if (select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - res= join->prepare(&sl->ref_pointer_array, - (TABLE_LIST*) sl->table_list.first, sl->with_wild, - sl->where, - ((sl->braces) ? sl->order_list.elements : 0) + - sl->group_list.elements, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl, this, t_and_f); - t_and_f=0; - if (res | thd->is_fatal_error) + /* + As far as union share table space we should reassign table map, + which can be spoiled by 'prepare' of JOIN of other UNION parts + if it use same tables + */ + uint tablenr=0; + for (TABLE_LIST *table_list= (TABLE_LIST*) sl->table_list.first; + table_list; + table_list= table_list->next, tablenr++) { - thd->lex.current_select= lex_select_save; - DBUG_RETURN(res); + if (table_list->shared) + { + /* + review notes: Check it carefully. I still can't understand + why I should not touch table->used_keys. For my point of + view we should do here same procedura as it was done by + setup_table + */ + DBUG_PRINT("SUBS", ("shared %s", table_list->real_name)); + setup_table_map(table_list->table, table_list, tablenr); + } } res= sl->join->optimize(); } @@ -327,8 +321,7 @@ int st_select_lex_unit::exec() /* Send result to 'result' */ - // to correct ORDER BY reference resolving - thd->lex.current_select= select_cursor; + res= -1; { List<Item_func_match> empty_list; @@ -336,7 +329,7 @@ int st_select_lex_unit::exec() if (!thd->is_fatal_error) // Check if EOM { - SELECT_LEX *fake_select = new SELECT_LEX(&thd->lex); + thd->lex.current_select= fake_select_lex; offset_limit_cnt= (select_cursor->braces ? global_parameters->offset_limit : 0); select_limit_cnt= (select_cursor->braces ? @@ -346,19 +339,38 @@ int st_select_lex_unit::exec() select_limit_cnt= HA_POS_ERROR; // no limit if (select_limit_cnt == HA_POS_ERROR) thd->options&= ~OPTION_FOUND_ROWS; - fake_select->ftfunc_list= &empty_list; - fake_select->table_list.link_in_list((byte *)&result_table_list, - (byte **)&result_table_list.next); - res= mysql_select(thd, &ref_pointer_array, &result_table_list, + fake_select_lex->ftfunc_list= &empty_list; + fake_select_lex->table_list.link_in_list((byte *)&result_table_list, + (byte **) + &result_table_list.next); + JOIN *join= fake_select_lex->join; + if (!join) + { + /* + allocate JOIN for fake select only once (privent + mysql_select automatic allocation) + */ + fake_select_lex->join= new JOIN(thd, item_list, thd->options, result); + } + else + { + JOIN_TAB *tab,*end; + for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) + { + delete tab->select; + delete tab->quick; + } + join->init(thd, item_list, thd->options, result); + } + res= mysql_select(thd, &fake_select_lex->ref_pointer_array, + &result_table_list, 0, item_list, NULL, global_parameters->order_list.elements, (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result, this, fake_select, 0); + thd->options, result, this, fake_select_lex, 0); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; - fake_select->exclude(); - delete fake_select; /* Mark for slow query log if any of the union parts didn't use indexes efficiently @@ -382,14 +394,21 @@ int st_select_lex_unit::cleanup() free_tmp_table(thd, table); table= 0; // Safety } + JOIN *join; for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select()) { - JOIN *join; if ((join= sl->join)) { error|= sl->join->cleanup(); delete join; } } + if (fake_select_lex && (join= fake_select_lex->join)) + { + join->tables_list= 0; + join->tables= 0; + error|= join->cleanup(); + delete join; + } DBUG_RETURN(error); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index aef58e6cb94..5af02a7b2ba 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1847,7 +1847,7 @@ table_to_table: table_ident TO_SYM table_ident { LEX *lex=Lex; - SELECT_LEX_NODE *sl= lex->current_select; + SELECT_LEX *sl= lex->current_select; if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING, TL_IGNORE) || !sl->add_table_to_list(lex->thd, $3,NULL,TL_OPTION_UPDATING, @@ -1883,7 +1883,7 @@ preload_keys: ; preload_keys_spec: - keys_or_index { Select->select_lex()->interval_list.empty(); } + keys_or_index { Select->interval_list.empty(); } preload_key_list_or_empty { LEX *lex=Lex; @@ -1924,7 +1924,7 @@ select_init: '(' SELECT_SYM select_part2 ')' { LEX *lex= Lex; - SELECT_LEX * sel= lex->current_select->select_lex(); + SELECT_LEX * sel= lex->current_select; if (sel->set_braces(1)) { send_error(lex->thd, ER_SYNTAX_ERROR); @@ -1938,14 +1938,14 @@ select_init: } /* select in braces, can't contain global parameters */ sel->master_unit()->global_parameters= - sel->master_unit(); + sel->master_unit()->fake_select_lex; } union_opt; select_init2: select_part2 { LEX *lex= Lex; - SELECT_LEX * sel= lex->current_select->select_lex(); + SELECT_LEX * sel= lex->current_select; if (lex->current_select->set_braces(0)) { send_error(lex->thd, ER_SYNTAX_ERROR); @@ -1964,7 +1964,7 @@ select_init2: select_part2: { LEX *lex=Lex; - SELECT_LEX * sel= lex->current_select->select_lex(); + SELECT_LEX * sel= lex->current_select; if (lex->current_select == &lex->select_lex) lex->lock_option= TL_READ; /* Only for global SELECT */ if (sel->linkage != UNION_TYPE) @@ -2055,7 +2055,7 @@ select_item_list: THD *thd= YYTHD; if (add_item_to_list(thd, new Item_field(NULL, NULL, "*"))) YYABORT; - (thd->lex.current_select->select_lex()->with_wild)++; + (thd->lex.current_select->with_wild)++; }; @@ -2706,9 +2706,9 @@ sum_expr: | COUNT_SYM '(' in_sum_expr ')' { $$=new Item_sum_count($3); } | COUNT_SYM '(' DISTINCT - { Select->select_lex()->in_sum_expr++; } + { Select->in_sum_expr++; } expr_list - { Select->select_lex()->in_sum_expr--; } + { Select->in_sum_expr--; } ')' { $$=new Item_sum_count_distinct(* $5); } | GROUP_UNIQUE_USERS '(' text_literal ',' NUM ',' NUM ',' in_sum_expr ')' @@ -2764,7 +2764,7 @@ in_sum_expr: } expr { - Select->select_lex()->in_sum_expr--; + Select->in_sum_expr--; $$= $3; }; @@ -2818,13 +2818,13 @@ when_list: when_list2: expr THEN_SYM expr { - SELECT_LEX_NODE *sel=Select; + SELECT_LEX *sel=Select; sel->when_list.head()->push_back($1); sel->when_list.head()->push_back($3); } | when_list2 WHEN_SYM expr THEN_SYM expr { - SELECT_LEX_NODE *sel=Select; + SELECT_LEX *sel=Select; sel->when_list.head()->push_back($3); sel->when_list.head()->push_back($5); }; @@ -2841,7 +2841,7 @@ join_table_list: | join_table_list normal_join join_table_list USING { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$3->db; sel->table2=$3->alias; } @@ -2852,7 +2852,7 @@ join_table_list: { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list LEFT opt_outer JOIN_SYM join_table_list { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$5->db; sel->table2=$5->alias; } @@ -2868,7 +2868,7 @@ join_table_list: { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$5; } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$5->db; sel->table2=$5->alias; } @@ -2891,14 +2891,14 @@ normal_join: join_table: { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->use_index_ptr=sel->ignore_index_ptr=0; sel->table_join_options= 0; } table_ident opt_table_alias opt_key_definition { LEX *lex= Lex; - SELECT_LEX_NODE *sel= lex->current_select; + SELECT_LEX *sel= lex->current_select; if (!($$= sel->add_table_to_list(lex->thd, $2, $3, sel->get_table_join_options(), lex->lock_option, @@ -2948,28 +2948,28 @@ opt_key_definition: /* empty */ {} | USE_SYM key_usage_list { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; } | FORCE_SYM key_usage_list { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; sel->table_join_options|= TL_OPTION_FORCE_INDEX; } | IGNORE_SYM key_usage_list { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->ignore_index= *$2; sel->ignore_index_ptr= &sel->ignore_index; }; key_usage_list: - key_or_index { Select->select_lex()->interval_list.empty(); } + key_or_index { Select->interval_list.empty(); } '(' key_list_or_empty ')' - { $$= &Select->select_lex()->interval_list; } + { $$= &Select->interval_list; } ; key_list_or_empty: @@ -2979,22 +2979,22 @@ key_list_or_empty: key_usage_list2: key_usage_list2 ',' ident - { Select->select_lex()-> + { Select-> interval_list.push_back(new String((const char*) $3.str, $3.length, system_charset_info)); } | ident - { Select->select_lex()-> + { Select-> interval_list.push_back(new String((const char*) $1.str, $1.length, system_charset_info)); } | PRIMARY_SYM - { Select->select_lex()-> + { Select-> interval_list.push_back(new String("PRIMARY", 7, system_charset_info)); }; using_list: ident { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1, $1.str), new Item_field(sel->db2, sel->table2, @@ -3003,7 +3003,7 @@ using_list: } | using_list ',' ident { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) YYABORT; }; @@ -3044,10 +3044,10 @@ opt_all: ; where_clause: - /* empty */ { Select->select_lex()->where= 0; } + /* empty */ { Select->where= 0; } | WHERE expr { - Select->select_lex()->where= $2; + Select->where= $2; if ($2) $2->top_level_item(); } @@ -3057,11 +3057,11 @@ having_clause: /* empty */ | HAVING { - Select->select_lex()->parsing_place= SELECT_LEX_NODE::IN_HAVING; + Select->parsing_place= SELECT_LEX_NODE::IN_HAVING; } expr { - SELECT_LEX *sel= Select->select_lex(); + SELECT_LEX *sel= Select; sel->having= $3; sel->parsing_place= SELECT_LEX_NODE::NO_MATTER; if ($3) @@ -3099,7 +3099,7 @@ olap_opt: "global union parameters"); YYABORT; } - lex->current_select->select_lex()->olap= CUBE_TYPE; + lex->current_select->olap= CUBE_TYPE; net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE"); YYABORT; /* To be deleted in 5.1 */ } @@ -3112,7 +3112,7 @@ olap_opt: "global union parameters"); YYABORT; } - lex->current_select->select_lex()->olap= ROLLUP_TYPE; + lex->current_select->olap= ROLLUP_TYPE; } ; @@ -3129,7 +3129,7 @@ order_clause: { LEX *lex=Lex; if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && - lex->current_select->select_lex()->olap != + lex->current_select->olap != UNSPECIFIED_OLAP_TYPE) { net_printf(lex->thd, ER_WRONG_USAGE, @@ -3154,7 +3154,7 @@ order_dir: opt_limit_clause_init: /* empty */ { - SELECT_LEX_NODE *sel= Select; + SELECT_LEX *sel= Select; sel->offset_limit= 0L; sel->select_limit= Lex->thd->variables.select_limit; } @@ -3173,19 +3173,19 @@ limit_clause: limit_options: ULONG_NUM { - SELECT_LEX_NODE *sel= Select; + SELECT_LEX *sel= Select; sel->select_limit= $1; sel->offset_limit= 0L; } | ULONG_NUM ',' ULONG_NUM { - SELECT_LEX_NODE *sel= Select; + SELECT_LEX *sel= Select; sel->select_limit= $3; sel->offset_limit= $1; } | ULONG_NUM OFFSET_SYM ULONG_NUM { - SELECT_LEX_NODE *sel= Select; + SELECT_LEX *sel= Select; sel->select_limit= $1; sel->offset_limit= $3; } @@ -4165,14 +4165,14 @@ table_wild: ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); - Lex->current_select->select_lex()->with_wild++; + Lex->current_select->with_wild++; } | ident '.' ident '.' '*' { $$ = new Item_field((YYTHD->client_capabilities & CLIENT_NO_SCHEMA ? NullS : $1.str), $3.str,"*"); - Lex->current_select->select_lex()->with_wild++; + Lex->current_select->with_wild++; } ; @@ -4182,7 +4182,7 @@ order_ident: simple_ident: ident { - SELECT_LEX_NODE *sel=Select; + SELECT_LEX *sel=Select; $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || sel->get_in_sum_expr() > 0) ? (Item*) new Item_field(NullS,NullS,$1.str) : @@ -4192,7 +4192,7 @@ simple_ident: { THD *thd= YYTHD; LEX *lex= &thd->lex; - SELECT_LEX_NODE *sel= lex->current_select; + SELECT_LEX *sel= lex->current_select; if (sel->no_table_names_allowed) { my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, @@ -4208,7 +4208,7 @@ simple_ident: { THD *thd= YYTHD; LEX *lex= &thd->lex; - SELECT_LEX_NODE *sel= lex->current_select; + SELECT_LEX *sel= lex->current_select; if (sel->no_table_names_allowed) { my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, @@ -4224,7 +4224,7 @@ simple_ident: { THD *thd= YYTHD; LEX *lex= &thd->lex; - SELECT_LEX_NODE *sel= lex->current_select; + SELECT_LEX *sel= lex->current_select; if (sel->no_table_names_allowed) { my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE, @@ -4928,7 +4928,7 @@ opt_table: '*' { LEX *lex= Lex; - lex->current_select->select_lex()->db= lex->thd->db; + lex->current_select->db= lex->thd->db; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) @@ -4940,7 +4940,7 @@ opt_table: | ident '.' '*' { LEX *lex= Lex; - lex->current_select->select_lex()->db = $1.str; + lex->current_select->db = $1.str; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) @@ -4952,7 +4952,7 @@ opt_table: | '*' '.' '*' { LEX *lex= Lex; - lex->current_select->select_lex()->db = NULL; + lex->current_select->db = NULL; if (lex->grant == GLOBAL_ACLS) lex->grant= GLOBAL_ACLS & ~GRANT_ACL; else if (lex->columns.elements) @@ -5147,11 +5147,12 @@ optional_order_or_limit: THD *thd= YYTHD; LEX *lex= &thd->lex; DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE); - SELECT_LEX *sel= lex->current_select->select_lex(); + SELECT_LEX *sel= lex->current_select; SELECT_LEX_UNIT *unit= sel->master_unit(); - unit->global_parameters= unit; - unit->no_table_names_allowed= 1; - lex->current_select= unit; + SELECT_LEX *fake= unit->fake_select_lex; + unit->global_parameters= fake; + fake->no_table_names_allowed= 1; + lex->current_select= fake; thd->where= "global ORDER clause"; } order_or_limit @@ -5219,7 +5220,9 @@ subselect_start: { LEX *lex=Lex; if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN && - lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL) { + lex->sql_command <= (int)SQLCOM_HA_READ) || + lex->sql_command == (int)SQLCOM_KILL) + { send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } diff --git a/sql/table.h b/sql/table.h index 2fab0087da4..fce2d97e393 100644 --- a/sql/table.h +++ b/sql/table.h @@ -165,15 +165,8 @@ typedef struct st_table_list struct st_table_list *natural_join; /* natural join on this table*/ /* ... join ... USE INDEX ... IGNORE INDEX */ List<String> *use_index, *ignore_index; - /* - Usually hold reference on opened table, but may hold reference - to node of complete list of tables used in UNION & subselect. - */ - union - { - TABLE *table; /* opened table */ - st_table_list *table_list; /* pointer to node of list of all tables */ - }; + TABLE *table; /* opened table */ + st_table_list *table_list; /* pointer to node of list of all tables */ class st_select_lex_unit *derived; /* SELECT_LEX_UNIT of derived table */ GRANT_INFO grant; thr_lock_type lock_type; |