mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 03:52:35 +01:00
subselect with union
new error handling Item_ref bug fixed include/mysql_com.h: new error handling query cache pointer description mysql-test/r/distinct.result: new result's after Monty's bug fixing mysql-test/r/subselect.result: subselect with union test mysql-test/t/subselect.test: subselect with union test sql/item.cc: subselect with union Item_ref bug fixed sql/item_cmpfunc.cc: Monty's bug fixing sql/item_subselect.cc: TODO changing subselect with union sql/item_subselect.h: subselect with union sql/mysql_priv.h: Item_ref bug fixed sql/mysqld.cc: new error handling sql/net_pkg.cc: new error handling sql/net_serv.cc: new error handling sql/sql_base.cc: Item_ref bug fixed sql/sql_class.cc: new error handling sql/sql_class.h: new error handling sql/sql_derived.cc: subselect with union sql/sql_insert.cc: new error handling (only with mysql_select now) sql/sql_lex.cc: subselect with union sql/sql_lex.h: subselect with union sql/sql_parse.cc: new error handling sql/sql_select.cc: new error handling subselect with union removed thd->where=0 hack sql/sql_select.h: subselect with union sql/sql_union.cc: subselect with union sql/sql_update.cc: new error handling (only with mysql_select now) sql/sql_yacc.yy: subselect with union
This commit is contained in:
parent
1648e47889
commit
3fbcafea9c
25 changed files with 686 additions and 382 deletions
|
@ -132,7 +132,12 @@ typedef struct st_net {
|
|||
unsigned int *return_status;
|
||||
unsigned char reading_or_writing;
|
||||
char save_char;
|
||||
my_bool report_error; /* We should report error (we have unreported error) */
|
||||
my_bool no_send_ok;
|
||||
/*
|
||||
Pointer to query object in query cache, do not equal NULL (0) for
|
||||
queries in cache that have not stored its results yet
|
||||
*/
|
||||
gptr query_cache_query;
|
||||
} NET;
|
||||
|
||||
|
|
|
@ -92,7 +92,8 @@ NULL NULL NULL
|
|||
0 0
|
||||
select id >= 0 and id <= 5 as grp,count(*) from t1 group by grp;
|
||||
grp count(*)
|
||||
0 7
|
||||
NULL 1
|
||||
0 6
|
||||
1 6
|
||||
SELECT DISTINCT FACILITY FROM t1;
|
||||
FACILITY
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
select (select 2);
|
||||
(select 2)
|
||||
2
|
||||
drop table if exists t1,t2,t3,t4;
|
||||
drop table if exists t1,t2,t3,t4,t5;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int, b int);
|
||||
create table t3 (a int);
|
||||
|
@ -82,4 +82,21 @@ select b,max(a) as ma from t4 group by b having b >= (select max(t2.a)
|
|||
from t2 where t2.b=t4.b);
|
||||
b ma
|
||||
7 12
|
||||
drop table t1,t2,t3,t4;
|
||||
create table t5 (a int);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a
|
||||
NULL 1
|
||||
2 2
|
||||
insert into t5 values (5);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a
|
||||
NULL 1
|
||||
2 2
|
||||
insert into t5 values (2);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
(select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a) a
|
||||
NULL 1
|
||||
2 2
|
||||
select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2;
|
||||
Subselect return more than 1 record
|
||||
drop table t1,t2,t3,t4,t5;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
select (select 2);
|
||||
drop table if exists t1,t2,t3,t4;
|
||||
drop table if exists t1,t2,t3,t4,t5;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int, b int);
|
||||
create table t3 (a int);
|
||||
|
@ -33,4 +33,12 @@ select b,max(a) as ma from t4 group by b having b < (select max(t2.a)
|
|||
from t2 where t2.b=t4.b);
|
||||
select b,max(a) as ma from t4 group by b having b >= (select max(t2.a)
|
||||
from t2 where t2.b=t4.b);
|
||||
drop table t1,t2,t3,t4;
|
||||
create table t5 (a int);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
insert into t5 values (5);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
insert into t5 values (2);
|
||||
select (select a from t1 where t1.a=t2.a union select a from t5 where t5.a=t2.a), a from t2;
|
||||
-- error 1230
|
||||
select (select a from t1 where t1.a=t2.a union all select a from t5 where t5.a=t2.a), a from t2;
|
||||
drop table t1,t2,t3,t4,t5;
|
||||
|
|
25
sql/item.cc
25
sql/item.cc
|
@ -457,7 +457,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||
if (!field) // If field is not checked
|
||||
{
|
||||
Field *tmp;
|
||||
if (!(tmp=find_field_in_tables(thd,this,tables)))
|
||||
if (!(tmp=find_field_in_tables(thd, this, tables, 0)))
|
||||
{
|
||||
/*
|
||||
We can't find table field in table list of current select,
|
||||
|
@ -473,9 +473,14 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||
sl && !tmp;
|
||||
sl= sl->outer_select())
|
||||
tmp=find_field_in_tables(thd, this,
|
||||
(TABLE_LIST*)(last= sl)->table_list.first);
|
||||
(TABLE_LIST*)(last= sl)->table_list.first,
|
||||
0);
|
||||
if (!tmp)
|
||||
return 1;
|
||||
{
|
||||
// Call to produce appropriate error message
|
||||
find_field_in_tables(thd, this, tables, 1);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
depended_from= last;
|
||||
|
@ -488,7 +493,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||
s= s->outer_select())
|
||||
if( !s->depended )
|
||||
{
|
||||
s->depended= 1; //Select is depended of outer select
|
||||
// Select is depended of outer select
|
||||
s->depended= s->master_unit()->depended= 1;
|
||||
//Tables will be reopened many times
|
||||
for (TABLE_LIST *tbl=
|
||||
(TABLE_LIST*)s->table_list.first;
|
||||
|
@ -803,7 +809,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
|
|||
{
|
||||
if (!ref)
|
||||
{
|
||||
if (!(ref= find_item_in_list(this,thd->lex.select->item_list)))
|
||||
if (!(ref= find_item_in_list(this, thd->lex.select->item_list, 0)))
|
||||
{
|
||||
/*
|
||||
We can't find table field in table list of current select,
|
||||
|
@ -818,9 +824,13 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
|
|||
for (SELECT_LEX *sl= thd->lex.select->outer_select();
|
||||
sl && !ref;
|
||||
sl= sl->outer_select())
|
||||
ref= find_item_in_list(this, (last= sl)->item_list);
|
||||
ref= find_item_in_list(this, (last= sl)->item_list, 0);
|
||||
if (!ref)
|
||||
{
|
||||
// Call to report error
|
||||
find_item_in_list(this, thd->lex.select->item_list, 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
depended_from= last;
|
||||
|
@ -833,7 +843,8 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
|
|||
s= s->outer_select())
|
||||
if( !s->depended )
|
||||
{
|
||||
s->depended= 1; //Select is depended of outer select
|
||||
// Select is depended of outer select
|
||||
s->depended= s->master_unit()->depended= 1;
|
||||
//Tables will be reopened many times
|
||||
for (TABLE_LIST *tbl=
|
||||
(TABLE_LIST*)s->table_list.first;
|
||||
|
|
|
@ -1101,6 +1101,8 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
|||
used_tables_cache|=item->used_tables();
|
||||
with_sum_func= with_sum_func || item->with_sum_func;
|
||||
const_item_cache&=item->const_item();
|
||||
if (item->maybe_null)
|
||||
maybe_null=1;
|
||||
}
|
||||
if (thd)
|
||||
thd->cond_count+=list.elements;
|
||||
|
|
|
@ -23,9 +23,6 @@ SUBSELECT TODO:
|
|||
- remove double 'having' & 'having_list' from JOIN
|
||||
(sql_select.h/sql_select.cc)
|
||||
|
||||
- subselect in HAVING clause
|
||||
- add subselect union select (sql_union.cc)
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
@ -37,21 +34,17 @@ SUBSELECT TODO:
|
|||
|
||||
Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
|
||||
select_subselect *result):
|
||||
assigned(0), executed(0), optimized(0), error(0)
|
||||
engine_owner(1), value_assigned(0)
|
||||
{
|
||||
DBUG_ENTER("Item_subselect::Item_subselect");
|
||||
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
|
||||
this->result= result;
|
||||
SELECT_LEX_UNIT *unit= select_lex->master_unit();
|
||||
unit->offset_limit_cnt= unit->global_parameters->offset_limit;
|
||||
unit->select_limit_cnt= unit->global_parameters->select_limit+
|
||||
unit->global_parameters ->offset_limit;
|
||||
if (unit->select_limit_cnt < unit->global_parameters->select_limit)
|
||||
unit->select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (unit->select_limit_cnt == HA_POS_ERROR)
|
||||
select_lex->options&= ~OPTION_FOUND_ROWS;
|
||||
join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
|
||||
this->select_lex= select_lex;
|
||||
|
||||
if (select_lex->next_select())
|
||||
engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
|
||||
this);
|
||||
else
|
||||
engine= new subselect_single_select_engine(thd, select_lex, result,
|
||||
this);
|
||||
assign_null();
|
||||
/*
|
||||
item value is NULL if select_subselect not changed this value
|
||||
|
@ -61,6 +54,12 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
Item_subselect::~Item_subselect()
|
||||
{
|
||||
if (engine_owner)
|
||||
delete engine;
|
||||
}
|
||||
|
||||
void Item_subselect::make_field (Send_field *tmp_field)
|
||||
{
|
||||
if (null_value)
|
||||
|
@ -78,62 +77,17 @@ void Item_subselect::make_field (Send_field *tmp_field)
|
|||
bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
||||
{
|
||||
// Is it one field subselect?
|
||||
if (select_lex->item_list.elements > max_columns)
|
||||
if (engine->cols() > max_columns)
|
||||
{
|
||||
my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
|
||||
my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
|
||||
return 1;
|
||||
}
|
||||
SELECT_LEX *save_select= thd->lex.select;
|
||||
thd->lex.select= select_lex;
|
||||
if(join->prepare((TABLE_LIST*) select_lex->table_list.first,
|
||||
select_lex->where,
|
||||
(ORDER*) select_lex->order_list.first,
|
||||
(ORDER*) select_lex->group_list.first,
|
||||
select_lex->having,
|
||||
(ORDER*) 0, select_lex,
|
||||
select_lex->master_unit()))
|
||||
return 1;
|
||||
thd->lex.select= save_select;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Item_subselect::exec()
|
||||
{
|
||||
DBUG_ENTER("Item_subselect::exec");
|
||||
if (!optimized)
|
||||
{
|
||||
optimized=1;
|
||||
if (join->optimize())
|
||||
{
|
||||
executed= 1;
|
||||
DBUG_RETURN(join->error?join->error:1);
|
||||
}
|
||||
}
|
||||
if (join->select_lex->depended && executed)
|
||||
{
|
||||
if (join->reinit())
|
||||
{
|
||||
error= 1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
assign_null();
|
||||
executed= assigned= 0;
|
||||
}
|
||||
if (!executed)
|
||||
{
|
||||
SELECT_LEX *save_select= join->thd->lex.select;
|
||||
join->thd->lex.select= select_lex;
|
||||
join->exec();
|
||||
join->thd->lex.select= save_select;
|
||||
executed= 1;
|
||||
DBUG_RETURN(join->error);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
return engine->prepare();
|
||||
}
|
||||
|
||||
inline table_map Item_subselect::used_tables() const
|
||||
{
|
||||
return (table_map) select_lex->depended ? 1L : 0L;
|
||||
return (table_map) engine->depended() ? 1L : 0L;
|
||||
}
|
||||
|
||||
Item_singleval_subselect::Item_singleval_subselect(THD *thd,
|
||||
|
@ -151,21 +105,21 @@ Item::Type Item_subselect::type() const
|
|||
|
||||
double Item_singleval_subselect::val ()
|
||||
{
|
||||
if (exec())
|
||||
if (engine->exec())
|
||||
return 0;
|
||||
return real_value;
|
||||
}
|
||||
|
||||
longlong Item_singleval_subselect::val_int ()
|
||||
{
|
||||
if (exec())
|
||||
if (engine->exec())
|
||||
return 0;
|
||||
return int_value;
|
||||
}
|
||||
|
||||
String *Item_singleval_subselect::val_str (String *str)
|
||||
{
|
||||
if (exec() || null_value)
|
||||
if (engine->exec() || null_value)
|
||||
return 0;
|
||||
return &str_value;
|
||||
}
|
||||
|
@ -183,23 +137,143 @@ Item_exists_subselect::Item_exists_subselect(THD *thd,
|
|||
|
||||
double Item_exists_subselect::val ()
|
||||
{
|
||||
if (exec())
|
||||
if (engine->exec())
|
||||
return 0;
|
||||
return (double) value;
|
||||
}
|
||||
|
||||
longlong Item_exists_subselect::val_int ()
|
||||
{
|
||||
if (exec())
|
||||
if (engine->exec())
|
||||
return 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
String *Item_exists_subselect::val_str(String *str)
|
||||
{
|
||||
if (exec())
|
||||
if (engine->exec())
|
||||
return 0;
|
||||
str->set(value);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
subselect_single_select_engine::subselect_single_select_engine(THD *thd,
|
||||
st_select_lex *select,
|
||||
select_subselect *result,
|
||||
Item_subselect *item):
|
||||
subselect_engine(thd, item, result),
|
||||
executed(0), optimized(0)
|
||||
{
|
||||
select_lex= select;
|
||||
SELECT_LEX_UNIT *unit= select_lex->master_unit();
|
||||
unit->offset_limit_cnt= unit->global_parameters->offset_limit;
|
||||
unit->select_limit_cnt= unit->global_parameters->select_limit+
|
||||
unit->global_parameters ->offset_limit;
|
||||
if (unit->select_limit_cnt < unit->global_parameters->select_limit)
|
||||
unit->select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (unit->select_limit_cnt == HA_POS_ERROR)
|
||||
select_lex->options&= ~OPTION_FOUND_ROWS;
|
||||
join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
|
||||
if (!join || !result)
|
||||
{
|
||||
//out of memory
|
||||
thd->fatal_error= 1;
|
||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||
}
|
||||
this->select_lex= select_lex;
|
||||
}
|
||||
|
||||
subselect_union_engine::subselect_union_engine(THD *thd,
|
||||
st_select_lex_unit *u,
|
||||
select_subselect *result,
|
||||
Item_subselect *item):
|
||||
subselect_engine(thd, item, result)
|
||||
{
|
||||
unit= u;
|
||||
if( !result)
|
||||
{
|
||||
//out of memory
|
||||
thd->fatal_error= 1;
|
||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||
}
|
||||
unit->item= item;
|
||||
}
|
||||
|
||||
int subselect_single_select_engine::prepare()
|
||||
{
|
||||
SELECT_LEX *save_select= thd->lex.select;
|
||||
thd->lex.select= select_lex;
|
||||
if(join->prepare((TABLE_LIST*) select_lex->table_list.first,
|
||||
select_lex->where,
|
||||
(ORDER*) select_lex->order_list.first,
|
||||
(ORDER*) select_lex->group_list.first,
|
||||
select_lex->having,
|
||||
(ORDER*) 0, select_lex,
|
||||
select_lex->master_unit(), 0))
|
||||
return 1;
|
||||
thd->lex.select= save_select;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int subselect_union_engine::prepare()
|
||||
{
|
||||
return unit->prepare(thd, result);
|
||||
}
|
||||
|
||||
|
||||
int subselect_single_select_engine::exec()
|
||||
{
|
||||
DBUG_ENTER("subselect_single_select_engine::exec");
|
||||
if (!optimized)
|
||||
{
|
||||
optimized=1;
|
||||
if (join->optimize())
|
||||
{
|
||||
executed= 1;
|
||||
DBUG_RETURN(join->error?join->error:1);
|
||||
}
|
||||
}
|
||||
if (select_lex->depended && executed)
|
||||
{
|
||||
if (join->reinit())
|
||||
DBUG_RETURN(1);
|
||||
item->assign_null();
|
||||
item->assigned((executed= 0));
|
||||
}
|
||||
if (!executed)
|
||||
{
|
||||
SELECT_LEX *save_select= join->thd->lex.select;
|
||||
join->thd->lex.select= select_lex;
|
||||
join->exec();
|
||||
join->thd->lex.select= save_select;
|
||||
executed= 1;
|
||||
DBUG_RETURN(join->error||thd->fatal_error);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
int subselect_union_engine::exec()
|
||||
{
|
||||
return unit->exec();
|
||||
}
|
||||
|
||||
uint subselect_single_select_engine::cols()
|
||||
{
|
||||
return select_lex->item_list.elements;
|
||||
}
|
||||
|
||||
uint subselect_union_engine::cols()
|
||||
{
|
||||
return unit->first_select()->item_list.elements;
|
||||
}
|
||||
|
||||
bool subselect_single_select_engine::depended()
|
||||
{
|
||||
return select_lex->depended;
|
||||
}
|
||||
|
||||
bool subselect_union_engine::depended()
|
||||
{
|
||||
return unit->depended;
|
||||
}
|
||||
|
|
|
@ -20,31 +20,25 @@
|
|||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
struct st_select_lex;
|
||||
class st_select_lex;
|
||||
class st_select_lex_unit;
|
||||
class JOIN;
|
||||
class select_subselect;
|
||||
class subselect_engine;
|
||||
|
||||
/* base class for subselects */
|
||||
|
||||
class Item_subselect :public Item
|
||||
{
|
||||
my_bool engine_owner; /* Is this item owner of engine */
|
||||
my_bool value_assigned; /* value already assigned to subselect */
|
||||
protected:
|
||||
/* engine that perform execution of subselect (single select or union) */
|
||||
subselect_engine *engine;
|
||||
/* allowed number of columns (1 for single value subqueries) */
|
||||
uint max_columns;
|
||||
my_bool assigned; /* value already assigned to subselect */
|
||||
my_bool executed; /* simple subselect is executed */
|
||||
my_bool optimized; /* simple subselect is optimized */
|
||||
my_bool error; /* error in query */
|
||||
|
||||
int exec();
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
}
|
||||
public:
|
||||
st_select_lex *select_lex;
|
||||
JOIN *join;
|
||||
select_subselect *result;
|
||||
|
||||
Item_subselect(THD *thd, st_select_lex *select_lex,
|
||||
select_subselect* result);
|
||||
Item_subselect(Item_subselect *item)
|
||||
|
@ -52,14 +46,17 @@ public:
|
|||
null_value= item->null_value;
|
||||
decimals= item->decimals;
|
||||
max_columns= item->max_columns;
|
||||
assigned= item->assigned;
|
||||
executed= item->executed;
|
||||
select_lex= item->select_lex;
|
||||
join= item->join;
|
||||
result= item->result;
|
||||
engine= item->engine;
|
||||
engine_owner= 0;
|
||||
name= item->name;
|
||||
error= item->error;
|
||||
}
|
||||
~Item_subselect();
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
}
|
||||
bool assigned() { return value_assigned; }
|
||||
void assigned(bool a) { value_assigned= a; }
|
||||
enum Type type() const;
|
||||
bool is_null() { return null_value; }
|
||||
void make_field (Send_field *);
|
||||
|
@ -75,18 +72,10 @@ public:
|
|||
class Item_singleval_subselect :public Item_subselect
|
||||
{
|
||||
protected:
|
||||
longlong int_value;
|
||||
double real_value;
|
||||
enum Item_result res_type;
|
||||
longlong int_value; /* here stored integer value of this item */
|
||||
double real_value; /* here stored real value of this item */
|
||||
enum Item_result res_type; /* type of results */
|
||||
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
int_value= 0;
|
||||
real_value= 0;
|
||||
max_length= 4;
|
||||
res_type= STRING_RESULT;
|
||||
}
|
||||
public:
|
||||
Item_singleval_subselect(THD *thd, st_select_lex *select_lex);
|
||||
Item_singleval_subselect(Item_singleval_subselect *item):
|
||||
|
@ -98,6 +87,14 @@ public:
|
|||
decimals= item->decimals;
|
||||
res_type= item->res_type;
|
||||
}
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
int_value= 0;
|
||||
real_value= 0;
|
||||
max_length= 4;
|
||||
res_type= STRING_RESULT;
|
||||
}
|
||||
double val ();
|
||||
longlong val_int ();
|
||||
String *val_str (String *);
|
||||
|
@ -112,12 +109,8 @@ public:
|
|||
class Item_exists_subselect :public Item_subselect
|
||||
{
|
||||
protected:
|
||||
longlong value;
|
||||
longlong value; /* value of this item (boolean: exists/not-exists) */
|
||||
|
||||
virtual void assign_null()
|
||||
{
|
||||
value= 0;
|
||||
}
|
||||
public:
|
||||
Item_exists_subselect(THD *thd, st_select_lex *select_lex);
|
||||
Item_exists_subselect(Item_exists_subselect *item):
|
||||
|
@ -125,6 +118,11 @@ public:
|
|||
{
|
||||
value= item->value;
|
||||
}
|
||||
virtual void assign_null()
|
||||
{
|
||||
value= 0;
|
||||
}
|
||||
|
||||
Item *new_item() { return new Item_exists_subselect(this); }
|
||||
enum Item_result result_type() const { return INT_RESULT;}
|
||||
longlong val_int();
|
||||
|
@ -133,3 +131,58 @@ public:
|
|||
|
||||
friend class select_exists_subselect;
|
||||
};
|
||||
|
||||
class subselect_engine
|
||||
{
|
||||
protected:
|
||||
select_subselect *result; /* results storage class */
|
||||
THD *thd; /* pointer to current THD */
|
||||
Item_subselect *item; /* item, that use this engine */
|
||||
public:
|
||||
static void *operator new(size_t size)
|
||||
{
|
||||
return (void*) sql_alloc((uint) size);
|
||||
}
|
||||
static void operator delete(void *ptr, size_t size) {}
|
||||
|
||||
subselect_engine(THD *thd, Item_subselect *si, select_subselect *res)
|
||||
{
|
||||
result= res;
|
||||
item= si;
|
||||
this->thd= thd;
|
||||
}
|
||||
virtual int prepare()= 0;
|
||||
virtual int exec()= 0;
|
||||
virtual uint cols()= 0; /* return number of columnss in select */
|
||||
virtual bool depended()= 0; /* depended from outer select */
|
||||
};
|
||||
|
||||
class subselect_single_select_engine: public subselect_engine
|
||||
{
|
||||
my_bool executed; /* simple subselect is executed */
|
||||
my_bool optimized; /* simple subselect is optimized */
|
||||
st_select_lex *select_lex; /* corresponding select_lex */
|
||||
JOIN * join; /* corresponding JOIN structure */
|
||||
public:
|
||||
subselect_single_select_engine(THD *thd, st_select_lex *select,
|
||||
select_subselect *result,
|
||||
Item_subselect *item);
|
||||
virtual int prepare();
|
||||
virtual int exec();
|
||||
virtual uint cols();
|
||||
virtual bool depended();
|
||||
};
|
||||
|
||||
class subselect_union_engine: public subselect_engine
|
||||
{
|
||||
st_select_lex_unit *unit; /* corresponding unit structure */
|
||||
public:
|
||||
subselect_union_engine(THD *thd,
|
||||
st_select_lex_unit *u,
|
||||
select_subselect *result,
|
||||
Item_subselect *item);
|
||||
virtual int prepare();
|
||||
virtual int exec();
|
||||
virtual uint cols();
|
||||
virtual bool depended();
|
||||
};
|
||||
|
|
|
@ -373,7 +373,7 @@ int handle_select(THD *thd, LEX *lex, select_result *result);
|
|||
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
|
||||
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
|
||||
ulong select_type,select_result *result,
|
||||
SELECT_LEX_UNIT *unit);
|
||||
SELECT_LEX_UNIT *unit, bool fake_select_lex);
|
||||
int mysql_union(THD *thd, LEX *lex,select_result *result);
|
||||
int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *s, TABLE_LIST *t);
|
||||
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
|
||||
|
@ -438,7 +438,8 @@ bool wait_for_tables(THD *thd);
|
|||
bool table_is_used(TABLE *table, bool wait_for_name_lock);
|
||||
bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
|
||||
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
|
||||
Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables);
|
||||
Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables,
|
||||
bool report_error);
|
||||
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
|
||||
bool check_grant,bool allow_rowid);
|
||||
#ifdef HAVE_OPENSSL
|
||||
|
@ -526,7 +527,7 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find);
|
|||
|
||||
SQL_SELECT *make_select(TABLE *head, table_map const_tables,
|
||||
table_map read_tables, COND *conds, int *error);
|
||||
Item ** find_item_in_list(Item *item,List<Item> &items);
|
||||
Item ** find_item_in_list(Item *item, List<Item> &items, bool report_error);
|
||||
bool insert_fields(THD *thd,TABLE_LIST *tables,
|
||||
const char *db_name, const char *table_name,
|
||||
List_iterator<Item> *it);
|
||||
|
|
|
@ -1608,8 +1608,9 @@ static int my_message_sql(uint error, const char *str,
|
|||
NET *net;
|
||||
DBUG_ENTER("my_message_sql");
|
||||
DBUG_PRINT("error",("Message: '%s'",str));
|
||||
if ((net=my_pthread_getspecific_ptr(NET*,THR_NET)))
|
||||
if ((net= my_pthread_getspecific_ptr(NET*,THR_NET)))
|
||||
{
|
||||
net->report_error= 1;
|
||||
if (!net->last_error[0]) // Return only first message
|
||||
{
|
||||
strmake(net->last_error,str,sizeof(net->last_error)-1);
|
||||
|
|
|
@ -72,7 +72,10 @@ void send_error(NET *net, uint sql_errno, const char *err)
|
|||
}
|
||||
VOID(net_write_command(net,(uchar) 255,(char*) err,length));
|
||||
if (thd)
|
||||
thd->fatal_error=0; // Error message is given
|
||||
{
|
||||
thd->fatal_error= 0; // Error message is given
|
||||
thd->net.report_error= 0;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,7 @@ int my_net_init(NET *net, Vio* vio)
|
|||
net->where_b = net->remain_in_buf=0;
|
||||
net->last_errno=0;
|
||||
net->query_cache_query=0;
|
||||
net->report_error= 0;
|
||||
|
||||
if (vio != 0) /* If real connection */
|
||||
{
|
||||
|
@ -141,8 +142,9 @@ static my_bool net_realloc(NET *net, ulong length)
|
|||
if (length >= max_allowed_packet)
|
||||
{
|
||||
DBUG_PRINT("error",("Packet too large (%lu)", length));
|
||||
net->error=1;
|
||||
net->last_errno=ER_NET_PACKET_TOO_LARGE;
|
||||
net->error= 1;
|
||||
net->report_error= 1;
|
||||
net->last_errno= ER_NET_PACKET_TOO_LARGE;
|
||||
return 1;
|
||||
}
|
||||
pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1);
|
||||
|
@ -152,9 +154,10 @@ static my_bool net_realloc(NET *net, ulong length)
|
|||
NET_HEADER_SIZE + COMP_HEADER_SIZE,
|
||||
MYF(MY_WME))))
|
||||
{
|
||||
net->error=1;
|
||||
net->error= 1;
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_OUT_OF_RESOURCES;
|
||||
net->last_errno= ER_OUT_OF_RESOURCES;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
@ -348,10 +351,12 @@ net_real_write(NET *net,const char *packet,ulong len)
|
|||
COMP_HEADER_SIZE, MYF(MY_WME))))
|
||||
{
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_OUT_OF_RESOURCES;
|
||||
net->error=2;
|
||||
net->last_errno= ER_OUT_OF_RESOURCES;
|
||||
net->error= 2;
|
||||
//TODO is it needed to set this variable if we have no socket
|
||||
net->report_error= 1;
|
||||
#endif
|
||||
net->reading_or_writing=0;
|
||||
net->reading_or_writing= 0;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
memcpy(b+header_length,packet,len);
|
||||
|
@ -401,7 +406,8 @@ net_real_write(NET *net,const char *packet,ulong len)
|
|||
"%s: my_net_write: fcntl returned error %d, aborting thread\n",
|
||||
my_progname,vio_errno(net->vio));
|
||||
#endif /* EXTRA_DEBUG */
|
||||
net->error=2; /* Close socket */
|
||||
net->error= 2; /* Close socket */
|
||||
net->report_error= 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -428,7 +434,8 @@ net_real_write(NET *net,const char *packet,ulong len)
|
|||
continue;
|
||||
}
|
||||
#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
|
||||
net->error=2; /* Close socket */
|
||||
net->error= 2; /* Close socket */
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
|
||||
ER_NET_ERROR_ON_WRITE);
|
||||
|
@ -562,9 +569,10 @@ my_real_read(NET *net, ulong *complen)
|
|||
my_progname,vio_errno(net->vio));
|
||||
#endif /* EXTRA_DEBUG */
|
||||
len= packet_error;
|
||||
net->error=2; /* Close socket */
|
||||
net->error= 2; /* Close socket */
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_NET_FCNTL_ERROR;
|
||||
net->last_errno= ER_NET_FCNTL_ERROR;
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
@ -593,7 +601,8 @@ my_real_read(NET *net, ulong *complen)
|
|||
#endif
|
||||
DBUG_PRINT("error",("Couldn't read packet: remain: %lu errno: %d length: %ld alarmed: %d", remain,vio_errno(net->vio),length,alarmed));
|
||||
len= packet_error;
|
||||
net->error=2; /* Close socket */
|
||||
net->error= 2; /* Close socket */
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED :
|
||||
ER_NET_READ_ERROR);
|
||||
|
@ -622,6 +631,7 @@ my_real_read(NET *net, ulong *complen)
|
|||
#endif
|
||||
}
|
||||
len= packet_error;
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER;
|
||||
#endif
|
||||
|
@ -794,7 +804,8 @@ my_net_read(NET *net)
|
|||
if (my_uncompress((byte*) net->buff + net->where_b, &packet_len,
|
||||
&complen))
|
||||
{
|
||||
net->error=2; /* caller will close socket */
|
||||
net->error= 2; /* caller will close socket */
|
||||
net->report_error= 1;
|
||||
#ifdef MYSQL_SERVER
|
||||
net->last_errno=ER_NET_UNCOMPRESS_ERROR;
|
||||
#endif
|
||||
|
|
|
@ -1711,7 +1711,8 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
|
|||
|
||||
|
||||
Field *
|
||||
find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
|
||||
find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables,
|
||||
bool report_error)
|
||||
{
|
||||
Field *found=0;
|
||||
const char *db=item->db_name;
|
||||
|
@ -1748,7 +1749,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
|
|||
}
|
||||
if (found)
|
||||
return found;
|
||||
if (!found_table)
|
||||
if (!found_table && report_error)
|
||||
{
|
||||
char buff[NAME_LEN*2+1];
|
||||
if (db)
|
||||
|
@ -1760,8 +1761,9 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
|
|||
thd->where);
|
||||
}
|
||||
else
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||
item->full_name(),thd->where);
|
||||
if (report_error)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||
item->full_name(),thd->where);
|
||||
return (Field*) 0;
|
||||
}
|
||||
bool allow_rowid= tables && !tables->next; // Only one table
|
||||
|
@ -1778,8 +1780,9 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
|
|||
{
|
||||
if (!thd->where) // Returns first found
|
||||
break;
|
||||
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
||||
name,thd->where);
|
||||
if (report_error)
|
||||
my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
|
||||
name,thd->where);
|
||||
return (Field*) 0;
|
||||
}
|
||||
found=field;
|
||||
|
@ -1787,13 +1790,14 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
|
|||
}
|
||||
if (found)
|
||||
return found;
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),
|
||||
MYF(0),item->full_name(),thd->where);
|
||||
if (report_error)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR),
|
||||
MYF(0), item->full_name(), thd->where);
|
||||
return (Field*) 0;
|
||||
}
|
||||
|
||||
Item **
|
||||
find_item_in_list(Item *find,List<Item> &items)
|
||||
find_item_in_list(Item *find,List<Item> &items, bool report_error)
|
||||
{
|
||||
List_iterator<Item> li(items);
|
||||
Item **found=0,*item;
|
||||
|
@ -1841,9 +1845,9 @@ find_item_in_list(Item *find,List<Item> &items)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (!found && current_thd->where)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
|
||||
find->full_name(),current_thd->where);
|
||||
if (!found && report_error)
|
||||
my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0),
|
||||
find->full_name(), current_thd->where);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
@ -2303,8 +2307,8 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name,
|
|||
|
||||
int setup_ftfuncs(THD *thd)
|
||||
{
|
||||
List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list),
|
||||
lj(thd->lex.select->ftfunc_list);
|
||||
List_iterator<Item_func_match> li(*(thd->lex.select->ftfunc_list)),
|
||||
lj(*(thd->lex.select->ftfunc_list));
|
||||
Item_func_match *ftf, *ftf2;
|
||||
|
||||
while ((ftf=li++))
|
||||
|
@ -2324,9 +2328,9 @@ int setup_ftfuncs(THD *thd)
|
|||
|
||||
int init_ftfuncs(THD *thd, bool no_order)
|
||||
{
|
||||
if (thd->lex.select->ftfunc_list.elements)
|
||||
if (thd->lex.select->ftfunc_list->elements)
|
||||
{
|
||||
List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list);
|
||||
List_iterator<Item_func_match> li(*(thd->lex.select->ftfunc_list));
|
||||
Item_func_match *ifm;
|
||||
DBUG_PRINT("info",("Performing FULLTEXT search"));
|
||||
thd->proc_info="FULLTEXT initialization";
|
||||
|
|
|
@ -407,13 +407,19 @@ bool select_send::send_data(List<Item> &items)
|
|||
if (item->send(thd, packet))
|
||||
{
|
||||
packet->free(); // Free used
|
||||
my_error(ER_OUT_OF_RESOURCES,MYF(0));
|
||||
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
}
|
||||
thd->sent_row_count++;
|
||||
bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length());
|
||||
DBUG_RETURN(error);
|
||||
if (!thd->net.report_error)
|
||||
{
|
||||
DBUG_RETURN(my_net_write(&thd->net,
|
||||
(char*) packet->ptr(),
|
||||
packet->length()));
|
||||
}
|
||||
else
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
bool select_send::send_eof()
|
||||
|
@ -423,8 +429,13 @@ bool select_send::send_eof()
|
|||
{
|
||||
mysql_unlock_tables(thd, thd->lock); thd->lock=0;
|
||||
}
|
||||
::send_eof(&thd->net);
|
||||
return 0;
|
||||
if (!thd->net.report_error)
|
||||
{
|
||||
::send_eof(&thd->net);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -460,7 +471,7 @@ select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
|
|||
option);
|
||||
if (!access(path,F_OK))
|
||||
{
|
||||
my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name);
|
||||
my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name);
|
||||
return 1;
|
||||
}
|
||||
/* Create the file world readable */
|
||||
|
@ -646,9 +657,9 @@ err:
|
|||
}
|
||||
|
||||
|
||||
void select_export::send_error(uint errcode,const char *err)
|
||||
void select_export::send_error(uint errcode, const char *err)
|
||||
{
|
||||
::send_error(&thd->net,errcode,err);
|
||||
my_message(errcode, err, MYF(0));;
|
||||
(void) end_io_cache(&cache);
|
||||
(void) my_close(file,MYF(0));
|
||||
file= -1;
|
||||
|
@ -660,9 +671,7 @@ bool select_export::send_eof()
|
|||
int error=test(end_io_cache(&cache));
|
||||
if (my_close(file,MYF(MY_WME)))
|
||||
error=1;
|
||||
if (error)
|
||||
::send_error(&thd->net);
|
||||
else
|
||||
if (!error)
|
||||
::send_ok(&thd->net,row_count);
|
||||
file= -1;
|
||||
return error;
|
||||
|
@ -735,7 +744,7 @@ bool select_dump::send_data(List<Item> &items)
|
|||
}
|
||||
if (row_count++ > 1)
|
||||
{
|
||||
my_error(ER_TOO_MANY_ROWS,MYF(0));
|
||||
my_error(ER_TOO_MANY_ROWS, MYF(0));
|
||||
goto err;
|
||||
}
|
||||
while ((item=li++))
|
||||
|
@ -760,7 +769,7 @@ err:
|
|||
|
||||
void select_dump::send_error(uint errcode,const char *err)
|
||||
{
|
||||
::send_error(&thd->net,errcode,err);
|
||||
my_message(errcode, err, MYF(0));
|
||||
(void) end_io_cache(&cache);
|
||||
(void) my_close(file,MYF(0));
|
||||
(void) my_delete(path,MYF(0)); // Delete file on error
|
||||
|
@ -772,9 +781,7 @@ bool select_dump::send_eof()
|
|||
int error=test(end_io_cache(&cache));
|
||||
if (my_close(file,MYF(MY_WME)))
|
||||
error=1;
|
||||
if (error)
|
||||
::send_error(&thd->net);
|
||||
else
|
||||
if (!error)
|
||||
::send_ok(&thd->net,row_count);
|
||||
file= -1;
|
||||
return error;
|
||||
|
@ -789,8 +796,9 @@ bool select_singleval_subselect::send_data(List<Item> &items)
|
|||
{
|
||||
DBUG_ENTER("select_singleval_subselect::send_data");
|
||||
Item_singleval_subselect *it= (Item_singleval_subselect *)item;
|
||||
if (it->assigned){
|
||||
my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
|
||||
if (it->assigned()){
|
||||
thd->fatal_error= 1;
|
||||
my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (unit->offset_limit_cnt)
|
||||
|
@ -816,7 +824,7 @@ bool select_singleval_subselect::send_data(List<Item> &items)
|
|||
it->int_value= val_item->val_int();
|
||||
it->res_type= val_item->result_type();
|
||||
}
|
||||
it->assigned= 1;
|
||||
it->assigned(1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -830,7 +838,7 @@ bool select_exists_subselect::send_data(List<Item> &items)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
it->value= 1;
|
||||
it->assigned= 1;
|
||||
it->assigned(1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -621,7 +621,7 @@ public:
|
|||
virtual void initialize_tables (JOIN *join=0) {}
|
||||
virtual void send_error(uint errcode,const char *err)
|
||||
{
|
||||
::send_error(&thd->net,errcode,err);
|
||||
my_message(errcode, err, MYF(0));
|
||||
}
|
||||
virtual bool send_eof()=0;
|
||||
virtual void abort() {}
|
||||
|
|
|
@ -99,7 +99,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
|
|||
(ORDER*) sl->group_list.first,
|
||||
sl->having, (ORDER*) NULL,
|
||||
sl->options | thd->options | SELECT_NO_UNLOCK,
|
||||
derived_result, unit);
|
||||
derived_result, unit, 0);
|
||||
if (!res)
|
||||
{
|
||||
// Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables
|
||||
|
|
|
@ -1331,6 +1331,7 @@ bool select_insert::send_data(List<Item> &values)
|
|||
|
||||
void select_insert::send_error(uint errcode,const char *err)
|
||||
{
|
||||
//TODO error should be sent at the query processing end
|
||||
::send_error(&thd->net,errcode,err);
|
||||
table->file->extra(HA_EXTRA_NO_CACHE);
|
||||
table->file->activate_all_index(thd);
|
||||
|
@ -1357,6 +1358,7 @@ bool select_insert::send_eof()
|
|||
if (error)
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
//TODO error should be sent at the query processing end
|
||||
::send_error(&thd->net);
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -146,7 +146,8 @@ LEX *lex_start(THD *thd, uchar *buf,uint length)
|
|||
lex->length=0;
|
||||
lex->select->in_sum_expr=0;
|
||||
lex->select->expr_list.empty();
|
||||
lex->select->ftfunc_list.empty();
|
||||
lex->select->ftfunc_list_alloc.empty();
|
||||
lex->select->ftfunc_list= &lex->select->ftfunc_list_alloc;
|
||||
lex->convert_set=(lex->thd=thd)->convert_set;
|
||||
lex->yacc_yyss=lex->yacc_yyvs=0;
|
||||
lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE);
|
||||
|
@ -918,6 +919,8 @@ void st_select_lex_unit::init_query()
|
|||
global_parameters= this;
|
||||
select_limit_cnt= HA_POS_ERROR;
|
||||
offset_limit_cnt= 0;
|
||||
optimized= 0;
|
||||
item= 0;
|
||||
}
|
||||
|
||||
void st_select_lex::init_query()
|
||||
|
@ -941,9 +944,11 @@ void st_select_lex::init_select()
|
|||
expr_list.empty();
|
||||
interval_list.empty();
|
||||
use_index.empty();
|
||||
ftfunc_list.empty();
|
||||
ftfunc_list_alloc.empty();
|
||||
ftfunc_list= &ftfunc_list_alloc;
|
||||
linkage= UNSPECIFIED_TYPE;
|
||||
depended= having_fix_field= 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -216,7 +216,22 @@ private:
|
|||
*/
|
||||
class st_lex;
|
||||
class st_select_lex;
|
||||
class THD;
|
||||
class select_result;
|
||||
class JOIN;
|
||||
class select_union;
|
||||
class st_select_lex_unit: public st_select_lex_node {
|
||||
protected:
|
||||
List<Item> item_list;
|
||||
List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */
|
||||
TABLE_LIST result_table_list;
|
||||
select_union *union_result;
|
||||
TABLE *table; /* temporary table using for appending UNION results */
|
||||
THD *thd;
|
||||
select_result *result;
|
||||
int res;
|
||||
bool describe, found_rows_for_union,
|
||||
optimized; // optimize phase already performed for UNION (unit)
|
||||
public:
|
||||
/*
|
||||
Pointer to 'last' select or pointer to unit where stored
|
||||
|
@ -225,12 +240,21 @@ public:
|
|||
st_select_lex_node *global_parameters;
|
||||
/* LIMIT clause runtime counters */
|
||||
ha_rows select_limit_cnt, offset_limit_cnt;
|
||||
bool depended; /* depended from outer select subselect */
|
||||
/* not NULL if union used in subselect, point to subselect item */
|
||||
Item_subselect *item;
|
||||
|
||||
void init_query();
|
||||
bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result);
|
||||
st_select_lex* outer_select() { return (st_select_lex*) master; }
|
||||
st_select_lex* first_select() { return (st_select_lex*) slave; }
|
||||
st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; }
|
||||
|
||||
/* UNION methods */
|
||||
int prepare(THD *thd, select_result *result);
|
||||
int exec();
|
||||
int cleanup();
|
||||
|
||||
friend void mysql_init_query(THD *thd);
|
||||
private:
|
||||
bool create_total_list_n_last_return(THD *thd, st_lex *lex,
|
||||
|
@ -241,7 +265,6 @@ typedef struct st_select_lex_unit SELECT_LEX_UNIT;
|
|||
/*
|
||||
SELECT_LEX - store information of parsed SELECT_LEX statment
|
||||
*/
|
||||
class JOIN;
|
||||
class st_select_lex: public st_select_lex_node {
|
||||
public:
|
||||
char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */
|
||||
|
@ -252,7 +275,12 @@ public:
|
|||
List<Item> item_list; /* list of fields & expressions */
|
||||
List<String> interval_list, use_index, *use_index_ptr,
|
||||
ignore_index, *ignore_index_ptr;
|
||||
List<Item_func_match> ftfunc_list;
|
||||
/*
|
||||
Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake
|
||||
select_lex for calling mysql_select under results of union
|
||||
*/
|
||||
List<Item_func_match> *ftfunc_list;
|
||||
List<Item_func_match> ftfunc_list_alloc;
|
||||
JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */
|
||||
uint in_sum_expr;
|
||||
bool create_refs,
|
||||
|
|
|
@ -665,7 +665,7 @@ pthread_handler_decl(handle_one_connection,arg)
|
|||
if (thd->user_connect)
|
||||
decrease_user_connections(thd->user_connect);
|
||||
free_root(&thd->mem_root,MYF(0));
|
||||
if (net->error && net->vio != 0)
|
||||
if (net->error && net->vio != 0 && net->report_error)
|
||||
{
|
||||
if (!thd->killed && opt_warnings)
|
||||
sql_print_error(ER(ER_NEW_ABORTING_CONNECTION),
|
||||
|
@ -1169,6 +1169,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
|
|||
break;
|
||||
}
|
||||
case COM_PING:
|
||||
DBUG_PRINT("info", ("query: PING"));
|
||||
thread_safe_increment(com_other,&LOCK_thread_count);
|
||||
send_ok(net); // Tell client we are alive
|
||||
break;
|
||||
|
@ -1257,6 +1258,7 @@ mysql_execute_command(void)
|
|||
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||
DBUG_ENTER("mysql_execute_command");
|
||||
|
||||
thd->net.report_error= 0;
|
||||
if (thd->slave_thread)
|
||||
{
|
||||
/*
|
||||
|
@ -1864,7 +1866,7 @@ mysql_execute_command(void)
|
|||
(ORDER *)NULL,
|
||||
select_lex->options | thd->options |
|
||||
SELECT_NO_JOIN_CACHE,
|
||||
result, unit);
|
||||
result, unit, 0);
|
||||
delete result;
|
||||
}
|
||||
else
|
||||
|
@ -2029,13 +2031,13 @@ mysql_execute_command(void)
|
|||
lex->lock_option,
|
||||
table_count)))
|
||||
{
|
||||
res=mysql_select(thd,tables,select_lex->item_list,
|
||||
select_lex->where,
|
||||
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
|
||||
(ORDER *)NULL,
|
||||
select_lex->options | thd->options |
|
||||
SELECT_NO_JOIN_CACHE,
|
||||
result, unit);
|
||||
res= mysql_select(thd,tables,select_lex->item_list,
|
||||
select_lex->where,
|
||||
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
|
||||
(ORDER *)NULL,
|
||||
select_lex->options | thd->options |
|
||||
SELECT_NO_JOIN_CACHE,
|
||||
result, unit, 0);
|
||||
delete result;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -178,9 +178,14 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
|||
select_lex->having,
|
||||
(ORDER*) lex->proc_list.first,
|
||||
select_lex->options | thd->options,
|
||||
result, &(lex->unit));
|
||||
result, &(lex->unit), 0);
|
||||
if (res && result)
|
||||
result->abort();
|
||||
if (res || thd->net.report_error)
|
||||
{
|
||||
send_error(&thd->net, 0, MYF(0));
|
||||
res= 1;
|
||||
}
|
||||
delete result;
|
||||
return res;
|
||||
}
|
||||
|
@ -198,9 +203,10 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
|
|||
*/
|
||||
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, SELECT_LEX_UNIT *unit)
|
||||
COND *conds_init, ORDER *order_init, ORDER *group_init,
|
||||
Item *having_init,
|
||||
ORDER *proc_param_init, SELECT_LEX *select,
|
||||
SELECT_LEX_UNIT *unit, bool fake_select_lex)
|
||||
{
|
||||
DBUG_ENTER("JOIN::prepare");
|
||||
|
||||
|
@ -211,7 +217,8 @@ JOIN::prepare(TABLE_LIST *tables_init,
|
|||
proc_param= proc_param_init;
|
||||
tables_list= tables_init;
|
||||
select_lex= select;
|
||||
select->join= this;
|
||||
if (!fake_select_lex)
|
||||
select->join= this;
|
||||
union_part= (unit->first_select()->next_select() != 0);
|
||||
|
||||
/* Check that all tables, fields, conds and order are ok */
|
||||
|
@ -231,7 +238,7 @@ JOIN::prepare(TABLE_LIST *tables_init,
|
|||
select_lex->having_fix_field= 1;
|
||||
bool having_fix_rc= having->fix_fields(thd, tables_list, &having);
|
||||
select_lex->having_fix_field= 0;
|
||||
if (having_fix_rc || thd->fatal_error)
|
||||
if (having_fix_rc || thd->net.report_error)
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
if (having->with_sum_func)
|
||||
having->split_sum_func(all_fields);
|
||||
|
@ -538,7 +545,7 @@ JOIN::optimize()
|
|||
make_join_readinfo(this,
|
||||
(select_options & (SELECT_DESCRIBE |
|
||||
SELECT_NO_JOIN_CACHE)) |
|
||||
(thd->lex.select->ftfunc_list.elements ?
|
||||
(thd->lex.select->ftfunc_list->elements ?
|
||||
SELECT_NO_JOIN_CACHE : 0));
|
||||
|
||||
/* Need to tell Innobase that to play it safe, it should fetch all
|
||||
|
@ -650,16 +657,16 @@ JOIN::exec()
|
|||
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;
|
||||
}
|
||||
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();
|
||||
error=(int) result->send_eof();
|
||||
}
|
||||
delete procedure;
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -995,8 +1002,9 @@ JOIN::cleanup(THD *thd)
|
|||
|
||||
int
|
||||
mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
|
||||
ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
|
||||
ulong select_options, select_result *result, SELECT_LEX_UNIT *unit)
|
||||
ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
|
||||
ulong select_options, select_result *result,
|
||||
SELECT_LEX_UNIT *unit, bool fake_select_lex)
|
||||
{
|
||||
JOIN *join = new JOIN(thd, fields, select_options, result);
|
||||
|
||||
|
@ -1005,7 +1013,7 @@ mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
|
|||
thd->used_tables=0; // Updated by setup_fields
|
||||
|
||||
if (join->prepare(tables, conds, order, group, having, proc_param,
|
||||
&(thd->lex.select_lex), unit))
|
||||
&(thd->lex.select_lex), unit, fake_select_lex))
|
||||
{
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
@ -1026,7 +1034,7 @@ err:
|
|||
thd->limit_found_rows = join->send_records;
|
||||
thd->examined_row_count = join->examined_rows;
|
||||
thd->proc_info="end";
|
||||
int error= join->cleanup(thd);
|
||||
int error= (fake_select_lex?0:join->cleanup(thd)) || thd->net.report_error;
|
||||
delete join;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
@ -1760,7 +1768,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab,
|
|||
add_key_part(keyuse,field);
|
||||
}
|
||||
|
||||
if (thd->lex.select->ftfunc_list.elements)
|
||||
if (thd->lex.select->ftfunc_list->elements)
|
||||
{
|
||||
add_ft_keys(keyuse,join_tab,cond,normal_tables);
|
||||
}
|
||||
|
@ -4329,7 +4337,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
|
|||
VOID(table->file->extra(HA_EXTRA_WRITE_CACHE));
|
||||
empty_record(table);
|
||||
}
|
||||
join->tmp_table=table; /* Save for easy recursion */
|
||||
join->tmp_table= table; /* Save for easy recursion */
|
||||
join->fields= fields;
|
||||
|
||||
/* Set up select_end */
|
||||
|
@ -4379,20 +4387,14 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure)
|
|||
}
|
||||
else
|
||||
{
|
||||
error=sub_select(join,join_tab,0);
|
||||
error= sub_select(join,join_tab,0);
|
||||
if (error >= 0)
|
||||
error=sub_select(join,join_tab,1);
|
||||
error= sub_select(join,join_tab,1);
|
||||
if (error == -3)
|
||||
error=0; /* select_limit used */
|
||||
error= 0; /* select_limit used */
|
||||
}
|
||||
|
||||
/* Return 1 if error is sent; -1 if error should be sent */
|
||||
if (error < 0)
|
||||
{
|
||||
join->result->send_error(0,NullS); /* purecov: inspected */
|
||||
error=1; // Error sent
|
||||
}
|
||||
else
|
||||
if (error >= 0)
|
||||
{
|
||||
error=0;
|
||||
if (!table) // If sending data to client
|
||||
|
@ -6445,10 +6447,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields,
|
|||
order->in_field_list=1;
|
||||
return 0;
|
||||
}
|
||||
const char *save_where=thd->where;
|
||||
thd->where=0; // No error if not found
|
||||
Item **item=find_item_in_list(*order->item,fields);
|
||||
thd->where=save_where;
|
||||
Item **item=find_item_in_list(*order->item, fields, 0);
|
||||
if (item)
|
||||
{
|
||||
order->item=item; // use it
|
||||
|
@ -6546,17 +6545,15 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields,
|
|||
DBUG_ENTER("setup_new_fields");
|
||||
|
||||
thd->set_query_id=1; // Not really needed, but...
|
||||
thd->where=0; // Don't give error
|
||||
for ( ; new_field ; new_field=new_field->next)
|
||||
{
|
||||
if ((item=find_item_in_list(*new_field->item,fields)))
|
||||
if ((item=find_item_in_list(*new_field->item, fields, 0)))
|
||||
new_field->item=item; /* Change to shared Item */
|
||||
else
|
||||
{
|
||||
thd->where="procedure list";
|
||||
if ((*new_field->item)->fix_fields(thd, tables, new_field->item))
|
||||
DBUG_RETURN(1); /* purecov: inspected */
|
||||
thd->where=0;
|
||||
all_fields.push_front(*new_field->item);
|
||||
new_field->item=all_fields.head_ref();
|
||||
}
|
||||
|
|
|
@ -209,6 +209,7 @@ class JOIN :public Sql_alloc{
|
|||
send_records(0), found_records(0), examined_rows(0),
|
||||
thd(thd),
|
||||
sum_funcs(0),
|
||||
procedure(0),
|
||||
having(0),
|
||||
select_options(select_options),
|
||||
result(result),
|
||||
|
@ -235,7 +236,8 @@ class JOIN :public Sql_alloc{
|
|||
|
||||
int prepare(TABLE_LIST *tables,
|
||||
COND *conds, ORDER *order, ORDER *group, Item *having,
|
||||
ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit);
|
||||
ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit,
|
||||
bool fake_select_lex);
|
||||
int optimize();
|
||||
int global_optimize();
|
||||
int reinit();
|
||||
|
|
368
sql/sql_union.cc
368
sql/sql_union.cc
|
@ -24,160 +24,14 @@
|
|||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
|
||||
int mysql_union(THD *thd, LEX *lex,select_result *result)
|
||||
int mysql_union(THD *thd, LEX *lex, select_result *result)
|
||||
{
|
||||
SELECT_LEX *sl;
|
||||
SELECT_LEX_UNIT *unit= &(lex->unit);
|
||||
List<Item> item_list;
|
||||
TABLE *table;
|
||||
int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0;
|
||||
int res;
|
||||
bool found_rows_for_union=false;
|
||||
TABLE_LIST result_table_list;
|
||||
TMP_TABLE_PARAM tmp_table_param;
|
||||
select_union *union_result;
|
||||
DBUG_ENTER("mysql_union");
|
||||
st_select_lex_node * global;
|
||||
|
||||
/* Global option */
|
||||
if (((void*)(global= unit->global_parameters)) == ((void*)unit))
|
||||
{
|
||||
found_rows_for_union = lex->select_lex.options & OPTION_FOUND_ROWS &&
|
||||
!describe && global->select_limit;
|
||||
if (found_rows_for_union)
|
||||
lex->select_lex.options ^= OPTION_FOUND_ROWS;
|
||||
}
|
||||
|
||||
if (describe)
|
||||
{
|
||||
Item *item;
|
||||
item_list.push_back(new Item_empty_string("table",NAME_LEN));
|
||||
item_list.push_back(new Item_empty_string("type",10));
|
||||
item_list.push_back(item=new Item_empty_string("possible_keys",
|
||||
NAME_LEN*MAX_KEY));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_int("key_len",0,3));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_empty_string("ref",
|
||||
NAME_LEN*MAX_REF_PARTS));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(new Item_real("rows",0.0,0,10));
|
||||
item_list.push_back(new Item_empty_string("Extra",255));
|
||||
}
|
||||
else
|
||||
{
|
||||
Item *item;
|
||||
List_iterator<Item> it(lex->select_lex.item_list);
|
||||
TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
|
||||
|
||||
/* Create a list of items that will be in the result set */
|
||||
while ((item= it++))
|
||||
if (item_list.push_back(item))
|
||||
DBUG_RETURN(-1);
|
||||
if (setup_fields(thd,first_table,item_list,0,0,1))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
|
||||
tmp_table_param.field_count=item_list.elements;
|
||||
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
|
||||
(ORDER*) 0, !describe & !lex->union_option,
|
||||
1, 0,
|
||||
(lex->select_lex.options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
unit)))
|
||||
DBUG_RETURN(-1);
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
bzero((char*) &result_table_list,sizeof(result_table_list));
|
||||
result_table_list.db= (char*) "";
|
||||
result_table_list.real_name=result_table_list.name=(char*) "union";
|
||||
result_table_list.table=table;
|
||||
|
||||
if (!(union_result=new select_union(table)))
|
||||
{
|
||||
res= -1;
|
||||
goto exit;
|
||||
}
|
||||
union_result->save_time_stamp=!describe;
|
||||
union_result->tmp_table_param=&tmp_table_param;
|
||||
for (sl= &lex->select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
lex->select=sl;
|
||||
unit->offset_limit_cnt= sl->offset_limit;
|
||||
unit->select_limit_cnt= sl->select_limit+sl->offset_limit;
|
||||
if (unit->select_limit_cnt < sl->select_limit)
|
||||
unit->select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (unit->select_limit_cnt == HA_POS_ERROR)
|
||||
sl->options&= ~OPTION_FOUND_ROWS;
|
||||
|
||||
res= mysql_select(thd,
|
||||
(TABLE_LIST*) sl->table_list.first,
|
||||
sl->item_list,
|
||||
sl->where,
|
||||
(sl->braces) ?
|
||||
(ORDER *)sl->order_list.first : (ORDER *) 0,
|
||||
(ORDER*) sl->group_list.first,
|
||||
sl->having,
|
||||
(ORDER*) NULL,
|
||||
sl->options | thd->options |
|
||||
SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0),
|
||||
union_result, unit);
|
||||
if (res)
|
||||
goto exit;
|
||||
}
|
||||
if (union_result->flush())
|
||||
{
|
||||
res= 1; // Error is already sent
|
||||
goto exit;
|
||||
}
|
||||
delete union_result;
|
||||
|
||||
/* Send result to 'result' */
|
||||
lex->select = &lex->select_lex;
|
||||
res =-1;
|
||||
{
|
||||
/* Create a list of fields in the temporary table */
|
||||
List_iterator<Item> it(item_list);
|
||||
Field **field;
|
||||
#if 0
|
||||
List<Item_func_match> ftfunc_list;
|
||||
ftfunc_list.empty();
|
||||
#else
|
||||
thd->lex.select_lex.ftfunc_list.empty();
|
||||
#endif
|
||||
|
||||
for (field=table->field ; *field ; field++)
|
||||
{
|
||||
(void) it++;
|
||||
(void) it.replace(new Item_field(*field));
|
||||
}
|
||||
if (!thd->fatal_error) // Check if EOM
|
||||
{
|
||||
st_select_lex_node * global= unit->global_parameters;
|
||||
unit->offset_limit_cnt= global->offset_limit;
|
||||
unit->select_limit_cnt= global->select_limit+global->offset_limit;
|
||||
if (unit->select_limit_cnt < global->select_limit)
|
||||
unit->select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (unit->select_limit_cnt == HA_POS_ERROR)
|
||||
thd->options&= ~OPTION_FOUND_ROWS;
|
||||
if (describe)
|
||||
unit->select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
res= mysql_select(thd,&result_table_list,
|
||||
item_list, NULL,
|
||||
(describe) ? 0 : (ORDER*)global->order_list.first,
|
||||
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
||||
thd->options, result, unit);
|
||||
if (found_rows_for_union && !res)
|
||||
thd->limit_found_rows = (ulonglong)table->file->records;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
free_tmp_table(thd,table);
|
||||
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||
int res= 0;
|
||||
if (!(res= unit->prepare(thd, result)))
|
||||
res= unit->exec();
|
||||
res|= unit->cleanup();
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
@ -246,3 +100,213 @@ bool select_union::flush()
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef JOIN * JOIN_P;
|
||||
int st_select_lex_unit::prepare(THD *thd, select_result *result)
|
||||
{
|
||||
describe=(first_select()->options & SELECT_DESCRIBE) ? 1 : 0;
|
||||
res= 0;
|
||||
found_rows_for_union= false;
|
||||
TMP_TABLE_PARAM tmp_table_param;
|
||||
DBUG_ENTER("st_select_lex_unit::prepare");
|
||||
this->thd= thd;
|
||||
this->result= result;
|
||||
|
||||
/* Global option */
|
||||
if (((void*)(global_parameters)) == ((void*)this))
|
||||
{
|
||||
found_rows_for_union = first_select()->options & OPTION_FOUND_ROWS &&
|
||||
!describe && global_parameters->select_limit;
|
||||
if (found_rows_for_union)
|
||||
first_select()->options ^= OPTION_FOUND_ROWS;
|
||||
}
|
||||
item_list.empty();
|
||||
if (describe)
|
||||
{
|
||||
Item *item;
|
||||
item_list.push_back(new Item_empty_string("table",NAME_LEN));
|
||||
item_list.push_back(new Item_empty_string("type",10));
|
||||
item_list.push_back(item=new Item_empty_string("possible_keys",
|
||||
NAME_LEN*MAX_KEY));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_empty_string("key",NAME_LEN));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_int("key_len",0,3));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(item=new Item_empty_string("ref",
|
||||
NAME_LEN*MAX_REF_PARTS));
|
||||
item->maybe_null=1;
|
||||
item_list.push_back(new Item_real("rows",0.0,0,10));
|
||||
item_list.push_back(new Item_empty_string("Extra",255));
|
||||
}
|
||||
else
|
||||
{
|
||||
Item *item;
|
||||
List_iterator<Item> it(first_select()->item_list);
|
||||
TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first;
|
||||
|
||||
/* Create a list of items that will be in the result set */
|
||||
while ((item= it++))
|
||||
if (item_list.push_back(item))
|
||||
DBUG_RETURN(-1);
|
||||
if (setup_fields(thd,first_table,item_list,0,0,1))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
|
||||
tmp_table_param.field_count=item_list.elements;
|
||||
if (!(table= create_tmp_table(thd, &tmp_table_param, item_list,
|
||||
(ORDER*) 0, !describe &
|
||||
!thd->lex.union_option,
|
||||
1, 0,
|
||||
(first_select()->options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS),
|
||||
this)))
|
||||
DBUG_RETURN(-1);
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
bzero((char*) &result_table_list,sizeof(result_table_list));
|
||||
result_table_list.db= (char*) "";
|
||||
result_table_list.real_name=result_table_list.name=(char*) "union";
|
||||
result_table_list.table=table;
|
||||
|
||||
if (!(union_result=new select_union(table)))
|
||||
DBUG_RETURN(-1);
|
||||
|
||||
union_result->save_time_stamp=!describe;
|
||||
union_result->tmp_table_param=&tmp_table_param;
|
||||
|
||||
// prepare selects
|
||||
joins.empty();
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
JOIN *join= new JOIN(thd, sl->item_list,
|
||||
sl->options | thd->options | SELECT_NO_UNLOCK |
|
||||
((describe) ? SELECT_DESCRIBE : 0),
|
||||
union_result);
|
||||
joins.push_back(new JOIN_P(join));
|
||||
thd->lex.select=sl;
|
||||
offset_limit_cnt= sl->offset_limit;
|
||||
select_limit_cnt= sl->select_limit+sl->offset_limit;
|
||||
if (select_limit_cnt < sl->select_limit)
|
||||
select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (select_limit_cnt == HA_POS_ERROR)
|
||||
sl->options&= ~OPTION_FOUND_ROWS;
|
||||
|
||||
res= join->prepare((TABLE_LIST*) sl->table_list.first,
|
||||
sl->where,
|
||||
(sl->braces) ?
|
||||
(ORDER *)sl->order_list.first : (ORDER *) 0,
|
||||
(ORDER*) sl->group_list.first,
|
||||
sl->having,
|
||||
(ORDER*) NULL,
|
||||
sl, this, 0);
|
||||
if (res | thd->fatal_error)
|
||||
DBUG_RETURN(res | thd->fatal_error);
|
||||
}
|
||||
DBUG_RETURN(res | thd->fatal_error);
|
||||
}
|
||||
|
||||
int st_select_lex_unit::exec()
|
||||
{
|
||||
DBUG_ENTER("st_select_lex_unit::exec");
|
||||
if(depended || !item || !item->assigned())
|
||||
{
|
||||
if (optimized && item && item->assigned())
|
||||
item->assigned(0); // We will reinit & rexecute unit
|
||||
|
||||
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
|
||||
{
|
||||
thd->lex.select=sl;
|
||||
offset_limit_cnt= sl->offset_limit;
|
||||
select_limit_cnt= sl->select_limit+sl->offset_limit;
|
||||
if (select_limit_cnt < sl->select_limit)
|
||||
select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (select_limit_cnt == HA_POS_ERROR)
|
||||
sl->options&= ~OPTION_FOUND_ROWS;
|
||||
|
||||
if (!optimized)
|
||||
sl->join->optimize();
|
||||
else
|
||||
sl->join->reinit();
|
||||
|
||||
sl->join->exec();
|
||||
res= sl->join->error;
|
||||
|
||||
if (res)
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
optimized= 1;
|
||||
}
|
||||
|
||||
if (union_result->flush())
|
||||
{
|
||||
res= 1; // Error is already sent
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
/* Send result to 'result' */
|
||||
thd->lex.select = first_select();
|
||||
res =-1;
|
||||
{
|
||||
/* Create a list of fields in the temporary table */
|
||||
List_iterator<Item> it(item_list);
|
||||
Field **field;
|
||||
#if 0
|
||||
List<Item_func_match> ftfunc_list;
|
||||
ftfunc_list.empty();
|
||||
#else
|
||||
List<Item_func_match> empty_list;
|
||||
empty_list.empty();
|
||||
thd->lex.select_lex.ftfunc_list= &empty_list;
|
||||
#endif
|
||||
|
||||
for (field=table->field ; *field ; field++)
|
||||
{
|
||||
(void) it++;
|
||||
(void) it.replace(new Item_field(*field));
|
||||
}
|
||||
if (!thd->fatal_error) // Check if EOM
|
||||
{
|
||||
offset_limit_cnt= global_parameters->offset_limit;
|
||||
select_limit_cnt= global_parameters->select_limit+
|
||||
global_parameters->offset_limit;
|
||||
if (select_limit_cnt < global_parameters->select_limit)
|
||||
select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
if (select_limit_cnt == HA_POS_ERROR)
|
||||
thd->options&= ~OPTION_FOUND_ROWS;
|
||||
if (describe)
|
||||
select_limit_cnt= HA_POS_ERROR; // no limit
|
||||
res= mysql_select(thd,&result_table_list,
|
||||
item_list, NULL,
|
||||
(describe) ?
|
||||
0:
|
||||
(ORDER*)global_parameters->order_list.first,
|
||||
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
||||
thd->options, result, this, 1);
|
||||
if (found_rows_for_union && !res)
|
||||
thd->limit_found_rows = (ulonglong)table->file->records;
|
||||
}
|
||||
}
|
||||
thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
int st_select_lex_unit::cleanup()
|
||||
{
|
||||
DBUG_ENTER("st_select_lex_unit::cleanup");
|
||||
delete union_result;
|
||||
free_tmp_table(thd,table);
|
||||
table= 0; // Safety
|
||||
|
||||
List_iterator<JOIN*> j(joins);
|
||||
JOIN** join;
|
||||
while ((join= j++))
|
||||
{
|
||||
(*join)->cleanup(thd);
|
||||
delete *join;
|
||||
delete join;
|
||||
}
|
||||
joins.empty();
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
|
@ -642,6 +642,8 @@ bool multi_update::send_data(List<Item> &values)
|
|||
|
||||
void multi_update::send_error(uint errcode,const char *err)
|
||||
{
|
||||
|
||||
//TODO error should be sent at the query processing end
|
||||
/* First send error what ever it is ... */
|
||||
::send_error(&thd->net,errcode,err);
|
||||
|
||||
|
@ -766,6 +768,7 @@ bool multi_update::send_eof()
|
|||
if (error == -1)
|
||||
error = 0;
|
||||
thd->proc_info="end";
|
||||
//TODO error should be sent at the query processing end
|
||||
if (error)
|
||||
send_error(error,"An error occured in multi-table update");
|
||||
|
||||
|
|
|
@ -1763,10 +1763,10 @@ simple_expr:
|
|||
| singleval_subselect { $$= $1; }
|
||||
| '{' ident expr '}' { $$= $3; }
|
||||
| MATCH ident_list_arg AGAINST '(' expr ')'
|
||||
{ Select->ftfunc_list.push_back((Item_func_match *)
|
||||
{ Select->ftfunc_list->push_back((Item_func_match *)
|
||||
($$=new Item_func_match_nl(*$2,$5))); }
|
||||
| MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')'
|
||||
{ Select->ftfunc_list.push_back((Item_func_match *)
|
||||
{ Select->ftfunc_list->push_back((Item_func_match *)
|
||||
($$=new Item_func_match_bool(*$2,$5))); }
|
||||
| BINARY expr %prec NEG { $$= new Item_func_binary($2); }
|
||||
| CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); }
|
||||
|
@ -3999,7 +3999,8 @@ singleval_subselect:
|
|||
singleval_subselect_init:
|
||||
select_init
|
||||
{
|
||||
$$= new Item_singleval_subselect(current_thd, Lex->select);
|
||||
$$= new Item_singleval_subselect(current_thd,
|
||||
Lex->select->master_unit()->first_select());
|
||||
};
|
||||
|
||||
exists_subselect:
|
||||
|
@ -4012,7 +4013,8 @@ exists_subselect:
|
|||
exists_subselect_init:
|
||||
select_init
|
||||
{
|
||||
$$= new Item_exists_subselect(current_thd, Lex->select);
|
||||
$$= new Item_exists_subselect(current_thd,
|
||||
Lex->select->master_unit()->first_select());
|
||||
};
|
||||
|
||||
subselect_start:
|
||||
|
|
Loading…
Reference in a new issue