Commit e077890b authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

simple subselects ported to new select_lex structures

parent 4cb3760b
...@@ -243,4 +243,6 @@ ...@@ -243,4 +243,6 @@
#define ER_MIXING_NOT_ALLOWED 1224 #define ER_MIXING_NOT_ALLOWED 1224
#define ER_DUP_ARGUMENT 1225 #define ER_DUP_ARGUMENT 1225
#define ER_USER_LIMIT_REACHED 1226 #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
...@@ -43,7 +43,8 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \ ...@@ -43,7 +43,8 @@ sqlsources = convert.cc derror.cc field.cc field_conv.cc filesort.cc \
hostname.cc init.cc \ hostname.cc init.cc \
item.cc item_buff.cc item_cmpfunc.cc item_create.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_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 \ 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 \ opt_sum.cc procedure.cc records.cc sql_acl.cc \
repl_failsafe.cc slave.cc \ repl_failsafe.cc slave.cc \
......
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), 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
drop table t1,t2,t3,t4;
#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), 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 limit 1);
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;
drop table t1,t2,t3,t4;
...@@ -46,7 +46,7 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ ...@@ -46,7 +46,7 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \
$(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@
noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
item_strfunc.h item_timefunc.h item_uniq.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 \ procedure.h sql_class.h sql_lex.h sql_list.h \
sql_manager.h sql_map.h sql_string.h unireg.h \ sql_manager.h sql_map.h sql_string.h unireg.h \
field.h handler.h \ field.h handler.h \
...@@ -60,7 +60,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.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 \ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \
item_cmpfunc.cc item_strfunc.cc item_timefunc.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 \ field.cc key.cc sql_class.cc sql_list.cc \
net_serv.cc net_pkg.cc lock.cc my_lock.c \ net_serv.cc net_pkg.cc lock.cc my_lock.c \
sql_string.cc sql_manager.cc sql_map.cc \ sql_string.cc sql_manager.cc sql_map.cc \
......
...@@ -32,7 +32,8 @@ public: ...@@ -32,7 +32,8 @@ public:
enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM,
INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM,
COPY_STR_ITEM,FIELD_AVG_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 }; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
String str_value; /* used to store value */ String str_value; /* used to store value */
...@@ -46,7 +47,6 @@ public: ...@@ -46,7 +47,6 @@ public:
my_bool unsigned_flag; my_bool unsigned_flag;
my_bool with_sum_func; my_bool with_sum_func;
// alloc & destruct is done as start of select using sql_alloc // alloc & destruct is done as start of select using sql_alloc
Item(); Item();
virtual ~Item() { name=0; } /*lint -e1509 */ virtual ~Item() { name=0; } /*lint -e1509 */
...@@ -371,6 +371,7 @@ public: ...@@ -371,6 +371,7 @@ public:
#include "item_strfunc.h" #include "item_strfunc.h"
#include "item_timefunc.h" #include "item_timefunc.h"
#include "item_uniq.h" #include "item_uniq.h"
#include "item_subselect.h"
class Item_copy_string :public Item class Item_copy_string :public Item
{ {
...@@ -458,3 +459,4 @@ extern Item_result item_cmp_type(Item_result a,Item_result b); ...@@ -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 Item *resolve_const_item(Item *item,Item *cmp_item);
extern bool field_is_equal_to_item(Field *field,Item *item); extern bool field_is_equal_to_item(Field *field,Item *item);
Item *get_system_var(LEX_STRING name); Item *get_system_var(LEX_STRING name);
...@@ -38,7 +38,9 @@ public: ...@@ -38,7 +38,9 @@ public:
Field *tmp_table_field(TABLE *t_arg) Field *tmp_table_field(TABLE *t_arg)
{ {
if (!t_arg) return result_field; 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); 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);
} }
}; };
......
/* 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)
- depended from outer select subselects
*/
#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)
{
DBUG_ENTER("Item_subselect::Item_subselect");
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
result= new select_subselect(this);
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_UNIT*) select_lex->master))
return 1;
if (join->optimize())
{
executed= 1;
return 1;
}
thd->lex.select= save_select;
return 0;
}
int Item_subselect::exec()
{
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;
}
/* 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:
my_bool executed; /* simple subselect is executed */
longlong int_value;
double real_value;
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;
}
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;
};
...@@ -237,3 +237,5 @@ ...@@ -237,3 +237,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -231,3 +231,5 @@ ...@@ -231,3 +231,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -236,3 +236,5 @@ ...@@ -236,3 +236,5 @@
"Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.", "Het combineren van transactionele en niet-transactionele tabellen is uitgeschakeld.",
"Optie '%s' tweemaal gebruikt in opdracht", "Optie '%s' tweemaal gebruikt in opdracht",
"Gebruiker '%-64s' heeft het maximale gebruik van de '%s' faciliteit overschreden (huidige waarde: %ld)", "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",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -233,3 +233,5 @@ ...@@ -233,3 +233,5 @@
"Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud", "Transaktsioone toetavate ning mittetoetavate tabelite kooskasutamine ei ole lubatud",
"Mrangut '%s' on lauses kasutatud topelt", "Mrangut '%s' on lauses kasutatud topelt",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -231,3 +231,5 @@ ...@@ -231,3 +231,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -230,3 +230,5 @@ ...@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -230,3 +230,5 @@ ...@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -230,3 +230,5 @@ ...@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -230,3 +230,5 @@ ...@@ -230,3 +230,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -232,3 +232,5 @@ ...@@ -232,3 +232,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -232,3 +232,5 @@ ...@@ -232,3 +232,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -231,3 +231,5 @@ ...@@ -231,3 +231,5 @@
" transactional non-transactional ", " transactional non-transactional ",
" '%s' ", " '%s' ",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
" ",
" ",
...@@ -236,3 +236,5 @@ ...@@ -236,3 +236,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -229,3 +229,5 @@ ...@@ -229,3 +229,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -228,3 +228,5 @@ ...@@ -228,3 +228,5 @@
"Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat", "Blandning av transaktionella och icke-transaktionella tabeller är inaktiverat",
"Option '%s' användes två gånger", "Option '%s' användes två gånger",
"Användare '%-64s' har överskridit '%s' (nuvarande värde: %ld)", "Användare '%-64s' har överskridit '%s' (nuvarande värde: %ld)",
"Subselect return more than 1 field",
"Subselect return more than 1 record",
...@@ -233,3 +233,5 @@ ...@@ -233,3 +233,5 @@
"Mixing of transactional and non-transactional tables is disabled", "Mixing of transactional and non-transactional tables is disabled",
"Option '%s' used twice in statement", "Option '%s' used twice in statement",
"User '%-64s' has exceeded the '%s' resource (current value: %ld)", "User '%-64s' has exceeded the '%s' resource (current value: %ld)",
"i i i 1 ",
"i i i 1 ",
...@@ -774,3 +774,30 @@ bool select_dump::send_eof() ...@@ -774,3 +774,30 @@ bool select_dump::send_eof()
file= -1; file= -1;
return error; return error;
} }
select_subselect::select_subselect(Item_subselect *item)
{
this->item=item;
}
bool select_subselect::send_data(List<Item> &items)
{
if (item->executed){
my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
return 1;
}
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();
}
return 0;
}
...@@ -685,6 +685,19 @@ class select_union :public select_result { ...@@ -685,6 +685,19 @@ class select_union :public select_result {
bool flush(); 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 */ /* Structs used when sorting */
typedef struct st_sort_field { typedef struct st_sort_field {
......
...@@ -901,6 +901,7 @@ void st_select_lex_node::init_select() ...@@ -901,6 +901,7 @@ void st_select_lex_node::init_select()
void st_select_lex_unit::init_query() void st_select_lex_unit::init_query()
{ {
linkage= GLOBAL_OPTIONS_TYPE;
st_select_lex_node::init_query(); st_select_lex_node::init_query();
global_parameters= this; global_parameters= this;
select_limit_cnt= HA_POS_ERROR; select_limit_cnt= HA_POS_ERROR;
......
...@@ -156,6 +156,19 @@ int handle_select(THD *thd, LEX *lex, select_result *result) ...@@ -156,6 +156,19 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
{ {
int res; int res;
register SELECT_LEX *select_lex = &lex->select_lex; register SELECT_LEX *select_lex = &lex->select_lex;
if (select_lex->link_next)
{
/* Fix tables 'to-be-unioned-from' list to point at opened tables */
for (SELECT_LEX *sl= select_lex;
sl;
sl= (SELECT_LEX*)sl->link_next)
{
for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
cursor;
cursor=cursor->next)
cursor->table= cursor->table_list->table;
}
}
if (select_lex->next) if (select_lex->next)
res=mysql_union(thd,lex,result); res=mysql_union(thd,lex,result);
else else
...@@ -180,50 +193,42 @@ int handle_select(THD *thd, LEX *lex, select_result *result) ...@@ -180,50 +193,42 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
** mysql_select assumes that all tables are already opened ** 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 int
mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, JOIN::prepare(TABLE_LIST *tables_init,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param, COND *conds_init, ORDER *order_init, ORDER *group_init,
ulong select_options,select_result *result, Item *having_init,
SELECT_LEX_UNIT *unit) ORDER *proc_param_init, SELECT_LEX *select, SELECT_LEX_UNIT *unit)
{ {
TABLE *tmp_table; DBUG_ENTER("JOIN::prepare");
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 */ 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;
select_distinct=test(select_options & SELECT_DISTINCT); /* Check that all tables, fields, conds and order are ok */
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) || if (setup_tables(tables_list) ||
setup_fields(thd,tables,fields,1,&all_fields,1) || setup_fields(thd,tables_list,fields_list,1,&all_fields,1) ||
setup_conds(thd,tables,&conds) || setup_conds(thd,tables_list,&conds) ||
setup_order(thd,tables,fields,all_fields,order) || setup_order(thd,tables_list,fields_list,all_fields,order) ||
setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields)) setup_group(thd,tables_list,fields_list,all_fields,group_list,
&hidden_group_fields))
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
if (having) if (having)
{ {
thd->where="having clause"; thd->where="having clause";
thd->allow_sum_func=1; 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 */ DBUG_RETURN(-1); /* purecov: inspected */
if (having->with_sum_func) if (having->with_sum_func)
having->split_sum_func(all_fields); having->split_sum_func(all_fields);
...@@ -236,13 +241,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -236,13 +241,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
TODO: Add check of calculation of GROUP functions and fields: TODO: Add check of calculation of GROUP functions and fields:
SELECT COUNT(*)+table.col1 from table1; SELECT COUNT(*)+table.col1 from table1;
*/ */
join.table=0;
join.tables=0;
{ {
if (!group) if (!group_list)
{ {
uint flag=0; uint flag=0;
List_iterator_fast<Item> it(fields); List_iterator_fast<Item> it(fields_list);
Item *item; Item *item;
while ((item= it++)) while ((item= it++))
{ {
...@@ -258,22 +261,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -258,22 +261,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
} }
} }
TABLE_LIST *table; TABLE_LIST *table;
for (table=tables ; table ; table=table->next) for (table=tables_list ; table ; table=table->next)
join.tables++; tables++;
} }
procedure=setup_procedure(thd,proc_param,result,fields,&error); procedure=setup_procedure(thd,proc_param,result,fields_list,&error);
if (error) if (error)
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
if (procedure) 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 */ { /* purecov: inspected */
delete procedure; /* purecov: inspected */ delete procedure; /* purecov: inspected */
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
} }
if (procedure->group) if (procedure->group)
{ {
if (!test_if_subpart(procedure->group,group)) if (!test_if_subpart(procedure->group,group_list))
{ /* purecov: inspected */ { /* purecov: inspected */
my_message(0,"Can't handle procedures with differents groups yet", my_message(0,"Can't handle procedures with differents groups yet",
MYF(0)); /* purecov: inspected */ MYF(0)); /* purecov: inspected */
...@@ -282,7 +286,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -282,7 +286,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
} }
} }
#ifdef NOT_NEEDED #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)); my_message(0,"Select must have a group with this procedure",MYF(0));
delete procedure; delete procedure;
...@@ -298,52 +302,54 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -298,52 +302,54 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
} }
/* Init join struct */ /* Init join struct */
join.thd=thd; count_field_types(&tmp_table_param, all_fields, 0);
join.lock=thd->lock; this->group= group_list != 0;
join.join_tab=0; row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR :
join.tmp_table_param.copy_field=0; unit->select_limit_cnt);
join.sum_funcs=0; this->unit= unit;
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 :
unit->select_limit_cnt);
join.unit= unit;
#ifdef RESTRICTED_GROUP #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)); my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0));
delete procedure; delete procedure;
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
#endif #endif
if (!procedure && result->prepare(fields, unit)) if (!procedure && result->prepare(fields_list, unit))
{ /* purecov: inspected */ { /* purecov: inspected */
DBUG_RETURN(-1); /* 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 #ifdef HAVE_REF_TO_FIELDS // Not done yet
/* Add HAVING to WHERE if possible */ /* Add HAVING to WHERE if possible */
if (having && !group && ! join.sum_func_count) if (having && !group_list && ! sum_func_count)
{ {
if (!conds) if (!conds)
{ {
conds=having; conds= having;
having=0; having= 0;
} }
else if ((conds=new Item_cond_and(conds,having))) else if ((conds=new Item_cond_and(conds,having)))
{ {
conds->fix_fields(thd,tables); conds->fix_fields(thd, tables_list);
conds->change_ref_to_fields(thd,tables); conds->change_ref_to_fields(thd, tables_list);
having=0; having= 0;
} }
} }
#endif #endif
...@@ -352,110 +358,76 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -352,110 +358,76 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
if (thd->fatal_error) // Out of memory if (thd->fatal_error) // Out of memory
{ {
delete procedure; delete procedure;
DBUG_RETURN(0); error = 0;
DBUG_RETURN(1);
} }
if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt) if (cond_value == Item::COND_FALSE || !unit->select_limit_cnt)
{ /* Impossible cond */ { /* Impossible cond */
if (select_options & SELECT_DESCRIBE && select_lex->next) zero_result_cause= "Impossible WHERE";
select_describe(&join,false,false,false,"Impossible WHERE"); DBUG_RETURN(0);
else
error=return_zero_rows(result, tables, fields,
join.tmp_table_param.sum_func_count != 0 && !group,
select_options,"Impossible WHERE",having,
procedure, unit);
delete procedure;
DBUG_RETURN(error);
} }
/* Optimize count(*), min() and max() */ /* 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; 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 (res < 0)
{ {
if (select_options & SELECT_DESCRIBE && select_lex->next) zero_result_cause= "No matching min/max row";
select_describe(&join,false,false,false,"No matching min/max row"); DBUG_RETURN(0);
else
error=return_zero_rows(result, tables, fields, !group,
select_options, "No matching min/max row",
having, procedure, unit);
delete procedure;
DBUG_RETURN(error);
} }
if (select_options & SELECT_DESCRIBE) if (select_options & SELECT_DESCRIBE)
{ {
if (select_lex->next) if (select_lex->next)
select_describe(&join,false,false,false,"Select tables optimized away"); select_describe(this, false, false, false,
"Select tables optimized away");
else else
describe_info(thd,"Select tables optimized away"); describe_info(thd, "Select tables optimized away");
delete procedure; 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 if (!tables_list)
error=0; {
if (select_options & SELECT_DESCRIBE) test_function_query= 1;
{ DBUG_RETURN(0);
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; error= -1;
join.sort_by_table=get_sort_by_table(order,group,tables); sort_by_table= get_sort_by_table(order, group_list, tables_list);
/* Calculate how to do the join */ /* Calculate how to do the join */
thd->proc_info="statistics"; thd->proc_info= "statistics";
if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error) if (make_join_statistics(this, tables_list, conds, &keyuse) ||
goto err; thd->fatal_error)
thd->proc_info="preparing"; DBUG_RETURN(-1);
result->initialize_tables(&join); thd->proc_info= "preparing";
if (join.const_table_map != join.found_const_table_map && result->initialize_tables(this);
if (const_table_map != found_const_table_map &&
!(select_options & SELECT_DESCRIBE)) !(select_options & SELECT_DESCRIBE))
{ {
error= return_zero_rows(result, tables, fields, zero_result_cause= "";
join.tmp_table_param.sum_func_count != 0 && select_options= 0; //TODO why option in return_zero_rows was droped
!group, 0, "", having, procedure, unit); DBUG_RETURN(0);
goto err;
} }
if (!(thd->options & OPTION_BIG_SELECTS) && 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)) !(select_options & SELECT_DESCRIBE))
{ /* purecov: inspected */ { /* purecov: inspected */
result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */ result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */
error= 1; /* 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)) !(select_options & SELECT_NO_UNLOCK))
{ {
TABLE **table, **end; TABLE **table, **end;
for (table=join.table, end=table + join.const_tables ; for (table=this->table, end=table + const_tables ;
table != end; table != end;
table++) table++)
{ {
...@@ -467,98 +439,94 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -467,98 +439,94 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
} }
(*table)->file->index_end(); (*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 */ /* Handle the case where we have an OUTER JOIN without a WHERE */
conds=new Item_int((longlong) 1,1); // Always true conds=new Item_int((longlong) 1,1); // Always true
} }
select=make_select(*join.table, join.const_table_map, select=make_select(*table, const_table_map,
join.const_table_map,conds,&error); const_table_map, conds, &error);
if (error) if (error)
{ /* purecov: inspected */ { /* purecov: inspected */
error= -1; /* purecov: inspected */ error= -1; /* purecov: inspected */
goto err; /* purecov: inspected */ DBUG_RETURN(-1);
} }
if (make_join_select(&join,select,conds)) if (make_join_select(this, select, conds))
{ {
if (select_options & SELECT_DESCRIBE && select_lex->next) zero_result_cause=
select_describe(&join,false,false,false,"Impossible WHERE noticed after reading const tables"); "Impossible WHERE noticed after reading const tables";
else DBUG_RETURN(0);
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, unit);
goto err;
} }
error= -1; /* if goto err */ error= -1; /* if goto err */
/* Optimize distinct away if possible */ /* Optimize distinct away if possible */
order=remove_const(&join,order,conds,&simple_order); order= remove_const(this, order, conds, &simple_order);
if (group || join.tmp_table_param.sum_func_count) if (group_list || tmp_table_param.sum_func_count)
{ {
if (! hidden_group_fields) if (! hidden_group_fields)
select_distinct=0; select_distinct=0;
} }
else if (select_distinct && join.tables - join.const_tables == 1 && else if (select_distinct && tables - const_tables == 1 &&
(unit->select_limit_cnt == HA_POS_ERROR || (unit->select_limit_cnt == HA_POS_ERROR ||
(join.select_options & OPTION_FOUND_ROWS) || (select_options & OPTION_FOUND_ROWS) ||
order && order &&
!(skip_sort_order= !(skip_sort_order=
test_if_skip_sort_order(&join.join_tab[join.const_tables], test_if_skip_sort_order(&join_tab[const_tables],
order, unit->select_limit_cnt,1)))) 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; no_order= !order;
join.group=1; // For end_write_group group= 1; // For end_write_group
} }
else if (thd->fatal_error) // End of memory else if (thd->fatal_error) // End of memory
goto err; DBUG_RETURN(-1);
} }
group=remove_const(&join,group,conds,&simple_group); group_list= remove_const(this, group_list, conds, &simple_group);
if (!group && join.group) if (!group_list && group)
{ {
order=0; // The output has only one row order=0; // The output has only one row
simple_order=1; simple_order=1;
} }
calc_group_buffer(&join,group); calc_group_buffer(this, group_list);
join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */ send_group_parts= tmp_table_param.group_parts; /* Save org parts */
if (procedure && procedure->group) if (procedure && procedure->group)
{ {
group=procedure->group=remove_const(&join,procedure->group,conds, group_list= procedure->group= remove_const(this, procedure->group, conds,
&simple_group); &simple_group);
calc_group_buffer(&join,group); calc_group_buffer(this, group_list);
} }
if (test_if_subpart(group,order) || if (test_if_subpart(group_list, order) ||
(!group && join.tmp_table_param.sum_func_count)) (!group_list && tmp_table_param.sum_func_count))
order=0; order=0;
// Can't use sort on head table if using row cache // 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; simple_group=0;
if (order) if (order)
simple_order=0; simple_order=0;
} }
need_tmp= (join.const_tables != join.tables && need_tmp= (const_tables != tables &&
((select_distinct || !simple_order || !simple_group) || ((select_distinct || !simple_order || !simple_group) ||
(group && order) || buffer_result)); (group_list && order) || buffer_result));
// No cache for MATCH // No cache for MATCH
make_join_readinfo(&join, make_join_readinfo(this,
(select_options & (SELECT_DESCRIBE | (select_options & (SELECT_DESCRIBE |
SELECT_NO_JOIN_CACHE)) | 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 /* Need to tell Innobase that to play it safe, it should fetch all
columns of the tables: this is because MySQL columns of the tables: this is because MySQL
...@@ -567,60 +535,132 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -567,60 +535,132 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
by MySQL. */ by MySQL. */
#ifdef HAVE_INNOBASE_DB #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) if (table_h->db_type == DB_TYPE_INNODB)
table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE);
} }
} }
#endif #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 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 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 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. as in other cases the join is done before the sort.
*/ */
if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL && if ((order || group_list) && join_tab[const_tables].type != JT_ALL &&
join.join_tab[join.const_tables].type != JT_FT && join_tab[const_tables].type != JT_FT &&
(order && simple_order || group && simple_group)) (order && simple_order || group_list && simple_group))
{ {
if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables])) if (add_ref_to_table_cond(thd,&join_tab[const_tables]))
goto err; DBUG_RETURN(-1);
} }
if (!(select_options & SELECT_BIG_RESULT) && if (!(select_options & SELECT_BIG_RESULT) &&
((group && join.const_tables != join.tables && ((group_list && const_tables != tables &&
(!simple_group || (!simple_group ||
!test_if_skip_sort_order(&join.join_tab[join.const_tables], group, !test_if_skip_sort_order(&join_tab[const_tables], group_list,
unit->select_limit_cnt, 0))) || unit->select_limit_cnt,
0))) ||
select_distinct) && 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 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,
unit);
DBUG_VOID_RETURN;
}
Item *having_list = having;
having = 0;
if (select_options & SELECT_DESCRIBE) if (select_options & SELECT_DESCRIBE)
{ {
if (!order && !no_order) if (!order && !no_order)
order=group; order=group_list;
if (order && if (order &&
(join.const_tables == join.tables || (const_tables == tables ||
(simple_order && (simple_order &&
test_if_skip_sort_order(&join.join_tab[join.const_tables], order, test_if_skip_sort_order(&join_tab[const_tables], order,
(join.const_tables != join.tables - 1 || (const_tables != tables - 1 ||
(join.select_options & OPTION_FOUND_ROWS)) ? (select_options & OPTION_FOUND_ROWS)) ?
HA_POS_ERROR : unit->select_limit_cnt, 0)))) HA_POS_ERROR : unit->select_limit_cnt,
0))))
order=0; order=0;
select_describe(&join,need_tmp, select_describe(this, need_tmp,
order != 0 && !skip_sort_order, order != 0 && !skip_sort_order,
select_distinct); select_distinct);
error=0; error=0;
goto err; DBUG_VOID_RETURN;
} }
/* Perform FULLTEXT search before all regular searches */ /* Perform FULLTEXT search before all regular searches */
...@@ -632,44 +672,45 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -632,44 +672,45 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
DBUG_PRINT("info",("Creating tmp table")); DBUG_PRINT("info",("Creating tmp table"));
thd->proc_info="Creating tmp table"; thd->proc_info="Creating tmp table";
if (!(tmp_table = if (!(exec_tmp_table =
create_tmp_table(thd,&join.tmp_table_param,all_fields, create_tmp_table(thd, &tmp_table_param, all_fields,
((!simple_group && !procedure && ((!simple_group && !procedure &&
!(test_flags & TEST_NO_KEY_GROUP)) ? !(test_flags & TEST_NO_KEY_GROUP)) ?
group : (ORDER*) 0), group_list : (ORDER*) 0),
group ? 0 : select_distinct, group_list ? 0 : select_distinct,
group && simple_group, group_list && simple_group,
(order == 0 || skip_sort_order) && (order == 0 || skip_sort_order) &&
!(join.select_options & OPTION_FOUND_ROWS), !(select_options & OPTION_FOUND_ROWS),
join.select_options, unit))) select_options, unit)))
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
if (having && (join.sort_and_group || (tmp_table->distinct && !group))) if (having_list &&
join.having=having; (sort_and_group || (exec_tmp_table->distinct && !group_list)))
having=having_list;
/* if group or order on first table, sort first */ /* if group or order on first table, sort first */
if (group && simple_group) if (group_list && simple_group)
{ {
DBUG_PRINT("info",("Sorting for group")); DBUG_PRINT("info",("Sorting for group"));
thd->proc_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) || HA_POS_ERROR) ||
make_sum_func_list(&join,all_fields) || make_sum_func_list(this, all_fields) ||
alloc_group_fields(&join,group)) alloc_group_fields(this, group_list))
goto err; DBUG_VOID_RETURN;
group=0; group_list=0;
} }
else else
{ {
if (make_sum_func_list(&join,all_fields)) if (make_sum_func_list(this, all_fields))
goto err; DBUG_VOID_RETURN;
if (!group && ! tmp_table->distinct && order && simple_order) if (!group_list && ! exec_tmp_table->distinct && order && simple_order)
{ {
DBUG_PRINT("info",("Sorting for order")); DBUG_PRINT("info",("Sorting for order"));
thd->proc_info="Sorting for order"; thd->proc_info="Sorting for order";
if (create_sort_index(&join.join_tab[join.const_tables],order, if (create_sort_index(&join_tab[const_tables], order,
HA_POS_ERROR)) HA_POS_ERROR))
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
order=0; order=0;
} }
} }
...@@ -680,58 +721,58 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -680,58 +721,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 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; 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 do
{ {
if (used_tables & join_tab->table->map) if (used_tables & join_tab->table->map)
break; break;
join_tab->not_used_in_distinct=1; 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 #" */ /* Optimize "select distinct b from t1 order by key_part_1 limit #" */
if (order && skip_sort_order) if (order && skip_sort_order)
{ {
(void) test_if_skip_sort_order(&join.join_tab[join.const_tables], (void) test_if_skip_sort_order(&this->join_tab[const_tables],
order, unit->select_limit_cnt, 0); order, unit->select_limit_cnt, 0);
order=0; order=0;
} }
} }
/* Copy data to the temporary table */ /* Copy data to the temporary table */
thd->proc_info="Copying to tmp table"; thd->proc_info= "Copying to tmp table";
if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0))) if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0)))
{ {
error=tmp_error; error= tmp_error;
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
} }
if (join.having) if (having)
join.having=having=0; // Allready done having= having_list= 0; // Allready done
/* Change sum_fields reference to calculated fields in tmp_table */ /* 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)) if (change_to_use_tmp_fields(all_fields))
goto err; DBUG_VOID_RETURN;
join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+ tmp_table_param.field_count+= tmp_table_param.sum_func_count+
join.tmp_table_param.func_count; tmp_table_param.func_count;
join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0; tmp_table_param.sum_func_count= tmp_table_param.func_count= 0;
} }
else else
{ {
if (change_refs_to_tmp_fields(thd,all_fields)) if (change_refs_to_tmp_fields(thd,all_fields))
goto err; DBUG_VOID_RETURN;
join.tmp_table_param.field_count+=join.tmp_table_param.func_count; tmp_table_param.field_count+= tmp_table_param.func_count;
join.tmp_table_param.func_count=0; tmp_table_param.func_count= 0;
} }
if (procedure) if (procedure)
procedure->update_refs(); procedure->update_refs();
if (tmp_table->group) if (exec_tmp_table->group)
{ // Already grouped { // Already grouped
if (!order && !no_order) if (!order && !no_order)
order=group; /* order by group */ order= group_list; /* order by group */
group=0; group_list= 0;
} }
/* /*
...@@ -742,153 +783,196 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, ...@@ -742,153 +783,196 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
** like SEC_TO_TIME(SUM(...)). ** 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 && (select_distinct &&
join.tmp_table_param.using_indirect_summary_function)) tmp_table_param.using_indirect_summary_function))
{ /* Must copy to another table */ { /* Must copy to another table */
TABLE *tmp_table2; TABLE *tmp_table2;
DBUG_PRINT("info",("Creating group table")); DBUG_PRINT("info",("Creating group table"));
/* Free first data from old join */ /* Free first data from old join */
join_free(&join); join_free(this);
if (make_simple_join(&join,tmp_table)) if (make_simple_join(this, exec_tmp_table))
goto err; DBUG_VOID_RETURN;
calc_group_buffer(&join,group); calc_group_buffer(this, group_list);
count_field_types(&join.tmp_table_param,all_fields, count_field_types(&tmp_table_param, all_fields,
select_distinct && !group); select_distinct && !group_list);
join.tmp_table_param.hidden_field_count=(all_fields.elements- tmp_table_param.hidden_field_count= (all_fields.elements-
fields.elements); fields_list.elements);
/* group data to new table */ /* 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, (ORDER*) 0,
select_distinct && !group, select_distinct && !group_list,
1, 0, 1, 0,
join.select_options, unit))) select_options, unit)))
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
if (group) if (group_list)
{ {
thd->proc_info="Creating sort index"; thd->proc_info="Creating sort index";
if (create_sort_index(join.join_tab,group,HA_POS_ERROR) || if (create_sort_index(join_tab, group_list, HA_POS_ERROR) ||
alloc_group_fields(&join,group)) alloc_group_fields(this, group_list))
{ {
free_tmp_table(thd,tmp_table2); /* purecov: inspected */ 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"; thd->proc_info="Copying to group table";
tmp_error= -1; tmp_error= -1;
if (make_sum_func_list(&join,all_fields) || if (make_sum_func_list(this, all_fields) ||
(tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0))) (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0)))
{ {
error=tmp_error; error=tmp_error;
free_tmp_table(thd,tmp_table2); free_tmp_table(thd,tmp_table2);
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
} }
end_read_record(&join.join_tab->read_record); end_read_record(&join_tab->read_record);
free_tmp_table(thd,tmp_table); free_tmp_table(thd,exec_tmp_table);
join.const_tables=join.tables; // Mark free for join_free() const_tables= tables; // Mark free for join_free()
tmp_table=tmp_table2; exec_tmp_table= tmp_table2;
join.join_tab[0].table=0; // Table is freed join_tab[0].table= 0; // Table is freed
if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore
goto err; DBUG_VOID_RETURN;
join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count; tmp_table_param.field_count+= tmp_table_param.sum_func_count;
join.tmp_table_param.sum_func_count=0; tmp_table_param.sum_func_count= 0;
} }
if (tmp_table->distinct) if (exec_tmp_table->distinct)
select_distinct=0; /* Each row is unique */ select_distinct=0; /* Each row is unique */
join_free(&join); /* Free quick selects */ join_free(this); /* Free quick selects */
if (select_distinct && ! group) if (select_distinct && ! group_list)
{ {
thd->proc_info="Removing duplicates"; thd->proc_info="Removing duplicates";
if (having) if (having_list)
having->update_used_tables(); having_list->update_used_tables();
if (remove_duplicates(&join,tmp_table,fields, having)) if (remove_duplicates(this, exec_tmp_table, fields_list, having_list))
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
having=0; having_list=0;
select_distinct=0; select_distinct=0;
} }
tmp_table->reginfo.lock_type=TL_UNLOCK; exec_tmp_table->reginfo.lock_type=TL_UNLOCK;
if (make_simple_join(&join,tmp_table)) if (make_simple_join(this, exec_tmp_table))
goto err; DBUG_VOID_RETURN;
calc_group_buffer(&join,group); calc_group_buffer(this, group_list);
count_field_types(&join.tmp_table_param,all_fields,0); count_field_types(&tmp_table_param, all_fields, 0);
} }
if (procedure) if (procedure)
{ {
if (procedure->change_columns(fields) || if (procedure->change_columns(fields_list) ||
result->prepare(fields, unit)) result->prepare(fields_list, unit))
goto err; DBUG_VOID_RETURN;
count_field_types(&join.tmp_table_param, all_fields, 0); 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))) (procedure && (procedure->flags & PROC_GROUP)))
{ {
alloc_group_fields(&join,group); alloc_group_fields(this, group_list);
setup_copy_fields(thd, &join.tmp_table_param,all_fields); setup_copy_fields(thd, &tmp_table_param,all_fields);
if (make_sum_func_list(&join,all_fields) || thd->fatal_error) if (make_sum_func_list(this, all_fields) || thd->fatal_error)
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
} }
if (group || order) if (group_list || order)
{ {
DBUG_PRINT("info",("Sorting for send_fields")); DBUG_PRINT("info",("Sorting for send_fields"));
thd->proc_info="Sorting result"; thd->proc_info="Sorting result";
/* If we have already done the group, add HAVING to sorted table */ /* 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 having_list->update_used_tables(); // Some tables may have been const
JOIN_TAB *table=&join.join_tab[join.const_tables]; JOIN_TAB *table= &join_tab[const_tables];
table_map used_tables= join.const_table_map | table->table->map; 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 (sort_table_cond)
{ {
if (!table->select) if (!table->select)
if (!(table->select=new SQL_SELECT)) if (!(table->select=new SQL_SELECT))
goto err; DBUG_VOID_RETURN;
if (!table->select->cond) if (!table->select->cond)
table->select->cond=sort_table_cond; table->select->cond=sort_table_cond;
else // This should never happen else // This should never happen
if (!(table->select->cond=new Item_cond_and(table->select->cond, if (!(table->select->cond=new Item_cond_and(table->select->cond,
sort_table_cond))) sort_table_cond)))
goto err; DBUG_VOID_RETURN;
table->select_cond=table->select->cond; table->select_cond=table->select->cond;
DBUG_EXECUTE("where",print_where(table->select->cond, DBUG_EXECUTE("where",print_where(table->select->cond,
"select and having");); "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");); DBUG_EXECUTE("where",print_where(conds,"having after sort"););
} }
} }
if (create_sort_index(&join.join_tab[join.const_tables], if (create_sort_index(&join_tab[const_tables],
group ? group : order, group_list ? group_list : order,
(having || group || (having_list || group_list ||
join.const_tables != join.tables - 1 || const_tables != tables - 1 ||
(join.select_options & OPTION_FOUND_ROWS)) ? (select_options & OPTION_FOUND_ROWS)) ?
HA_POS_ERROR : unit->select_limit_cnt)) HA_POS_ERROR : unit->select_limit_cnt))
goto err; /* purecov: inspected */ DBUG_VOID_RETURN;
} }
join.having=having; // Actually a parameter having=having_list; // Actually a parameter
thd->proc_info="Sending data"; 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; Clean up join. Return error that hold JOIN.
thd->examined_row_count = join.examined_rows; */
thd->proc_info="end";
join.lock=0; // It's faster to unlock later int
join_free(&join); JOIN::cleanup(THD *thd)
thd->proc_info="end2"; // QQ {
if (tmp_table) lock=0; // It's faster to unlock later
free_tmp_table(thd,tmp_table); join_free(this);
thd->proc_info="end3"; // QQ if (exec_tmp_table)
free_tmp_table(thd, exec_tmp_table);
delete select; delete select;
delete_dynamic(&keyuse); delete_dynamic(&keyuse);
delete procedure; 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); DBUG_RETURN(error);
} }
...@@ -2538,7 +2622,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) ...@@ -2538,7 +2622,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
static void static void
make_join_readinfo(JOIN *join,uint options) make_join_readinfo(JOIN *join, uint options)
{ {
uint i; uint i;
SELECT_LEX *select_lex = &(join->thd->lex.select_lex); SELECT_LEX *select_lex = &(join->thd->lex.select_lex);
......
***************
*** 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;
...@@ -149,8 +149,7 @@ class TMP_TABLE_PARAM { ...@@ -149,8 +149,7 @@ class TMP_TABLE_PARAM {
} }
}; };
class JOIN :public Sql_alloc{
class JOIN {
public: public:
JOIN_TAB *join_tab,**best_ref,**map2table; JOIN_TAB *join_tab,**best_ref,**map2table;
TABLE **table,**all_tables,*sort_by_table; TABLE **table,**all_tables,*sort_by_table;
...@@ -175,6 +174,70 @@ class JOIN { ...@@ -175,6 +174,70 @@ class JOIN {
MYSQL_LOCK *lock; MYSQL_LOCK *lock;
// unit structure (with global parameters) for this select // unit structure (with global parameters) for this select
SELECT_LEX_UNIT *unit; 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
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();
void exec();
int cleanup(THD *thd);
}; };
......
***************
*** 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);
...@@ -40,17 +40,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) ...@@ -40,17 +40,6 @@ int mysql_union(THD *thd, LEX *lex,select_result *result)
DBUG_ENTER("mysql_union"); DBUG_ENTER("mysql_union");
st_select_lex_node * global; st_select_lex_node * global;
/* Fix tables 'to-be-unioned-from' list to point at opened tables */
for (sl= &lex->select_lex;
sl;
sl= (SELECT_LEX *) sl->next)
{
for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
cursor;
cursor=cursor->next)
cursor->table= cursor->table_list->table;
}
/* Global option */ /* Global option */
if (((void*)(global= unit->global_parameters)) == ((void*)unit)) if (((void*)(global= unit->global_parameters)) == ((void*)unit))
{ {
......
...@@ -544,7 +544,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -544,7 +544,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr 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 table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
using_list using_list subselect subselect_init
%type <item_list> %type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg 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); ...@@ -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 table_to_table_list table_to_table opt_table_list opt_as
handler_rkey_function handler_read_or_scan handler_rkey_function handler_read_or_scan
single_multi table_wild_list table_wild_one opt_wild union union_list 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 END_OF_INPUT
%type <NONE> %type <NONE>
...@@ -1547,8 +1547,8 @@ optional_braces: ...@@ -1547,8 +1547,8 @@ optional_braces:
| '(' ')' {} | '(' ')' {}
/* all possible expressions */ /* all possible expressions */
expr: expr_expr {$$ = $1; } expr: expr_expr { $$= $1; }
| simple_expr {$$ = $1; } | simple_expr { $$= $1; }
/* expressions that begin with 'expr' */ /* expressions that begin with 'expr' */
expr_expr: expr_expr:
...@@ -1688,6 +1688,7 @@ simple_expr: ...@@ -1688,6 +1688,7 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); } | NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); } | '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; } | '(' expr ')' { $$= $2; }
| subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; } | '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')' | MATCH ident_list_arg AGAINST '(' expr ')'
{ Select->ftfunc_list.push_back((Item_func_match *) { Select->ftfunc_list.push_back((Item_func_match *)
...@@ -3849,3 +3850,30 @@ optional_order_or_limit: ...@@ -3849,3 +3850,30 @@ optional_order_or_limit:
union_option: union_option:
/* empty */ {} /* empty */ {}
| ALL {Lex->union_option=1;} | 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 = (SELECT_LEX*)lex->select->master->master;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment