summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <bell@sanja.is.com.ua>2002-10-04 14:15:59 +0300
committerunknown <bell@sanja.is.com.ua>2002-10-04 14:15:59 +0300
commit05c5908a9e801d604a5651ccb9fde081378435f9 (patch)
treec7e9f63a5d35171d649cbd11f951d58a8f953720 /sql
parente607221a3cd778131cc9250108473819c9b8c8a0 (diff)
parentf094b6af4c5c32bfda7f74461d47675ab61722a0 (diff)
downloadmariadb-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.cc6
-rw-r--r--sql/item_subselect.cc259
-rw-r--r--sql/item_subselect.h135
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/mysqld.cc1
-rw-r--r--sql/net_pkg.cc3
-rw-r--r--sql/net_serv.cc39
-rw-r--r--sql/sql_base.cc17
-rw-r--r--sql/sql_class.cc78
-rw-r--r--sql/sql_class.h7
-rw-r--r--sql/sql_derived.cc23
-rw-r--r--sql/sql_insert.cc2
-rw-r--r--sql/sql_lex.cc11
-rw-r--r--sql/sql_lex.h34
-rw-r--r--sql/sql_parse.cc123
-rw-r--r--sql/sql_select.cc212
-rw-r--r--sql/sql_select.h4
-rw-r--r--sql/sql_union.cc328
-rw-r--r--sql/sql_update.cc3
-rw-r--r--sql/sql_yacc.yy12
-rw-r--r--sql/table.h3
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;
};