summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysqld_error.h4
-rw-r--r--libmysqld/Makefile.am3
-rw-r--r--mysql-test/r/subselect.result43
-rw-r--r--mysql-test/r/union.result1
-rw-r--r--mysql-test/t/subselect.test23
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/item.cc29
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_strfunc.h8
-rw-r--r--sql/item_subselect.cc157
-rw-r--r--sql/item_subselect.h82
-rw-r--r--sql/item_sum.cc8
-rw-r--r--sql/mysql_priv.h9
-rw-r--r--sql/share/czech/errmsg.txt2
-rw-r--r--sql/share/danish/errmsg.txt2
-rw-r--r--sql/share/dutch/errmsg.txt2
-rw-r--r--sql/share/english/errmsg.txt2
-rw-r--r--sql/share/estonian/errmsg.txt2
-rw-r--r--sql/share/french/errmsg.txt2
-rw-r--r--sql/share/german/errmsg.txt2
-rw-r--r--sql/share/greek/errmsg.txt2
-rw-r--r--sql/share/hungarian/errmsg.txt2
-rw-r--r--sql/share/italian/errmsg.txt2
-rw-r--r--sql/share/japanese/errmsg.txt2
-rw-r--r--sql/share/korean/errmsg.txt2
-rw-r--r--sql/share/norwegian-ny/errmsg.txt2
-rw-r--r--sql/share/norwegian/errmsg.txt2
-rw-r--r--sql/share/polish/errmsg.txt2
-rw-r--r--sql/share/portuguese/errmsg.txt2
-rw-r--r--sql/share/romanian/errmsg.txt2
-rw-r--r--sql/share/russian/errmsg.txt2
-rw-r--r--sql/share/serbian/errmsg.txt2
-rw-r--r--sql/share/slovak/errmsg.txt2
-rw-r--r--sql/share/spanish/errmsg.txt2
-rw-r--r--sql/share/swedish/errmsg.txt2
-rw-r--r--sql/share/ukrainian/errmsg.txt2
-rw-r--r--sql/sql_class.cc53
-rw-r--r--sql/sql_class.h57
-rw-r--r--sql/sql_delete.cc3
-rw-r--r--sql/sql_derived.cc37
-rw-r--r--sql/sql_insert.cc14
-rw-r--r--sql/sql_lex.cc196
-rw-r--r--sql/sql_lex.h188
-rw-r--r--sql/sql_parse.cc214
-rw-r--r--sql/sql_select.cc811
-rw-r--r--sql/sql_select.cc.rej1576
-rw-r--r--sql/sql_select.h75
-rw-r--r--sql/sql_select.h.rej96
-rw-r--r--sql/sql_union.cc129
-rw-r--r--sql/sql_update.cc14
-rw-r--r--sql/sql_yacc.yy80
-rw-r--r--sql/table.h26
52 files changed, 3316 insertions, 676 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index c910078331e..4c08bc77e8f 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -243,4 +243,6 @@
#define ER_MIXING_NOT_ALLOWED 1224
#define ER_DUP_ARGUMENT 1225
#define ER_USER_LIMIT_REACHED 1226
-#define ER_ERROR_MESSAGES 227
+#define ER_SUBSELECT_NO_1_COL 1227
+#define ER_SUBSELECT_NO_1_ROW 1228
+#define ER_ERROR_MESSAGES 229
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index c98e1c7e973..ee35011db3a 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -43,7 +43,8 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
hostname.cc init.cc \
item.cc item_buff.cc item_cmpfunc.cc item_create.cc \
item_func.cc item_strfunc.cc item_sum.cc item_timefunc.cc \
- item_uniq.cc key.cc lock.cc log.cc log_event.cc mf_iocache.cc\
+ item_uniq.cc item_subselect.cc \
+ key.cc lock.cc log.cc log_event.cc mf_iocache.cc\
mini_client.cc net_pkg.cc net_serv.cc opt_ft.cc opt_range.cc \
opt_sum.cc procedure.cc records.cc sql_acl.cc \
repl_failsafe.cc slave.cc \
diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
new file mode 100644
index 00000000000..64ceea72498
--- /dev/null
+++ b/mysql-test/r/subselect.result
@@ -0,0 +1,43 @@
+drop table if exists t1,t2,t3,t4;
+create table t1 (a int);
+create table t2 (a int, b int);
+create table t3 (a int);
+create table t4 (a int, b int);
+insert into t1 values (2);
+insert into t2 values (1,7),(2,7);
+insert into t4 values (4,8),(3,8),(5,9);
+select (select a from t1 where t1.a=t2.a), a from t2;
+(select a from t1 where t1.a=t2.a) a
+NULL 1
+2 2
+select (select a from t1 where t1.a=t2.b), a from t2;
+(select a from t1 where t1.a=t2.b) a
+NULL 1
+NULL 2
+select (select a from t1), a from t2;
+(select a from t1) a
+2 1
+2 2
+select (select a from t3), a from t2;
+(select a from t3) a
+NULL 1
+NULL 2
+select * from t2 where t2.a=(select a from t1);
+a b
+2 7
+insert into t3 values (6),(7),(3);
+select * from t2 where t2.b=(select a from t3 order by 1 limit 1);
+a b
+1 7
+2 7
+select * from t2 where t2.b=(select a from t3 order by 1 limit 1)
+union (select * from t4 order by a limit 2) limit 3;
+a b
+1 7
+2 7
+3 8
+select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2;
+(select a from t3 where a<t2.a*4 order by 1 desc limit 1) a
+3 1
+7 2
+drop table t1,t2,t3,t4;
diff --git a/mysql-test/r/union.result b/mysql-test/r/union.result
index 7d914d029af..29b925b6746 100644
--- a/mysql-test/r/union.result
+++ b/mysql-test/r/union.result
@@ -88,7 +88,6 @@ explain (select a,b from t1 limit 2) union all (select a,b from t2 order by a l
table type possible_keys key key_len ref rows Extra
t1 ALL NULL NULL NULL NULL 4
t2 ALL NULL NULL NULL NULL 4 Using filesort
-t1 ALL NULL NULL NULL NULL 4
(select sql_calc_found_rows a,b from t1 limit 2) union all (select a,b from t2 order by a) limit 2;
a b
1 a
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
new file mode 100644
index 00000000000..7383608ed9e
--- /dev/null
+++ b/mysql-test/t/subselect.test
@@ -0,0 +1,23 @@
+
+#select (select 2);
+drop table if exists t1,t2,t3,t4;
+create table t1 (a int);
+create table t2 (a int, b int);
+create table t3 (a int);
+create table t4 (a int, b int);
+insert into t1 values (2);
+insert into t2 values (1,7),(2,7);
+insert into t4 values (4,8),(3,8),(5,9);
+select (select a from t1 where t1.a=t2.a), a from t2;
+select (select a from t1 where t1.a=t2.b), a from t2;
+select (select a from t1), a from t2;
+select (select a from t3), a from t2;
+select * from t2 where t2.a=(select a from t1);
+insert into t3 values (6),(7),(3);
+select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1);
+select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
+union (select * from t4 order by a limit 2) limit 3;
+select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2;
+select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from
+(select * from t2 where a>1) as tt;
+drop table t1,t2,t3,t4;
diff --git a/sql/Makefile.am b/sql/Makefile.am
index f58075358b6..bd626ea10b7 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -46,7 +46,7 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.h \
- item_create.h mysql_priv.h \
+ item_create.h item_subselect.h mysql_priv.h \
procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \
@@ -60,7 +60,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \
- thr_malloc.cc item_create.cc \
+ thr_malloc.cc item_create.cc item_subselect.cc\
field.cc key.cc sql_class.cc sql_list.cc \
net_serv.cc net_pkg.cc lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \
diff --git a/sql/item.cc b/sql/item.cc
index d5b9487eea6..8a785ee3902 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -320,7 +320,34 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables)
{
Field *tmp;
if (!(tmp=find_field_in_tables(thd,this,tables)))
- return 1;
+ {
+ /*
+ We can't find table field in table list of current select,
+ consequently we have to find it in outer subselect(s).
+ We can't join lists of outer & current select, because of scope
+ of view rules. For example if both tables (outer & current) have
+ field 'field' it is not mistake to refer to this field without
+ mention of table name, but if we join tables in one list it will
+ cause error ER_NON_UNIQ_ERROR in find_field_in_tables.
+ */
+ for (SELECT_LEX *sl= thd->lex.select->outer_select();
+ sl && !tmp;
+ sl= sl->outer_select())
+ tmp=find_field_in_tables(thd, this,
+ (TABLE_LIST*)sl->table_list.first);
+ if (!tmp)
+ return 1;
+ else
+ if( !thd->lex.select->depended )
+ {
+ thd->lex.select->depended= 1; //Select is depended of outer select(s)
+ //Tables will be reopened many times
+ for (TABLE_LIST *tbl= (TABLE_LIST*)thd->lex.select->table_list.first;
+ tbl;
+ tbl= tbl->next)
+ tbl->shared= 1;
+ }
+ }
set_field(tmp);
}
else if (thd && thd->set_query_id && field->query_id != thd->query_id)
diff --git a/sql/item.h b/sql/item.h
index 927e86398c2..f9879f2f70d 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -32,7 +32,8 @@ public:
enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM,
INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM,
COPY_STR_ITEM,FIELD_AVG_ITEM,
- PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM};
+ PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM,
+ SUBSELECT_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
String str_value; /* used to store value */
@@ -46,7 +47,6 @@ public:
my_bool unsigned_flag;
my_bool with_sum_func;
-
// alloc & destruct is done as start of select using sql_alloc
Item();
virtual ~Item() { name=0; } /*lint -e1509 */
@@ -371,6 +371,7 @@ public:
#include "item_strfunc.h"
#include "item_timefunc.h"
#include "item_uniq.h"
+#include "item_subselect.h"
class Item_copy_string :public Item
{
@@ -458,3 +459,4 @@ extern Item_result item_cmp_type(Item_result a,Item_result b);
extern Item *resolve_const_item(Item *item,Item *cmp_item);
extern bool field_is_equal_to_item(Field *field,Item *item);
Item *get_system_var(LEX_STRING name);
+
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 8627ecd0d73..03ef65c352a 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -37,8 +37,12 @@ public:
void left_right_max_length();
Field *tmp_table_field(TABLE *t_arg)
{
- if (!t_arg) return result_field;
- return (max_length > 255) ? (Field *)new Field_blob(max_length,maybe_null, name,t_arg, binary) : (Field *) new Field_string(max_length,maybe_null, name,t_arg, binary, default_charset_info);
+ if (!t_arg)
+ return result_field;
+ return (max_length > 255) ?
+ (Field *)new Field_blob(max_length,maybe_null, name,t_arg, binary) :
+ (Field *) new Field_string(max_length,maybe_null, name,t_arg, binary,
+ default_charset_info);
}
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
new file mode 100644
index 00000000000..72bbbcba5a7
--- /dev/null
+++ b/sql/item_subselect.cc
@@ -0,0 +1,157 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/*
+ subselect Item
+
+SUBSELECT TODO:
+ - add function from mysql_select that use JOIN* as parameter to JOIN methods
+ (sql_select.h/sql_select.cc)
+ - remove double 'having' & 'having_list' from JOIN
+ (sql_select.h/sql_select.cc)
+
+ - add subselect union select (sql_union.cc)
+
+*/
+
+#ifdef __GNUC__
+#pragma implementation // gcc: Class implementation
+#endif
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+
+Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
+ executed(0), optimized(0), error(0)
+{
+ DBUG_ENTER("Item_subselect::Item_subselect");
+ DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
+ result= new select_subselect(this);
+ 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+
+ select_lex->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);
+ this->select_lex= select_lex;
+ maybe_null= 1;
+ /*
+ item value is NULL if select_subselect not changed this value
+ (i.e. some rows will be found returned)
+ */
+ assign_null();
+ DBUG_VOID_RETURN;
+}
+
+Item::Type Item_subselect::type() const
+{
+ return SUBSELECT_ITEM;
+}
+
+double Item_subselect::val ()
+{
+ if (exec())
+ return 0;
+ return real_value;
+}
+
+longlong Item_subselect::val_int ()
+{
+ if (exec())
+ return 0;
+ return int_value;
+}
+
+String *Item_subselect::val_str (String *str)
+{
+ if (exec() || null_value)
+ return 0;
+ return &str_value;
+}
+
+void Item_subselect::make_field (Send_field *tmp_field)
+{
+ if (null_value)
+ {
+ init_make_field(tmp_field,FIELD_TYPE_NULL);
+ tmp_field->length=4;
+ } else {
+ init_make_field(tmp_field, ((result_type() == STRING_RESULT) ?
+ FIELD_TYPE_VAR_STRING :
+ (result_type() == INT_RESULT) ?
+ FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE));
+ }
+}
+
+bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
+{
+ // Is it one field subselect?
+ if (select_lex->item_list.elements != 1)
+ {
+ my_printf_error(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 Item_subselect::exec()
+{
+ if (!optimized)
+ {
+ optimized=1;
+ if (join->optimize())
+ {
+ executed= 1;
+ return (join->error?join->error:1);
+ }
+ }
+ if (join->select_lex->depended && executed)
+ {
+ if (join->reinit())
+ {
+ error= 1;
+ return 1;
+ }
+ assign_null();
+ 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;
+ //if (!executed)
+ //No rows returned => value is null (returned as inited)
+ // executed= 1;
+ return join->error;
+ }
+ return 0;
+}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
new file mode 100644
index 00000000000..e27f14fb83d
--- /dev/null
+++ b/sql/item_subselect.h
@@ -0,0 +1,82 @@
+/* Copyright (C) 2000 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+/* subselect Item */
+
+#ifdef __GNUC__
+#pragma interface /* gcc class implementation */
+#endif
+
+struct st_select_lex;
+class JOIN;
+class select_subselect;
+
+/* simple (not depended of covered select ) subselect */
+
+class Item_subselect :public Item
+{
+protected:
+ longlong int_value;
+ double real_value;
+ my_bool executed; /* simple subselect is executed */
+ my_bool optimized; /* simple subselect is optimized */
+ my_bool error; /* error in query */
+ enum Item_result res_type;
+
+ int exec();
+ void assign_null()
+ {
+ null_value= 1;
+ int_value= 0;
+ real_value= 0;
+ max_length= 4;
+ res_type= STRING_RESULT;
+ }
+public:
+ st_select_lex *select_lex;
+ JOIN *join;
+ select_subselect *result;
+
+ Item_subselect(THD *thd, st_select_lex *select_lex);
+ Item_subselect(Item_subselect *item)
+ {
+ null_value= item->null_value;
+ int_value= item->int_value;
+ real_value= item->real_value;
+ max_length= item->max_length;
+ decimals= item->decimals;
+ res_type= item->res_type;
+ executed= item->executed;
+ select_lex= item->select_lex;
+ join= item->join;
+ result= item->result;
+ name= item->name;
+ error= item->error;
+ }
+ enum Type type() const;
+ double val ();
+ longlong val_int ();
+ String *val_str (String *);
+ bool is_null() { return null_value; }
+ void make_field (Send_field *);
+ bool fix_fields(THD *thd, TABLE_LIST *tables);
+ Item *new_item() { return new Item_subselect(this); }
+ enum Item_result result_type() const { return res_type; }
+
+ friend class select_subselect;
+};
+
+
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 2275ce4eeb6..a1ffae2ed82 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -940,6 +940,7 @@ bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables)
bool Item_sum_count_distinct::setup(THD *thd)
{
List<Item> list;
+ SELECT_LEX *select_lex= current_lex->select;
/* Create a table with an unique key over all parameters */
for (uint i=0; i < arg_count ; i++)
{
@@ -961,9 +962,10 @@ bool Item_sum_count_distinct::setup(THD *thd)
free_tmp_table(thd, table);
tmp_table_param->cleanup();
}
- if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
- 0, 0,
- current_lex->select->options | thd->options)))
+ if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
+ 0, 0,
+ select_lex->options | thd->options,
+ select_lex->master_unit())))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 4c71e845207..1719fe69b17 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -291,7 +291,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
void mysql_init_select(LEX *lex);
-bool mysql_new_select(LEX *lex);
+bool mysql_new_select(LEX *lex, bool move_down);
void mysql_init_multi_delete(LEX *lex);
void init_max_user_conn(void);
void free_max_user_conn(void);
@@ -359,9 +359,10 @@ int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
int handle_select(THD *thd, LEX *lex, select_result *result);
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
- ulong select_type,select_result *result);
-int mysql_union(THD *thd,LEX *lex,select_result *result);
-int mysql_derived(THD *thd,LEX *lex,SELECT_LEX *s, TABLE_LIST *t);
+ ulong select_type,select_result *result,
+ SELECT_LEX_UNIT *unit);
+int mysql_union(THD *thd, LEX *lex,select_result *result);
+int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item);
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 950ca4f6623..f654f2a2240 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -237,3 +237,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index d87ed4ee629..cb9912d5783 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -231,3 +231,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index c8b47cb3c19..be4cd7d7896 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -236,3 +236,5 @@
"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
"Optie '%s' tweemaal gebruikt in opdracht",
"Gebruiker '%-64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 5033449c266..533a305cd1d 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 6a83468eae5..d303cf22102 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -233,3 +233,5 @@
"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
"Määrangut '%s' on lauses kasutatud topelt",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index cf3e3e845e4..cae31a7c799 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 19d46fabab8..8f3b59da035 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -231,3 +231,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index f9b4f137f82..f6c92f7c27c 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 38877371243..1dd72efc63a 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index e8cfd5a63a9..e658bc2975e 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 98bc099954f..55fe7d79768 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index f6cc890cb39..38d9416edc9 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index adffc27949f..c84e8242778 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 09a1ea4684c..dae9cf927c5 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 12a9bd358b5..312ae153cbe 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -232,3 +232,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index b7feb0a7b0d..6dca23872e2 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 8e48cabfc39..6e89a0119e2 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -232,3 +232,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 8ed33ec21a0..5df743b0dbf 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -231,3 +231,5 @@
"ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ transactional É non-transactional ÔÁÂÌÉà ÏÔËÌÀÞÅÎÏ",
"ïÐÃÉÑ '%s' ÉÓÐÏÌØÚÏ×ÁÎÁ Ä×ÁÖÄÙ",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÇÏ ÐÏÌÑ",
+"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 105860f0e4b..8e3b6e2a318 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -234,3 +234,5 @@
"Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno",
"Opcija '%s' je upotrebljena dva puta u istom iskazu",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 06503cdf69e..37a2d30e1ae 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -236,3 +236,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 4240581c5b8..2e371e75cbd 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -229,3 +229,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index e774f4a2c5c..58c8e5af54f 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -228,3 +228,5 @@
"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
"Option '%s' användes två gånger",
"Användare '%-64s' har överskridit '%s' (nuvarande värde: %ld)",
+"Subselect return more than 1 field",
+"Subselect return more than 1 record",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index c4c89433331..4dad29345e5 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -233,3 +233,5 @@
"Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)",
+"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÓÔÏ×ÂÅÃØ",
+"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÚÁÐÉÓ",
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index d5d5c8fa6f9..975d36069f9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -391,9 +391,9 @@ bool select_send::send_data(List<Item> &items)
String *packet= &thd->packet;
DBUG_ENTER("send_data");
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
packet->length(0); // Reset packet
@@ -441,11 +441,12 @@ select_export::~select_export()
}
int
-select_export::prepare(List<Item> &list)
+select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
char path[FN_REFLEN];
uint option=4;
bool blob_flag=0;
+ unit= u;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|=1; // Force use of db directory
#endif
@@ -512,9 +513,9 @@ bool select_export::send_data(List<Item> &items)
String tmp(buff,sizeof(buff),default_charset_info),*res;
tmp.length(0);
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
row_count++;
@@ -680,9 +681,11 @@ select_dump::~select_dump()
}
int
-select_dump::prepare(List<Item> &list __attribute__((unused)))
+select_dump::prepare(List<Item> &list __attribute__((unused)),
+ SELECT_LEX_UNIT *u)
{
uint option=4;
+ unit= u;
#ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS
option|=1; // Force use of db directory
#endif
@@ -721,9 +724,9 @@ bool select_dump::send_data(List<Item> &items)
Item *item;
DBUG_ENTER("send_data");
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
if (row_count++ > 1)
@@ -773,3 +776,37 @@ bool select_dump::send_eof()
file= -1;
return error;
}
+
+select_subselect::select_subselect(Item_subselect *item)
+{
+ this->item=item;
+}
+
+bool select_subselect::send_data(List<Item> &items)
+{
+ DBUG_ENTER("select_subselect::send_data");
+ if (item->executed){
+ my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
+ DBUG_RETURN(1);
+ }
+ if (unit->offset_limit_cnt)
+ { // using limit offset,count
+ unit->offset_limit_cnt--;
+ DBUG_RETURN(0);
+ }
+ Item *val_item= (Item *)item->select_lex->item_list.head();
+ if ((item->null_value= val_item->is_null()))
+ {
+ item->assign_null();
+ } else {
+ item->max_length= val_item->max_length;
+ item->decimals= val_item->decimals;
+ item->binary= val_item->binary;
+ val_item->val_str(&item->str_value);
+ item->int_value= val_item->val_int();
+ item->real_value= val_item->val();
+ item->res_type= val_item->result_type();
+ }
+ item->executed= 1;
+ DBUG_RETURN(0);
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5dc761ff811..16c67375d99 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -379,7 +379,7 @@ public:
#endif
ulonglong next_insert_id,last_insert_id,current_insert_id,
limit_found_rows;
- ha_rows select_limit,offset_limit,default_select_limit,cuted_fields,
+ ha_rows default_select_limit,cuted_fields,
max_join_size, sent_row_count, examined_row_count;
table_map used_tables;
UC *user_connect;
@@ -548,10 +548,15 @@ void send_error(NET *net,uint sql_errno=0, const char *err=0);
class select_result :public Sql_alloc {
protected:
THD *thd;
+ SELECT_LEX_UNIT *unit;
public:
select_result();
virtual ~select_result() {};
- virtual int prepare(List<Item> &list) { return 0; }
+ virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u)
+ {
+ unit= u;
+ return 0;
+ }
virtual bool send_fields(List<Item> &list,uint flag)=0;
virtual bool send_data(List<Item> &items)=0;
virtual void initialize_tables (JOIN *join=0) {}
@@ -584,7 +589,7 @@ class select_export :public select_result {
public:
select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {}
~select_export();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list,
uint flag) { return 0; }
bool send_data(List<Item> &items);
@@ -603,7 +608,7 @@ public:
select_dump(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L)
{ path[0]=0; }
~select_dump();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list,
uint flag) { return 0; }
bool send_data(List<Item> &items);
@@ -626,7 +631,7 @@ class select_insert :public select_result {
info.handle_duplicates=duplic;
}
~select_insert();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list, uint flag)
{ return 0; }
bool send_data(List<Item> &items);
@@ -655,7 +660,7 @@ public:
create_info(create_info_par),
lock(0)
{}
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &values);
bool send_eof();
void abort();
@@ -669,7 +674,7 @@ class select_union :public select_result {
select_union(TABLE *table_par);
~select_union();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list, uint flag)
{ return 0; }
bool send_data(List<Item> &items);
@@ -677,6 +682,19 @@ class select_union :public select_result {
bool flush();
};
+/* Single value subselect interface class */
+class select_subselect :public select_result
+{
+ Item_subselect *item;
+public:
+ select_subselect(Item_subselect *item);
+ bool send_fields(List<Item> &list, uint flag) { return 0; };
+ bool send_data(List<Item> &items);
+ bool send_eof() { return 0; };
+
+ friend class Ttem_subselect;
+};
+
/* Structs used when sorting */
typedef struct st_sort_field {
@@ -703,19 +721,28 @@ class Table_ident :public Sql_alloc {
public:
LEX_STRING db;
LEX_STRING table;
- SELECT_LEX *sel;
- inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force)
- :table(table_arg), sel((SELECT_LEX *)0)
+ SELECT_LEX_UNIT *sel;
+ inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force)
+ :table(table_arg), sel((SELECT_LEX_UNIT *)0)
{
if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
db.str=0;
else
db= db_arg;
}
- inline Table_ident(LEX_STRING table_arg) :table(table_arg), sel((SELECT_LEX *)0) {db.str=0;}
- inline Table_ident(SELECT_LEX *s) : sel(s) {db.str=0; table.str=(char *)""; table.length=0;}
+ inline Table_ident(LEX_STRING table_arg)
+ :table(table_arg), sel((SELECT_LEX_UNIT *)0)
+ {
+ db.str=0;
+ }
+ inline Table_ident(SELECT_LEX_UNIT *s) : sel(s)
+ {
+ db.str=0; table.str=(char *)""; table.length=0;
+ }
inline void change_db(char *db_name)
- { db.str= db_name; db.length=(uint) strlen(db_name); }
+ {
+ db.str= db_name; db.length= (uint) strlen(db_name);
+ }
};
// this is needed for user_vars hash
@@ -775,7 +802,7 @@ public:
multi_delete(THD *thd, TABLE_LIST *dt, thr_lock_type lock_option_arg,
uint num_of_tables);
~multi_delete();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list,
uint flag) { return 0; }
bool send_data(List<Item> &items);
@@ -804,7 +831,7 @@ public:
enum enum_duplicates handle_duplicates,
thr_lock_type lock_option_arg, uint num);
~multi_update();
- int prepare(List<Item> &list);
+ int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_fields(List<Item> &list,
uint flag) { return 0; }
bool send_data(List<Item> &items);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index f5a5a684fc0..2e565a59ca0 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -232,9 +232,10 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt,
int
-multi_delete::prepare(List<Item> &values)
+multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("multi_delete::prepare");
+ unit= u;
do_delete = true;
thd->proc_info="deleting from main table";
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index af43c5dcd96..fb40a85fd91 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -28,21 +28,25 @@
static const char *any_db="*any*"; // Special symbol for check_access
-int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
+int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
{
- SELECT_LEX *sl=s;
+ /*
+ TODO: make derived tables with union inside (now only 1 SELECT may be
+ procesed)
+ */
+ SELECT_LEX *sl= unit->first_select();
List<Item> item_list;
TABLE *table;
int res;
select_union *derived_result;
- TABLE_LIST *tables=(TABLE_LIST *)sl->table_list.first;
+ TABLE_LIST *tables= (TABLE_LIST *)sl->table_list.first;
TMP_TABLE_PARAM tmp_table_param;
DBUG_ENTER("mysql_derived");
if (tables)
- res=check_table_access(thd,SELECT_ACL, tables);
+ res= check_table_access(thd,SELECT_ACL, tables);
else
- res=check_access(thd, SELECT_ACL, any_db);
+ res= check_access(thd, SELECT_ACL, any_db);
if (res)
DBUG_RETURN(-1);
@@ -52,7 +56,7 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
{
if (cursor->derived)
{
- res=mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor);
+ res=mysql_derived(thd, lex, (SELECT_LEX_UNIT *)cursor->derived, cursor);
if (res) DBUG_RETURN(res);
}
}
@@ -72,8 +76,10 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
- (ORDER*) 0, 0, 1, 0,
- (sl->options | thd->options | TMP_TABLE_ALL_COLUMNS))))
+ (ORDER*) 0, 0, 1, 0,
+ (sl->options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ unit)))
{
res=-1;
goto exit;
@@ -81,11 +87,11 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
if ((derived_result=new select_union(table)))
{
- thd->offset_limit=sl->offset_limit;
- thd->select_limit=sl->select_limit+sl->offset_limit;
- if (thd->select_limit < sl->select_limit)
- thd->select_limit= HA_POS_ERROR;
- if (thd->select_limit == HA_POS_ERROR)
+ unit->offset_limit_cnt= sl->offset_limit;
+ unit->select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (unit->select_limit_cnt < sl->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR;
+ if (unit->select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res=mysql_select(thd, tables, sl->item_list,
@@ -93,7 +99,7 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
(ORDER*) sl->group_list.first,
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
- derived_result);
+ derived_result, unit);
if (!res)
{
// Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables
@@ -103,9 +109,8 @@ int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
{
t->real_name=table->real_name;
t->table=table;
- sl->prev->next=sl->next;
+ sl->exclude();
t->derived=(SELECT_LEX *)0; // just in case ...
- if (!sl->next) lex->last_select = sl;
}
}
delete derived_result;
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 69fc7c00955..2e6c009741e 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1266,10 +1266,11 @@ bool delayed_insert::handle_inserts(void)
***************************************************************************/
int
-select_insert::prepare(List<Item> &values)
+select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("select_insert::prepare");
+ unit= u;
save_time_stamp=table->time_stamp;
if (check_insert_fields(thd,table,*fields,values,1))
DBUG_RETURN(1);
@@ -1302,9 +1303,9 @@ select_insert::~select_insert()
bool select_insert::send_data(List<Item> &values)
{
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
return 0;
}
if (fields->elements)
@@ -1380,10 +1381,11 @@ bool select_insert::send_eof()
***************************************************************************/
int
-select_create::prepare(List<Item> &values)
+select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("select_create::prepare");
+ unit= u;
table=create_table_from_items(thd, create_info, db, name,
extra_fields, keys, &values, &lock);
if (!table)
@@ -1413,9 +1415,9 @@ select_create::prepare(List<Item> &values)
bool select_create::send_data(List<Item> &values)
{
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
return 0;
}
fill_record(field,values);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 31ec6d1cecc..008ef44d83a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -879,3 +879,199 @@ int yylex(void *arg)
}
}
}
+
+/*
+ st_select_lex structures initialisations
+*/
+
+void st_select_lex_node::init_query()
+{
+ next= master= slave= link_next= 0;
+ prev= link_prev= 0;
+}
+
+void st_select_lex_node::init_select()
+{
+ order_list.elements= 0;
+ order_list.first= 0;
+ order_list.next= (byte**) &order_list.first;
+ select_limit= HA_POS_ERROR;
+ offset_limit= 0;
+}
+
+void st_select_lex_unit::init_query()
+{
+ linkage= GLOBAL_OPTIONS_TYPE;
+ st_select_lex_node::init_query();
+ global_parameters= this;
+ select_limit_cnt= HA_POS_ERROR;
+ offset_limit_cnt= 0;
+}
+
+void st_select_lex::init_query()
+{
+ st_select_lex_node::init_query();
+ table_list.elements= 0;
+ table_list.first= 0;
+ table_list.next= (byte**) &table_list.first;
+ item_list.empty();
+}
+
+void st_select_lex::init_select()
+{
+ st_select_lex_node::init_select();
+ group_list.elements= 0;
+ group_list.first= 0;
+ group_list.next= (byte**) &group_list.first;
+ options= 0;
+ where= having= 0;
+ when_list.empty();
+ expr_list.empty();
+ interval_list.empty();
+ use_index.empty();
+ ftfunc_list.empty();
+ linkage=UNSPECIFIED_TYPE;
+ depended= 0;
+}
+
+/*
+ st_select_lex structures linking
+*/
+
+/* include on level down */
+void st_select_lex_node::include_down(st_select_lex_node *upper)
+{
+ if ((next= upper->slave))
+ next->prev= &next;
+ prev= &upper->slave;
+ upper->slave= this;
+ master= upper;
+}
+
+/* include neighbour (on same level) */
+void st_select_lex_node::include_neighbour(st_select_lex_node *before)
+{
+ if ((next= before->next))
+ next->prev= &next;
+ prev= &before->next;
+ before->next= this;
+ master= before->master;
+}
+
+/* including in global SELECT_LEX list */
+void st_select_lex_node::include_global(st_select_lex_node **plink)
+{
+ if ((link_next= *plink))
+ link_next->link_prev= &link_next;
+ link_prev= plink;
+ *plink= this;
+}
+
+//excluding from global list (internal function)
+void st_select_lex_node::fast_exclude()
+{
+ if(link_prev)
+ {
+ if ((*link_prev= link_next))
+ link_next->link_prev= link_prev;
+ // Remove slave structure
+ for (; slave; slave= slave->next)
+ slave->fast_exclude();
+ }
+}
+
+/*
+ excluding select_lex structure (except first (first select can't be
+ deleted, because it is most upper select))
+*/
+void st_select_lex_node::exclude()
+{
+ //exclude from global list
+ fast_exclude();
+ //exclude from other structures
+ if ((*prev= next))
+ next->prev= prev;
+ /*
+ We do not need following statements, because prev pointer of first
+ list element point to master->slave
+ if (master->slave == this)
+ master->slave= next;
+ */
+}
+
+/*
+ This is used for UNION & subselect to create a new table list of all used
+ tables.
+ The table_list->table entry in all used tables are set to point
+ to the entries in this list.
+*/
+
+// interface
+bool st_select_lex_unit::create_total_list(THD *thd, st_lex *lex,
+ TABLE_LIST **result)
+{
+ *result= 0;
+ return create_total_list_n_last_return(thd, lex, &result);
+}
+
+// list creator
+bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result)
+{
+ TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first;
+ TABLE_LIST **new_table_list= *result, *aux;
+ SELECT_LEX *sl= (SELECT_LEX*)slave;
+ for (; sl; sl= sl->next_select())
+ {
+ // check usage of ORDER BY in union
+ if (sl->order_list.first && sl->next_select() && !sl->braces)
+ {
+ net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
+ return 1;
+ }
+ for (SELECT_LEX_UNIT *inner= sl->first_inner_unit();
+ inner;
+ inner= inner->next_unit())
+ if (inner->create_total_list_n_last_return(thd, lex,
+ &slave_list_last))
+ return 1;
+ if ((aux= (TABLE_LIST*) sl->table_list.first))
+ {
+ TABLE_LIST *next;
+ for (; aux; aux= next)
+ {
+ TABLE_LIST *cursor;
+ next= aux->next;
+ for (cursor= **result; cursor; cursor= cursor->next)
+ if (!strcmp(cursor->db, aux->db) &&
+ !strcmp(cursor->real_name, aux->real_name) &&
+ !strcmp(cursor->name, aux->name))
+ break;
+ if (!cursor)
+ {
+ /* Add not used table to the total table list */
+ aux->lock_type= lex->lock_option;
+ if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux,
+ sizeof(*aux))))
+ {
+ send_error(&thd->net,0);
+ return 1;
+ }
+ *new_table_list= cursor;
+ new_table_list= &cursor->next;
+ *new_table_list= 0; // end result list
+ }
+ else
+ aux->shared= 1; // Mark that it's used twice
+ aux->table_list= cursor;
+ }
+ }
+ }
+ if (slave_list_first)
+ {
+ *new_table_list= slave_list_first;
+ new_table_list= slave_list_last;
+ }
+ *result= new_table_list;
+ return 0;
+}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index e53a2e7bda8..5c113e46a2b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -103,28 +103,180 @@ typedef struct st_lex_master_info
} LEX_MASTER_INFO;
-enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT, DERIVED_TABLE_TYPE};
+enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE,
+ EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE};
-/* The state of the lex parsing for selects */
+/*
+ The state of the lex parsing for selects
+
+ All select describing structures linked with following pointers:
+ - list of neighbors (next/prev) (prev of first element point to slave
+ pointer of upper structure)
+ - one level units for unit (union) structure
+ - member of one union(unit) for ordinary select_lex
+ - pointer to master
+ - outer select_lex for unit (union)
+ - unit structure for ordinary select_lex
+ - pointer to slave
+ - first list element of select_lex belonged to this unit for unit
+ - first unit in list of units that belong to this select_lex (as
+ subselects or derived tables) for ordinary select_lex
+ - list of all select_lex (for group operation like correcting list of opened
+ tables)
+ for example for following query:
-typedef struct st_select_lex {
- enum sub_select_type linkage;
- char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */
- Item *where,*having;
- ha_rows select_limit,offset_limit;
+ select *
+ from table1
+ where table1.field IN (select * from table1_1_1 union
+ select * from table1_1_2)
+ union
+ select *
+ from table2
+ where table2.field=(select (select f1 from table2_1_1_1_1
+ where table2_1_1_1_1.f2=table2_1_1.f3)
+ from table2_1_1
+ where table2_1_1.f1=table2.f2)
+ union
+ select * from table3;
+
+ we will have following structure:
+
+
+ main unit
+ select1 select2 select3
+ |^^ |^
+ s||| ||master
+ l||| |+---------------------------------+
+ a||| +---------------------------------+|
+ v|||master slave ||
+ e||+-------------------------+ ||
+ V| neighbor | V|
+ unit 1.1<==================>unit1.2 unit2.1
+ select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2
+ |^
+ ||
+ V|
+ unit2.1.1.1
+ select2.1.1.1.1
+
+
+ relation in main unit will be following:
+
+ main unit
+ |^^^
+ ||||
+ |||+------------------------------+
+ ||+--------------+ |
+ slave||master | |
+ V| neighbor | neighbor |
+ select1<========>select2<========>select3
+
+ list of all select_lex will be following (as it will be constructed by
+ parser):
+
+ select1->select2->select3->select2.1.1->select 2.1.2->select2.1.1.1.1-+
+ |
+ +---------------------------------------------------------------------+
+ |
+ +->select1.1.1->select1.1.2
+
+*/
+
+/*
+ Base class for st_select_lex (SELECT_LEX) &
+ st_select_lex_unit (SELECT_LEX_UNIT)
+*/
+class st_select_lex_node {
+protected:
+ st_select_lex_node *next, **prev, /* neighbor list */
+ *master, *slave, /* vertical links */
+ *link_next, **link_prev; /* list of whole SELECT_LEX */
+public:
ulong options;
+ enum sub_select_type linkage;
+ //uint sort_default;
+ SQL_LIST order_list; /* ORDER clause */
+ ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+ void init_query();
+ void init_select();
+ void include_down(st_select_lex_node *upper);
+ void include_neighbour(st_select_lex_node *before);
+ void include_global(st_select_lex_node **plink);
+ void exclude();
+private:
+ void fast_exclude();
+};
+
+/*
+ SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group
+ SELECT_LEXs
+*/
+class st_lex;
+class st_select_lex;
+class st_select_lex_unit: public st_select_lex_node {
+public:
+ /*
+ Pointer to 'last' select or pointer to unit where stored
+ global parameters for union
+ */
+ st_select_lex_node *global_parameters;
+ /* LIMIT clause runtime counters */
+ ha_rows select_limit_cnt, offset_limit_cnt;
+ void init_query();
+ 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; }
+
+ friend void mysql_init_query(THD *thd);
+private:
+ bool create_total_list_n_last_return(THD *thd, st_lex *lex,
+ TABLE_LIST ***result);
+};
+typedef struct st_select_lex_unit SELECT_LEX_UNIT;
+
+/*
+ SELECT_LEX - store information of parsed SELECT_LEX statment
+*/
+class st_select_lex: public st_select_lex_node {
+public:
+ char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
+ Item *where, *having; /* WHERE & HAVING clauses */
List<List_item> expr_list;
- List<List_item> when_list;
- SQL_LIST order_list,table_list,group_list;
- List<Item> item_list;
- List<String> interval_list,use_index, *use_index_ptr,
+ List<List_item> when_list; /* WHEN clause */
+ SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */
+ List<Item> item_list; /* list of fields & expressions */
+ List<String> interval_list, use_index, *use_index_ptr,
ignore_index, *ignore_index_ptr;
List<Item_func_match> ftfunc_list;
- uint in_sum_expr, sort_default;
- bool create_refs, braces;
- st_select_lex *next, *prev;
-} SELECT_LEX;
+ uint in_sum_expr;
+ bool create_refs,
+ braces, /* SELECT ... UNION (SELECT ... ) <- this braces */
+ depended; /* depended from outer select subselect */
+ void init_query();
+ void init_select();
+ st_select_lex_unit* master_unit() { return (st_select_lex_unit*) master; }
+ st_select_lex_unit* first_inner_unit()
+ {
+ return (st_select_lex_unit*) slave;
+ }
+ st_select_lex* outer_select()
+ {
+ return (st_select_lex*) master_unit()->outer_select();
+ }
+ st_select_lex* next_select() { return (st_select_lex*) next; }
+ st_select_lex* next_select_in_list()
+ {
+ return (st_select_lex*) link_next;
+ }
+ st_select_lex_node** next_select_in_list_addr()
+ {
+ return &link_next;
+ }
+ friend void mysql_init_query(THD *thd);
+};
+typedef struct st_select_lex SELECT_LEX;
class Set_option :public Sql_alloc {
public:
@@ -137,13 +289,15 @@ public:
:name(par_name), item(par_item), name_length(length), type(par_type) {}
};
-
/* The state of the lex parsing. This is saved in the THD struct */
typedef struct st_lex {
uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval;
- SELECT_LEX select_lex, *select, *last_select;
+ SELECT_LEX_UNIT unit; /* most upper unit */
+ SELECT_LEX select_lex, /* first SELECT_LEX */
+ /* current SELECT_LEX in parsing */
+ *select;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 469de136fbb..3492854329a 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -65,12 +65,11 @@ static void decrease_user_connections(UC *uc);
static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
static bool check_dup(const char *db, const char *name, TABLE_LIST *tables);
-static void mysql_init_query(THD *thd);
+void mysql_init_query(THD *thd);
static void remove_escape(char *name);
static void refresh_status(void);
static bool append_file_to_dir(THD *thd, char **filename_ptr,
char *table_name);
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result);
const char *any_db="*any*"; // Special symbol for check_access
@@ -1203,11 +1202,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
void
mysql_execute_command(void)
{
- int res=0;
- THD *thd=current_thd;
+ int res= 0;
+ THD *thd= current_thd;
LEX *lex= &thd->lex;
- TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first;
- SELECT_LEX *select_lex = lex->select;
+ TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first;
+ SELECT_LEX *select_lex= lex->select;
+ SELECT_LEX_UNIT *unit= &lex->unit;
DBUG_ENTER("mysql_execute_command");
if (thd->slave_thread)
@@ -1240,11 +1240,14 @@ mysql_execute_command(void)
{
for (TABLE_LIST *cursor= tables;
cursor;
- cursor=cursor->next)
- if (cursor->derived && mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor))
+ cursor= cursor->next)
+ if (cursor->derived && mysql_derived(thd, lex,
+ (SELECT_LEX_UNIT *)cursor->derived,
+ cursor))
DBUG_VOID_RETURN;
}
- if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
+ if ((lex->select_lex.next_select_in_list() &&
+ lex->unit.create_total_list(thd, lex, &tables)) ||
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
DBUG_VOID_RETURN;
@@ -1272,11 +1275,12 @@ mysql_execute_command(void)
break; // Error message is given
}
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
+ unit->offset_limit_cnt= 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;
if (lex->exchange)
@@ -1501,10 +1505,11 @@ mysql_execute_command(void)
for (table = tables->next ; table ; table=table->next)
table->lock_type= lex->lock_option;
}
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+
+ select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
/* Skip first table, which is the table we are creating */
lex->select_lex.table_list.first=
@@ -1786,13 +1791,13 @@ mysql_execute_command(void)
while ((item=value_list++))
total_list.push_back(item);
- res=mysql_select(thd,tables,total_list,
- select_lex->where,
- (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
- (ORDER *)NULL,
- select_lex->options | thd->options |
- SELECT_NO_JOIN_CACHE,
- result);
+ res= mysql_select(thd, tables, total_list,
+ select_lex->where,
+ (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
+ (ORDER *)NULL,
+ select_lex->options | thd->options |
+ SELECT_NO_JOIN_CACHE,
+ result, unit);
delete result;
}
else
@@ -1842,10 +1847,10 @@ mysql_execute_command(void)
}
select_result *result;
- thd->offset_limit=select_lex->offset_limit;
- thd->select_limit=select_lex->select_limit+select_lex->offset_limit;
- if (thd->select_limit < select_lex->select_limit)
- thd->select_limit= HA_POS_ERROR; // No limit
+ unit->offset_limit_cnt= select_lex->offset_limit;
+ unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // No limit
if (check_dup(tables->db, tables->real_name, tables->next))
{
@@ -1938,7 +1943,7 @@ mysql_execute_command(void)
goto error;
}
auxi->lock_type=walk->lock_type=TL_WRITE;
- auxi->table= (TABLE *) walk; // Remember corresponding table
+ auxi->table_list= walk; // Remember corresponding table
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
if (add_item_to_list(new Item_null()))
@@ -1951,7 +1956,7 @@ mysql_execute_command(void)
break;
/* Fix tables-to-be-deleted-from list to point at opened tables */
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
- auxi->table= ((TABLE_LIST*) auxi->table)->table;
+ auxi->table= auxi->table_list->table;
if (!thd->fatal_error && (result=new multi_delete(thd,aux_tables,
lex->lock_option,table_count)))
{
@@ -1961,7 +1966,7 @@ mysql_execute_command(void)
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
- result);
+ result, unit);
delete result;
}
else
@@ -2660,22 +2665,25 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize)
Initialize global thd variables needed for query
****************************************************************************/
-static void
+void
mysql_init_query(THD *thd)
{
DBUG_ENTER("mysql_init_query");
- thd->lex.select_lex.item_list.empty();
+ thd->lex.unit.init_query();
+ thd->lex.unit.init_select();
+ thd->lex.select_lex.init_query();
+ thd->lex.unit.slave= &thd->lex.select_lex;
+ thd->lex.unit.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->lex.value_list.empty();
- thd->lex.select_lex.table_list.elements=0;
- thd->free_list=0; thd->lex.union_option=0;
- thd->lex.select = thd->lex.last_select = &thd->lex.select_lex;
- thd->lex.select_lex.table_list.first=0;
- thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
- thd->lex.select_lex.next=0;
- thd->fatal_error=0; // Safety
- thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0;
- thd->sent_row_count=thd->examined_row_count=0;
- thd->safe_to_cache_query=1;
+ thd->free_list= 0;
+ thd->lex.union_option= 0;
+ thd->lex.select= &thd->lex.select_lex;
+ thd->fatal_error= 0; // Safety
+ thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
+ thd->sent_row_count= thd->examined_row_count= 0;
+ thd->safe_to_cache_query= 1;
DBUG_VOID_RETURN;
}
@@ -2683,53 +2691,53 @@ void
mysql_init_select(LEX *lex)
{
SELECT_LEX *select_lex = lex->select;
- select_lex->where=select_lex->having=0;
+ select_lex->init_select();
select_lex->select_limit=lex->thd->default_select_limit;
select_lex->offset_limit=0;
- select_lex->options=0;
- select_lex->linkage=UNSPECIFIED_TYPE;
lex->exchange = 0;
lex->proc_list.first=0;
- select_lex->order_list.elements=select_lex->group_list.elements=0;
- select_lex->order_list.first=0;
- select_lex->order_list.next= (byte**) &select_lex->order_list.first;
- select_lex->group_list.first=0;
- select_lex->group_list.next= (byte**) &select_lex->group_list.first;
- select_lex->next = select_lex->prev = (SELECT_LEX *)NULL;
}
bool
-mysql_new_select(LEX *lex)
+mysql_new_select(LEX *lex, bool move_down)
{
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
if (!select_lex)
return 1;
- lex->select=lex->last_select;
- lex->select->next=select_lex;
- lex->select=lex->last_select=select_lex;
- select_lex->table_list.next= (byte**) &select_lex->table_list.first;
- select_lex->item_list.empty();
- select_lex->when_list.empty();
- select_lex->expr_list.empty();
- select_lex->interval_list.empty();
- select_lex->use_index.empty();
- select_lex->ftfunc_list.empty();
+ select_lex->init_query();
+ select_lex->init_select();
+ if (move_down)
+ {
+ /* first select_lex of subselect or derived table */
+ SELECT_LEX_UNIT *unit=
+ (SELECT_LEX_UNIT *) lex->thd->calloc(sizeof(SELECT_LEX_UNIT));
+ if (!unit)
+ return 1;
+ unit->init_query();
+ unit->init_select();
+ unit->include_down(lex->select);
+ select_lex->include_down(unit);
+ }
+ else
+ select_lex->include_neighbour(lex->select);
+
+ select_lex->master_unit()->global_parameters= select_lex;
+ select_lex->include_global(lex->select->next_select_in_list_addr());
+ lex->select= select_lex;
return 0;
}
void mysql_init_multi_delete(LEX *lex)
{
- lex->sql_command = SQLCOM_DELETE_MULTI;
+ lex->sql_command= SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
- lex->select->select_limit=HA_POS_ERROR;
- lex->auxilliary_table_list=lex->select_lex.table_list;
- lex->select->table_list.elements=0;
- lex->select->table_list.first=0;
- lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
+ lex->select->select_limit= HA_POS_ERROR;
+ lex->auxilliary_table_list= lex->select_lex.table_list;
+ lex->select->init_query();
}
void
-mysql_parse(THD *thd,char *inBuf,uint length)
+mysql_parse(THD *thd, char *inBuf, uint length)
{
DBUG_ENTER("mysql_parse");
@@ -3160,7 +3168,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
ptr->real_name_length=table->table.length;
ptr->lock_type=flags;
ptr->updating=updating;
- ptr->derived=(SELECT_LEX *)table->sel;
+ ptr->derived= (SELECT_LEX_UNIT *) table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index));
@@ -3187,68 +3195,6 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
}
-/*
-** This is used for UNION to create a new table list of all used tables
-** The table_list->table entry in all used tables are set to point
-** to the entries in this list.
-*/
-
-static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
-{
- /* Handle the case when we are not using union */
- if (!lex->select_lex.next)
- {
- *result= (TABLE_LIST*) lex->select_lex.table_list.first;
- return 0;
- }
-
- SELECT_LEX *sl;
- TABLE_LIST **new_table_list= result, *aux;
-
- *new_table_list=0; // end result list
- for (sl= &lex->select_lex; sl; sl=sl->next)
- {
- if (sl->order_list.first && sl->next && !sl->braces)
- {
- net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
- return 1;
- }
- if ((aux= (TABLE_LIST*) sl->table_list.first))
- {
- TABLE_LIST *next;
- for (; aux; aux=next)
- {
- TABLE_LIST *cursor;
- next= aux->next;
- for (cursor= *result; cursor; cursor=cursor->next)
- if (!strcmp(cursor->db,aux->db) &&
- !strcmp(cursor->real_name,aux->real_name) &&
- !strcmp(cursor->name, aux->name))
- break;
- if (!cursor)
- {
- /* Add not used table to the total table list */
- aux->lock_type= lex->lock_option;
- if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux,
- sizeof(*aux))))
- {
- send_error(&thd->net,0);
- return 1;
- }
- *new_table_list= cursor;
- new_table_list= &cursor->next;
- *new_table_list=0; // end result list
- }
- else
- aux->shared=1; // Mark that it's used twice
- aux->table=(TABLE *) cursor;
- }
- }
- }
- return 0;
-}
-
-
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (!b->on_expr)
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index c539afb00c1..4748e857276 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -65,7 +65,8 @@ static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond,
static int return_zero_rows(select_result *res,TABLE_LIST *tables,
List<Item> &fields, bool send_row,
uint select_options, const char *info,
- Item *having, Procedure *proc);
+ Item *having, Procedure *proc,
+ SELECT_LEX_UNIT *unit);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
@@ -155,7 +156,20 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
{
int res;
register SELECT_LEX *select_lex = &lex->select_lex;
- if (select_lex->next)
+ 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;
+ }
+ }
+ if (select_lex->next_select())
res=mysql_union(thd,lex,result);
else
res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first,
@@ -166,7 +180,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
select_lex->having,
(ORDER*) lex->proc_list.first,
select_lex->options | thd->options,
- result);
+ result, &(lex->unit));
if (res && result)
result->abort();
delete result;
@@ -179,49 +193,43 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
** mysql_select assumes that all tables are already opened
*****************************************************************************/
+/*
+ Prepare of whole select (including subselect in future).
+ return -1 on error
+ 0 on success
+*/
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)
+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)
{
- TABLE *tmp_table;
- int error, tmp_error;
- bool need_tmp,hidden_group_fields;
- bool simple_order,simple_group,no_order, skip_sort_order, buffer_result;
- Item::cond_result cond_value;
- SQL_SELECT *select;
- DYNAMIC_ARRAY keyuse;
- JOIN join;
- Procedure *procedure;
- List<Item> all_fields(fields);
- bool select_distinct;
- SELECT_LEX *select_lex = &(thd->lex.select_lex);
- SELECT_LEX *cur_sel = thd->lex.select;
- DBUG_ENTER("mysql_select");
-
+ DBUG_ENTER("JOIN::prepare");
+
+ conds= conds_init;
+ order= order_init;
+ group_list= group_init;
+ having= having_init;
+ proc_param= proc_param_init;
+ tables_list= tables_init;
+ select_lex= select;
+ union_part= (unit->first_select()->next_select() != 0);
+
/* Check that all tables, fields, conds and order are ok */
- select_distinct=test(select_options & SELECT_DISTINCT);
- buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
- tmp_table=0;
- select=0;
- no_order=skip_sort_order=0;
- bzero((char*) &keyuse,sizeof(keyuse));
- thd->proc_info="init";
- thd->used_tables=0; // Updated by setup_fields
-
- if (setup_tables(tables) ||
- setup_fields(thd,tables,fields,1,&all_fields,1) ||
- setup_conds(thd,tables,&conds) ||
- setup_order(thd,tables,fields,all_fields,order) ||
- setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
+ if (setup_tables(tables_list) ||
+ setup_fields(thd,tables_list,fields_list,1,&all_fields,1) ||
+ setup_conds(thd,tables_list,&conds) ||
+ setup_order(thd,tables_list,fields_list,all_fields,order) ||
+ setup_group(thd,tables_list,fields_list,all_fields,group_list,
+ &hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */
if (having)
{
thd->where="having clause";
thd->allow_sum_func=1;
- if (having->fix_fields(thd,tables) || thd->fatal_error)
+ if (having->fix_fields(thd,tables_list) || thd->fatal_error)
DBUG_RETURN(-1); /* purecov: inspected */
if (having->with_sum_func)
having->split_sum_func(all_fields);
@@ -234,13 +242,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
TODO: Add check of calculation of GROUP functions and fields:
SELECT COUNT(*)+table.col1 from table1;
*/
- join.table=0;
- join.tables=0;
{
- if (!group)
+ if (!group_list)
{
uint flag=0;
- List_iterator_fast<Item> it(fields);
+ List_iterator_fast<Item> it(fields_list);
Item *item;
while ((item= it++))
{
@@ -256,22 +262,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
TABLE_LIST *table;
- for (table=tables ; table ; table=table->next)
- join.tables++;
+ for (table=tables_list ; table ; table=table->next)
+ tables++;
}
- procedure=setup_procedure(thd,proc_param,result,fields,&error);
+ procedure=setup_procedure(thd,proc_param,result,fields_list,&error);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
if (procedure)
{
- if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields))
+ if (setup_new_fields(thd, tables_list, fields_list, all_fields,
+ procedure->param_fields))
{ /* purecov: inspected */
delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
if (procedure->group)
{
- if (!test_if_subpart(procedure->group,group))
+ if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */
@@ -280,7 +287,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
}
#ifdef NOT_NEEDED
- else if (!group && procedure->flags & PROC_GROUP)
+ else if (!group_list && procedure->flags & PROC_GROUP)
{
my_message(0,"Select must have a group with this procedure",MYF(0));
delete procedure;
@@ -296,51 +303,53 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
/* Init join struct */
- join.thd=thd;
- join.lock=thd->lock;
- join.join_tab=0;
- join.tmp_table_param.copy_field=0;
- join.sum_funcs=0;
- join.send_records=join.found_records=join.examined_rows=0;
- join.tmp_table_param.end_write_records= HA_POS_ERROR;
- join.first_record=join.sort_and_group=0;
- join.select_options=select_options;
- join.result=result;
- count_field_types(&join.tmp_table_param,all_fields,0);
- join.const_tables=0;
- join.having=0;
- join.do_send_rows = 1;
- join.group= group != 0;
- join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
- thd->select_limit);
+ count_field_types(&tmp_table_param, all_fields, 0);
+ this->group= group_list != 0;
+ row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
+ unit->select_limit_cnt);
+ this->unit= unit;
#ifdef RESTRICTED_GROUP
- if (join.sum_func_count && !group && (join.func_count || join.field_count))
+ if (sum_func_count && !group_list && (func_count || field_count))
{
my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure;
DBUG_RETURN(-1);
}
#endif
- if (!procedure && result->prepare(fields))
+ if (!procedure && result->prepare(fields_list, unit))
{ /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */
}
+ DBUG_RETURN(0); // All OK
+}
+
+/*
+ global select optimisation.
+ return 0 - success
+ 1 - go out
+ -1 - go out with cleaning
+ error code saved in field 'error'
+*/
+int
+JOIN::optimize()
+{
+ DBUG_ENTER("JOIN::optimize");
#ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */
- if (having && !group && ! join.sum_func_count)
+ if (having && !group_list && ! sum_func_count)
{
if (!conds)
{
- conds=having;
- having=0;
+ conds= having;
+ having= 0;
}
else if ((conds=new Item_cond_and(conds,having)))
{
- conds->fix_fields(thd,tables);
- conds->change_ref_to_fields(thd,tables);
- having=0;
+ conds->fix_fields(thd, tables_list);
+ conds->change_ref_to_fields(thd, tables_list);
+ having= 0;
}
}
#endif
@@ -349,110 +358,87 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (thd->fatal_error) // Out of memory
{
delete procedure;
- DBUG_RETURN(0);
+ error = 0;
+ DBUG_RETURN(1);
}
- if (cond_value == Item::COND_FALSE || !thd->select_limit)
+ if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt)
{ /* Impossible cond */
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"Impossible WHERE");
- else
- error=return_zero_rows(result, tables, fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,"Impossible WHERE",having,
- procedure);
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "Impossible WHERE";
+ DBUG_RETURN(0);
}
/* Optimize count(*), min() and max() */
- if (tables && join.tmp_table_param.sum_func_count && ! group)
+ if (tables_list && tmp_table_param.sum_func_count && ! group_list)
{
int res;
- if ((res=opt_sum_query(tables, all_fields, conds)))
+ if ((res=opt_sum_query(tables_list, all_fields, conds)))
{
if (res < 0)
{
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"No matching min/max row");
- else
- error=return_zero_rows(result, tables, fields, !group,
- select_options,"No matching min/max row",
- having,procedure);
- delete procedure;
- DBUG_RETURN(error);
+ zero_result_cause= "No matching min/max row";
+ DBUG_RETURN(0);
}
if (select_options & SELECT_DESCRIBE)
{
- if (select_lex->next)
- select_describe(&join,false,false,false,"Select tables optimized away");
+ if (union_part)
+ select_describe(this, false, false, false,
+ "Select tables optimized away");
else
- describe_info(thd,"Select tables optimized away");
+ describe_info(thd, "Select tables optimized away");
delete procedure;
- DBUG_RETURN(error);
+ DBUG_RETURN(1);
}
- tables=0; // All tables resolved
+ tables_list= 0; // All tables resolved
}
}
- if (!tables)
- { // Only test of functions
- error=0;
- if (select_options & SELECT_DESCRIBE)
- {
- if (select_lex->next)
- select_describe(&join,false,false,false,"No tables used");
- else
- describe_info(thd,"No tables used");
- }
- else
- {
- result->send_fields(fields,1);
- if (!having || having->val_int())
- {
- if (join.do_send_rows && result->send_data(fields))
- {
- result->send_error(0,NullS); /* purecov: inspected */
- error=1;
- }
- else
- error=(int) result->send_eof();
- }
- else
- error=(int) result->send_eof();
- }
- delete procedure;
- DBUG_RETURN(error);
+
+ if (!tables_list)
+ {
+ test_function_query= 1;
+ DBUG_RETURN(0);
}
- error = -1;
- join.sort_by_table=get_sort_by_table(order,group,tables);
+ error= -1;
+ sort_by_table= get_sort_by_table(order, group_list, tables_list);
/* Calculate how to do the join */
- thd->proc_info="statistics";
- if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
- goto err;
- thd->proc_info="preparing";
- result->initialize_tables(&join);
- if (join.const_table_map != join.found_const_table_map &&
+ thd->proc_info= "statistics";
+ if (make_join_statistics(this, tables_list, conds, &keyuse) ||
+ thd->fatal_error)
+ DBUG_RETURN(-1);
+
+ if (select_lex->depended)
+ {
+ /*
+ Just remove all const-table optimization in case of depended query
+ TODO: optimize
+ */
+ const_table_map= 0;
+ const_tables= 0;
+ found_const_table_map= 0;
+ }
+ thd->proc_info= "preparing";
+ result->initialize_tables(this);
+ if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE))
{
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 &&
- !group,0,"",having,procedure);
- goto err;
+ zero_result_cause= "";
+ select_options= 0; //TODO why option in return_zero_rows was droped
+ DBUG_RETURN(0);
}
if (!(thd->options & OPTION_BIG_SELECTS) &&
- join.best_read > (double) thd->max_join_size &&
+ best_read > (double) thd->max_join_size &&
!(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */
result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
error= 1; /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_RETURN(-1);
}
- if (join.const_tables && !thd->locked_tables &&
+ if (const_tables && !thd->locked_tables &&
!(select_options & SELECT_NO_UNLOCK))
{
TABLE **table, **end;
- for (table=join.table, end=table + join.const_tables ;
+ for (table=this->table, end=table + const_tables ;
table != end;
table++)
{
@@ -464,97 +450,94 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
}
(*table)->file->index_end();
}
- mysql_unlock_some_tables(thd, join.table,join.const_tables);
+ mysql_unlock_some_tables(thd, this->table, const_tables);
}
- if (!conds && join.outer_join)
+ if (!conds && outer_join)
{
/* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true
}
- select=make_select(*join.table, join.const_table_map,
- join.const_table_map,conds,&error);
+ select=make_select(*table, const_table_map,
+ const_table_map, conds, &error);
if (error)
{ /* purecov: inspected */
error= -1; /* purecov: inspected */
- goto err; /* purecov: inspected */
- }
- if (make_join_select(&join,select,conds))
- {
- if (select_options & SELECT_DESCRIBE && select_lex->next)
- select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
- else
- error=return_zero_rows(result,tables,fields,
- join.tmp_table_param.sum_func_count != 0 && !group,
- select_options,
- "Impossible WHERE noticed after reading const tables",
- having,procedure);
- goto err;
+ DBUG_RETURN(-1);
+ }
+ if (make_join_select(this, select, conds))
+ {
+ zero_result_cause=
+ "Impossible WHERE noticed after reading const tables";
+ DBUG_RETURN(0);
}
error= -1; /* if goto err */
/* Optimize distinct away if possible */
- order=remove_const(&join,order,conds,&simple_order);
- if (group || join.tmp_table_param.sum_func_count)
+ order= remove_const(this, order, conds, &simple_order);
+ if (group_list || tmp_table_param.sum_func_count)
{
if (! hidden_group_fields)
select_distinct=0;
}
- else if (select_distinct && join.tables - join.const_tables == 1 &&
- (thd->select_limit == HA_POS_ERROR ||
- (join.select_options & OPTION_FOUND_ROWS) ||
+ else if (select_distinct && tables - const_tables == 1 &&
+ (unit->select_limit_cnt == HA_POS_ERROR ||
+ (select_options & OPTION_FOUND_ROWS) ||
order &&
!(skip_sort_order=
- test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,1))))
+ test_if_skip_sort_order(&join_tab[const_tables],
+ order,
+ unit->select_limit_cnt,
+ 1))))
{
- if ((group=create_distinct_group(order,fields)))
+ if ((group_list= create_distinct_group(order, fields_list)))
{
- select_distinct=0;
+ select_distinct= 0;
no_order= !order;
- join.group=1; // For end_write_group
+ group= 1; // For end_write_group
}
else if (thd->fatal_error) // End of memory
- goto err;
+ DBUG_RETURN(-1);
}
- group=remove_const(&join,group,conds,&simple_group);
- if (!group && join.group)
+ group_list= remove_const(this, group_list, conds, &simple_group);
+ if (!group_list && group)
{
order=0; // The output has only one row
simple_order=1;
}
- calc_group_buffer(&join,group);
- join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
+ calc_group_buffer(this, group_list);
+ send_group_parts= tmp_table_param.group_parts; /* Save org parts */
if (procedure && procedure->group)
{
- group=procedure->group=remove_const(&join,procedure->group,conds,
- &simple_group);
- calc_group_buffer(&join,group);
+ group_list= procedure->group= remove_const(this, procedure->group, conds,
+ &simple_group);
+ calc_group_buffer(this, group_list);
}
- if (test_if_subpart(group,order) ||
- (!group && join.tmp_table_param.sum_func_count))
+ if (test_if_subpart(group_list, order) ||
+ (!group_list && tmp_table_param.sum_func_count))
order=0;
// Can't use sort on head table if using row cache
- if (join.full_join)
+ if (full_join)
{
- if (group)
+ if (group_list)
simple_group=0;
if (order)
simple_order=0;
}
- need_tmp= (join.const_tables != join.tables &&
+ need_tmp= (const_tables != tables &&
((select_distinct || !simple_order || !simple_group) ||
- (group && order) || buffer_result));
+ (group_list && order) || buffer_result));
// No cache for MATCH
- make_join_readinfo(&join,
+ make_join_readinfo(this,
(select_options & (SELECT_DESCRIBE |
SELECT_NO_JOIN_CACHE)) |
- (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
+ (thd->lex.select->ftfunc_list.elements ?
+ SELECT_NO_JOIN_CACHE : 0));
/* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL
@@ -563,60 +546,149 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
by MySQL. */
#ifdef HAVE_INNOBASE_DB
- if (need_tmp || select_distinct || group || order)
+ if (need_tmp || select_distinct || group_list || order)
{
- for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
+ for (uint i_h = const_tables; i_h < tables; i_h++)
{
- TABLE* table_h = join.join_tab[i_h].table;
+ TABLE* table_h = join_tab[i_h].table;
if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
}
}
#endif
- DBUG_EXECUTE("info",TEST_join(&join););
+ DBUG_EXECUTE("info",TEST_join(this););
/*
Because filesort always does a full table scan or a quick range scan
we must add the removed reference to the select for the table.
We only need to do this when we have a simple_order or simple_group
as in other cases the join is done before the sort.
*/
- if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
- join.join_tab[join.const_tables].type != JT_FT &&
- (order && simple_order || group && simple_group))
+ if ((order || group_list) && join_tab[const_tables].type != JT_ALL &&
+ join_tab[const_tables].type != JT_FT &&
+ (order && simple_order || group_list && simple_group))
{
- if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
- goto err;
+ if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
+ DBUG_RETURN(-1);
}
if (!(select_options & SELECT_BIG_RESULT) &&
- ((group && join.const_tables != join.tables &&
+ ((group_list && const_tables != tables &&
(!simple_group ||
- !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
- thd->select_limit,0))) ||
+ !test_if_skip_sort_order(&join_tab[const_tables], group_list,
+ unit->select_limit_cnt,
+ 0))) ||
select_distinct) &&
- join.tmp_table_param.quick_group && !procedure)
+ tmp_table_param.quick_group && !procedure)
{
need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
}
+ DBUG_RETURN(0);
+}
+
+/*
+ Global optimization (with subselect) must be here (TODO)
+*/
+
+int
+JOIN::global_optimize()
+{
+ return 0;
+}
+
+int
+JOIN::reinit()
+{
+ DBUG_ENTER("JOIN::reinit");
+ //TODO move to unit reinit
+ unit->offset_limit_cnt =select_lex->offset_limit;
+ unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit;
+ if (unit->select_limit_cnt < select_lex->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ select_lex->options&= ~OPTION_FOUND_ROWS;
+
+ if (setup_tables(tables_list))
+ DBUG_RETURN(1);
+ DBUG_RETURN(0);
+}
+
+/*
+ Exec select
+*/
+void
+JOIN::exec()
+{
+ int tmp_error;
+
+ DBUG_ENTER("JOIN::exec");
+
+ if (test_function_query)
+ { // Only test of functions
+ error=0;
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (union_part)
+ select_describe(this, false, false, false, "No tables used");
+ else
+ describe_info(thd, "No tables used");
+ }
+ else
+ {
+ result->send_fields(fields_list,1);
+ if (!having || having->val_int())
+ {
+ if (do_send_rows && result->send_data(fields_list))
+ {
+ result->send_error(0,NullS); /* purecov: inspected */
+ error=1;
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ else
+ error=(int) result->send_eof();
+ }
+ delete procedure;
+ DBUG_VOID_RETURN;
+ }
+
+ if (zero_result_cause)
+ {
+ if (select_options & SELECT_DESCRIBE && union_part)
+ select_describe(this, false, false, false, zero_result_cause);
+ else
+ error=return_zero_rows(result, tables_list, fields_list,
+ tmp_table_param.sum_func_count != 0 &&
+ !group_list,
+ select_options,
+ zero_result_cause,
+ having,procedure,
+ unit);
+ DBUG_VOID_RETURN;
+ }
+
+ Item *having_list = having;
+ having = 0;
if (select_options & SELECT_DESCRIBE)
{
if (!order && !no_order)
- order=group;
+ order=group_list;
if (order &&
- (join.const_tables == join.tables ||
+ (const_tables == tables ||
(simple_order &&
- test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
- (join.const_tables != join.tables - 1 ||
- (join.select_options & OPTION_FOUND_ROWS)) ?
- HA_POS_ERROR : thd->select_limit,0))))
+ test_if_skip_sort_order(&join_tab[const_tables], order,
+ (const_tables != tables - 1 ||
+ (select_options & OPTION_FOUND_ROWS)) ?
+ HA_POS_ERROR : unit->select_limit_cnt,
+ 0))))
order=0;
- select_describe(&join,need_tmp,
+ select_describe(this, need_tmp,
order != 0 && !skip_sort_order,
select_distinct);
error=0;
- goto err;
+ DBUG_VOID_RETURN;
}
/* Perform FULLTEXT search before all regular searches */
@@ -628,44 +700,45 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
DBUG_PRINT("info",("Creating tmp table"));
thd->proc_info="Creating tmp table";
- if (!(tmp_table =
- create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ if (!(exec_tmp_table =
+ create_tmp_table(thd, &tmp_table_param, all_fields,
((!simple_group && !procedure &&
!(test_flags & TEST_NO_KEY_GROUP)) ?
- group : (ORDER*) 0),
- group ? 0 : select_distinct,
- group && simple_group,
+ group_list : (ORDER*) 0),
+ group_list ? 0 : select_distinct,
+ group_list && simple_group,
(order == 0 || skip_sort_order) &&
- !(join.select_options & OPTION_FOUND_ROWS),
- join.select_options)))
- goto err; /* purecov: inspected */
+ !(select_options & OPTION_FOUND_ROWS),
+ select_options, unit)))
+ DBUG_VOID_RETURN;
- if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
- join.having=having;
+ if (having_list &&
+ (sort_and_group || (exec_tmp_table->distinct && !group_list)))
+ having=having_list;
/* if group or order on first table, sort first */
- if (group && simple_group)
+ if (group_list && simple_group)
{
DBUG_PRINT("info",("Sorting for group"));
thd->proc_info="Sorting for group";
- if (create_sort_index(&join.join_tab[join.const_tables],group,
+ if (create_sort_index(&join_tab[const_tables], group_list,
HA_POS_ERROR) ||
- make_sum_func_list(&join,all_fields) ||
- alloc_group_fields(&join,group))
- goto err;
- group=0;
+ make_sum_func_list(this, all_fields) ||
+ alloc_group_fields(this, group_list))
+ DBUG_VOID_RETURN;
+ group_list=0;
}
else
{
- if (make_sum_func_list(&join,all_fields))
- goto err;
- if (!group && ! tmp_table->distinct && order && simple_order)
+ if (make_sum_func_list(this, all_fields))
+ DBUG_VOID_RETURN;
+ if (!group_list && ! exec_tmp_table->distinct && order && simple_order)
{
DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order";
- if (create_sort_index(&join.join_tab[join.const_tables],order,
- HA_POS_ERROR))
- goto err; /* purecov: inspected */
+ if (create_sort_index(&join_tab[const_tables], order,
+ HA_POS_ERROR))
+ DBUG_VOID_RETURN;
order=0;
}
}
@@ -676,58 +749,58 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
In this case we can stop scanning t2 when we have found one t1.a
*/
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
{
table_map used_tables= thd->used_tables;
- JOIN_TAB *join_tab=join.join_tab+join.tables-1;
+ JOIN_TAB *join_tab= this->join_tab+tables-1;
do
{
if (used_tables & join_tab->table->map)
break;
join_tab->not_used_in_distinct=1;
- } while (join_tab-- != join.join_tab);
+ } while (join_tab-- != this->join_tab);
/* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order)
{
- (void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
- order, thd->select_limit,0);
+ (void) test_if_skip_sort_order(&this->join_tab[const_tables],
+ order, unit->select_limit_cnt, 0);
order=0;
}
}
/* Copy data to the temporary table */
- thd->proc_info="Copying to tmp table";
- if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ thd->proc_info= "Copying to tmp table";
+ if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0)))
{
- error=tmp_error;
- goto err; /* purecov: inspected */
+ error= tmp_error;
+ DBUG_VOID_RETURN;
}
- if (join.having)
- join.having=having=0; // Allready done
+ if (having)
+ having= having_list= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */
- if (join.sort_and_group || tmp_table->group)
+ if (sort_and_group || exec_tmp_table->group)
{
if (change_to_use_tmp_fields(all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
- join.tmp_table_param.func_count;
- join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count+
+ tmp_table_param.func_count;
+ tmp_table_param.sum_func_count= tmp_table_param.func_count= 0;
}
else
{
if (change_refs_to_tmp_fields(thd,all_fields))
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
- join.tmp_table_param.func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.func_count;
+ tmp_table_param.func_count= 0;
}
if (procedure)
procedure->update_refs();
- if (tmp_table->group)
+ if (exec_tmp_table->group)
{ // Already grouped
if (!order && !no_order)
- order=group; /* order by group */
- group=0;
+ order= group_list; /* order by group */
+ group_list= 0;
}
/*
@@ -738,153 +811,196 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
** like SEC_TO_TIME(SUM(...)).
*/
- if (group && (!test_if_subpart(group,order) || select_distinct) ||
+ if (group_list && (!test_if_subpart(group_list,order) ||
+ select_distinct) ||
(select_distinct &&
- join.tmp_table_param.using_indirect_summary_function))
+ tmp_table_param.using_indirect_summary_function))
{ /* Must copy to another table */
TABLE *tmp_table2;
DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */
- join_free(&join);
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,
- select_distinct && !group);
- join.tmp_table_param.hidden_field_count=(all_fields.elements-
- fields.elements);
+ join_free(this);
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields,
+ select_distinct && !group_list);
+ tmp_table_param.hidden_field_count= (all_fields.elements-
+ fields_list.elements);
/* group data to new table */
- if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields,
(ORDER*) 0,
- select_distinct && !group,
+ select_distinct && !group_list,
1, 0,
- join.select_options)))
- goto err; /* purecov: inspected */
- if (group)
+ select_options, unit)))
+ DBUG_VOID_RETURN;
+ if (group_list)
{
thd->proc_info="Creating sort index";
- if (create_sort_index(join.join_tab,group,HA_POS_ERROR) ||
- alloc_group_fields(&join,group))
+ if (create_sort_index(join_tab, group_list, HA_POS_ERROR) ||
+ alloc_group_fields(this, group_list))
{
free_tmp_table(thd,tmp_table2); /* purecov: inspected */
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- group=0;
+ group_list= 0;
}
thd->proc_info="Copying to group table";
tmp_error= -1;
- if (make_sum_func_list(&join,all_fields) ||
- (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
+ if (make_sum_func_list(this, all_fields) ||
+ (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0)))
{
error=tmp_error;
free_tmp_table(thd,tmp_table2);
- goto err; /* purecov: inspected */
+ DBUG_VOID_RETURN;
}
- end_read_record(&join.join_tab->read_record);
- free_tmp_table(thd,tmp_table);
- join.const_tables=join.tables; // Mark free for join_free()
- tmp_table=tmp_table2;
- join.join_tab[0].table=0; // Table is freed
+ end_read_record(&join_tab->read_record);
+ free_tmp_table(thd,exec_tmp_table);
+ const_tables= tables; // Mark free for join_free()
+ exec_tmp_table= tmp_table2;
+ join_tab[0].table= 0; // Table is freed
if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
- goto err;
- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
- join.tmp_table_param.sum_func_count=0;
+ DBUG_VOID_RETURN;
+ tmp_table_param.field_count+= tmp_table_param.sum_func_count;
+ tmp_table_param.sum_func_count= 0;
}
- if (tmp_table->distinct)
+ if (exec_tmp_table->distinct)
select_distinct=0; /* Each row is unique */
- join_free(&join); /* Free quick selects */
- if (select_distinct && ! group)
+ join_free(this); /* Free quick selects */
+ if (select_distinct && ! group_list)
{
thd->proc_info="Removing duplicates";
- if (having)
- having->update_used_tables();
- if (remove_duplicates(&join,tmp_table,fields, having))
- goto err; /* purecov: inspected */
- having=0;
+ if (having_list)
+ having_list->update_used_tables();
+ if (remove_duplicates(this, exec_tmp_table, fields_list, having_list))
+ DBUG_VOID_RETURN;
+ having_list=0;
select_distinct=0;
}
- tmp_table->reginfo.lock_type=TL_UNLOCK;
- if (make_simple_join(&join,tmp_table))
- goto err;
- calc_group_buffer(&join,group);
- count_field_types(&join.tmp_table_param,all_fields,0);
+ exec_tmp_table->reginfo.lock_type=TL_UNLOCK;
+ if (make_simple_join(this, exec_tmp_table))
+ DBUG_VOID_RETURN;
+ calc_group_buffer(this, group_list);
+ count_field_types(&tmp_table_param, all_fields, 0);
}
if (procedure)
{
- if (procedure->change_columns(fields) ||
- result->prepare(fields))
- goto err;
- count_field_types(&join.tmp_table_param,all_fields,0);
+ if (procedure->change_columns(fields_list) ||
+ result->prepare(fields_list, unit))
+ DBUG_VOID_RETURN;
+ count_field_types(&tmp_table_param, all_fields, 0);
}
- if (join.group || join.tmp_table_param.sum_func_count ||
+ if (group || tmp_table_param.sum_func_count ||
(procedure && (procedure->flags & PROC_GROUP)))
{
- alloc_group_fields(&join,group);
- setup_copy_fields(thd, &join.tmp_table_param,all_fields);
- if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
- goto err; /* purecov: inspected */
+ alloc_group_fields(this, group_list);
+ setup_copy_fields(thd, &tmp_table_param,all_fields);
+ if (make_sum_func_list(this, all_fields) || thd->fatal_error)
+ DBUG_VOID_RETURN;
}
- if (group || order)
+ if (group_list || order)
{
DBUG_PRINT("info",("Sorting for send_fields"));
thd->proc_info="Sorting result";
/* If we have already done the group, add HAVING to sorted table */
- if (having && ! group && ! join.sort_and_group)
+ if (having_list && ! group_list && ! sort_and_group)
{
- having->update_used_tables(); // Some tables may have been const
- JOIN_TAB *table=&join.join_tab[join.const_tables];
- table_map used_tables= join.const_table_map | table->table->map;
+ having_list->update_used_tables(); // Some tables may have been const
+ JOIN_TAB *table= &join_tab[const_tables];
+ table_map used_tables= const_table_map | table->table->map;
- Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
+ Item* sort_table_cond= make_cond_for_table(having_list, used_tables,
+ used_tables);
if (sort_table_cond)
{
if (!table->select)
if (!(table->select=new SQL_SELECT))
- goto err;
+ DBUG_VOID_RETURN;
if (!table->select->cond)
table->select->cond=sort_table_cond;
else // This should never happen
if (!(table->select->cond=new Item_cond_and(table->select->cond,
sort_table_cond)))
- goto err;
+ DBUG_VOID_RETURN;
table->select_cond=table->select->cond;
DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having"););
- having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ having_list= make_cond_for_table(having_list, ~ (table_map) 0,
+ ~used_tables);
DBUG_EXECUTE("where",print_where(conds,"having after sort"););
}
}
- if (create_sort_index(&join.join_tab[join.const_tables],
- group ? group : order,
- (having || group ||
- join.const_tables != join.tables - 1 ||
- (join.select_options & OPTION_FOUND_ROWS)) ?
- HA_POS_ERROR : thd->select_limit))
- goto err; /* purecov: inspected */
+ if (create_sort_index(&join_tab[const_tables],
+ group_list ? group_list : order,
+ (having_list || group_list ||
+ const_tables != tables - 1 ||
+ (select_options & OPTION_FOUND_ROWS)) ?
+ HA_POS_ERROR : unit->select_limit_cnt))
+ DBUG_VOID_RETURN;
}
- join.having=having; // Actually a parameter
+ having=having_list; // Actually a parameter
thd->proc_info="Sending data";
- error=do_select(&join,&fields,NULL,procedure);
+ error=do_select(this, &fields_list, NULL, procedure);
+ DBUG_VOID_RETURN;
+}
-err:
- thd->limit_found_rows = join.send_records;
- thd->examined_row_count = join.examined_rows;
- thd->proc_info="end";
- join.lock=0; // It's faster to unlock later
- join_free(&join);
- thd->proc_info="end2"; // QQ
- if (tmp_table)
- free_tmp_table(thd,tmp_table);
- thd->proc_info="end3"; // QQ
+/*
+ Clean up join. Return error that hold JOIN.
+*/
+
+int
+JOIN::cleanup(THD *thd)
+{
+ lock=0; // It's faster to unlock later
+ join_free(this);
+ if (exec_tmp_table)
+ free_tmp_table(thd, exec_tmp_table);
delete select;
delete_dynamic(&keyuse);
delete procedure;
- thd->proc_info="end4"; // QQ
+ return error;
+}
+
+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)
+{
+ JOIN *join = new JOIN(thd, fields, select_options, result);
+
+ DBUG_ENTER("mysql_select");
+ thd->proc_info="init";
+ thd->used_tables=0; // Updated by setup_fields
+
+ if (join->prepare(tables, conds, order, group, having, proc_param,
+ &(thd->lex.select_lex), unit))
+ {
+ DBUG_RETURN(-1);
+ }
+ switch(join->optimize())
+ {
+ case 1:
+ DBUG_RETURN(join->error);
+ case -1:
+ goto err;
+ }
+
+ if(join->global_optimize())
+ goto err;
+
+ join->exec();
+
+err:
+ thd->limit_found_rows = join->send_records;
+ thd->examined_row_count = join->examined_rows;
+ thd->proc_info="end";
+ int error= join->cleanup(thd);
+ delete join;
DBUG_RETURN(error);
}
@@ -2480,7 +2596,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
if ((tab->keys & ~ tab->const_keys && i > 0) ||
(tab->const_keys && i == join->const_tables &&
- join->thd->select_limit < join->best_positions[i].records_read &&
+ join->unit->select_limit_cnt <
+ join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
/* Join with outer join condition */
@@ -2491,7 +2608,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(join->select_options &
OPTION_FOUND_ROWS ?
HA_POS_ERROR :
- join->thd->select_limit)) < 0)
+ join->unit->select_limit_cnt)) < 0)
DBUG_RETURN(1); // Impossible range
sel->cond=orig_cond;
}
@@ -2533,7 +2650,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
static void
-make_join_readinfo(JOIN *join,uint options)
+make_join_readinfo(JOIN *join, uint options)
{
uint i;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
@@ -2929,7 +3046,7 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order)
static int
return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
bool send_row, uint select_options,const char *info,
- Item *having, Procedure *procedure)
+ Item *having, Procedure *procedure, SELECT_LEX_UNIT *unit)
{
DBUG_ENTER("return_zero_rows");
@@ -2940,7 +3057,7 @@ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
}
if (procedure)
{
- if (result->prepare(fields)) // This hasn't been done yet
+ if (result->prepare(fields, unit)) // This hasn't been done yet
DBUG_RETURN(-1);
}
if (send_row)
@@ -3475,7 +3592,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, ulong select_options)
+ bool allow_distinct_limit, ulong select_options,
+ SELECT_LEX_UNIT *unit)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -3846,8 +3964,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
test(null_pack_length));
if (allow_distinct_limit)
{
- set_if_smaller(table->max_rows,thd->select_limit);
- param->end_write_records=thd->select_limit;
+ set_if_smaller(table->max_rows, unit->select_limit_cnt);
+ param->end_write_records= unit->select_limit_cnt;
}
else
param->end_write_records= HA_POS_ERROR;
@@ -4892,7 +5010,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
error=join->result->send_data(*join->fields);
if (error)
DBUG_RETURN(-1); /* purecov: inspected */
- if (++join->send_records >= join->thd->select_limit && join->do_send_rows)
+ if (++join->send_records >= join->unit->select_limit_cnt &&
+ join->do_send_rows)
{
if (join->select_options & OPTION_FOUND_ROWS)
{
@@ -4907,8 +5026,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
}
else
{
- join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->do_send_rows= 0;
+ join->unit->select_limit= HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -4969,13 +5088,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
DBUG_RETURN(-1); /* purecov: inspected */
if (end_of_records)
DBUG_RETURN(0);
- if (!error && ++join->send_records >= join->thd->select_limit &&
+ if (!error && ++join->send_records >= join->unit->select_limit_cnt &&
join->do_send_rows)
{
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3); // Abort nicely
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
}
}
}
@@ -5056,7 +5175,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
if (!(join->select_options & OPTION_FOUND_ROWS))
DBUG_RETURN(-3);
join->do_send_rows=0;
- join->thd->select_limit = HA_POS_ERROR;
+ join->unit->select_limit_cnt = HA_POS_ERROR;
DBUG_RETURN(0);
}
}
@@ -5755,7 +5874,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having)
if (!field_count)
{ // only const items
- join->thd->select_limit=1; // Only send first row
+ join->unit->select_limit_cnt= 1; // Only send first row
DBUG_RETURN(0);
}
Field **first_field=entry->field+entry->fields - field_count;
@@ -7156,7 +7275,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
result->send_error(0,NullS);
}
}
- if (!join->thd->lex.select->next)
+ if (!join->thd->lex.select->next_select())
{
save_lock=thd->lock;
thd->lock=(MYSQL_LOCK *)0;
diff --git a/sql/sql_select.cc.rej b/sql/sql_select.cc.rej
new file mode 100644
index 00000000000..e5be98e9859
--- /dev/null
+++ b/sql/sql_select.cc.rej
@@ -0,0 +1,1576 @@
+***************
+*** 65,71 ****
+ static int return_zero_rows(select_result *res,TABLE_LIST *tables,
+ List<Item> &fields, bool send_row,
+ uint select_options, const char *info,
+- Item *having, Procedure *proc);
+ static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
+ static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
+ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
+--- 65,72 ----
+ static int return_zero_rows(select_result *res,TABLE_LIST *tables,
+ List<Item> &fields, bool send_row,
+ uint select_options, const char *info,
++ Item *having, Procedure *proc,
++ SELECT_LEX *select_lex);
+ static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
+ static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
+ static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
+***************
+*** 180,228 ****
+ ** mysql_select assumes that all tables are already opened
+ *****************************************************************************/
+
+ 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)
+- {
+- TABLE *tmp_table;
+- int error, tmp_error;
+- bool need_tmp,hidden_group_fields;
+- bool simple_order,simple_group,no_order, skip_sort_order, buffer_result;
+- Item::cond_result cond_value;
+- SQL_SELECT *select;
+- DYNAMIC_ARRAY keyuse;
+- JOIN join;
+- Procedure *procedure;
+- List<Item> all_fields(fields);
+- bool select_distinct;
+- SELECT_LEX *select_lex = &(thd->lex.select_lex);
+- SELECT_LEX *cur_sel = thd->lex.select;
+- DBUG_ENTER("mysql_select");
+
+- /* Check that all tables, fields, conds and order are ok */
+
+- select_distinct=test(select_options & SELECT_DISTINCT);
+- buffer_result=test(select_options & OPTION_BUFFER_RESULT) && !test(select_options & OPTION_FOUND_ROWS);
+- tmp_table=0;
+- select=0;
+- no_order=skip_sort_order=0;
+- bzero((char*) &keyuse,sizeof(keyuse));
+- thd->proc_info="init";
+- thd->used_tables=0; // Updated by setup_fields
+
+- if (setup_tables(tables) ||
+- setup_fields(thd,tables,fields,1,&all_fields,1) ||
+- setup_conds(thd,tables,&conds) ||
+- setup_order(thd,tables,fields,all_fields,order) ||
+- setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
+ DBUG_RETURN(-1); /* purecov: inspected */
+
+ if (having)
+ {
+ thd->where="having clause";
+ thd->allow_sum_func=1;
+- if (having->fix_fields(thd,tables) || thd->fatal_error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (having->with_sum_func)
+ having->split_sum_func(all_fields);
+--- 195,237 ----
+ ** mysql_select assumes that all tables are already opened
+ *****************************************************************************/
+
++ /*
++ Prepare of whole select (including subselect in future).
++ return -1 on error
++ 0 on success
++ */
+ int
+
++ 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)
++ {
++ DBUG_ENTER("JOIN::prepare");
++
++ conds= conds_init;
++ order= order_init;
++ group_list= group_init;
++ having= having_init;
++ proc_param= proc_param_init;
++ tables_list= tables_init;
++ select_lex= select;
+
++ /* Check that all tables, fields, conds and order are ok */
+
++ if (setup_tables(tables_list) ||
++ setup_fields(thd,tables_list,fields_list,1,&all_fields,1) ||
++ setup_conds(thd,tables_list,&conds) ||
++ setup_order(thd,tables_list,fields_list,all_fields,order) ||
++ setup_group(thd,tables_list,fields_list,all_fields,group_list,
++ &hidden_group_fields))
+ DBUG_RETURN(-1); /* purecov: inspected */
+
+ if (having)
+ {
+ thd->where="having clause";
+ thd->allow_sum_func=1;
++ if (having->fix_fields(thd,tables_list) || thd->fatal_error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (having->with_sum_func)
+ having->split_sum_func(all_fields);
+***************
+*** 297,347 ****
+ }
+
+ /* Init join struct */
+- join.thd=thd;
+- join.lock=thd->lock;
+- join.join_tab=0;
+- join.tmp_table_param.copy_field=0;
+- join.sum_funcs=0;
+- join.send_records=join.found_records=join.examined_rows=0;
+- join.tmp_table_param.end_write_records= HA_POS_ERROR;
+- join.first_record=join.sort_and_group=0;
+- join.select_options=select_options;
+- join.result=result;
+- count_field_types(&join.tmp_table_param,all_fields,0);
+- join.const_tables=0;
+- join.having=0;
+- join.do_send_rows = 1;
+- join.group= group != 0;
+- join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR :
+- thd->select_limit);
+
+ #ifdef RESTRICTED_GROUP
+- if (join.sum_func_count && !group && (join.func_count || join.field_count))
+ {
+ my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
+ delete procedure;
+ DBUG_RETURN(-1);
+ }
+ #endif
+- if (!procedure && result->prepare(fields))
+ { /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
+
+ #ifdef HAVE_REF_TO_FIELDS // Not done yet
+ /* Add HAVING to WHERE if possible */
+- if (having && !group && ! join.sum_func_count)
+ {
+ if (!conds)
+ {
+- conds=having;
+- having=0;
+ }
+ else if ((conds=new Item_cond_and(conds,having)))
+ {
+- conds->fix_fields(thd,tables);
+- conds->change_ref_to_fields(thd,tables);
+- having=0;
+ }
+ }
+ #endif
+--- 305,358 ----
+ }
+
+ /* Init join struct */
++ count_field_types(&tmp_table_param, all_fields, 0);
++ this->group= group_list != 0;
++ row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
++ select_lex->first_in_union->select_limit_cnt);
+
+ #ifdef RESTRICTED_GROUP
++ if (sum_func_count && !group_list && (func_count || field_count))
+ {
+ my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
+ delete procedure;
+ DBUG_RETURN(-1);
+ }
+ #endif
++ if (!procedure && result->prepare(fields_list, select_lex->first_in_union))
+ { /* purecov: inspected */
+ DBUG_RETURN(-1); /* purecov: inspected */
+ }
++ DBUG_RETURN(0); // All OK
++ }
++
++ /*
++ global select optimisation.
++ return 0 - success
++ 1 - go out
++ -1 - go out with cleaning
++
++ error code saved in field 'error'
++ */
++ int
++ JOIN::optimize()
++ {
++ DBUG_ENTER("JOIN::optimize");
++ SELECT_LEX *select_lex = &(thd->lex.select_lex);
+
+ #ifdef HAVE_REF_TO_FIELDS // Not done yet
+ /* Add HAVING to WHERE if possible */
++ if (having && !group_list && ! sum_func_count)
+ {
+ if (!conds)
+ {
++ conds= having;
++ having= 0;
+ }
+ else if ((conds=new Item_cond_and(conds,having)))
+ {
++ conds->fix_fields(thd, tables_list);
++ conds->change_ref_to_fields(thd, tables_list);
++ having= 0;
+ }
+ }
+ #endif
+***************
+*** 350,459 ****
+ if (thd->fatal_error) // Out of memory
+ {
+ delete procedure;
+- DBUG_RETURN(0);
+ }
+- if (cond_value == Item::COND_FALSE || !thd->select_limit)
+ { /* Impossible cond */
+- if (select_options & SELECT_DESCRIBE && select_lex->next)
+- select_describe(&join,false,false,false,"Impossible WHERE");
+- else
+- error=return_zero_rows(result, tables, fields,
+- join.tmp_table_param.sum_func_count != 0 && !group,
+- select_options,"Impossible WHERE",having,
+- procedure);
+- delete procedure;
+- DBUG_RETURN(error);
+ }
+
+ /* Optimize count(*), min() and max() */
+- if (tables && join.tmp_table_param.sum_func_count && ! group)
+ {
+ int res;
+- if ((res=opt_sum_query(tables, all_fields, conds)))
+ {
+ if (res < 0)
+ {
+- if (select_options & SELECT_DESCRIBE && select_lex->next)
+- select_describe(&join,false,false,false,"No matching min/max row");
+- else
+- error=return_zero_rows(result, tables, fields, !group,
+- select_options,"No matching min/max row",
+- having,procedure);
+- delete procedure;
+- DBUG_RETURN(error);
+ }
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (select_lex->next)
+- select_describe(&join,false,false,false,"Select tables optimized away");
+ else
+- describe_info(thd,"Select tables optimized away");
+ delete procedure;
+- DBUG_RETURN(error);
+ }
+- tables=0; // All tables resolved
+ }
+ }
+- if (!tables)
+- { // Only test of functions
+- error=0;
+- if (select_options & SELECT_DESCRIBE)
+- {
+- if (select_lex->next)
+- select_describe(&join,false,false,false,"No tables used");
+- else
+- describe_info(thd,"No tables used");
+- }
+- else
+- {
+- result->send_fields(fields,1);
+- if (!having || having->val_int())
+- {
+- if (join.do_send_rows && result->send_data(fields))
+- {
+- result->send_error(0,NullS); /* purecov: inspected */
+- error=1;
+- }
+- else
+- error=(int) result->send_eof();
+- }
+- else
+- error=(int) result->send_eof();
+- }
+- delete procedure;
+- DBUG_RETURN(error);
+ }
+
+- error = -1;
+- join.sort_by_table=get_sort_by_table(order,group,tables);
+
+ /* Calculate how to do the join */
+- thd->proc_info="statistics";
+- if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error)
+- goto err;
+- thd->proc_info="preparing";
+- result->initialize_tables(&join);
+- if (join.const_table_map != join.found_const_table_map &&
+ !(select_options & SELECT_DESCRIBE))
+ {
+- error=return_zero_rows(result,tables,fields,
+- join.tmp_table_param.sum_func_count != 0 &&
+- !group,0,"",having,procedure);
+- goto err;
+ }
+ if (!(thd->options & OPTION_BIG_SELECTS) &&
+- join.best_read > (double) thd->max_join_size &&
+ !(select_options & SELECT_DESCRIBE))
+ { /* purecov: inspected */
+ result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
+ error= 1; /* purecov: inspected */
+- goto err; /* purecov: inspected */
+ }
+- if (join.const_tables && !thd->locked_tables &&
+ !(select_options & SELECT_NO_UNLOCK))
+ {
+ TABLE **table, **end;
+- for (table=join.table, end=table + join.const_tables ;
+ table != end;
+ table++)
+ {
+--- 361,436 ----
+ if (thd->fatal_error) // Out of memory
+ {
+ delete procedure;
++ error = 0;
++ DBUG_RETURN(1);
+ }
++ if (cond_value == Item::COND_FALSE ||
++ !select_lex->first_in_union->select_limit_cnt)
+ { /* Impossible cond */
++ zero_result_cause= "Impossible WHERE";
++ DBUG_RETURN(0);
+ }
+
+ /* Optimize count(*), min() and max() */
++ if (tables_list && tmp_table_param.sum_func_count && ! group_list)
+ {
+ int res;
++ if ((res=opt_sum_query(tables_list, all_fields, conds)))
+ {
+ if (res < 0)
+ {
++ zero_result_cause= "No matching min/max row";
++ DBUG_RETURN(0);
+ }
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (select_lex->next)
++ select_describe(this, false, false, false,
++ "Select tables optimized away");
+ else
++ describe_info(thd, "Select tables optimized away");
+ delete procedure;
++ DBUG_RETURN(1);
+ }
++ tables_list=0; // All tables resolved
+ }
+ }
++ if (!tables_list)
++ {
++ test_function_query= 1;
++ DBUG_RETURN(0);
+ }
+
++ error= -1;
++ sort_by_table= get_sort_by_table(order, group_list, tables_list);
+
+ /* Calculate how to do the join */
++ thd->proc_info= "statistics";
++ if (make_join_statistics(this, tables_list, conds, &keyuse) ||
++ thd->fatal_error)
++ DBUG_RETURN(-1);
++ thd->proc_info= "preparing";
++ result->initialize_tables(this);
++ if (const_table_map != found_const_table_map &&
+ !(select_options & SELECT_DESCRIBE))
+ {
++ zero_result_cause= "";
++ select_options= 0; //TODO why option in return_zero_rows was droped
++ DBUG_RETURN(0);
+ }
+ if (!(thd->options & OPTION_BIG_SELECTS) &&
++ best_read > (double) thd->max_join_size &&
+ !(select_options & SELECT_DESCRIBE))
+ { /* purecov: inspected */
+ result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
+ error= 1; /* purecov: inspected */
++ DBUG_RETURN(-1);
+ }
++ if (const_tables && !thd->locked_tables &&
+ !(select_options & SELECT_NO_UNLOCK))
+ {
+ TABLE **table, **end;
++ for (table=this->table, end=table + const_tables ;
+ table != end;
+ table++)
+ {
+***************
+*** 465,561 ****
+ }
+ (*table)->file->index_end();
+ }
+- mysql_unlock_some_tables(thd, join.table,join.const_tables);
+ }
+- if (!conds && join.outer_join)
+ {
+ /* Handle the case where we have an OUTER JOIN without a WHERE */
+ conds=new Item_int((longlong) 1,1); // Always true
+ }
+- select=make_select(*join.table, join.const_table_map,
+- join.const_table_map,conds,&error);
+ if (error)
+ { /* purecov: inspected */
+ error= -1; /* purecov: inspected */
+- goto err; /* purecov: inspected */
+ }
+- if (make_join_select(&join,select,conds))
+ {
+- if (select_options & SELECT_DESCRIBE && select_lex->next)
+- select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables");
+- else
+- error=return_zero_rows(result,tables,fields,
+- join.tmp_table_param.sum_func_count != 0 && !group,
+- select_options,
+- "Impossible WHERE noticed after reading const tables",
+- having,procedure);
+- goto err;
+ }
+
+ error= -1; /* if goto err */
+
+ /* Optimize distinct away if possible */
+- order=remove_const(&join,order,conds,&simple_order);
+- if (group || join.tmp_table_param.sum_func_count)
+ {
+ if (! hidden_group_fields)
+ select_distinct=0;
+ }
+- else if (select_distinct && join.tables - join.const_tables == 1 &&
+- (thd->select_limit == HA_POS_ERROR ||
+- (join.select_options & OPTION_FOUND_ROWS) ||
+ order &&
+ !(skip_sort_order=
+- test_if_skip_sort_order(&join.join_tab[join.const_tables],
+- order, thd->select_limit,1))))
+ {
+- if ((group=create_distinct_group(order,fields)))
+ {
+ select_distinct=0;
+ no_order= !order;
+- join.group=1; // For end_write_group
+ }
+ else if (thd->fatal_error) // End of memory
+- goto err;
+ }
+- group=remove_const(&join,group,conds,&simple_group);
+- if (!group && join.group)
+ {
+ order=0; // The output has only one row
+ simple_order=1;
+ }
+
+- calc_group_buffer(&join,group);
+- join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */
+ if (procedure && procedure->group)
+ {
+- group=procedure->group=remove_const(&join,procedure->group,conds,
+- &simple_group);
+- calc_group_buffer(&join,group);
+ }
+
+- if (test_if_subpart(group,order) ||
+- (!group && join.tmp_table_param.sum_func_count))
+ order=0;
+
+ // Can't use sort on head table if using row cache
+- if (join.full_join)
+ {
+- if (group)
+ simple_group=0;
+ if (order)
+ simple_order=0;
+ }
+
+- need_tmp= (join.const_tables != join.tables &&
+ ((select_distinct || !simple_order || !simple_group) ||
+- (group && order) || buffer_result));
+
+ // No cache for MATCH
+- make_join_readinfo(&join,
+ (select_options & (SELECT_DESCRIBE |
+ SELECT_NO_JOIN_CACHE)) |
+- (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : 0));
+
+ /* Need to tell Innobase that to play it safe, it should fetch all
+ columns of the tables: this is because MySQL
+--- 442,535 ----
+ }
+ (*table)->file->index_end();
+ }
++ mysql_unlock_some_tables(thd, this->table, const_tables);
+ }
++ if (!conds && outer_join)
+ {
+ /* Handle the case where we have an OUTER JOIN without a WHERE */
+ conds=new Item_int((longlong) 1,1); // Always true
+ }
++ select=make_select(*table, const_table_map,
++ const_table_map, conds, &error);
+ if (error)
+ { /* purecov: inspected */
+ error= -1; /* purecov: inspected */
++ DBUG_RETURN(-1);
+ }
++ if (make_join_select(this, select, conds))
+ {
++ zero_result_cause=
++ "Impossible WHERE noticed after reading const tables";
++ DBUG_RETURN(0);
+ }
+
+ error= -1; /* if goto err */
+
+ /* Optimize distinct away if possible */
++ order=remove_const(this,order,conds,&simple_order);
++ if (group_list || tmp_table_param.sum_func_count)
+ {
+ if (! hidden_group_fields)
+ select_distinct=0;
+ }
++ else if (select_distinct && tables - const_tables == 1 &&
++ (select_lex->first_in_union->select_limit_cnt == HA_POS_ERROR ||
++ (select_options & OPTION_FOUND_ROWS) ||
+ order &&
+ !(skip_sort_order=
++ test_if_skip_sort_order(&join_tab[const_tables],
++ order,
++ select_lex->first_in_union->select_limit_cnt,
++ 1))))
+ {
++ if ((group_list=create_distinct_group(order, fields_list)))
+ {
+ select_distinct=0;
+ no_order= !order;
++ group=1; // For end_write_group
+ }
+ else if (thd->fatal_error) // End of memory
++ DBUG_RETURN(-1);
+ }
++ group_list= remove_const(this, group_list, conds, &simple_group);
++ if (!group_list && group)
+ {
+ order=0; // The output has only one row
+ simple_order=1;
+ }
+
++ calc_group_buffer(this, group_list);
++ send_group_parts=tmp_table_param.group_parts; /* Save org parts */
+ if (procedure && procedure->group)
+ {
++ group_list= procedure->group= remove_const(this, procedure->group, conds,
++ &simple_group);
++ calc_group_buffer(this, group_list);
+ }
+
++ if (test_if_subpart(group_list, order) ||
++ (!group_list && tmp_table_param.sum_func_count))
+ order=0;
+
+ // Can't use sort on head table if using row cache
++ if (full_join)
+ {
++ if (group_list)
+ simple_group=0;
+ if (order)
+ simple_order=0;
+ }
+
++ need_tmp= (const_tables != tables &&
+ ((select_distinct || !simple_order || !simple_group) ||
++ (group_list && order) || buffer_result));
+
+ // No cache for MATCH
++ make_join_readinfo(this,
+ (select_options & (SELECT_DESCRIBE |
+ SELECT_NO_JOIN_CACHE)) |
++ (thd->lex.select->ftfunc_list.elements ?
++ SELECT_NO_JOIN_CACHE : 0));
+
+ /* Need to tell Innobase that to play it safe, it should fetch all
+ columns of the tables: this is because MySQL
+***************
+*** 564,624 ****
+ by MySQL. */
+
+ #ifdef HAVE_INNOBASE_DB
+- if (need_tmp || select_distinct || group || order)
+ {
+- for (uint i_h = join.const_tables; i_h < join.tables; i_h++)
+ {
+- TABLE* table_h = join.join_tab[i_h].table;
+ if (table_h->db_type == DB_TYPE_INNODB)
+ table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
+ }
+ }
+ #endif
+
+- DBUG_EXECUTE("info",TEST_join(&join););
+ /*
+ Because filesort always does a full table scan or a quick range scan
+ we must add the removed reference to the select for the table.
+ We only need to do this when we have a simple_order or simple_group
+ as in other cases the join is done before the sort.
+ */
+- if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL &&
+- join.join_tab[join.const_tables].type != JT_FT &&
+- (order && simple_order || group && simple_group))
+ {
+- if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables]))
+- goto err;
+ }
+
+ if (!(select_options & SELECT_BIG_RESULT) &&
+- ((group && join.const_tables != join.tables &&
+ (!simple_group ||
+- !test_if_skip_sort_order(&join.join_tab[join.const_tables], group,
+- thd->select_limit,0))) ||
+ select_distinct) &&
+- join.tmp_table_param.quick_group && !procedure)
+ {
+ need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
+ }
+
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (!order && !no_order)
+- order=group;
+ if (order &&
+- (join.const_tables == join.tables ||
+ (simple_order &&
+- test_if_skip_sort_order(&join.join_tab[join.const_tables], order,
+- (join.const_tables != join.tables - 1 ||
+- (join.select_options & OPTION_FOUND_ROWS)) ?
+- HA_POS_ERROR : thd->select_limit,0))))
+ order=0;
+- select_describe(&join,need_tmp,
+ (order != 0 &&
+- (!need_tmp || order != group || simple_group)),
+ select_distinct);
+ error=0;
+- goto err;
+ }
+
+ /* Perform FULLTEXT search before all regular searches */
+--- 538,672 ----
+ by MySQL. */
+
+ #ifdef HAVE_INNOBASE_DB
++ if (need_tmp || select_distinct || group_list || order)
+ {
++ for (uint i_h = const_tables; i_h < tables; i_h++)
+ {
++ TABLE* table_h = join_tab[i_h].table;
+ if (table_h->db_type == DB_TYPE_INNODB)
+ table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
+ }
+ }
+ #endif
+
++ DBUG_EXECUTE("info",TEST_join(this););
+ /*
+ Because filesort always does a full table scan or a quick range scan
+ we must add the removed reference to the select for the table.
+ We only need to do this when we have a simple_order or simple_group
+ as in other cases the join is done before the sort.
+ */
++ if ((order || group_list) && join_tab[const_tables].type != JT_ALL &&
++ join_tab[const_tables].type != JT_FT &&
++ (order && simple_order || group_list && simple_group))
+ {
++ if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
++ DBUG_RETURN(-1);
+ }
+
+ if (!(select_options & SELECT_BIG_RESULT) &&
++ ((group_list && const_tables != tables &&
+ (!simple_group ||
++ !test_if_skip_sort_order(&join_tab[const_tables], group_list,
++ select_lex->first_in_union->select_limit_cnt,
++ 0))) ||
+ select_distinct) &&
++ tmp_table_param.quick_group && !procedure)
+ {
+ need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort
+ }
++ DBUG_RETURN(0);
++ }
++
++ /*
++ global uptimisation (with subselect) must be here (TODO)
++ */
++
++ int
++ JOIN::global_optimize()
++ {
++ return 0;
++ }
++
++ /*
++ exec select
++ */
++
++ void
++ JOIN::exec()
++ {
++ int tmp_error;
++
++ DBUG_ENTER("JOIN::exec");
++
++ if (test_function_query)
++ { // Only test of functions
++ error=0;
++ if (select_options & SELECT_DESCRIBE)
++ {
++ if (select_lex->next)
++ select_describe(this, false, false, false, "No tables used");
++ else
++ describe_info(thd, "No tables used");
++ }
++ else
++ {
++ result->send_fields(fields_list,1);
++ if (!having || having->val_int())
++ {
++ if (do_send_rows && result->send_data(fields_list))
++ {
++ result->send_error(0,NullS); /* purecov: inspected */
++ error=1;
++ }
++ else
++ error=(int) result->send_eof();
++ }
++ else
++ error=(int) result->send_eof();
++ }
++ delete procedure;
++ DBUG_VOID_RETURN;
++ }
++
++ if (zero_result_cause)
++ {
++ if (select_options & SELECT_DESCRIBE && select_lex->next)
++ select_describe(this, false, false, false, zero_result_cause);
++ else
++ error=return_zero_rows(result, tables_list, fields_list,
++ tmp_table_param.sum_func_count != 0 &&
++ !group_list,
++ select_options,
++ zero_result_cause,
++ having,procedure,
++ select_lex->first_in_union);
++ DBUG_VOID_RETURN;
++ }
++
++ Item *having_list = having;
++ having = 0;
+
+ if (select_options & SELECT_DESCRIBE)
+ {
+ if (!order && !no_order)
++ order=group_list;
+ if (order &&
++ (const_tables == tables ||
+ (simple_order &&
++ test_if_skip_sort_order(&join_tab[const_tables], order,
++ (const_tables != tables - 1 ||
++ (select_options & OPTION_FOUND_ROWS)) ?
++ HA_POS_ERROR :
++ select_lex->first_in_union->select_limit_cnt,
++ 0))))
+ order=0;
++ select_describe(this, need_tmp,
+ (order != 0 &&
++ (!need_tmp || order != group_list || simple_group)),
+ select_distinct);
+ error=0;
++ DBUG_VOID_RETURN;
+ }
+
+ /* Perform FULLTEXT search before all regular searches */
+***************
+*** 630,673 ****
+ DBUG_PRINT("info",("Creating tmp table"));
+ thd->proc_info="Creating tmp table";
+
+- if (!(tmp_table =
+- create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ ((!simple_group && !procedure &&
+ !(test_flags & TEST_NO_KEY_GROUP)) ?
+- group : (ORDER*) 0),
+- group ? 0 : select_distinct,
+- group && simple_group,
+ (order == 0 || skip_sort_order) &&
+- !(join.select_options & OPTION_FOUND_ROWS),
+- join.select_options)))
+- goto err; /* purecov: inspected */
+-
+- if (having && (join.sort_and_group || (tmp_table->distinct && !group)))
+- join.having=having;
+
+ /* if group or order on first table, sort first */
+- if (group && simple_group)
+ {
+ DBUG_PRINT("info",("Sorting for group"));
+ thd->proc_info="Sorting for group";
+- if (create_sort_index(&join.join_tab[join.const_tables],group,
+ HA_POS_ERROR) ||
+- make_sum_func_list(&join,all_fields) ||
+- alloc_group_fields(&join,group))
+- goto err;
+- group=0;
+ }
+ else
+ {
+- if (make_sum_func_list(&join,all_fields))
+- goto err;
+- if (!group && ! tmp_table->distinct && order && simple_order)
+ {
+ DBUG_PRINT("info",("Sorting for order"));
+ thd->proc_info="Sorting for order";
+- if (create_sort_index(&join.join_tab[join.const_tables],order,
+ HA_POS_ERROR))
+- goto err; /* purecov: inspected */
+ order=0;
+ }
+ }
+--- 678,722 ----
+ DBUG_PRINT("info",("Creating tmp table"));
+ thd->proc_info="Creating tmp table";
+
++ if (!(exec_tmp_table =
++ create_tmp_table(thd,&tmp_table_param,all_fields,
+ ((!simple_group && !procedure &&
+ !(test_flags & TEST_NO_KEY_GROUP)) ?
++ group_list : (ORDER*) 0),
++ group_list ? 0 : select_distinct,
++ group_list && simple_group,
+ (order == 0 || skip_sort_order) &&
++ !(select_options & OPTION_FOUND_ROWS),
++ select_options, select_lex->first_in_union)))
++ DBUG_VOID_RETURN;
++
++ if (having_list &&
++ (sort_and_group || (exec_tmp_table->distinct && !group_list)))
++ having=having_list;
+
+ /* if group or order on first table, sort first */
++ if (group_list && simple_group)
+ {
+ DBUG_PRINT("info",("Sorting for group"));
+ thd->proc_info="Sorting for group";
++ if (create_sort_index(&join_tab[const_tables],group_list,
+ HA_POS_ERROR) ||
++ make_sum_func_list(this, all_fields) ||
++ alloc_group_fields(this, group_list))
++ DBUG_VOID_RETURN;
++ group_list=0;
+ }
+ else
+ {
++ if (make_sum_func_list(this, all_fields))
++ DBUG_VOID_RETURN;
++ if (!group_list && ! exec_tmp_table->distinct && order && simple_order)
+ {
+ DBUG_PRINT("info",("Sorting for order"));
+ thd->proc_info="Sorting for order";
++ if (create_sort_index(&join_tab[const_tables], order,
+ HA_POS_ERROR))
++ DBUG_VOID_RETURN;
+ order=0;
+ }
+ }
+***************
+*** 678,735 ****
+ In this case we can stop scanning t2 when we have found one t1.a
+ */
+
+- if (tmp_table->distinct)
+ {
+ table_map used_tables= thd->used_tables;
+- JOIN_TAB *join_tab=join.join_tab+join.tables-1;
+ do
+ {
+ if (used_tables & join_tab->table->map)
+ break;
+ join_tab->not_used_in_distinct=1;
+- } while (join_tab-- != join.join_tab);
+ /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
+ if (order && skip_sort_order)
+ {
+- (void) test_if_skip_sort_order(&join.join_tab[join.const_tables],
+- order, thd->select_limit,0);
+ order=0;
+ }
+ }
+
+ /* Copy data to the temporary table */
+ thd->proc_info="Copying to tmp table";
+- if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0)))
+ {
+- error=tmp_error;
+- goto err; /* purecov: inspected */
+ }
+- if (join.having)
+- join.having=having=0; // Allready done
+
+ /* Change sum_fields reference to calculated fields in tmp_table */
+- if (join.sort_and_group || tmp_table->group)
+ {
+ if (change_to_use_tmp_fields(all_fields))
+- goto err;
+- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+
+- join.tmp_table_param.func_count;
+- join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0;
+ }
+ else
+ {
+ if (change_refs_to_tmp_fields(thd,all_fields))
+- goto err;
+- join.tmp_table_param.field_count+=join.tmp_table_param.func_count;
+- join.tmp_table_param.func_count=0;
+ }
+ if (procedure)
+ procedure->update_refs();
+- if (tmp_table->group)
+ { // Already grouped
+ if (!order && !no_order)
+- order=group; /* order by group */
+- group=0;
+ }
+
+ /*
+--- 727,786 ----
+ In this case we can stop scanning t2 when we have found one t1.a
+ */
+
++ if (exec_tmp_table->distinct)
+ {
+ table_map used_tables= thd->used_tables;
++ JOIN_TAB *join_tab= this->join_tab+tables-1;
+ do
+ {
+ if (used_tables & join_tab->table->map)
+ break;
+ join_tab->not_used_in_distinct=1;
++ } while (join_tab-- != this->join_tab);
+ /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
+ if (order && skip_sort_order)
+ {
++ (void) test_if_skip_sort_order(&this->join_tab[const_tables],
++ order,
++ select_lex->first_in_union->select_limit_cnt,
++ 0);
+ order=0;
+ }
+ }
+
+ /* Copy data to the temporary table */
+ thd->proc_info="Copying to tmp table";
++ if ((tmp_error=do_select(this, (List<Item> *) 0, exec_tmp_table, 0)))
+ {
++ error= tmp_error;
++ DBUG_VOID_RETURN;
+ }
++ if (having)
++ having= having_list= 0; // Allready done
+
+ /* Change sum_fields reference to calculated fields in tmp_table */
++ if (sort_and_group || exec_tmp_table->group)
+ {
+ if (change_to_use_tmp_fields(all_fields))
++ DBUG_VOID_RETURN;
++ tmp_table_param.field_count+= tmp_table_param.sum_func_count+
++ tmp_table_param.func_count;
++ tmp_table_param.sum_func_count= tmp_table_param.func_count= 0;
+ }
+ else
+ {
+ if (change_refs_to_tmp_fields(thd,all_fields))
++ DBUG_VOID_RETURN;
++ tmp_table_param.field_count+= tmp_table_param.func_count;
++ tmp_table_param.func_count= 0;
+ }
+ if (procedure)
+ procedure->update_refs();
++ if (exec_tmp_table->group)
+ { // Already grouped
+ if (!order && !no_order)
++ order= group_list; /* order by group */
++ group_list= 0;
+ }
+
+ /*
+***************
+*** 740,892 ****
+ ** like SEC_TO_TIME(SUM(...)).
+ */
+
+- if (group && (!test_if_subpart(group,order) || select_distinct) ||
+ (select_distinct &&
+- join.tmp_table_param.using_indirect_summary_function))
+ { /* Must copy to another table */
+ TABLE *tmp_table2;
+ DBUG_PRINT("info",("Creating group table"));
+
+ /* Free first data from old join */
+- join_free(&join);
+- if (make_simple_join(&join,tmp_table))
+- goto err;
+- calc_group_buffer(&join,group);
+- count_field_types(&join.tmp_table_param,all_fields,
+- select_distinct && !group);
+- join.tmp_table_param.hidden_field_count=(all_fields.elements-
+- fields.elements);
+
+ /* group data to new table */
+- if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields,
+ (ORDER*) 0,
+- select_distinct && !group,
+ 1, 0,
+- join.select_options)))
+- goto err; /* purecov: inspected */
+- if (group)
+ {
+ thd->proc_info="Creating sort index";
+- if (create_sort_index(join.join_tab,group,HA_POS_ERROR) ||
+- alloc_group_fields(&join,group))
+ {
+ free_tmp_table(thd,tmp_table2); /* purecov: inspected */
+- goto err; /* purecov: inspected */
+ }
+- group=0;
+ }
+ thd->proc_info="Copying to group table";
+ tmp_error= -1;
+- if (make_sum_func_list(&join,all_fields) ||
+- (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0)))
+ {
+ error=tmp_error;
+ free_tmp_table(thd,tmp_table2);
+- goto err; /* purecov: inspected */
+ }
+- end_read_record(&join.join_tab->read_record);
+- free_tmp_table(thd,tmp_table);
+- join.const_tables=join.tables; // Mark free for join_free()
+- tmp_table=tmp_table2;
+- join.join_tab[0].table=0; // Table is freed
+
+ if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
+- goto err;
+- join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count;
+- join.tmp_table_param.sum_func_count=0;
+ }
+
+- if (tmp_table->distinct)
+ select_distinct=0; /* Each row is unique */
+
+- join_free(&join); /* Free quick selects */
+- if (select_distinct && ! group)
+ {
+ thd->proc_info="Removing duplicates";
+- if (having)
+- having->update_used_tables();
+- if (remove_duplicates(&join,tmp_table,fields, having))
+- goto err; /* purecov: inspected */
+- having=0;
+ select_distinct=0;
+ }
+- tmp_table->reginfo.lock_type=TL_UNLOCK;
+- if (make_simple_join(&join,tmp_table))
+- goto err;
+- calc_group_buffer(&join,group);
+- count_field_types(&join.tmp_table_param,all_fields,0);
+ }
+ if (procedure)
+ {
+- if (procedure->change_columns(fields) ||
+- result->prepare(fields))
+- goto err;
+- count_field_types(&join.tmp_table_param,all_fields,0);
+ }
+- if (join.group || join.tmp_table_param.sum_func_count ||
+ (procedure && (procedure->flags & PROC_GROUP)))
+ {
+- alloc_group_fields(&join,group);
+- setup_copy_fields(thd, &join.tmp_table_param,all_fields);
+- if (make_sum_func_list(&join,all_fields) || thd->fatal_error)
+- goto err; /* purecov: inspected */
+ }
+- if (group || order)
+ {
+ DBUG_PRINT("info",("Sorting for send_fields"));
+ thd->proc_info="Sorting result";
+ /* If we have already done the group, add HAVING to sorted table */
+- if (having && ! group && ! join.sort_and_group)
+ {
+- having->update_used_tables(); // Some tables may have been const
+- JOIN_TAB *table=&join.join_tab[join.const_tables];
+- table_map used_tables= join.const_table_map | table->table->map;
+
+- Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables);
+ if (sort_table_cond)
+ {
+ if (!table->select)
+ if (!(table->select=new SQL_SELECT))
+- goto err;
+ if (!table->select->cond)
+ table->select->cond=sort_table_cond;
+ else // This should never happen
+ if (!(table->select->cond=new Item_cond_and(table->select->cond,
+ sort_table_cond)))
+- goto err;
+ table->select_cond=table->select->cond;
+ DBUG_EXECUTE("where",print_where(table->select->cond,
+ "select and having"););
+- having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
+ DBUG_EXECUTE("where",print_where(conds,"having after sort"););
+ }
+ }
+- if (create_sort_index(&join.join_tab[join.const_tables],
+- group ? group : order,
+- (having || group ||
+- join.const_tables != join.tables - 1 ||
+- (join.select_options & OPTION_FOUND_ROWS)) ?
+- HA_POS_ERROR : thd->select_limit))
+- goto err; /* purecov: inspected */
+ }
+- join.having=having; // Actually a parameter
+ thd->proc_info="Sending data";
+- error=do_select(&join,&fields,NULL,procedure);
+
+- err:
+- thd->limit_found_rows = join.send_records;
+- thd->examined_row_count = join.examined_rows;
+- thd->proc_info="end";
+- join.lock=0; // It's faster to unlock later
+- join_free(&join);
+- thd->proc_info="end2"; // QQ
+- if (tmp_table)
+- free_tmp_table(thd,tmp_table);
+- thd->proc_info="end3"; // QQ
+ delete select;
+ delete_dynamic(&keyuse);
+ delete procedure;
+- thd->proc_info="end4"; // QQ
+ DBUG_RETURN(error);
+ }
+
+--- 791,987 ----
+ ** like SEC_TO_TIME(SUM(...)).
+ */
+
++ if (group_list && (!test_if_subpart(group_list,order) || select_distinct) ||
+ (select_distinct &&
++ tmp_table_param.using_indirect_summary_function))
+ { /* Must copy to another table */
+ TABLE *tmp_table2;
+ DBUG_PRINT("info",("Creating group table"));
+
+ /* Free first data from old join */
++ join_free(this);
++ if (make_simple_join(this, exec_tmp_table))
++ DBUG_VOID_RETURN;
++ calc_group_buffer(this, group_list);
++ count_field_types(&tmp_table_param, all_fields,
++ select_distinct && !group_list);
++ tmp_table_param.hidden_field_count= (all_fields.elements-
++ fields_list.elements);
+
+ /* group data to new table */
++ if (!(tmp_table2 = create_tmp_table(thd,&tmp_table_param, all_fields,
+ (ORDER*) 0,
++ select_distinct && !group_list,
+ 1, 0,
++ select_options,
++ select_lex->first_in_union)))
++ DBUG_VOID_RETURN;
++ if (group_list)
+ {
+ thd->proc_info="Creating sort index";
++ if (create_sort_index(join_tab,group_list,HA_POS_ERROR) ||
++ alloc_group_fields(this, group_list))
+ {
+ free_tmp_table(thd,tmp_table2); /* purecov: inspected */
++ DBUG_VOID_RETURN;
+ }
++ group_list=0;
+ }
+ thd->proc_info="Copying to group table";
+ tmp_error= -1;
++ if (make_sum_func_list(this, all_fields) ||
++ (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0)))
+ {
+ error=tmp_error;
+ free_tmp_table(thd,tmp_table2);
++ DBUG_VOID_RETURN;
+ }
++ end_read_record(&join_tab->read_record);
++ free_tmp_table(thd,exec_tmp_table);
++ const_tables= tables; // Mark free for join_free()
++ exec_tmp_table= tmp_table2;
++ join_tab[0].table= 0; // Table is freed
+
+ if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
++ DBUG_VOID_RETURN;
++ tmp_table_param.field_count+= tmp_table_param.sum_func_count;
++ tmp_table_param.sum_func_count=0;
+ }
+
++ if (exec_tmp_table->distinct)
+ select_distinct=0; /* Each row is unique */
+
++ join_free(this); /* Free quick selects */
++ if (select_distinct && ! group_list)
+ {
+ thd->proc_info="Removing duplicates";
++ if (having_list)
++ having_list->update_used_tables();
++ if (remove_duplicates(this, exec_tmp_table, fields_list, having_list))
++ DBUG_VOID_RETURN;
++ having_list=0;
+ select_distinct=0;
+ }
++ exec_tmp_table->reginfo.lock_type=TL_UNLOCK;
++ if (make_simple_join(this, exec_tmp_table))
++ DBUG_VOID_RETURN;
++ calc_group_buffer(this, group_list);
++ count_field_types(&tmp_table_param, all_fields, 0);
+ }
+ if (procedure)
+ {
++ if (procedure->change_columns(fields_list) ||
++ result->prepare(fields_list, select_lex->first_in_union))
++ DBUG_VOID_RETURN;
++ count_field_types(&tmp_table_param,all_fields,0);
+ }
++ if (group || tmp_table_param.sum_func_count ||
+ (procedure && (procedure->flags & PROC_GROUP)))
+ {
++ alloc_group_fields(this, group_list);
++ setup_copy_fields(thd, &tmp_table_param,all_fields);
++ if (make_sum_func_list(this, all_fields) || thd->fatal_error)
++ DBUG_VOID_RETURN;
+ }
++ if (group_list || order)
+ {
+ DBUG_PRINT("info",("Sorting for send_fields"));
+ thd->proc_info="Sorting result";
+ /* If we have already done the group, add HAVING to sorted table */
++ if (having_list && ! group_list && ! sort_and_group)
+ {
++ having_list->update_used_tables(); // Some tables may have been const
++ JOIN_TAB *table=&join_tab[const_tables];
++ table_map used_tables= const_table_map | table->table->map;
+
++ Item* sort_table_cond=make_cond_for_table(having_list, used_tables,
++ used_tables);
+ if (sort_table_cond)
+ {
+ if (!table->select)
+ if (!(table->select=new SQL_SELECT))
++ DBUG_VOID_RETURN;
+ if (!table->select->cond)
+ table->select->cond=sort_table_cond;
+ else // This should never happen
+ if (!(table->select->cond=new Item_cond_and(table->select->cond,
+ sort_table_cond)))
++ DBUG_VOID_RETURN;
+ table->select_cond=table->select->cond;
+ DBUG_EXECUTE("where",print_where(table->select->cond,
+ "select and having"););
++ having_list= make_cond_for_table(having_list, ~ (table_map) 0,
++ ~used_tables);
+ DBUG_EXECUTE("where",print_where(conds,"having after sort"););
+ }
+ }
++ if (create_sort_index(&join_tab[const_tables],
++ group_list ? group_list : order,
++ (having_list || group_list ||
++ const_tables != tables - 1 ||
++ (select_options & OPTION_FOUND_ROWS)) ?
++ HA_POS_ERROR :
++ select_lex->first_in_union->select_limit_cnt))
++ DBUG_VOID_RETURN;
+ }
++ having=having_list; // Actually a parameter
+ thd->proc_info="Sending data";
++ error=do_select(this, &fields_list, NULL, procedure);
++ DBUG_VOID_RETURN;
++ }
+
++ /*
++ Clean up join. Return error that hold JOIN.
++ */
++
++ int
++ JOIN::cleanup(THD *thd)
++ {
++ lock=0; // It's faster to unlock later
++ join_free(this);
++ if (exec_tmp_table)
++ free_tmp_table(thd, exec_tmp_table);
+ delete select;
+ delete_dynamic(&keyuse);
+ delete procedure;
++ return error;
++ }
++
++ 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)
++ {
++ JOIN *join = new JOIN(thd, fields, select_options, result);
++
++ DBUG_ENTER("mysql_select");
++ thd->proc_info="init";
++ thd->used_tables=0; // Updated by setup_fields
++
++ if (join->prepare(tables, conds, order, group, having, proc_param,
++ &(thd->lex.select_lex)))
++ {
++ DBUG_RETURN(-1);
++ }
++ switch(join->optimize())
++ {
++ case 1:
++ DBUG_RETURN(join->error);
++ case -1:
++ goto err;
++ }
++
++ if(join->global_optimize())
++ goto err;
++
++ join->exec();
++
++ err:
++ thd->limit_found_rows = join->send_records;
++ thd->examined_row_count = join->examined_rows;
++ thd->proc_info="end";
++ int error= join->cleanup(thd);
++ delete join;
+ DBUG_RETURN(error);
+ }
+
+***************
+*** 2480,2486 ****
+
+ if ((tab->keys & ~ tab->const_keys && i > 0) ||
+ (tab->const_keys && i == join->const_tables &&
+- join->thd->select_limit < join->best_positions[i].records_read &&
+ !(join->select_options & OPTION_FOUND_ROWS)))
+ {
+ /* Join with outer join condition */
+--- 2575,2582 ----
+
+ if ((tab->keys & ~ tab->const_keys && i > 0) ||
+ (tab->const_keys && i == join->const_tables &&
++ join->select_lex->first_in_union->select_limit_cnt <
++ join->best_positions[i].records_read &&
+ !(join->select_options & OPTION_FOUND_ROWS)))
+ {
+ /* Join with outer join condition */
+***************
+*** 2491,2497 ****
+ (join->select_options &
+ OPTION_FOUND_ROWS ?
+ HA_POS_ERROR :
+- join->thd->select_limit)) < 0)
+ DBUG_RETURN(1); // Impossible range
+ sel->cond=orig_cond;
+ }
+--- 2587,2593 ----
+ (join->select_options &
+ OPTION_FOUND_ROWS ?
+ HA_POS_ERROR :
++ join->select_lex->first_in_union->select_limit_cnt)) < 0)
+ DBUG_RETURN(1); // Impossible range
+ sel->cond=orig_cond;
+ }
+***************
+*** 2933,2939 ****
+ static int
+ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
+ bool send_row, uint select_options,const char *info,
+- Item *having, Procedure *procedure)
+ {
+ DBUG_ENTER("return_zero_rows");
+
+--- 3029,3035 ----
+ static int
+ return_zero_rows(select_result *result,TABLE_LIST *tables,List<Item> &fields,
+ bool send_row, uint select_options,const char *info,
++ Item *having, Procedure *procedure, SELECT_LEX *select_lex)
+ {
+ DBUG_ENTER("return_zero_rows");
+
+***************
+*** 2944,2950 ****
+ }
+ if (procedure)
+ {
+- if (result->prepare(fields)) // This hasn't been done yet
+ DBUG_RETURN(-1);
+ }
+ if (send_row)
+--- 3040,3047 ----
+ }
+ if (procedure)
+ {
++ if (result->prepare(fields,
++ select_lex->first_in_union))//This hasn't been done yet
+ DBUG_RETURN(-1);
+ }
+ if (send_row)
+***************
+*** 3479,3485 ****
+ TABLE *
+ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
+- bool allow_distinct_limit, ulong select_options)
+ {
+ TABLE *table;
+ uint i,field_count,reclength,null_count,null_pack_length,
+--- 3576,3583 ----
+ TABLE *
+ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
++ bool allow_distinct_limit, ulong select_options,
++ SELECT_LEX *first_select)
+ {
+ TABLE *table;
+ uint i,field_count,reclength,null_count,null_pack_length,
+***************
+*** 3850,3857 ****
+ test(null_pack_length));
+ if (allow_distinct_limit)
+ {
+- set_if_smaller(table->max_rows,thd->select_limit);
+- param->end_write_records=thd->select_limit;
+ }
+ else
+ param->end_write_records= HA_POS_ERROR;
+--- 3948,3955 ----
+ test(null_pack_length));
+ if (allow_distinct_limit)
+ {
++ set_if_smaller(table->max_rows,first_select->select_limit_cnt);
++ param->end_write_records=first_select->select_limit_cnt;
+ }
+ else
+ param->end_write_records= HA_POS_ERROR;
+***************
+*** 4896,4902 ****
+ error=join->result->send_data(*join->fields);
+ if (error)
+ DBUG_RETURN(-1); /* purecov: inspected */
+- if (++join->send_records >= join->thd->select_limit && join->do_send_rows)
+ {
+ if (join->select_options & OPTION_FOUND_ROWS)
+ {
+--- 4994,5002 ----
+ error=join->result->send_data(*join->fields);
+ if (error)
+ DBUG_RETURN(-1); /* purecov: inspected */
++ if (++join->send_records >=
++ join->select_lex->first_in_union->select_limit_cnt &&
++ join->do_send_rows)
+ {
+ if (join->select_options & OPTION_FOUND_ROWS)
+ {
+***************
+*** 4912,4918 ****
+ else
+ {
+ join->do_send_rows=0;
+- join->thd->select_limit = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
+ }
+--- 5012,5018 ----
+ else
+ {
+ join->do_send_rows=0;
++ join->select_lex->first_in_union->select_limit_cnt = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
+ }
+***************
+*** 4973,4985 ****
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (end_of_records)
+ DBUG_RETURN(0);
+- if (!error && ++join->send_records >= join->thd->select_limit &&
+ join->do_send_rows)
+ {
+ if (!(join->select_options & OPTION_FOUND_ROWS))
+ DBUG_RETURN(-3); // Abort nicely
+ join->do_send_rows=0;
+- join->thd->select_limit = HA_POS_ERROR;
+ }
+ }
+ }
+--- 5073,5086 ----
+ DBUG_RETURN(-1); /* purecov: inspected */
+ if (end_of_records)
+ DBUG_RETURN(0);
++ if (!error && ++join->send_records >=
++ join->select_lex->first_in_union->select_limit_cnt &&
+ join->do_send_rows)
+ {
+ if (!(join->select_options & OPTION_FOUND_ROWS))
+ DBUG_RETURN(-3); // Abort nicely
+ join->do_send_rows=0;
++ join->select_lex->first_in_union->select_limit_cnt = HA_POS_ERROR;
+ }
+ }
+ }
+***************
+*** 5060,5066 ****
+ if (!(join->select_options & OPTION_FOUND_ROWS))
+ DBUG_RETURN(-3);
+ join->do_send_rows=0;
+- join->thd->select_limit = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
+ }
+--- 5161,5167 ----
+ if (!(join->select_options & OPTION_FOUND_ROWS))
+ DBUG_RETURN(-3);
+ join->do_send_rows=0;
++ join->select_lex->first_in_union->select_limit_cnt = HA_POS_ERROR;
+ DBUG_RETURN(0);
+ }
+ }
+***************
+*** 5743,5749 ****
+
+ if (!field_count)
+ { // only const items
+- join->thd->select_limit=1; // Only send first row
+ DBUG_RETURN(0);
+ }
+ Field **first_field=entry->field+entry->fields - field_count;
+--- 5844,5850 ----
+
+ if (!field_count)
+ { // only const items
++ join->select_lex->first_in_union->select_limit_cnt=1;// Only send first row
+ DBUG_RETURN(0);
+ }
+ Field **first_field=entry->field+entry->fields - field_count;
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 054d427a4e0..3062747a08f 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -149,8 +149,7 @@ class TMP_TABLE_PARAM {
}
};
-
-class JOIN {
+class JOIN :public Sql_alloc{
public:
JOIN_TAB *join_tab,**best_ref,**map2table;
TABLE **table,**all_tables,*sort_by_table;
@@ -173,6 +172,75 @@ class JOIN {
select_result *result;
TMP_TABLE_PARAM tmp_table_param;
MYSQL_LOCK *lock;
+ // unit structure (with global parameters) for this select
+ SELECT_LEX_UNIT *unit;
+ // select that processed
+ SELECT_LEX *select_lex;
+
+ bool select_distinct, //Is select distinct?
+ no_order, simple_order, simple_group,
+ skip_sort_order, need_tmp,
+ hidden_group_fields,
+ buffer_result;
+ DYNAMIC_ARRAY keyuse;
+ Item::cond_result cond_value;
+ List<Item> all_fields;
+ List<Item> & fields_list; // hold field list passed to mysql_select
+ int error;
+
+ ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
+ COND *conds; // ---"---
+ TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
+ SQL_SELECT *select; //created in optimisation phase
+ TABLE *exec_tmp_table; //used in 'exec' to hold temporary
+
+ my_bool test_function_query; // need to return select items 1 row
+ const char *zero_result_cause; // not 0 if exec must return zero result
+
+ my_bool union_part; // this subselect is part of union
+
+ JOIN(THD *thd, List<Item> &fields,
+ ulong select_options, select_result *result):
+ join_tab(0),
+ table(0),
+ tables(0), const_tables(0),
+ sort_and_group(0), first_record(0),
+ do_send_rows(1),
+ send_records(0), found_records(0), examined_rows(0),
+ thd(thd),
+ sum_funcs(0),
+ having(0),
+ select_options(select_options),
+ result(result),
+ lock(thd->lock),
+ select_lex(0), //for safety
+ select_distinct(test(select_options & SELECT_DISTINCT)),
+ no_order(0), simple_order(0), simple_group(0), skip_sort_order(0),
+ need_tmp(0),
+ hidden_group_fields (0), /*safety*/
+ buffer_result(test(select_options & OPTION_BUFFER_RESULT) &&
+ !test(select_options & OPTION_FOUND_ROWS)),
+ all_fields(fields),
+ fields_list(fields),
+ select(0),
+ exec_tmp_table(0),
+ test_function_query(0),
+ zero_result_cause(0)
+ {
+ fields_list = fields;
+ bzero((char*) &keyuse,sizeof(keyuse));
+ tmp_table_param.copy_field=0;
+ tmp_table_param.end_write_records= HA_POS_ERROR;
+ }
+
+ int prepare(TABLE_LIST *tables,
+ COND *conds, ORDER *order, ORDER *group, Item *having,
+ ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit);
+ int optimize();
+ int global_optimize();
+ int reinit();
+ void exec();
+ int cleanup(THD *thd);
};
@@ -187,7 +255,8 @@ void TEST_join(JOIN *join);
bool store_val_in_field(Field *field,Item *val);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- bool allow_distinct_limit, ulong select_options);
+ bool allow_distinct_limit, ulong select_options,
+ SELECT_LEX_UNIT *unit);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
diff --git a/sql/sql_select.h.rej b/sql/sql_select.h.rej
new file mode 100644
index 00000000000..07b1c4403f9
--- /dev/null
+++ b/sql/sql_select.h.rej
@@ -0,0 +1,96 @@
+***************
+*** 173,178 ****
+ select_result *result;
+ TMP_TABLE_PARAM tmp_table_param;
+ MYSQL_LOCK *lock;
+ };
+
+
+--- 172,240 ----
+ select_result *result;
+ TMP_TABLE_PARAM tmp_table_param;
+ MYSQL_LOCK *lock;
++
++ bool select_distinct, //Is select distinct?
++ no_order, simple_order, simple_group,
++ skip_sort_order, need_tmp,
++ hidden_group_fields,
++ buffer_result;
++ DYNAMIC_ARRAY keyuse;
++ Item::cond_result cond_value;
++ List<Item> all_fields;
++ List<Item> & fields_list; // hold field list passed to mysql_select
++ int error;
++
++ ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select
++ COND *conds; // ---"---
++ TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_select
++ SQL_SELECT *select; //created in optimisation phase
++ TABLE *exec_tmp_table; //used in 'exec' to hold temporary table
++ SELECT_LEX *select_lex; //corresponding select_lex
++
++ my_bool test_function_query; // need to return select items 1 row
++ const char *zero_result_cause; // not 0 if exec must return zero result
++
++ JOIN(THD *thd, List<Item> &fields,
++ ulong select_options, select_result *result):
++ join_tab(0),
++ table(0),
++ tables(0), const_tables(0),
++ sort_and_group(0), first_record(0),
++ do_send_rows(1),
++ send_records(0), found_records(0), examined_rows(0),
++ thd(thd),
++ sum_funcs(0),
++ having(0),
++ select_options(select_options),
++ result(result),
++ lock(thd->lock),
++ select_distinct(test(select_options & SELECT_DISTINCT)),
++ no_order(0), simple_order(0), simple_group(0), skip_sort_order(0),
++ need_tmp(0),
++ hidden_group_fields (0), /*safety*/
++ buffer_result(test(select_options & OPTION_BUFFER_RESULT) &&
++ !test(select_options & OPTION_FOUND_ROWS)),
++ all_fields(fields),
++ fields_list(fields),
++ select(0),
++ exec_tmp_table(0),
++ select_lex(0), //for safety
++ test_function_query(0),
++ zero_result_cause(0)
++ {
++ fields_list = fields;
++ bzero((char*) &keyuse,sizeof(keyuse));
++ tmp_table_param.copy_field=0;
++ tmp_table_param.end_write_records= HA_POS_ERROR;
++ }
++
++ int prepare(TABLE_LIST *tables,
++ COND *conds, ORDER *order, ORDER *group, Item *having,
++ ORDER *proc_param, SELECT_LEX *select);
++ int optimize();
++ int global_optimize();
++ void exec();
++ int cleanup(THD *thd);
+ };
+
+
+***************
+*** 187,193 ****
+ bool store_val_in_field(Field *field,Item *val);
+ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
+- bool allow_distinct_limit, ulong select_options);
+ void free_tmp_table(THD *thd, TABLE *entry);
+ void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
+ bool reset_with_sum_func);
+--- 249,256 ----
+ bool store_val_in_field(Field *field,Item *val);
+ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
+ ORDER *group, bool distinct, bool save_sum_fields,
++ bool allow_distinct_limit, ulong select_options,
++ SELECT_LEX *first_select);
+ void free_tmp_table(THD *thd, TABLE *entry);
+ void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
+ bool reset_with_sum_func);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index c8237f3ae9b..585b5de11ab 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -27,56 +27,26 @@
int mysql_union(THD *thd, LEX *lex,select_result *result)
{
- SELECT_LEX *sl, *last_sl, *lex_sl;
- ORDER *order;
+ SELECT_LEX *sl;
+ SELECT_LEX_UNIT *unit= &(lex->unit);
List<Item> 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;
- TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first;
TMP_TABLE_PARAM tmp_table_param;
select_union *union_result;
DBUG_ENTER("mysql_union");
+ st_select_lex_node * global;
- /* Fix tables 'to-be-unioned-from' list to point at opened tables */
- last_sl= &lex->select_lex;
- for (sl= last_sl;
- sl && sl->linkage != NOT_A_SELECT;
- last_sl=sl, sl=sl->next)
+ /* Global option */
+ if (((void*)(global= unit->global_parameters)) == ((void*)unit))
{
- for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
- cursor;
- cursor=cursor->next)
- cursor->table= ((TABLE_LIST*) cursor->table)->table;
- }
-
- /* last_sel now points at the last select where the ORDER BY is stored */
- if (sl)
- {
- /*
- The found SL is an extra SELECT_LEX argument that contains
- the ORDER BY and LIMIT parameter for the whole UNION
- */
- lex_sl= sl;
- order= (ORDER *) lex_sl->order_list.first;
- found_rows_for_union = lex->select_lex.options & OPTION_FOUND_ROWS && !describe && sl->select_limit;
+ found_rows_for_union = lex->select_lex.options & OPTION_FOUND_ROWS &&
+ !describe && global->select_limit;
if (found_rows_for_union)
lex->select_lex.options ^= OPTION_FOUND_ROWS;
-// This is done to eliminate unnecessary slowing down of the first query
- if (!order || !describe)
- last_sl->next=0; // Remove this extra element
- }
- else if (!last_sl->braces)
- {
- lex_sl= last_sl; // ORDER BY is here
- order= (ORDER *) lex_sl->order_list.first;
- }
- else
- {
- lex_sl=0;
- order=0;
}
if (describe)
@@ -113,11 +83,12 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
- if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
- (ORDER*) 0, !describe & !lex->union_option,
- 1, 0,
- (lex->select_lex.options | thd->options |
- TMP_TABLE_ALL_COLUMNS))))
+ if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
+ (ORDER*) 0, !describe & !lex->union_option,
+ 1, 0,
+ (lex->select_lex.options | thd->options |
+ TMP_TABLE_ALL_COLUMNS),
+ unit)))
DBUG_RETURN(-1);
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -133,25 +104,28 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
}
union_result->save_time_stamp=!describe;
- for (sl= &lex->select_lex; sl; sl=sl->next)
+ for (sl= &lex->select_lex; sl; sl= sl->next_select())
{
lex->select=sl;
- thd->offset_limit=sl->offset_limit;
- thd->select_limit=sl->select_limit+sl->offset_limit;
- if (thd->select_limit < sl->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
+ unit->offset_limit_cnt= sl->offset_limit;
+ unit->select_limit_cnt= sl->select_limit+sl->offset_limit;
+ if (unit->select_limit_cnt < sl->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
- res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first,
- sl->item_list,
- sl->where,
- (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0,
- (ORDER*) sl->group_list.first,
- sl->having,
- (ORDER*) NULL,
- sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
- union_result);
+ res= mysql_select(thd,
+ (TABLE_LIST*) sl->table_list.first,
+ sl->item_list,
+ sl->where,
+ (sl->braces) ?
+ (ORDER *)sl->order_list.first : (ORDER *) 0,
+ (ORDER*) sl->group_list.first,
+ sl->having,
+ (ORDER*) NULL,
+ sl->options | thd->options |
+ SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
+ union_result, unit);
if (res)
goto exit;
}
@@ -183,26 +157,20 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
}
if (!thd->fatal_error) // Check if EOM
{
- if (lex_sl)
- {
- thd->offset_limit=lex_sl->offset_limit;
- thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit;
- if (thd->select_limit < lex_sl->select_limit)
- thd->select_limit= HA_POS_ERROR; // no limit
- if (thd->select_limit == HA_POS_ERROR)
- thd->options&= ~OPTION_FOUND_ROWS;
- }
- else
- {
- thd->offset_limit= 0;
- thd->select_limit= thd->default_select_limit;
- }
+ st_select_lex_node * global= unit->global_parameters;
+ unit->offset_limit_cnt= global->offset_limit;
+ unit->select_limit_cnt= global->select_limit+global->offset_limit;
+ if (unit->select_limit_cnt < global->select_limit)
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ if (unit->select_limit_cnt == HA_POS_ERROR)
+ thd->options&= ~OPTION_FOUND_ROWS;
if (describe)
- thd->select_limit= HA_POS_ERROR; // no limit
- res=mysql_select(thd,&result_table_list,
- item_list, NULL, (describe) ? 0 : order,
- (ORDER*) NULL, NULL, (ORDER*) NULL,
- thd->options, result);
+ unit->select_limit_cnt= HA_POS_ERROR; // no limit
+ res= mysql_select(thd,&result_table_list,
+ item_list, NULL,
+ (describe) ? 0 : (ORDER*)global->order_list.first,
+ (ORDER*) NULL, NULL, (ORDER*) NULL,
+ thd->options, result, unit);
if (found_rows_for_union && !res)
thd->limit_found_rows = (ulonglong)table->file->records;
}
@@ -226,7 +194,7 @@ select_union::select_union(TABLE *table_par)
We can always use DUP_IGNORE because the temporary table will only
contain a unique key if we are using not using UNION ALL
*/
- info.handle_duplicates=DUP_IGNORE;
+ info.handle_duplicates= DUP_IGNORE;
}
select_union::~select_union()
@@ -234,8 +202,9 @@ select_union::~select_union()
}
-int select_union::prepare(List<Item> &list)
+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,
@@ -247,9 +216,9 @@ int select_union::prepare(List<Item> &list)
bool select_union::send_data(List<Item> &values)
{
- if (thd->offset_limit)
+ if (unit->offset_limit_cnt)
{ // using limit offset,count
- thd->offset_limit--;
+ unit->offset_limit_cnt--;
return 0;
}
fill_record(table->field,values);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 2a45798ddf8..1bb0537a731 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -379,9 +379,10 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
}
int
-multi_update::prepare(List<Item> &values)
+multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
{
DBUG_ENTER("multi_update::prepare");
+ unit= u;
do_update = true;
thd->count_cuted_fields=1;
thd->cuted_fields=0L;
@@ -466,15 +467,20 @@ multi_update::prepare(List<Item> &values)
}
if (counter)
{
- Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true,default_charset_info);
+ Field_string offset(table_ref->table->file->ref_length, false,
+ "offset", table_ref->table, true,
+ default_charset_info);
temp_fields->push_front(new Item_field(((Field *)&offset)));
// Here I make tmp tables
int cnt=counter-1;
TMP_TABLE_PARAM tmp_table_param;
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=temp_fields->elements;
- if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, *temp_fields,
- (ORDER*) 0, 1, 0, 0, TMP_TABLE_ALL_COLUMNS)))
+ if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param,
+ *temp_fields,
+ (ORDER*) 0, 1, 0, 0,
+ TMP_TABLE_ALL_COLUMNS,
+ unit)))
{
error = 1; // A proper error message is due here
DBUG_RETURN(1);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 756afbd7a09..ebd26939ad5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -544,7 +544,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
- using_list
+ using_list subselect subselect_init
%type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg
@@ -612,7 +612,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild union union_list
- precision union_option
+ precision union_option subselect_start subselect_end
END_OF_INPUT
%type <NONE>
@@ -1472,7 +1472,14 @@ select:
select_init:
SELECT_SYM select_part2 { Select->braces=false; } union
|
- '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt
+ '(' SELECT_SYM select_part2 ')'
+ {
+ SELECT_LEX * sel=Select;
+ sel->braces=true;
+ /* select in braces, can't contain global parameters */
+ sel->master_unit()->global_parameters=
+ sel->master_unit();
+ } union_opt
select_part2:
@@ -1563,8 +1570,8 @@ optional_braces:
| '(' ')' {}
/* all possible expressions */
-expr: expr_expr {$$ = $1; }
- | simple_expr {$$ = $1; }
+expr: expr_expr { $$= $1; }
+ | simple_expr { $$= $1; }
/* expressions that begin with 'expr' */
expr_expr:
@@ -1704,6 +1711,7 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; }
+ | subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')'
{ Select->ftfunc_list.push_back((Item_func_match *)
@@ -2178,23 +2186,22 @@ join_table:
| '(' SELECT_SYM select_part3 ')' opt_table_alias
{
LEX *lex=Lex;
- SELECT_LEX *select_to_execute= lex->select;
- lex->select=lex->select->prev;
- if (!($$=add_table_to_list(new Table_ident(select_to_execute),
- $5,0,TL_UNLOCK)))
+ SELECT_LEX_UNIT *unit= lex->select->master_unit();
+ lex->select= unit->outer_select();
+ if (!($$= add_table_to_list(new Table_ident(unit),
+ $5,0,TL_UNLOCK)))
YYABORT;
}
select_part3:
{
- LEX *lex=Lex;
- lex->derived_tables=true;
- SELECT_LEX *tmp=lex->select;
- if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
+ LEX *lex= Lex;
+ lex->derived_tables= true;
+ if (lex->select->linkage == GLOBAL_OPTIONS_TYPE ||
+ mysql_new_select(lex, 1))
YYABORT;
mysql_init_select(lex);
- lex->select->linkage=DERIVED_TABLE_TYPE;
- lex->select->prev=tmp;
+ lex->select->linkage= DERIVED_TABLE_TYPE;
}
select_options select_item_list select_intoto
@@ -2318,7 +2325,7 @@ order_clause:
LEX *lex=Lex;
if (lex->sql_command == SQLCOM_MULTI_UPDATE)
YYABORT;
- lex->select->sort_default=1;
+ /*lex->select->sort_default=1;*/
} order_list
order_list:
@@ -3834,7 +3841,8 @@ union_list:
net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO");
YYABORT;
}
- if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
+ if (lex->select->linkage == GLOBAL_OPTIONS_TYPE ||
+ mysql_new_select(lex, 0))
YYABORT;
lex->select->linkage=UNION_TYPE;
}
@@ -3849,10 +3857,15 @@ optional_order_or_limit:
|
{
LEX *lex=Lex;
- if (!lex->select->braces || mysql_new_select(lex))
+ if (!lex->select->braces)
YYABORT;
- mysql_init_select(lex);
- lex->select->linkage=NOT_A_SELECT;
+ lex->select->master_unit()->global_parameters=
+ lex->select->master_unit();
+ /*
+ Following type conversion looks like hack, but all that need SELECT_LEX
+ fields always check linkage type.
+ */
+ lex->select= (SELECT_LEX*)lex->select->master_unit();
lex->select->select_limit=lex->thd->default_select_limit;
}
opt_order_clause limit_clause
@@ -3860,3 +3873,30 @@ optional_order_or_limit:
union_option:
/* empty */ {}
| ALL {Lex->union_option=1;}
+
+subselect:
+ subselect_start subselect_init
+ subselect_end
+ {
+ $$= $2;
+ }
+
+subselect_init:
+ select_init
+ {
+ $$= new Item_subselect(current_thd, Lex->select);
+ }
+
+subselect_start:
+ '('
+ {
+ if (mysql_new_select(Lex, 1))
+ YYABORT;
+ }
+
+subselect_end:
+ ')'
+ {
+ LEX *lex=Lex;
+ lex->select = lex->select->outer_select();
+ }
diff --git a/sql/table.h b/sql/table.h
index 183e1b2a38f..b89701bfc8e 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -140,18 +140,26 @@ typedef struct st_table_list {
struct st_table_list *next;
char *db,*name,*real_name;
uint32 db_length, real_name_length;
- Item *on_expr; /* Used with outer join */
- struct st_table_list *natural_join; /* natural join on this table*/
+ Item *on_expr; /* Used with outer join */
+ struct st_table_list *natural_join; /* natural join on this table*/
/* ... join ... USE INDEX ... IGNORE INDEX */
- List<String> *use_index,*ignore_index;
- TABLE *table;
+ List<String> *use_index, *ignore_index;
+ /*
+ Usually hold reference on opened table, but may hold reference
+ to node of complete list of tables used in UNION & subselect.
+ */
+ union
+ {
+ TABLE *table; /* opened table */
+ st_table_list *table_list; /* pointer to node of list of all tables */
+ };
GRANT_INFO grant;
thr_lock_type lock_type;
- uint outer_join; /* Which join type */
- bool straight; /* optimize with prev table */
- bool updating; /* for replicate-do/ignore table */
- bool shared; /* Used twice in union */
- void *derived;
+ uint outer_join; /* Which join type */
+ bool straight; /* optimize with prev table */
+ bool updating; /* for replicate-do/ignore table */
+ bool shared; /* Used twice in union */
+ void *derived; /* SELECT_LEX_UNIT of derived table */
} TABLE_LIST;
typedef struct st_changed_table_list {