diff options
author | unknown <bell@sanja.is.com.ua> | 2002-10-04 14:15:59 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2002-10-04 14:15:59 +0300 |
commit | 05c5908a9e801d604a5651ccb9fde081378435f9 (patch) | |
tree | c7e9f63a5d35171d649cbd11f951d58a8f953720 /sql | |
parent | e607221a3cd778131cc9250108473819c9b8c8a0 (diff) | |
parent | f094b6af4c5c32bfda7f74461d47675ab61722a0 (diff) | |
download | mariadb-git-05c5908a9e801d604a5651ccb9fde081378435f9.tar.gz |
merging
include/mysql_com.h:
Auto merged
mysql-test/r/create.result:
Auto merged
mysql-test/r/distinct.result:
Auto merged
mysql-test/r/group_by.result:
Auto merged
mysql-test/r/innodb.result:
Auto merged
mysql-test/r/key_primary.result:
Auto merged
mysql-test/r/merge.result:
Auto merged
mysql-test/r/odbc.result:
Auto merged
mysql-test/r/order_by.result:
Auto merged
mysql-test/r/union.result:
Auto merged
mysql-test/r/user_var.result:
Auto merged
mysql-test/r/varbinary.result:
Auto merged
mysql-test/t/union.test:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/sql_derived.cc:
Auto merged
sql/sql_select.h:
Auto merged
sql/sql_update.cc:
Auto merged
sql/table.h:
Auto merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 6 | ||||
-rw-r--r-- | sql/item_subselect.cc | 259 | ||||
-rw-r--r-- | sql/item_subselect.h | 135 | ||||
-rw-r--r-- | sql/mysql_priv.h | 9 | ||||
-rw-r--r-- | sql/mysqld.cc | 1 | ||||
-rw-r--r-- | sql/net_pkg.cc | 3 | ||||
-rw-r--r-- | sql/net_serv.cc | 39 | ||||
-rw-r--r-- | sql/sql_base.cc | 17 | ||||
-rw-r--r-- | sql/sql_class.cc | 78 | ||||
-rw-r--r-- | sql/sql_class.h | 7 | ||||
-rw-r--r-- | sql/sql_derived.cc | 23 | ||||
-rw-r--r-- | sql/sql_insert.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 11 | ||||
-rw-r--r-- | sql/sql_lex.h | 34 | ||||
-rw-r--r-- | sql/sql_parse.cc | 123 | ||||
-rw-r--r-- | sql/sql_select.cc | 212 | ||||
-rw-r--r-- | sql/sql_select.h | 4 | ||||
-rw-r--r-- | sql/sql_union.cc | 328 | ||||
-rw-r--r-- | sql/sql_update.cc | 3 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 12 | ||||
-rw-r--r-- | sql/table.h | 3 |
21 files changed, 861 insertions, 448 deletions
diff --git a/sql/item.cc b/sql/item.cc index 47c2926bef4..f1e25fb4d97 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -468,7 +468,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) s= s->outer_select()) if( !s->depended ) { - s->depended= 1; + // Select is depended of outer select + s->depended= s->master_unit()->depended= 1; //Tables will be reopened many times for (TABLE_LIST *tbl= (TABLE_LIST*)s->table_list.first; @@ -819,7 +820,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) s= s->outer_select()) if( !s->depended ) { - s->depended= 1; //Select is depended of outer select + // Select is depended of outer select + s->depended= s->master_unit()->depended= 1; //Tables will be reopened many times for (TABLE_LIST *tbl= (TABLE_LIST*)s->table_list.first; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index b0a94f0b8e6..99fc0bcdb67 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -23,9 +23,6 @@ SUBSELECT TODO: - remove double 'having' & 'having_list' from JOIN (sql_select.h/sql_select.cc) - - subselect in HAVING clause - - add subselect union select (sql_union.cc) - */ #ifdef __GNUC__ @@ -37,27 +34,17 @@ SUBSELECT TODO: Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex, select_subselect *result): - assigned(0), executed(0), optimized(0), error(0) + Item(), engine_owner(1), value_assigned(0) { DBUG_ENTER("Item_subselect::Item_subselect"); DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); - this->result= result; - SELECT_LEX_UNIT *unit= select_lex->master_unit(); - unit->offset_limit_cnt= unit->global_parameters->offset_limit; - unit->select_limit_cnt= unit->global_parameters->select_limit+ - unit->global_parameters ->offset_limit; - if (unit->select_limit_cnt < unit->global_parameters->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) - select_lex->options&= ~OPTION_FOUND_ROWS; - join= new JOIN(thd, select_lex->item_list, select_lex->options, result); - if (!join || !result) - { - //out of memory - thd->fatal_error= 1; - my_printf_error(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); - } - this->select_lex= select_lex; + + if (select_lex->next_select()) + engine= new subselect_union_engine(thd, select_lex->master_unit(), result, + this); + else + engine= new subselect_single_select_engine(thd, select_lex, result, + this); assign_null(); /* item value is NULL if select_subselect not changed this value @@ -67,6 +54,12 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex, DBUG_VOID_RETURN; } +Item_subselect::~Item_subselect() +{ + if (engine_owner) + delete engine; +} + void Item_subselect::make_field (Send_field *tmp_field) { if (null_value) @@ -84,62 +77,24 @@ void Item_subselect::make_field (Send_field *tmp_field) bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { // Is it one field subselect? - if (select_lex->item_list.elements > max_columns) + if (engine->cols() > max_columns) { - my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); + my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); return 1; } - SELECT_LEX *save_select= thd->lex.select; - thd->lex.select= select_lex; - if(join->prepare((TABLE_LIST*) select_lex->table_list.first, - select_lex->where, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*) 0, select_lex, - select_lex->master_unit())) - return 1; - thd->lex.select= save_select; - return 0; + int res= engine->prepare(); + fix_length_and_dec(); + return res; } -int Item_subselect::exec() +void Item_subselect::fix_length_and_dec() { - DBUG_ENTER("Item_subselect::exec"); - if (!optimized) - { - optimized=1; - if (join->optimize()) - { - executed= 1; - DBUG_RETURN(join->error?join->error:1); - } - } - if (join->select_lex->depended && executed) - { - if (join->reinit()) - { - error= 1; - DBUG_RETURN(1); - } - assign_null(); - executed= assigned= 0; - } - if (!executed) - { - SELECT_LEX *save_select= join->thd->lex.select; - join->thd->lex.select= select_lex; - join->exec(); - join->thd->lex.select= save_select; - executed= 1; - DBUG_RETURN(join->error); - } - DBUG_RETURN(0); + engine->fix_length_and_dec(); } inline table_map Item_subselect::used_tables() const { - return (table_map) select_lex->depended ? 1L : 0L; + return (table_map) engine->depended() ? 1L : 0L; } Item_singleval_subselect::Item_singleval_subselect(THD *thd, @@ -150,6 +105,12 @@ Item_singleval_subselect::Item_singleval_subselect(THD *thd, maybe_null= 1; } +void Item_singleval_subselect::fix_length_and_dec() +{ + engine->fix_length_and_dec(); + res_type= engine->type(); +} + Item::Type Item_subselect::type() const { return SUBSELECT_ITEM; @@ -157,21 +118,21 @@ Item::Type Item_subselect::type() const double Item_singleval_subselect::val () { - if (exec()) + if (engine->exec()) return 0; return real_value; } longlong Item_singleval_subselect::val_int () { - if (exec()) + if (engine->exec()) return 0; return int_value; } String *Item_singleval_subselect::val_str (String *str) { - if (exec() || null_value) + if (engine->exec() || null_value) return 0; return &str_value; } @@ -187,25 +148,177 @@ Item_exists_subselect::Item_exists_subselect(THD *thd, select_lex->select_limit= 1; // we need only 1 row to determinate existence } +void Item_exists_subselect::fix_length_and_dec() +{ + max_length= 1; + +} + double Item_exists_subselect::val () { - if (exec()) + if (engine->exec()) return 0; return (double) value; } longlong Item_exists_subselect::val_int () { - if (exec()) + if (engine->exec()) return 0; return value; } String *Item_exists_subselect::val_str(String *str) { - if (exec()) + if (engine->exec()) return 0; str->set(value); return str; } + +subselect_single_select_engine::subselect_single_select_engine(THD *thd, + st_select_lex *select, + select_subselect *result, + Item_subselect *item): + subselect_engine(thd, item, result), + executed(0), optimized(0) +{ + select_lex= select; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + unit->offset_limit_cnt= unit->global_parameters->offset_limit; + unit->select_limit_cnt= unit->global_parameters->select_limit+ + unit->global_parameters ->offset_limit; + if (unit->select_limit_cnt < unit->global_parameters->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; + join= new JOIN(thd, select_lex->item_list, select_lex->options, result); + if (!join || !result) + { + //out of memory + thd->fatal_error= 1; + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + this->select_lex= select_lex; +} + +subselect_union_engine::subselect_union_engine(THD *thd, + st_select_lex_unit *u, + select_subselect *result, + Item_subselect *item): + subselect_engine(thd, item, result) +{ + unit= u; + if( !result) + { + //out of memory + thd->fatal_error= 1; + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + unit->item= item; +} + +int subselect_single_select_engine::prepare() +{ + SELECT_LEX *save_select= thd->lex.select; + thd->lex.select= select_lex; + if(join->prepare((TABLE_LIST*) select_lex->table_list.first, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) 0, select_lex, + select_lex->master_unit(), 0)) + return 1; + thd->lex.select= save_select; + return 0; +} + +int subselect_union_engine::prepare() +{ + return unit->prepare(thd, result); +} + +void subselect_single_select_engine::fix_length_and_dec() +{ + List_iterator_fast<Item> li(select_lex->item_list); + Item *sel_item= li++; + item->max_length= sel_item->max_length; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; +} + +void subselect_union_engine::fix_length_and_dec() +{ + uint32 mlen= 0, len; + Item *sel_item= 0; + for(SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + { + List_iterator_fast<Item> li(sl->item_list); + Item *s_item= li++; + if ((len= s_item->max_length)) + mlen= len; + if (!sel_item) + sel_item= s_item; + } + item->max_length= mlen; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; +} + +int subselect_single_select_engine::exec() +{ + DBUG_ENTER("subselect_single_select_engine::exec"); + if (!optimized) + { + optimized=1; + if (join->optimize()) + { + executed= 1; + DBUG_RETURN(join->error?join->error:1); + } + } + if (select_lex->depended && executed) + { + if (join->reinit()) + DBUG_RETURN(1); + item->assign_null(); + item->assigned((executed= 0)); + } + if (!executed) + { + SELECT_LEX *save_select= join->thd->lex.select; + join->thd->lex.select= select_lex; + join->exec(); + join->thd->lex.select= save_select; + executed= 1; + DBUG_RETURN(join->error||thd->fatal_error); + } + DBUG_RETURN(0); +} + +int subselect_union_engine::exec() +{ + return unit->exec(); +} + +uint subselect_single_select_engine::cols() +{ + return select_lex->item_list.elements; +} + +uint subselect_union_engine::cols() +{ + return unit->first_select()->item_list.elements; +} + +bool subselect_single_select_engine::depended() +{ + return select_lex->depended; +} + +bool subselect_union_engine::depended() +{ + return unit->depended; +} diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 88ea01f9c68..92839eb0e5f 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -21,30 +21,24 @@ #endif class st_select_lex; +class st_select_lex_unit; class JOIN; class select_subselect; +class subselect_engine; /* base class for subselects */ class Item_subselect :public Item { + my_bool engine_owner; /* Is this item owner of engine */ + my_bool value_assigned; /* value already assigned to subselect */ protected: + /* engine that perform execution of subselect (single select or union) */ + subselect_engine *engine; + /* allowed number of columns (1 for single value subqueries) */ uint max_columns; - my_bool assigned; /* value already assigned to subselect */ - my_bool executed; /* simple subselect is executed */ - my_bool optimized; /* simple subselect is optimized */ - my_bool error; /* error in query */ - int exec(); - virtual void assign_null() - { - null_value= 1; - } public: - st_select_lex *select_lex; - JOIN *join; - select_subselect *result; - Item_subselect(THD *thd, st_select_lex *select_lex, select_subselect* result); Item_subselect(Item_subselect *item) @@ -52,18 +46,22 @@ public: null_value= item->null_value; decimals= item->decimals; max_columns= item->max_columns; - assigned= item->assigned; - executed= item->executed; - select_lex= item->select_lex; - join= item->join; - result= item->result; + engine= item->engine; + engine_owner= 0; name= item->name; - error= item->error; } + ~Item_subselect(); + virtual void assign_null() + { + null_value= 1; + } + bool assigned() { return value_assigned; } + void assigned(bool a) { value_assigned= a; } enum Type type() const; bool is_null() { return null_value; } void make_field (Send_field *); bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + virtual void fix_length_and_dec(); table_map used_tables() const; friend class select_subselect; @@ -75,18 +73,10 @@ public: class Item_singleval_subselect :public Item_subselect { protected: - longlong int_value; - double real_value; - enum Item_result res_type; + longlong int_value; /* here stored integer value of this item */ + double real_value; /* here stored real value of this item */ + enum Item_result res_type; /* type of results */ - virtual void assign_null() - { - null_value= 1; - int_value= 0; - real_value= 0; - max_length= 4; - res_type= STRING_RESULT; - } public: Item_singleval_subselect(THD *thd, st_select_lex *select_lex); Item_singleval_subselect(Item_singleval_subselect *item): @@ -98,12 +88,20 @@ public: decimals= item->decimals; res_type= item->res_type; } + virtual void assign_null() + { + null_value= 1; + int_value= 0; + real_value= 0; + max_length= 4; + res_type= STRING_RESULT; + } double val (); longlong val_int (); String *val_str (String *); Item *new_item() { return new Item_singleval_subselect(this); } enum Item_result result_type() const { return res_type; } - + void fix_length_and_dec(); friend class select_singleval_subselect; }; @@ -112,12 +110,8 @@ public: class Item_exists_subselect :public Item_subselect { protected: - longlong value; + longlong value; /* value of this item (boolean: exists/not-exists) */ - virtual void assign_null() - { - value= 0; - } public: Item_exists_subselect(THD *thd, st_select_lex *select_lex); Item_exists_subselect(Item_exists_subselect *item): @@ -125,11 +119,78 @@ public: { value= item->value; } + virtual void assign_null() + { + value= 0; + } + Item *new_item() { return new Item_exists_subselect(this); } enum Item_result result_type() const { return INT_RESULT;} longlong val_int(); double val(); String *val_str(String*); - + void fix_length_and_dec(); friend class select_exists_subselect; }; + +class subselect_engine +{ +protected: + select_subselect *result; /* results storage class */ + THD *thd; /* pointer to current THD */ + Item_subselect *item; /* item, that use this engine */ + enum Item_result res_type; /* type of results */ +public: + static void *operator new(size_t size) + { + return (void*) sql_alloc((uint) size); + } + static void operator delete(void *ptr, size_t size) {} + + subselect_engine(THD *thd, Item_subselect *si, select_subselect *res) + { + result= res; + item= si; + this->thd= thd; + res_type= STRING_RESULT; + } + + virtual int prepare()= 0; + virtual void fix_length_and_dec()= 0; + virtual int exec()= 0; + virtual uint cols()= 0; /* return number of columnss in select */ + virtual bool depended()= 0; /* depended from outer select */ + enum Item_result type() { return res_type; } +}; + +class subselect_single_select_engine: public subselect_engine +{ + my_bool executed; /* simple subselect is executed */ + my_bool optimized; /* simple subselect is optimized */ + st_select_lex *select_lex; /* corresponding select_lex */ + JOIN * join; /* corresponding JOIN structure */ +public: + subselect_single_select_engine(THD *thd, st_select_lex *select, + select_subselect *result, + Item_subselect *item); + virtual int prepare(); + virtual void fix_length_and_dec(); + virtual int exec(); + virtual uint cols(); + virtual bool depended(); +}; + +class subselect_union_engine: public subselect_engine +{ + st_select_lex_unit *unit; /* corresponding unit structure */ +public: + subselect_union_engine(THD *thd, + st_select_lex_unit *u, + select_subselect *result, + Item_subselect *item); + virtual int prepare(); + virtual void fix_length_and_dec(); + virtual int exec(); + virtual uint cols(); + virtual bool depended(); +}; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index dc58d3cc64e..8e691c8f96c 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -389,9 +389,14 @@ int handle_select(THD *thd, LEX *lex, select_result *result); int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds, ORDER *order, ORDER *group,Item *having,ORDER *proc_param, ulong select_type,select_result *result, - SELECT_LEX_UNIT *unit); + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool fake_select_lex); +void fix_tables_pointers(SELECT_LEX *select_lex); +int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type, + select_result *result); int mysql_union(THD *thd, LEX *lex,select_result *result); -int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t); +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t, + bool tables_is_opened); Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, Item_result_field ***copy_func, Field **from_field, bool group,bool modify_item); diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 900d529827e..a3a82d96b2e 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1647,6 +1647,7 @@ static int my_message_sql(uint error, const char *str, if ((thd=current_thd)) { NET *net= &thd->net; + net->report_error= 1; if (!net->last_error[0]) // Return only first message { strmake(net->last_error,str,sizeof(net->last_error)-1); diff --git a/sql/net_pkg.cc b/sql/net_pkg.cc index ef90c12586b..fc8bc77e713 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -66,10 +66,9 @@ void send_error(THD *thd, uint sql_errno, const char *err) else { length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); - } VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); thd->fatal_error=0; // Error message is given + thd->net.report_error= 0; DBUG_VOID_RETURN; } diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 51910167d97..d165125eb90 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -99,6 +99,7 @@ my_bool my_net_init(NET *net, Vio* vio) net->where_b = net->remain_in_buf=0; net->last_errno=0; net->query_cache_query=0; + net->report_error= 0; if (vio != 0) /* If real connection */ { @@ -134,8 +135,9 @@ my_bool net_realloc(NET *net, ulong length) if (length >= net->max_packet_size) { DBUG_PRINT("error",("Packet too large (%lu)", length)); - net->error=1; - net->last_errno=ER_NET_PACKET_TOO_LARGE; + net->error= 1; + net->report_error= 1; + net->last_errno= ER_NET_PACKET_TOO_LARGE; return 1; } pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); @@ -147,9 +149,10 @@ my_bool net_realloc(NET *net, ulong length) NET_HEADER_SIZE + COMP_HEADER_SIZE, MYF(MY_WME)))) { - net->error=1; + net->error= 1; + net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno=ER_OUT_OF_RESOURCES; + net->last_errno= ER_OUT_OF_RESOURCES; #endif return 1; } @@ -369,10 +372,12 @@ net_real_write(NET *net,const char *packet,ulong len) COMP_HEADER_SIZE, MYF(MY_WME)))) { #ifdef MYSQL_SERVER - net->last_errno=ER_OUT_OF_RESOURCES; - net->error=2; + net->last_errno= ER_OUT_OF_RESOURCES; + net->error= 2; + //TODO is it needed to set this variable if we have no socket + net->report_error= 1; #endif - net->reading_or_writing=0; + net->reading_or_writing= 0; DBUG_RETURN(1); } memcpy(b+header_length,packet,len); @@ -422,9 +427,10 @@ net_real_write(NET *net,const char *packet,ulong len) my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_ERROR_ON_WRITE; + net->last_errno= ER_NET_ERROR_ON_WRITE; #endif - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; goto end; } retry_count=0; @@ -450,7 +456,8 @@ net_real_write(NET *net,const char *packet,ulong len) continue; } #endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */ - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : ER_NET_ERROR_ON_WRITE); @@ -586,9 +593,10 @@ my_real_read(NET *net, ulong *complen) my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ len= packet_error; - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno=ER_NET_FCNTL_ERROR; + net->last_errno= ER_NET_FCNTL_ERROR; #endif goto end; } @@ -618,7 +626,8 @@ my_real_read(NET *net, ulong *complen) remain,vio_errno(net->vio), length, thr_got_alarm(&alarmed))); len= packet_error; - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); @@ -648,6 +657,7 @@ my_real_read(NET *net, ulong *complen) #endif } len= packet_error; + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER; #endif @@ -821,7 +831,8 @@ my_net_read(NET *net) if (my_uncompress((byte*) net->buff + net->where_b, &packet_len, &complen)) { - net->error=2; /* caller will close socket */ + net->error= 2; /* caller will close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno=ER_NET_UNCOMPRESS_ERROR; #endif diff --git a/sql/sql_base.cc b/sql/sql_base.cc index fb6f05848c7..8deae314484 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1852,8 +1852,9 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables, { if (!report_error) // Returns first found break; - my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), - name,thd->where); + if (report_error) + my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), + name,thd->where); return (Field*) 0; } found=field; @@ -1917,8 +1918,8 @@ find_item_in_list(Item *find, List<Item> &items, bool report_error) } } if (!found && report_error) - my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - find->full_name(),current_thd->where); + my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), + find->full_name(), current_thd->where); return found; } @@ -2390,8 +2391,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, int setup_ftfuncs(THD *thd) { - List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list), - lj(thd->lex.select->ftfunc_list); + List_iterator<Item_func_match> li(*(thd->lex.select->ftfunc_list)), + lj(*(thd->lex.select->ftfunc_list)); Item_func_match *ftf, *ftf2; while ((ftf=li++)) @@ -2412,9 +2413,9 @@ int setup_ftfuncs(THD *thd) int init_ftfuncs(THD *thd, bool no_order) { - if (thd->lex.select->ftfunc_list.elements) + if (thd->lex.select->ftfunc_list->elements) { - List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list); + List_iterator<Item_func_match> li(*(thd->lex.select->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); thd->proc_info="FULLTEXT initialization"; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 09f5a78fcc8..648e05c1610 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -384,6 +384,28 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) return new_table; } +int THD::send_explain_fields(select_result *result) +{ + List<Item> field_list; + Item *item; + field_list.push_back(new Item_int("id",0,3)); + field_list.push_back(new Item_empty_string("select_type",19)); + field_list.push_back(new Item_empty_string("table",NAME_LEN)); + field_list.push_back(new Item_empty_string("type",10)); + field_list.push_back(item=new Item_empty_string("possible_keys", + NAME_LEN*MAX_KEY)); + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); + item->maybe_null=1; + field_list.push_back(item=new Item_int("key_len",0,3)); + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("ref", + NAME_LEN*MAX_REF_PARTS)); + item->maybe_null=1; + field_list.push_back(new Item_real("rows",0.0,0,10)); + field_list.push_back(new Item_empty_string("Extra",255)); + return (result->send_fields(field_list,1)); +} #ifdef SIGNAL_WITH_VIO_CLOSE void THD::close_active_vio() @@ -446,13 +468,19 @@ bool select_send::send_data(List<Item> &items) if (item->send(thd, packet)) { packet->free(); // Free used - my_error(ER_OUT_OF_RESOURCES,MYF(0)); + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); DBUG_RETURN(1); } } thd->sent_row_count++; - bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length()); - DBUG_RETURN(error); + if (!thd->net.report_error) + { + DBUG_RETURN(my_net_write(&thd->net, + (char*) packet->ptr(), + packet->length())); + } + else + DBUG_RETURN(1); } bool select_send::send_eof() @@ -462,8 +490,13 @@ bool select_send::send_eof() { mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - ::send_eof(thd); - return 0; + if (!thd->net.report_error) + { + ::send_eof(thd); + return 0; + } + else + return 1; } @@ -499,7 +532,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u) option); if (!access(path,F_OK)) { - my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name); + my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name); return 1; } /* Create the file world readable */ @@ -685,9 +718,9 @@ err: } -void select_export::send_error(uint errcode,const char *err) +void select_export::send_error(uint errcode, const char *err) { - ::send_error(thd,errcode,err); + my_message(errcode, err, MYF(0));; (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); file= -1; @@ -699,9 +732,7 @@ bool select_export::send_eof() int error=test(end_io_cache(&cache)); if (my_close(file,MYF(MY_WME))) error=1; - if (error) - ::send_error(thd); - else + if (!error) ::send_ok(thd,row_count); file= -1; return error; @@ -774,7 +805,7 @@ bool select_dump::send_data(List<Item> &items) } if (row_count++ > 1) { - my_error(ER_TOO_MANY_ROWS,MYF(0)); + my_error(ER_TOO_MANY_ROWS, MYF(0)); goto err; } while ((item=li++)) @@ -799,7 +830,7 @@ err: void select_dump::send_error(uint errcode,const char *err) { - ::send_error(thd,errcode,err); + my_message(errcode, err, MYF(0)); (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); (void) my_delete(path,MYF(0)); // Delete file on error @@ -811,9 +842,7 @@ bool select_dump::send_eof() int error=test(end_io_cache(&cache)); if (my_close(file,MYF(MY_WME))) error=1; - if (error) - ::send_error(thd); - else + if (!error) ::send_ok(thd,row_count); file= -1; return error; @@ -828,8 +857,9 @@ bool select_singleval_subselect::send_data(List<Item> &items) { DBUG_ENTER("select_singleval_subselect::send_data"); Item_singleval_subselect *it= (Item_singleval_subselect *)item; - if (it->assigned){ - my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); + if (it->assigned()){ + thd->fatal_error= 1; + my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); DBUG_RETURN(1); } if (unit->offset_limit_cnt) @@ -847,15 +877,19 @@ bool select_singleval_subselect::send_data(List<Item> &items) if ((it->null_value= val_item->is_null())) { it->assign_null(); - } else { + } + else + { it->max_length= val_item->max_length; it->decimals= val_item->decimals; it->binary= val_item->binary; - val_item->val_str(&it->str_value); it->int_value= val_item->val_int(); + String *s= val_item->val_str(&it->str_value); + if (s != &it->str_value) + it->str_value.set(*s, 0, s->length()); it->res_type= val_item->result_type(); } - it->assigned= 1; + it->assigned(1); DBUG_RETURN(0); } @@ -869,7 +903,7 @@ bool select_exists_subselect::send_data(List<Item> &items) DBUG_RETURN(0); } it->value= 1; - it->assigned= 1; + it->assigned(1); DBUG_RETURN(0); } diff --git a/sql/sql_class.h b/sql/sql_class.h index a986326fe5d..e9a4109a4c1 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -330,6 +330,7 @@ typedef struct st_prep_stmt class delayed_insert; +class select_result; #define THD_SENTRY_MAGIC 0xfeedd1ff #define THD_SENTRY_GONE 0xdeadbeef @@ -491,6 +492,7 @@ public: uint server_status,open_options; uint32 query_length; uint32 db_length; + uint select_number; //number of select (used for EXPLAIN) /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; char scramble[9]; @@ -504,7 +506,7 @@ public: bool query_error, bootstrap, cleanup_done; bool safe_to_cache_query; bool volatile killed; - bool prepare_command; + bool prepare_command; Item_param *params; // Pointer to array of params /* @@ -621,6 +623,7 @@ public: void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); + int send_explain_fields(select_result *result); }; /* @@ -666,7 +669,7 @@ public: virtual void initialize_tables (JOIN *join=0) {} virtual void send_error(uint errcode,const char *err) { - ::send_error(thd,errcode,err); + my_message(errcode, err, MYF(0)); } virtual bool send_eof()=0; virtual void abort() {} diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index 6b144d36f53..81eade6edb7 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -28,7 +28,8 @@ static const char *any_db="*any*"; // Special symbol for check_access -int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t, + bool tables_is_opened) { /* TODO: make derived tables with union inside (now only 1 SELECT may be @@ -37,7 +38,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) SELECT_LEX *sl= unit->first_select(); List<Item> item_list; TABLE *table; - int res; + int res= 0; select_union *derived_result; TABLE_LIST *tables= (TABLE_LIST *)sl->table_list.first; TMP_TABLE_PARAM tmp_table_param; @@ -56,7 +57,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) { if (cursor->derived) { - res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, cursor); + res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, + cursor, 0); if (res) DBUG_RETURN(res); } } @@ -66,7 +68,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) while ((item= it++)) item_list.push_back(item); - if (!(res=open_and_lock_tables(thd,tables))) + if (tables_is_opened || !(res=open_and_lock_tables(thd,tables))) { if (tables && setup_fields(thd,tables,item_list,0,0,1)) { @@ -94,12 +96,12 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) if (unit->select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - res=mysql_select(thd, tables, sl->item_list, - sl->where, (ORDER *) sl->order_list.first, - (ORDER*) sl->group_list.first, - sl->having, (ORDER*) NULL, - sl->options | thd->options | SELECT_NO_UNLOCK, - derived_result, unit); + res= mysql_select(thd, tables, sl->item_list, + sl->where, (ORDER *) sl->order_list.first, + (ORDER*) sl->group_list.first, + sl->having, (ORDER*) NULL, + sl->options | thd->options | SELECT_NO_UNLOCK, + derived_result, unit, sl, 0); if (!res) { // Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables @@ -109,6 +111,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t) { t->real_name=table->real_name; t->table=table; + table->derived_select_number= sl->select_number; sl->exclude(); t->derived=(SELECT_LEX *)0; // just in case ... } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index b0e52d95808..d15d9a407d6 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1334,6 +1334,7 @@ bool select_insert::send_data(List<Item> &values) void select_insert::send_error(uint errcode,const char *err) { + //TODO error should be sent at the query processing end ::send_error(thd,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); @@ -1360,6 +1361,7 @@ bool select_insert::send_eof() if (error) { table->file->print_error(error,MYF(0)); + //TODO error should be sent at the query processing end ::send_error(thd); return 1; } diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 6ee1164806d..122ceeedc54 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -146,8 +146,9 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->length=0; lex->select_lex.in_sum_expr=0; lex->select_lex.expr_list.empty(); - lex->select_lex.ftfunc_list.empty(); - lex->convert_set=(lex->thd=thd)->variables.convert_set; + lex->select_lex.ftfunc_list_alloc.empty(); + lex->select_lex.ftfunc_list= &lex->select->ftfunc_list_alloc; + lex->convert_set= (lex->thd= thd)->variables.convert_set; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); lex->slave_thd_opt=0; @@ -943,6 +944,8 @@ void st_select_lex_unit::init_query() global_parameters= this; select_limit_cnt= HA_POS_ERROR; offset_limit_cnt= 0; + optimized= 0; + item= 0; } void st_select_lex::init_query() @@ -966,9 +969,11 @@ void st_select_lex::init_select() expr_list.empty(); interval_list.empty(); use_index.empty(); - ftfunc_list.empty(); + ftfunc_list_alloc.empty(); + ftfunc_list= &ftfunc_list_alloc; linkage= UNSPECIFIED_TYPE; depended= having_fix_field= 0; + } /* diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 46a1b8506f0..acf73f34d5d 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -212,7 +212,22 @@ private: */ class st_lex; class st_select_lex; +class THD; +class select_result; +class JOIN; +class select_union; class st_select_lex_unit: public st_select_lex_node { +protected: + List<Item> item_list; + List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */ + TABLE_LIST result_table_list; + select_union *union_result; + TABLE *table; /* temporary table using for appending UNION results */ + THD *thd; + select_result *result; + int res; + bool describe, found_rows_for_union, + optimized; // optimize phase already performed for UNION (unit) public: /* Pointer to 'last' select or pointer to unit where stored @@ -221,12 +236,21 @@ public: st_select_lex_node *global_parameters; /* LIMIT clause runtime counters */ ha_rows select_limit_cnt, offset_limit_cnt; + bool depended; /* depended from outer select subselect */ + /* not NULL if union used in subselect, point to subselect item */ + Item_subselect *item; + void init_query(); bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); st_select_lex* outer_select() { return (st_select_lex*) master; } st_select_lex* first_select() { return (st_select_lex*) slave; } st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } + /* UNION methods */ + int prepare(THD *thd, select_result *result); + int exec(); + int cleanup(); + friend void mysql_init_query(THD *thd); private: bool create_total_list_n_last_return(THD *thd, st_lex *lex, @@ -237,7 +261,6 @@ typedef class st_select_lex_unit SELECT_LEX_UNIT; /* SELECT_LEX - store information of parsed SELECT_LEX statment */ -class JOIN; class st_select_lex: public st_select_lex_node { public: @@ -250,9 +273,16 @@ public: List<Item> item_list; /* list of fields & expressions */ List<String> interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; - List<Item_func_match> ftfunc_list; + /* + Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake + select_lex for calling mysql_select under results of union + */ + List<Item_func_match> *ftfunc_list; + 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 */ uint in_sum_expr; + uint select_number; /* number of select (used for EXPLAIN) */ bool create_refs; bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ bool depended; /* depended from outer select subselect */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index f23c5edfe05..62744edd763 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -680,7 +680,7 @@ pthread_handler_decl(handle_one_connection,arg) if (thd->user_connect) decrease_user_connections(thd->user_connect); free_root(&thd->mem_root,MYF(0)); - if (net->error && net->vio != 0) + if (net->error && net->vio != 0 && net->report_error) { if (!thd->killed && thd->variables.log_warnings) sql_print_error(ER(ER_NEW_ABORTING_CONNECTION), @@ -1305,6 +1305,7 @@ mysql_execute_command(THD *thd) */ thd->old_total_warn_count= thd->total_warn_count; + thd->net.report_error= 0; if (thd->slave_thread) { /* @@ -1327,18 +1328,69 @@ mysql_execute_command(THD *thd) #endif } + select_result *explain_result= 0; /* - Skip if we are in the slave thread, some table rules have been given - and the table list says the query should not be replicated + TODO: make derived tables processing 'inside' SELECT processing. + TODO: solve problem with depended derived tables in subselects */ - if (lex->derived_tables) + if (lex->sql_command == SQLCOM_SELECT && + (select_lex->options & SELECT_DESCRIBE) && + lex->derived_tables) + { + if (!(explain_result= new select_send())) + { + send_error(&thd->net, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; + } + //check rights + for (TABLE_LIST *cursor= tables; + cursor; + cursor= cursor->next) + if (cursor->derived) + { + TABLE_LIST *tables= + (TABLE_LIST *)((SELECT_LEX_UNIT *) + cursor->derived)->first_select()->table_list.first; + int res; + if (tables) + res= check_table_access(thd,SELECT_ACL, tables); + else + res= check_access(thd, SELECT_ACL, any_db); + if (res) + DBUG_VOID_RETURN; + } + thd->send_explain_fields(explain_result); + // EXPLAIN derived tables + for (TABLE_LIST *cursor= tables; + cursor; + cursor= cursor->next) + if (cursor->derived) + { + SELECT_LEX *select_lex= ((SELECT_LEX_UNIT *) + cursor->derived)->first_select(); + if (!open_and_lock_tables(thd, + (TABLE_LIST*) select_lex->table_list.first)) + { + mysql_explain_select(thd, select_lex, + "DERIVED", explain_result); + // execute derived table SELECT to provide table for other SELECTs + if (mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, + cursor, 1)) + DBUG_VOID_RETURN; + } + else + DBUG_VOID_RETURN; + } + + } + else if (lex->derived_tables) { for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next) if (cursor->derived && mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, - cursor)) + cursor, 0)) DBUG_VOID_RETURN; } if ((lex->select_lex.next_select_in_list() && @@ -1420,8 +1472,46 @@ mysql_execute_command(THD *thd) if (!(res=open_and_lock_tables(thd,tables))) { - query_cache_store_query(thd, tables); - res=handle_select(thd, lex, result); + if (select_lex->options & SELECT_DESCRIBE) + { + delete result; // we do not need it for explain + if (!explain_result) + if (!(explain_result= new select_send())) + { + send_error(&thd->net, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; + } + else + thd->send_explain_fields(explain_result); + fix_tables_pointers(select_lex); + for ( SELECT_LEX *sl= select_lex; + sl && res == 0; + sl= sl->next_select_in_list()) + { + SELECT_LEX *first= sl->master_unit()->first_select(); + res= mysql_explain_select(thd, sl, + ((select_lex==sl)? + ((sl->next_select_in_list())?"PRIMARY": + "SIMPLE"): + ((sl == first)? + ((sl->depended)?"DEPENDENT SUBSELECT": + "SUBSELECT"): + ((sl->depended)?"DEPENDENT UNION": + "UNION"))), + explain_result); + } + if (res > 0) + res= -res; // mysql_explain_select do not report error + MYSQL_LOCK *save_lock= thd->lock; + thd->lock= (MYSQL_LOCK *)0; + explain_result->send_eof(); + thd->lock= save_lock; + } + else + { + query_cache_store_query(thd, tables); + res=handle_select(thd, lex, result); + } } else delete result; @@ -1939,7 +2029,7 @@ mysql_execute_command(THD *thd) (ORDER *)NULL, select_lex->options | thd->options | SELECT_NO_JOIN_CACHE, - result, unit); + result, unit, select_lex, 0); delete result; } else @@ -2100,13 +2190,13 @@ mysql_execute_command(THD *thd) lex->lock_option, table_count))) { - res=mysql_select(thd,tables,select_lex->item_list, - select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, - (ORDER *)NULL, - select_lex->options | thd->options | - SELECT_NO_JOIN_CACHE, - result, unit); + res= mysql_select(thd,tables,select_lex->item_list, + select_lex->where, + (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, + (ORDER *)NULL, + select_lex->options | thd->options | + SELECT_NO_JOIN_CACHE, + result, unit, select_lex, 0); delete result; } else @@ -2850,6 +2940,7 @@ mysql_init_query(THD *thd) thd->lex.unit.global_parameters= &thd->lex.select_lex; //Global limit & order thd->lex.select_lex.master= &thd->lex.unit; thd->lex.select_lex.prev= &thd->lex.unit.slave; + thd->select_number= thd->lex.select_lex.select_number= 1; thd->lex.value_list.empty(); thd->free_list= 0; thd->lex.union_option= 0; @@ -2882,6 +2973,7 @@ bool mysql_new_select(LEX *lex, bool move_down) { SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX)); + select_lex->select_number= ++lex->thd->select_number; if (!select_lex) return 1; select_lex->init_query(); @@ -2953,6 +3045,7 @@ mysql_parse(THD *thd, char *inBuf, uint length) mysql_init_query(thd); thd->query_length = length; + thd->lex.derived_tables= false; if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 55e07c8bb20..c4b100e453e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -144,7 +144,7 @@ static void init_sum_functions(Item_sum **func); static bool update_sum_func(Item_sum **func); static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct, const char *message=NullS); -static void describe_info(JOIN *join, const char *info); + /* This handles SELECT with and without UNION @@ -154,40 +154,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result) { int res; register SELECT_LEX *select_lex = &lex->select_lex; - if (select_lex->next_select_in_list()) - { - /* Fix tables 'to-be-unioned-from' list to point at opened tables */ - for (SELECT_LEX *sl= select_lex; - sl; - sl= sl->next_select_in_list()) - { - for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; - cursor; - cursor=cursor->next) - cursor->table= ((TABLE_LIST*) cursor->table)->table; - } - } - -#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1 - if (lex->olap) - { - SELECT_LEX *sl, *sl_next; - int error; - for (sl= &select_lex; sl; sl=sl_next) - { - sl_next=sl->next; // Save if sl->next changes - if (sl->olap != UNSPECIFIED_OLAP_TYPE) - { - if ((error=handle_olaps(lex,sl))) - return error; - lex->last_selects->next=sl_next; - } - } - lex->select = select_lex; - } -#endif /* DISABLED_UNTIL_REWRITTEN_IN_4_1 */ - if (select_lex->next_select()) + if (select_lex->next_select()) res=mysql_union(thd,lex,result); else res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, @@ -198,13 +166,34 @@ int handle_select(THD *thd, LEX *lex, select_result *result) select_lex->having, (ORDER*) lex->proc_list.first, select_lex->options | thd->options, - result, &(lex->unit)); + result, &(lex->unit), &(lex->select_lex), 0); if (res && result) result->abort(); + if (res || thd->net.report_error) + { + send_error(&thd->net, 0, MYF(0)); + res= 1; + } delete result; return res; } +void fix_tables_pointers(SELECT_LEX *select_lex) +{ + if (select_lex->next_select_in_list()) + { + /* Fix tables 'to-be-unioned-from' list to point at opened tables */ + for (SELECT_LEX *sl= select_lex; + sl; + sl= sl->next_select_in_list()) + { + for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; + cursor; + cursor=cursor->next) + cursor->table= cursor->table_list->table; + } + } +} /***************************************************************************** Check fields, find best join, do the select and output fields. @@ -221,10 +210,10 @@ JOIN::prepare(TABLE_LIST *tables_init, COND *conds_init, ORDER *order_init, ORDER *group_init, Item *having_init, ORDER *proc_param_init, SELECT_LEX *select, - SELECT_LEX_UNIT *unit) + SELECT_LEX_UNIT *unit, bool fake_select_lex) { DBUG_ENTER("JOIN::prepare"); - + conds= conds_init; order= order_init; group_list= group_init; @@ -232,7 +221,8 @@ JOIN::prepare(TABLE_LIST *tables_init, proc_param= proc_param_init; tables_list= tables_init; select_lex= select; - select_lex->join= this; + if (!fake_select_lex) + select_lex->join= this; union_part= (unit->first_select()->next_select() != 0); /* Check that all tables, fields, conds and order are ok */ @@ -252,7 +242,7 @@ JOIN::prepare(TABLE_LIST *tables_init, select_lex->having_fix_field= 1; bool having_fix_rc= having->fix_fields(thd, tables_list, &having); select_lex->having_fix_field= 0; - if (having_fix_rc || thd->fatal_error) + if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) having->split_sum_func(all_fields); @@ -358,7 +348,7 @@ int JOIN::optimize() { DBUG_ENTER("JOIN::optimize"); - + #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ if (having && !group_list && ! sum_func_count) @@ -403,7 +393,8 @@ JOIN::optimize() } if (select_options & SELECT_DESCRIBE) { - describe_info(this, "Select tables optimized away"); + select_describe(this, false, false, false, + "Select tables optimized away"); delete procedure; DBUG_RETURN(1); } @@ -565,7 +556,7 @@ JOIN::optimize() make_join_readinfo(this, (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) | - (thd->lex.select->ftfunc_list.elements ? + (thd->lex.select->ftfunc_list->elements ? SELECT_NO_JOIN_CACHE : 0)); /* @@ -668,7 +659,7 @@ JOIN::exec() { // Only test of functions error=0; if (select_options & SELECT_DESCRIBE) - describe_info(this, "No tables used"); + select_describe(this, false, false, false, "No tables used"); else { result->send_fields(fields_list,1); @@ -677,10 +668,10 @@ JOIN::exec() if (do_send_rows && result->send_data(fields_list)) { result->send_error(0,NullS); /* purecov: inspected */ - error=1; + error= 1; } else - error=(int) result->send_eof(); + error= (int) result->send_eof(); } else error=(int) result->send_eof(); @@ -692,6 +683,7 @@ JOIN::exec() if (zero_result_cause) { error=0; + (void) return_zero_rows(this, result, tables_list, fields_list, tmp_table_param.sum_func_count != 0 && !group_list, @@ -1021,8 +1013,10 @@ JOIN::cleanup(THD *thd) int mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, - ORDER *order, ORDER *group,Item *having, ORDER *proc_param, - ulong select_options, select_result *result, SELECT_LEX_UNIT *unit) + ORDER *order, ORDER *group,Item *having, ORDER *proc_param, + ulong select_options, select_result *result, + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool fake_select_lex) { JOIN *join = new JOIN(thd, fields, select_options, result); @@ -1031,7 +1025,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, thd->used_tables=0; // Updated by setup_fields if (join->prepare(tables, conds, order, group, having, proc_param, - &(thd->lex.select_lex), unit)) + select_lex, unit, fake_select_lex)) { DBUG_RETURN(-1); } @@ -1051,7 +1045,7 @@ err: thd->limit_found_rows = join->send_records; thd->examined_row_count = join->examined_rows; thd->proc_info="end"; - int error= join->cleanup(thd); + int error= (fake_select_lex?0:join->cleanup(thd)) || thd->net.report_error; delete join; DBUG_RETURN(error); } @@ -1785,7 +1779,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, add_key_part(keyuse,field); } - if (thd->lex.select->ftfunc_list.elements) + if (thd->lex.select->ftfunc_list->elements) { add_ft_keys(keyuse,join_tab,cond,normal_tables); } @@ -3114,9 +3108,10 @@ return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, if (select_options & SELECT_DESCRIBE) { - describe_info(join, info); + select_describe(join, false, false, false, info); DBUG_RETURN(0); } + if (procedure) { if (result->prepare(fields, unit)) // This hasn't been done yet @@ -3750,6 +3745,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->blob_ptr_size=mi_portable_sizeof_char_ptr; table->map=1; table->tmp_table= TMP_TABLE; + table->derived_select_number= 0; table->db_low_byte_first=1; // True for HEAP and MyISAM table->temp_pool_slot = temp_pool_slot; @@ -4366,7 +4362,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); empty_record(table); } - join->tmp_table=table; /* Save for easy recursion */ + join->tmp_table= table; /* Save for easy recursion */ join->fields= fields; /* Set up select_end */ @@ -4416,20 +4412,14 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) } else { - error=sub_select(join,join_tab,0); + error= sub_select(join,join_tab,0); if (error >= 0) - error=sub_select(join,join_tab,1); + error= sub_select(join,join_tab,1); if (error == -3) - error=0; /* select_limit used */ + error= 0; /* select_limit used */ } - /* Return 1 if error is sent; -1 if error should be sent */ - if (error < 0) - { - join->result->send_error(0,NullS); /* purecov: inspected */ - error=1; // Error sent - } - else + if (error >= 0) { error=0; if (!table) // If sending data to client @@ -6497,7 +6487,6 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, order->in_field_list=1; return 0; } - const char *save_where=thd->where; Item **item=find_item_in_list(*order->item, fields, 0); if (item) { @@ -6596,7 +6585,7 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, DBUG_ENTER("setup_new_fields"); thd->set_query_id=1; // Not really needed, but... - for (; new_field ; new_field=new_field->next) + for (; new_field ; new_field= new_field->next) { if ((item= find_item_in_list(*new_field->item, fields, 0))) new_field->item=item; /* Change to shared Item */ @@ -7190,7 +7179,6 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, Item *item; List<Item> item_list; THD *thd=join->thd; - MYSQL_LOCK *save_lock; SELECT_LEX *select_lex = &(join->thd->lex.select_lex); select_result *result=join->result; Item *item_null= new Item_null(); @@ -7199,28 +7187,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, /* Don't log this into the slow query log */ select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); join->unit->offset_limit_cnt= 0; - if (thd->lex.select == select_lex) - { - field_list.push_back(new Item_empty_string("table",NAME_LEN)); - field_list.push_back(new Item_empty_string("type",10)); - field_list.push_back(item=new Item_empty_string("possible_keys", - NAME_LEN*MAX_KEY)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); - item->maybe_null=1; - field_list.push_back(item=new Item_int("key_len",0,3)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("ref", - NAME_LEN*MAX_REF_PARTS)); - item->maybe_null=1; - field_list.push_back(new Item_real("rows",0.0,0,10)); - field_list.push_back(new Item_empty_string("Extra",255)); - if (result->send_fields(field_list,1)) - return; - } if (message) { + item_list.push_back(new Item_int((int)thd->lex.select->select_number)); + item_list.push_back(new Item_string(thd->lex.select->type, + strlen(thd->lex.select->type), + default_charset_info)); Item *empty= new Item_empty_string("",0); for (uint i=0 ; i < 7; i++) item_list.push_back(empty); @@ -7242,16 +7215,25 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, String tmp2(buff2,sizeof(buff2),default_charset_info); tmp1.length(0); tmp2.length(0); - item_list.empty(); - + item_list.push_back(new Item_int((int)thd->lex.select->select_number)); + item_list.push_back(new Item_string(thd->lex.select->type, + strlen(thd->lex.select->type), + default_charset_info)); if (tab->type == JT_ALL && tab->select && tab->select->quick) tab->type= JT_RANGE; - item_list.push_back(new Item_string(table->table_name, - strlen(table->table_name), - default_charset_info)); - item_list.push_back(new Item_string(join_type_str[tab->type], - strlen(join_type_str[tab->type]), - default_charset_info)); + if (table->tmp_table == TMP_TABLE && table->derived_select_number != 0) + { + // Derived table name generation + buff[512]; + int len= my_snprintf(buff, 512, "<derived%u>", + table->derived_select_number); + item_list.push_back(new Item_string(buff, len, default_charset_info)); + } + else + item_list.push_back(new Item_string(table->table_name, + strlen(table->table_name), + default_charset_info)); + item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type]),default_charset_info)); key_map bits; uint j; for (j=0,bits=tab->keys ; bits ; j++,bits>>=1) @@ -7381,38 +7363,24 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, result->send_error(0,NullS); } } - if (!thd->lex.select->next_select()) - { - save_lock=thd->lock; - thd->lock=(MYSQL_LOCK *)0; - result->send_eof(); - thd->lock=save_lock; - } DBUG_VOID_RETURN; } - -static void describe_info(JOIN *join, const char *info) +int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, + select_result *result) { - THD *thd= join->thd; - - /* If lex.select belong to UNION */ - if (thd->lex.select->master_unit()->first_select()->next_select()) - { - select_describe(join,FALSE,FALSE,FALSE,info); - return; - } - List<Item> field_list; - String *packet= &thd->packet; - - /* Don't log this into the slow query log */ - thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | - QUERY_NO_GOOD_INDEX_USED); - field_list.push_back(new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) - return; /* purecov: inspected */ - packet->length(0); - net_store_data(packet,info); - if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) - send_eof(thd); + select_lex->type= type; + thd->lex.select= select_lex; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + int res= mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, + select_lex->item_list, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) thd->lex.proc_list.first, + select_lex->options | thd->options | SELECT_DESCRIBE, + result, unit, select_lex, 0); + return res; } + diff --git a/sql/sql_select.h b/sql/sql_select.h index 89dee2a4019..7aa2e5da48a 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -210,6 +210,7 @@ class JOIN :public Sql_alloc send_records(0), found_records(0), examined_rows(0), thd(thd), sum_funcs(0), + procedure(0), having(0), select_options(select_options), result(result), @@ -237,7 +238,8 @@ class JOIN :public Sql_alloc int prepare(TABLE_LIST *tables, COND *conds, ORDER *order, ORDER *group, Item *having, - ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit); + ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit, + bool fake_select_lex); int optimize(); int global_optimize(); int reinit(); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 60563801d68..1a18759eb5b 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -24,31 +24,104 @@ #include "mysql_priv.h" #include "sql_select.h" +int mysql_union(THD *thd, LEX *lex, select_result *result) +{ + DBUG_ENTER("mysql_union"); + SELECT_LEX_UNIT *unit= &lex->unit; + int res= 0; + if (!(res= unit->prepare(thd, result))) + res= unit->exec(); + res|= unit->cleanup(); + DBUG_RETURN(res); +} + + +/*************************************************************************** +** store records in temporary table for UNION +***************************************************************************/ + +select_union::select_union(TABLE *table_par) + :table(table_par) +{ + bzero((char*) &info,sizeof(info)); + /* + We can always use DUP_IGNORE because the temporary table will only + contain a unique key if we are using not using UNION ALL + */ + info.handle_duplicates= DUP_IGNORE; +} + +select_union::~select_union() +{ +} + + +int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) +{ + unit= u; + if (save_time_stamp && list.elements != table->fields) + { + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); + return -1; + } + return 0; +} + +bool select_union::send_data(List<Item> &values) +{ + if (unit->offset_limit_cnt) + { // using limit offset,count + unit->offset_limit_cnt--; + return 0; + } + fill_record(table->field,values); + if ((write_record(table,&info))) + { + if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) + return 1; + } + return 0; +} + +bool select_union::send_eof() +{ + return 0; +} -int mysql_union(THD *thd, LEX *lex,select_result *result) +bool select_union::flush() { - SELECT_LEX *sl; - SELECT_LEX_UNIT *unit= &(lex->unit); - List<Item> item_list; - TABLE *table; - int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; - int res; - bool found_rows_for_union=false; - TABLE_LIST result_table_list; + int error; + if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) + { + table->file->print_error(error,MYF(0)); + ::send_error(thd); + return 1; + } + return 0; +} + +typedef JOIN * JOIN_P; +int st_select_lex_unit::prepare(THD *thd, select_result *result) +{ + describe=(first_select()->options & SELECT_DESCRIBE) ? 1 : 0; + res= 0; + found_rows_for_union= false; TMP_TABLE_PARAM tmp_table_param; - select_union *union_result; - DBUG_ENTER("mysql_union"); - st_select_lex_node * global; + DBUG_ENTER("st_select_lex_unit::prepare"); + this->thd= thd; + this->result= result; + SELECT_LEX *lex_select_save= thd->lex.select; /* Global option */ - if (((void*)(global= unit->global_parameters)) == ((void*)unit)) + if (((void*)(global_parameters)) == ((void*)this)) { - found_rows_for_union= (lex->select_lex.options & OPTION_FOUND_ROWS && - !describe && global->select_limit); + found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS && + !describe && global_parameters->select_limit; if (found_rows_for_union) - lex->select_lex.options ^= OPTION_FOUND_ROWS; + first_select()->options ^= OPTION_FOUND_ROWS; } - + item_list.empty(); if (describe) { Item *item; @@ -70,26 +143,27 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) else { Item *item; - List_iterator<Item> it(lex->select_lex.item_list); - TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first; + List_iterator<Item> it(first_select()->item_list); + TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first; /* Create a list of items that will be in the result set */ while ((item= it++)) if (item_list.push_back(item)) - DBUG_RETURN(-1); + goto err; if (setup_fields(thd,first_table,item_list,0,0,1)) - DBUG_RETURN(-1); + goto err; } bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); tmp_table_param.field_count=item_list.elements; if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, - (ORDER*) 0, !describe & !lex->union_option, + (ORDER*) 0, !describe & + !thd->lex.union_option, 1, 0, - (lex->select_lex.options | thd->options | + (first_select()->options | thd->options | TMP_TABLE_ALL_COLUMNS), - unit))) - DBUG_RETURN(-1); + this))) + goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); bzero((char*) &result_table_list,sizeof(result_table_list)); @@ -98,46 +172,90 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) result_table_list.table=table; if (!(union_result=new select_union(table))) - { - res= -1; - goto exit; - } + goto err; + union_result->save_time_stamp=!describe; union_result->tmp_table_param=&tmp_table_param; - for (sl= &lex->select_lex; sl; sl= sl->next_select()) + + // prepare selects + joins.empty(); + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) { - lex->select=sl; - unit->offset_limit_cnt= sl->offset_limit; - unit->select_limit_cnt= sl->select_limit+sl->offset_limit; - if (unit->select_limit_cnt < sl->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK | + ((describe) ? SELECT_DESCRIBE : 0), + union_result); + joins.push_back(new JOIN_P(join)); + thd->lex.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= mysql_select(thd, - (TABLE_LIST*) sl->table_list.first, - sl->item_list, - sl->where, - (sl->braces) ? - (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl->options | thd->options | - SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), - union_result, unit); - if (res) - goto exit; + res= join->prepare((TABLE_LIST*) sl->table_list.first, + sl->where, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, 0); + if (res | thd->fatal_error) + goto err; } + thd->lex.select= lex_select_save; + DBUG_RETURN(res | thd->fatal_error); +err: + thd->lex.select= lex_select_save; + DBUG_RETURN(-1); +} + +int st_select_lex_unit::exec() +{ + DBUG_ENTER("st_select_lex_unit::exec"); + if(depended || !item || !item->assigned()) + { + if (optimized && item && item->assigned()) + item->assigned(0); // We will reinit & rexecute unit + SELECT_LEX *lex_select_save= thd->lex.select; + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + thd->lex.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; + + if (!optimized) + sl->join->optimize(); + else + sl->join->reinit(); + + sl->join->exec(); + res= sl->join->error; + + if (res) + { + thd->lex.select= lex_select_save; + DBUG_RETURN(res); + } + } + thd->lex.select= lex_select_save; + optimized= 1; + } + if (union_result->flush()) { res= 1; // Error is already sent - goto exit; + DBUG_RETURN(res); } - delete union_result; /* Send result to 'result' */ - lex->select = &lex->select_lex; + thd->lex.select = first_select(); res =-1; { /* Create a list of fields in the temporary table */ @@ -147,7 +265,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) List<Item_func_match> ftfunc_list; ftfunc_list.empty(); #else - thd->lex.select_lex.ftfunc_list.empty(); + List<Item_func_match> empty_list; + empty_list.empty(); + thd->lex.select_lex.ftfunc_list= &empty_list; #endif for (field=table->field ; *field ; field++) @@ -157,93 +277,45 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) } if (!thd->fatal_error) // Check if EOM { - st_select_lex_node * global= unit->global_parameters; - unit->offset_limit_cnt= global->offset_limit; - unit->select_limit_cnt= global->select_limit+global->offset_limit; - if (unit->select_limit_cnt < global->select_limit) - unit->select_limit_cnt= HA_POS_ERROR; // no limit - if (unit->select_limit_cnt == HA_POS_ERROR) + offset_limit_cnt= global_parameters->offset_limit; + select_limit_cnt= global_parameters->select_limit+ + global_parameters->offset_limit; + if (select_limit_cnt < global_parameters->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) thd->options&= ~OPTION_FOUND_ROWS; if (describe) - unit->select_limit_cnt= HA_POS_ERROR; // no limit + select_limit_cnt= HA_POS_ERROR; // no limit res= mysql_select(thd,&result_table_list, item_list, NULL, - (describe) ? 0 : (ORDER*)global->order_list.first, + (describe) ? + 0: + (ORDER*)global_parameters->order_list.first, (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result, unit); + thd->options, result, this, first_select(), 1); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; } } - -exit: - free_tmp_table(thd,table); + thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc; DBUG_RETURN(res); } - -/*************************************************************************** -** store records in temporary table for UNION -***************************************************************************/ - -select_union::select_union(TABLE *table_par) - :table(table_par) +int st_select_lex_unit::cleanup() { - bzero((char*) &info,sizeof(info)); - /* - We can always use DUP_IGNORE because the temporary table will only - contain a unique key if we are using not using UNION ALL - */ - info.handle_duplicates= DUP_IGNORE; -} - -select_union::~select_union() -{ -} - - -int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) -{ - unit= u; - if (save_time_stamp && list.elements != table->fields) - { - my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); - return -1; - } - return 0; -} - -bool select_union::send_data(List<Item> &values) -{ - if (unit->offset_limit_cnt) - { // using limit offset,count - unit->offset_limit_cnt--; - return 0; - } - - fill_record(table->field,values); - if ((write_record(table,&info))) - { - if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) - return 1; - } - return 0; -} - -bool select_union::send_eof() -{ - return 0; -} - -bool select_union::flush() -{ - int error; - if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) + DBUG_ENTER("st_select_lex_unit::cleanup"); + delete union_result; + free_tmp_table(thd,table); + table= 0; // Safety + + List_iterator<JOIN*> j(joins); + JOIN** join; + while ((join= j++)) { - table->file->print_error(error,MYF(0)); - ::send_error(thd); - return 1; + (*join)->cleanup(thd); + delete *join; + delete join; } - return 0; + joins.empty(); + DBUG_RETURN(0); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index ccd4439a9d2..5d94b54f347 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -661,6 +661,8 @@ bool multi_update::send_data(List<Item> &values) void multi_update::send_error(uint errcode,const char *err) { + + //TODO error should be sent at the query processing end /* First send error what ever it is ... */ ::send_error(thd,errcode,err); @@ -783,6 +785,7 @@ bool multi_update::send_eof() if (error == -1) error = 0; thd->proc_info="end"; + //TODO error should be sent at the query processing end if (error) send_error(error,"An error occured in multi-table update"); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dbc401b3ddc..f7ab07b2da3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1807,10 +1807,10 @@ simple_expr: | singleval_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } | MATCH ident_list_arg AGAINST '(' expr ')' - { Select->ftfunc_list.push_back((Item_func_match *) + { Select->ftfunc_list->push_back((Item_func_match *) ($$=new Item_func_match_nl(*$2,$5))); } | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')' - { Select->ftfunc_list.push_back((Item_func_match *) + { Select->ftfunc_list->push_back((Item_func_match *) ($$=new Item_func_match_bool(*$2,$5))); } | BINARY expr %prec NEG { $$= new Item_func_binary($2); } | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); } @@ -4046,7 +4046,8 @@ singleval_subselect: singleval_subselect_init: select_init { - $$= new Item_singleval_subselect(current_thd, Lex->select); + $$= new Item_singleval_subselect(current_thd, + Lex->select->master_unit()->first_select()); }; exists_subselect: @@ -4059,7 +4060,8 @@ exists_subselect: exists_subselect_init: select_init { - $$= new Item_exists_subselect(current_thd, Lex->select); + $$= new Item_exists_subselect(current_thd, + Lex->select->master_unit()->first_select()); }; subselect_start: @@ -4074,4 +4076,4 @@ subselect_end: { LEX *lex=Lex; lex->select = lex->select->outer_select(); - }; + } diff --git a/sql/table.h b/sql/table.h index b9ebeda160a..d09194442c8 100644 --- a/sql/table.h +++ b/sql/table.h @@ -128,6 +128,9 @@ struct st_table { uint temp_pool_slot; + /* number of select if it is derived table */ + uint derived_select_number; + THD *in_use; /* Which thread uses this */ struct st_table *next,*prev; }; |