Commit 9eb7c2ff authored by unknown's avatar unknown

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1

into sanja.is.com.ua:/home/bell/mysql/bk/work-prepared-4.1


mysql-test/r/derived.result:
  Auto merged
mysql-test/t/derived.test:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/sql_union.cc:
  Auto merged
sql/sql_update.cc:
  Auto merged
parents d017b992 6c8a4dba
...@@ -966,8 +966,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -966,8 +966,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item_field::cleanup() void Item_field::cleanup()
{ {
DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup(); Item_ident::cleanup();
field= result_field= 0; field= result_field= 0;
DBUG_VOID_RETURN;
} }
void Item::init_make_field(Send_field *tmp_field, void Item::init_make_field(Send_field *tmp_field,
...@@ -1610,9 +1612,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ...@@ -1610,9 +1612,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
void Item_ref::cleanup() void Item_ref::cleanup()
{ {
DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup(); Item_ident::cleanup();
if (hook_ptr) if (hook_ptr)
*hook_ptr= orig_item; *hook_ptr= orig_item;
DBUG_VOID_RETURN;
} }
......
...@@ -128,7 +128,13 @@ class Item { ...@@ -128,7 +128,13 @@ class Item {
virtual ~Item() { name=0; } /*lint -e1509 */ virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs); void set_name(const char *str,uint length, CHARSET_INFO *cs);
void init_make_field(Send_field *tmp_field,enum enum_field_types type); void init_make_field(Send_field *tmp_field,enum enum_field_types type);
virtual void cleanup() { fixed=0; } virtual void cleanup()
{
DBUG_ENTER("Item::cleanup");
DBUG_PRINT("info", ("Type: %d", (int)type()));
fixed=0;
DBUG_VOID_RETURN;
}
virtual void make_field(Send_field *field); virtual void make_field(Send_field *field);
virtual bool fix_fields(THD *, struct st_table_list *, Item **); virtual bool fix_fields(THD *, struct st_table_list *, Item **);
virtual int save_in_field(Field *field, bool no_conversions); virtual int save_in_field(Field *field, bool no_conversions);
...@@ -996,8 +1002,10 @@ class Item_cache_row: public Item_cache ...@@ -996,8 +1002,10 @@ class Item_cache_row: public Item_cache
void bring_value(); void bring_value();
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_cache_row::cleanup");
Item_cache::cleanup(); Item_cache::cleanup();
values= 0; values= 0;
DBUG_VOID_RETURN;
} }
}; };
...@@ -1023,8 +1031,10 @@ class Item_type_holder: public Item ...@@ -1023,8 +1031,10 @@ class Item_type_holder: public Item
Field *example() { return field_example; } Field *example() { return field_example; }
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup(); Item::cleanup();
item_type= orig_type; item_type= orig_type;
DBUG_VOID_RETURN;
} }
}; };
......
...@@ -484,6 +484,14 @@ longlong Item_in_optimizer::val_int() ...@@ -484,6 +484,14 @@ longlong Item_in_optimizer::val_int()
return tmp; return tmp;
} }
void Item_in_optimizer::cleanup()
{
DBUG_ENTER("Item_in_optimizer::cleanup");
Item_bool_func::cleanup();
cache= 0;
DBUG_VOID_RETURN;
}
bool Item_in_optimizer::is_null() bool Item_in_optimizer::is_null()
{ {
cache->store(args[0]); cache->store(args[0]);
......
...@@ -105,6 +105,7 @@ class Item_in_optimizer: public Item_bool_func ...@@ -105,6 +105,7 @@ class Item_in_optimizer: public Item_bool_func
Item_in_optimizer return NULL, else it evaluate Item_in_subselect. Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/ */
longlong val_int(); longlong val_int();
void cleanup();
const char *func_name() const { return "<in_optimizer>"; } const char *func_name() const { return "<in_optimizer>"; }
Item_cache **get_cache() { return &cache; } Item_cache **get_cache() { return &cache; }
}; };
...@@ -207,9 +208,11 @@ class Item_bool_rowready_func2 :public Item_bool_func2 ...@@ -207,9 +208,11 @@ class Item_bool_rowready_func2 :public Item_bool_func2
} }
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_bool_rowready_func2::cleanup");
Item_bool_func2::cleanup(); Item_bool_func2::cleanup();
tmp_arg[0]= orig_a; tmp_arg[0]= orig_a;
tmp_arg[1]= orig_b; tmp_arg[1]= orig_b;
DBUG_VOID_RETURN;
} }
}; };
...@@ -718,10 +721,12 @@ class Item_func_in :public Item_int_func ...@@ -718,10 +721,12 @@ class Item_func_in :public Item_int_func
void fix_length_and_dec(); void fix_length_and_dec();
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_in::cleanup");
delete array; delete array;
delete in_item; delete in_item;
array= 0; array= 0;
in_item= 0; in_item= 0;
DBUG_VOID_RETURN;
} }
optimize_type select_optimize() const optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; } { return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
......
...@@ -999,6 +999,7 @@ class Item_func_match :public Item_real_func ...@@ -999,6 +999,7 @@ class Item_func_match :public Item_real_func
join_key(0), ft_handler(0), table(0), master(0), concat(0) { } join_key(0), ft_handler(0), table(0), master(0), concat(0) { }
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_match");
if (!master && ft_handler) if (!master && ft_handler)
{ {
ft_handler->please->close_search(ft_handler); ft_handler->please->close_search(ft_handler);
...@@ -1009,6 +1010,7 @@ class Item_func_match :public Item_real_func ...@@ -1009,6 +1010,7 @@ class Item_func_match :public Item_real_func
} }
if (concat) if (concat)
delete concat; delete concat;
DBUG_VOID_RETURN;
} }
enum Functype functype() const { return FT_FUNC; } enum Functype functype() const { return FT_FUNC; }
const char *func_name() const { return "match"; } const char *func_name() const { return "match"; }
......
...@@ -35,9 +35,9 @@ inline Item * and_items(Item* cond, Item *item) ...@@ -35,9 +35,9 @@ inline Item * and_items(Item* cond, Item *item)
} }
Item_subselect::Item_subselect(): Item_subselect::Item_subselect():
Item_result_field(), value_assigned(0), substitution(0), Item_result_field(), value_assigned(0), thd(0), substitution(0),
engine(0), used_tables_cache(0), have_to_be_excluded(0), engine(0), old_engine(0), used_tables_cache(0), have_to_be_excluded(0),
const_item_cache(1), engine_changed(0) const_item_cache(1), engine_changed(0), changed(0)
{ {
reset(); reset();
/* /*
...@@ -54,9 +54,10 @@ void Item_subselect::init(st_select_lex *select_lex, ...@@ -54,9 +54,10 @@ void Item_subselect::init(st_select_lex *select_lex,
DBUG_ENTER("Item_subselect::init"); DBUG_ENTER("Item_subselect::init");
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex)); DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
unit= select_lex->master_unit();
if (select_lex->next_select()) if (select_lex->next_select())
engine= new subselect_union_engine(select_lex->master_unit(), result, engine= new subselect_union_engine(unit, result,
this); this);
else else
engine= new subselect_single_select_engine(select_lex, result, this); engine= new subselect_single_select_engine(select_lex, result, this);
...@@ -65,8 +66,26 @@ void Item_subselect::init(st_select_lex *select_lex, ...@@ -65,8 +66,26 @@ void Item_subselect::init(st_select_lex *select_lex,
void Item_subselect::cleanup() void Item_subselect::cleanup()
{ {
DBUG_ENTER("Item_subselect::cleanup");
Item_result_field::cleanup(); Item_result_field::cleanup();
engine->cleanup(); if (old_engine)
{
engine->cleanup();
engine= old_engine;
old_engine= 0;
}
engine->cleanup();
reset();
value_assigned= 0;
DBUG_VOID_RETURN;
}
void Item_singlerow_subselect::cleanup()
{
DBUG_ENTER("Item_singlerow_subselect::cleanup");
value= 0; row= 0;
Item_subselect::cleanup();
DBUG_VOID_RETURN;
} }
Item_subselect::~Item_subselect() Item_subselect::~Item_subselect()
...@@ -85,13 +104,22 @@ Item_subselect::select_transformer(JOIN *join) ...@@ -85,13 +104,22 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{ {
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
char const *save_where= thd->where; char const *save_where= thd->where;
int res= engine->prepare(); int res= engine->prepare();
// all transformetion is done (used by prepared statements)
changed= 1;
if (!res) if (!res)
{ {
if (substitution) if (substitution)
{ {
// did we changed top item of WHERE condition
if (unit->outer_select()->where == (*ref))
unit->outer_select()->where= substitution; // correct WHERE for PS
(*ref)= substitution; (*ref)= substitution;
substitution->name= name; substitution->name= name;
if (have_to_be_excluded) if (have_to_be_excluded)
...@@ -240,8 +268,12 @@ void Item_singlerow_subselect::reset() ...@@ -240,8 +268,12 @@ void Item_singlerow_subselect::reset()
Item_subselect::trans_res Item_subselect::trans_res
Item_singlerow_subselect::select_transformer(JOIN *join) Item_singlerow_subselect::select_transformer(JOIN *join)
{ {
if (changed)
return RES_OK;
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
Statement backup;
if (!select_lex->master_unit()->first_select()->next_select() && if (!select_lex->master_unit()->first_select()->next_select() &&
!select_lex->table_list.elements && !select_lex->table_list.elements &&
select_lex->item_list.elements == 1 && select_lex->item_list.elements == 1 &&
...@@ -275,20 +307,30 @@ Item_singlerow_subselect::select_transformer(JOIN *join) ...@@ -275,20 +307,30 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (join->conds || join->having) if (join->conds || join->having)
{ {
Item *cond; Item *cond;
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (!join->having) if (!join->having)
cond= join->conds; cond= join->conds;
else if (!join->conds) else if (!join->conds)
cond= join->having; cond= join->having;
else else
if (!(cond= new Item_cond_and(join->conds, join->having))) if (!(cond= new Item_cond_and(join->conds, join->having)))
return RES_ERROR; goto err;
if (!(substitution= new Item_func_if(cond, substitution, if (!(substitution= new Item_func_if(cond, substitution,
new Item_null()))) new Item_null())))
return RES_ERROR; goto err;
} }
if (stmt)
thd->restore_backup_item_arena(&backup);
return RES_REDUCE; return RES_REDUCE;
} }
return RES_OK; return RES_OK;
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
return RES_ERROR;
} }
void Item_singlerow_subselect::store(uint i, Item *item) void Item_singlerow_subselect::store(uint i, Item *item)
...@@ -550,15 +592,22 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -550,15 +592,22 @@ Item_in_subselect::single_value_transformer(JOIN *join,
{ {
DBUG_ENTER("Item_in_subselect::single_value_transformer"); DBUG_ENTER("Item_in_subselect::single_value_transformer");
if (changed)
{
DBUG_RETURN(RES_OK);
}
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
Statement backup;
THD *thd_tmp= join->thd; thd->where= "scalar IN/ALL/ANY subquery";
thd_tmp->where= "scalar IN/ALL/ANY subquery"; if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
if (select_lex->item_list.elements > 1) if (select_lex->item_list.elements > 1)
{ {
my_error(ER_OPERAND_COLUMNS, MYF(0), 1); my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
DBUG_RETURN(RES_ERROR); goto err;
} }
if ((abort_on_null || (upper_not && upper_not->top_level())) && if ((abort_on_null || (upper_not && upper_not->top_level())) &&
...@@ -567,7 +616,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -567,7 +616,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (substitution) if (substitution)
{ {
// It is second (third, ...) SELECT of UNION => All is done // It is second (third, ...) SELECT of UNION => All is done
DBUG_RETURN(RES_OK); goto ok;
} }
Item *subs; Item *subs;
...@@ -597,10 +646,9 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -597,10 +646,9 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->item_list.empty(); select_lex->item_list.empty();
select_lex->item_list.push_back(item); select_lex->item_list.push_back(item);
if (item->fix_fields(thd_tmp, join->tables_list, &item)) if (item->fix_fields(thd, join->tables_list, &item))
{ goto err;
DBUG_RETURN(RES_ERROR);
}
subs= new Item_singlerow_subselect(select_lex); subs= new Item_singlerow_subselect(select_lex);
} }
else else
...@@ -611,16 +659,16 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -611,16 +659,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
subs= new Item_maxmin_subselect(this, select_lex, func->l_op()); subs= new Item_maxmin_subselect(this, select_lex, func->l_op());
} }
// left expression belong to outer select // left expression belong to outer select
SELECT_LEX *current= thd_tmp->lex->current_select, *up; SELECT_LEX *current= thd->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing(); thd->lex->current_select= up= current->return_after_parsing();
if (left_expr->fix_fields(thd_tmp, up->get_table_list(), &left_expr)) if (left_expr->fix_fields(thd, up->get_table_list(), &left_expr))
{ {
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR); goto err;
} }
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
substitution= func->create(left_expr, subs); substitution= func->create(left_expr, subs);
DBUG_RETURN(RES_OK); goto ok;
} }
if (!substitution) if (!substitution)
...@@ -629,16 +677,16 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -629,16 +677,16 @@ Item_in_subselect::single_value_transformer(JOIN *join,
SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this); substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX *current= thd_tmp->lex->current_select, *up; SELECT_LEX *current= thd->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing(); thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter //optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0)) if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{ {
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR); goto err;
} }
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
/* /*
As far as Item_ref_in_optimizer do not substitude itself on fix_fields As far as Item_ref_in_optimizer do not substitude itself on fix_fields
...@@ -665,12 +713,12 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -665,12 +713,12 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->ref_pointer_array, select_lex->ref_pointer_array,
(char *)"<ref>", (char *)"<ref>",
this->full_name())); this->full_name()));
join->having= and_items(join->having, item); select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having)) if (join->having->fix_fields(thd, join->tables_list, &join->having))
{ {
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR); goto err;
} }
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
} }
...@@ -687,39 +735,42 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -687,39 +735,42 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (!abort_on_null) if (!abort_on_null)
{ {
having= new Item_is_not_null_test(this, having); having= new Item_is_not_null_test(this, having);
join->having= (join->having ? select_lex->having=
new Item_cond_and(having, join->having) : join->having= (join->having ?
having); new Item_cond_and(having, join->having) :
having);
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, if (join->having->fix_fields(thd, join->tables_list,
&join->having)) &join->having))
{ {
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR); goto err;
} }
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
item= new Item_cond_or(item, item= new Item_cond_or(item,
new Item_func_isnull(isnull)); new Item_func_isnull(isnull));
} }
item->name= (char *)in_additional_cond; item->name= (char *)in_additional_cond;
join->conds= and_items(join->conds, item); select_lex->where= join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->conds)) if (join->conds->fix_fields(thd, join->tables_list, &join->conds))
DBUG_RETURN(RES_ERROR); goto err;
} }
else else
{ {
if (select_lex->master_unit()->first_select()->next_select()) if (select_lex->master_unit()->first_select()->next_select())
{ {
join->having= func->create(expr, select_lex->having=
new Item_null_helper(this, item, join->having=
(char *)"<no matter>", func->create(expr,
(char *)"<result>")); new Item_null_helper(this, item,
(char *)"<no matter>",
(char *)"<result>"));
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, if (join->having->fix_fields(thd, join->tables_list,
&join->having)) &join->having))
{ {
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR); goto err;
} }
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
} }
...@@ -730,18 +781,29 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -730,18 +781,29 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// fix_field of item will be done in time of substituting // fix_field of item will be done in time of substituting
substitution= item; substitution= item;
have_to_be_excluded= 1; have_to_be_excluded= 1;
if (thd_tmp->lex->describe) if (thd->lex->describe)
{ {
char warn_buff[MYSQL_ERRMSG_SIZE]; char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number); sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
push_warning(thd_tmp, MYSQL_ERROR::WARN_LEVEL_NOTE, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff); ER_SELECT_REDUCED, warn_buff);
} }
if (stmt)
thd->set_item_arena(&backup);
DBUG_RETURN(RES_REDUCE); DBUG_RETURN(RES_REDUCE);
} }
} }
} }
ok:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_ERROR);
} }
...@@ -750,15 +812,23 @@ Item_in_subselect::row_value_transformer(JOIN *join) ...@@ -750,15 +812,23 @@ Item_in_subselect::row_value_transformer(JOIN *join)
{ {
DBUG_ENTER("Item_in_subselect::row_value_transformer"); DBUG_ENTER("Item_in_subselect::row_value_transformer");
THD *thd_tmp= join->thd; if (changed)
thd_tmp->where= "row IN/ALL/ANY subquery"; {
DBUG_RETURN(RES_OK);
}
Statement backup;
Item *item= 0;
thd->where= "row IN/ALL/ANY subquery";
if (stmt)
thd->set_n_backup_item_arena(stmt, &backup);
SELECT_LEX *select_lex= join->select_lex; SELECT_LEX *select_lex= join->select_lex;
if (select_lex->item_list.elements != left_expr->cols()) if (select_lex->item_list.elements != left_expr->cols())
{ {
my_error(ER_OPERAND_COLUMNS, MYF(0), left_expr->cols()); my_error(ER_OPERAND_COLUMNS, MYF(0), left_expr->cols());
DBUG_RETURN(RES_ERROR); goto err;
} }
if (!substitution) if (!substitution)
...@@ -767,62 +837,68 @@ Item_in_subselect::row_value_transformer(JOIN *join) ...@@ -767,62 +837,68 @@ Item_in_subselect::row_value_transformer(JOIN *join)
SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX_UNIT *unit= select_lex->master_unit();
substitution= optimizer= new Item_in_optimizer(left_expr, this); substitution= optimizer= new Item_in_optimizer(left_expr, this);
SELECT_LEX *current= thd_tmp->lex->current_select, *up; SELECT_LEX *current= thd->lex->current_select, *up;
thd_tmp->lex->current_select= up= current->return_after_parsing(); thd->lex->current_select= up= current->return_after_parsing();
//optimizer never use Item **ref => we can pass 0 as parameter //optimizer never use Item **ref => we can pass 0 as parameter
if (!optimizer || optimizer->fix_left(thd_tmp, up->get_table_list(), 0)) if (!optimizer || optimizer->fix_left(thd, up->get_table_list(), 0))
{ {
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
DBUG_RETURN(RES_ERROR); goto err;
} }
thd_tmp->lex->current_select= current; thd->lex->current_select= current;
unit->uncacheable|= UNCACHEABLE_DEPENDENT; unit->uncacheable|= UNCACHEABLE_DEPENDENT;
} }
uint n= left_expr->cols();
select_lex->uncacheable|= UNCACHEABLE_DEPENDENT; select_lex->uncacheable|= UNCACHEABLE_DEPENDENT;
select_lex->setup_ref_array(thd_tmp, select_lex->setup_ref_array(thd,
select_lex->order_list.elements + select_lex->order_list.elements +
select_lex->group_list.elements); select_lex->group_list.elements);
Item *item= 0;
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{ {
Item *func= new Item_ref_null_helper(this, uint n= left_expr->cols();
select_lex->ref_pointer_array+i, List_iterator_fast<Item> li(select_lex->item_list);
(char *) "<no matter>", for (uint i= 0; i < n; i++)
(char *) "<list ref>"); {
func= Item *func= new Item_ref_null_helper(this,
eq_creator.create(new Item_ref((*optimizer->get_cache())-> select_lex->ref_pointer_array+i,
addr(i), (char *) "<no matter>",
NULL, (char *) "<list ref>");
(char *)"<no matter>", func=
eq_creator.create(new Item_ref((*optimizer->get_cache())->
addr(i),
NULL,
(char *)"<no matter>",
(char *)in_left_expr_name), (char *)in_left_expr_name),
func); func);
item= and_items(item, func); item= and_items(item, func);
}
} }
if (join->having || select_lex->with_sum_func || if (join->having || select_lex->with_sum_func ||
select_lex->group_list.first || select_lex->group_list.first ||
!select_lex->table_list.elements) !select_lex->table_list.elements)
{ {
join->having= and_items(join->having, item); select_lex->having= join->having= and_items(join->having, item);
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd_tmp, join->tables_list, &join->having)) if (join->having->fix_fields(thd, join->tables_list, &join->having))
{ {
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
DBUG_RETURN(RES_ERROR); goto err;
} }
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
} }
else else
{ {
join->conds= and_items(join->conds, item); select_lex->where= join->conds= and_items(join->conds, item);
if (join->conds->fix_fields(thd_tmp, join->tables_list, &join->having)) if (join->conds->fix_fields(thd, join->tables_list, &join->having))
DBUG_RETURN(RES_ERROR); goto err;
} }
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_OK); DBUG_RETURN(RES_OK);
err:
if (stmt)
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(RES_ERROR);
} }
...@@ -894,13 +970,30 @@ subselect_single_select_engine(st_select_lex *select, ...@@ -894,13 +970,30 @@ subselect_single_select_engine(st_select_lex *select,
this->select_lex= select_lex; this->select_lex= select_lex;
} }
void subselect_single_select_engine::cleanup() void subselect_single_select_engine::cleanup()
{ {
prepared= 0; DBUG_ENTER("subselect_single_select_engine::cleanup");
optimized= 0; prepared= optimized= executed= 0;
executed= 0; DBUG_VOID_RETURN;
}
void subselect_union_engine::cleanup()
{
DBUG_ENTER("subselect_union_engine::cleanup");
unit->reinit_exec_mechanism();
DBUG_VOID_RETURN;
} }
void subselect_uniquesubquery_engine::cleanup()
{
DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
DBUG_VOID_RETURN;
}
subselect_union_engine::subselect_union_engine(st_select_lex_unit *u, subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
select_subselect *result_arg, select_subselect *result_arg,
Item_subselect *item_arg) Item_subselect *item_arg)
......
...@@ -26,6 +26,7 @@ class JOIN; ...@@ -26,6 +26,7 @@ class JOIN;
class select_subselect; class select_subselect;
class subselect_engine; class subselect_engine;
class Item_bool_func2; class Item_bool_func2;
class Statement;
/* base class for subselects */ /* base class for subselects */
...@@ -35,22 +36,30 @@ class Item_subselect :public Item_result_field ...@@ -35,22 +36,30 @@ class Item_subselect :public Item_result_field
protected: protected:
/* thread handler, will be assigned in fix_fields only */ /* thread handler, will be assigned in fix_fields only */
THD *thd; THD *thd;
/* prepared statement, or 0 */
Statement *stmt;
/* substitution instead of subselect in case of optimization */ /* substitution instead of subselect in case of optimization */
Item *substitution; Item *substitution;
/* unit of subquery */
st_select_lex_unit *unit;
/* engine that perform execution of subselect (single select or union) */ /* engine that perform execution of subselect (single select or union) */
subselect_engine *engine; subselect_engine *engine;
/* old engine if engine was changed */
subselect_engine *old_engine;
/* cache of used external tables */ /* cache of used external tables */
table_map used_tables_cache; table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */ /* allowed number of columns (1 for single value subqueries) */
uint max_columns; uint max_columns;
/* work with 'substitution' */ /* work with 'substitution' */
bool have_to_be_excluded; bool have_to_be_excluded;
/* cache of constante state */ /* cache of constant state */
bool const_item_cache; bool const_item_cache;
public: public:
/* changed engine indicator */ /* changed engine indicator */
bool engine_changed; bool engine_changed;
/* subquery is transformed */
bool changed;
enum trans_res {RES_OK, RES_REDUCE, RES_ERROR}; enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS, enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
...@@ -94,6 +103,7 @@ class Item_subselect :public Item_result_field ...@@ -94,6 +103,7 @@ class Item_subselect :public Item_result_field
void print(String *str); void print(String *str);
bool change_engine(subselect_engine *eng) bool change_engine(subselect_engine *eng)
{ {
old_engine= engine;
engine= eng; engine= eng;
engine_changed= 1; engine_changed= 1;
return eng == 0; return eng == 0;
...@@ -116,6 +126,7 @@ class Item_singlerow_subselect :public Item_subselect ...@@ -116,6 +126,7 @@ class Item_singlerow_subselect :public Item_subselect
Item_singlerow_subselect(st_select_lex *select_lex); Item_singlerow_subselect(st_select_lex *select_lex);
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {} Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
void cleanup();
subs_type substype() { return SINGLEROW_SUBS; } subs_type substype() { return SINGLEROW_SUBS; }
void reset(); void reset();
...@@ -200,13 +211,6 @@ class Item_in_subselect :public Item_exists_subselect ...@@ -200,13 +211,6 @@ class Item_in_subselect :public Item_exists_subselect
{} {}
void cleanup()
{
Item_exists_subselect::cleanup();
abort_on_null= 0;
transformed= 0;
upper_not= 0;
}
subs_type substype() { return IN_SUBS; } subs_type substype() { return IN_SUBS; }
void reset() void reset()
{ {
...@@ -269,7 +273,7 @@ class subselect_engine: public Sql_alloc ...@@ -269,7 +273,7 @@ class subselect_engine: public Sql_alloc
maybe_null= 0; maybe_null= 0;
} }
virtual ~subselect_engine() {}; // to satisfy compiler virtual ~subselect_engine() {}; // to satisfy compiler
virtual void cleanup() {} virtual void cleanup()= 0;
// set_thd should be called before prepare() // set_thd should be called before prepare()
void set_thd(THD *thd_arg) { thd= thd_arg; } void set_thd(THD *thd_arg) { thd= thd_arg; }
...@@ -318,6 +322,7 @@ class subselect_union_engine: public subselect_engine ...@@ -318,6 +322,7 @@ class subselect_union_engine: public subselect_engine
subselect_union_engine(st_select_lex_unit *u, subselect_union_engine(st_select_lex_unit *u,
select_subselect *result, select_subselect *result,
Item_subselect *item); Item_subselect *item);
void cleanup();
int prepare(); int prepare();
void fix_length_and_dec(Item_cache** row); void fix_length_and_dec(Item_cache** row);
int exec(); int exec();
...@@ -345,6 +350,7 @@ class subselect_uniquesubquery_engine: public subselect_engine ...@@ -345,6 +350,7 @@ class subselect_uniquesubquery_engine: public subselect_engine
set_thd(thd_arg); set_thd(thd_arg);
} }
~subselect_uniquesubquery_engine(); ~subselect_uniquesubquery_engine();
void cleanup();
int prepare(); int prepare();
void fix_length_and_dec(Item_cache** row); void fix_length_and_dec(Item_cache** row);
int exec(); int exec();
......
...@@ -1084,6 +1084,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)), ...@@ -1084,6 +1084,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
void Item_sum_count_distinct::cleanup() void Item_sum_count_distinct::cleanup()
{ {
DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup(); Item_sum_int::cleanup();
/* /*
Free table and tree if they belong to this item (if item have not pointer Free table and tree if they belong to this item (if item have not pointer
...@@ -1104,6 +1105,7 @@ void Item_sum_count_distinct::cleanup() ...@@ -1104,6 +1105,7 @@ void Item_sum_count_distinct::cleanup()
use_tree= 0; use_tree= 0;
} }
} }
DBUG_VOID_RETURN;
} }
...@@ -1672,6 +1674,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, ...@@ -1672,6 +1674,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
void Item_func_group_concat::cleanup() void Item_func_group_concat::cleanup()
{ {
DBUG_ENTER("Item_func_group_concat::cleanup");
/* /*
Free table and tree if they belong to this item (if item have not pointer Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects ) to original item from which was made copy => it own its objects )
...@@ -1692,6 +1695,7 @@ void Item_func_group_concat::cleanup() ...@@ -1692,6 +1695,7 @@ void Item_func_group_concat::cleanup()
delete_tree(tree); delete_tree(tree);
} }
} }
DBUG_VOID_RETURN;
} }
......
...@@ -60,8 +60,10 @@ class Item_sum :public Item_result_field ...@@ -60,8 +60,10 @@ class Item_sum :public Item_result_field
Item_sum(THD *thd, Item_sum *item); Item_sum(THD *thd, Item_sum *item);
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_sum::cleanup");
Item_result_field::cleanup(); Item_result_field::cleanup();
result_field=0; result_field=0;
DBUG_VOID_RETURN;
} }
enum Type type() const { return SUM_FUNC_ITEM; } enum Type type() const { return SUM_FUNC_ITEM; }
......
...@@ -83,7 +83,7 @@ extern "C" void free_user_var(user_var_entry *entry) ...@@ -83,7 +83,7 @@ extern "C" void free_user_var(user_var_entry *entry)
** Thread specific functions ** Thread specific functions
****************************************************************************/ ****************************************************************************/
THD::THD():user_time(0), is_fatal_error(0), THD::THD():user_time(0), current_statement(0), is_fatal_error(0),
last_insert_id_used(0), last_insert_id_used(0),
insert_id_used(0), rand_used(0), in_lock_tables(0), insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0) global_read_lock(0), bootstrap(0)
...@@ -1244,6 +1244,21 @@ void Statement::set_statement(Statement *stmt) ...@@ -1244,6 +1244,21 @@ void Statement::set_statement(Statement *stmt)
mem_root= stmt->mem_root; mem_root= stmt->mem_root;
} }
void Statement::set_n_backup_item_arena(Statement *set, Statement *backup)
{
backup->mem_root= mem_root;
backup->free_list= free_list;
set_item_arena(set);
}
void Statement::set_item_arena(Statement *set)
{
mem_root= set->mem_root;
free_list= set->free_list;
}
Statement::~Statement() Statement::~Statement()
{ {
......
...@@ -427,7 +427,7 @@ class Statement ...@@ -427,7 +427,7 @@ class Statement
public: public:
/* FIXME: must be private */ /* FIXME: must be private */
LEX main_lex; LEX main_lex;
public:
/* /*
Uniquely identifies each statement object in thread scope; change during Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const statement lifetime. FIXME: must be const
...@@ -476,7 +476,7 @@ class Statement ...@@ -476,7 +476,7 @@ class Statement
char *query; char *query;
uint32 query_length; // current query length uint32 query_length; // current query length
/* /*
List of items created in the parser for this query. Every item puts List of items created in the parser for this query. Every item puts
itself to the list on creation (see Item::Item() for details)) itself to the list on creation (see Item::Item() for details))
*/ */
Item *free_list; Item *free_list;
...@@ -503,6 +503,15 @@ class Statement ...@@ -503,6 +503,15 @@ class Statement
void set_statement(Statement *stmt); void set_statement(Statement *stmt);
/* return class type */ /* return class type */
virtual Type type() const; virtual Type type() const;
void set_n_backup_item_arena(Statement *set, Statement *backup);
inline void restore_backup_item_arena(Statement *backup)
{
set_item_arena(backup);
// reset backup mem_root to avoid its freeing
init_alloc_root(&backup->mem_root, 0, 0);
}
void set_item_arena(Statement *set);
}; };
...@@ -688,6 +697,10 @@ class THD :public ilink, ...@@ -688,6 +697,10 @@ class THD :public ilink,
#ifdef SIGNAL_WITH_VIO_CLOSE #ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio; Vio* active_vio;
#endif #endif
/*
Current prepared Statement if there one, or 0
*/
Statement *current_statement;
/* /*
next_insert_id is set on SET INSERT_ID= #. This is used as the next next_insert_id is set on SET INSERT_ID= #. This is used as the next
generated auto_increment value in handler.cc generated auto_increment value in handler.cc
......
...@@ -1624,7 +1624,11 @@ void st_select_lex::print_limit(THD *thd, String *str) ...@@ -1624,7 +1624,11 @@ void st_select_lex::print_limit(THD *thd, String *str)
/* /*
There are st_select_lex::add_table_to_list & There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc st_select_lex::set_lock_for_tables are in sql_parse.cc
st_select_lex::print is in sql_select.h st_select_lex::print is in sql_select.h
st_select_lex_unit::prepare, st_select_lex_unit::exec,
st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism
are in sql_union.cc
*/ */
...@@ -355,6 +355,7 @@ class st_select_lex_unit: public st_select_lex_node { ...@@ -355,6 +355,7 @@ class st_select_lex_unit: public st_select_lex_node {
int prepare(THD *thd, select_result *result, ulong additional_options); int prepare(THD *thd, select_result *result, ulong additional_options);
int exec(); int exec();
int cleanup(); int cleanup();
void reinit_exec_mechanism();
bool check_updateable(char *db, char *table); bool check_updateable(char *db, char *table);
void print(String *str); void print(String *str);
......
...@@ -752,14 +752,21 @@ static bool mysql_test_select_fields(Prepared_statement *stmt, ...@@ -752,14 +752,21 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
JOIN *join= new JOIN(thd, fields, select_options, result);
thd->used_tables= 0; // Updated by setup_fields thd->used_tables= 0; // Updated by setup_fields
Statement backup;
if (join->prepare(&select_lex->ref_pointer_array, /*
(TABLE_LIST*)select_lex->get_table_list(), we do not want to have in statement memory all that junk,
wild_num, conds, og_num, order, group, having, proc, which will be created by preparation => substitute memory
select_lex, unit)) from original thread pool
*/
thd->set_n_backup_item_arena(&thd->stmt_backup, &backup);
if ((unit->prepare(thd, result, 0)))
{
thd->restore_backup_item_arena(&backup);
DBUG_RETURN(1); DBUG_RETURN(1);
}
thd->restore_backup_item_arena(&backup);
if (send_prep_stmt(stmt, fields.elements) || if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0) thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
...@@ -767,7 +774,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt, ...@@ -767,7 +774,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
#endif #endif
) )
DBUG_RETURN(1); DBUG_RETURN(1);
join->cleanup(); unit->cleanup();
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -898,6 +905,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) ...@@ -898,6 +905,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_backup.set_statement(thd); thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt); thd->set_statement(stmt);
thd->current_statement= stmt;
if (alloc_query(thd, packet, packet_length)) if (alloc_query(thd, packet, packet_length))
goto alloc_query_err; goto alloc_query_err;
...@@ -928,6 +936,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) ...@@ -928,6 +936,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
cleanup_items(thd->free_list); cleanup_items(thd->free_list);
stmt->set_statement(thd); stmt->set_statement(thd);
thd->set_statement(&thd->stmt_backup); thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
if (init_param_items(stmt)) if (init_param_items(stmt))
goto init_param_err; goto init_param_err;
...@@ -946,6 +955,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) ...@@ -946,6 +955,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_map.erase(stmt); thd->stmt_map.erase(stmt);
DBUG_RETURN(1); DBUG_RETURN(1);
insert_stmt_err: insert_stmt_err:
thd->current_statement= 0;
delete stmt; delete stmt;
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -979,6 +989,7 @@ void mysql_stmt_execute(THD *thd, char *packet) ...@@ -979,6 +989,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
stmt->query_id= thd->query_id; stmt->query_id= thd->query_id;
thd->stmt_backup.set_statement(thd); thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt); thd->set_statement(stmt);
thd->current_statement= stmt;
thd->free_list= 0; thd->free_list= 0;
/* /*
...@@ -1010,17 +1021,21 @@ void mysql_stmt_execute(THD *thd, char *packet) ...@@ -1010,17 +1021,21 @@ void mysql_stmt_execute(THD *thd, char *packet)
/* Fix ORDER list */ /* Fix ORDER list */
for (order=(ORDER *)sl->order_list.first ; order ; order=order->next) for (order=(ORDER *)sl->order_list.first ; order ; order=order->next)
order->item= (Item **)(order+1); order->item= (Item **)(order+1);
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
for (TABLE_LIST *tables= (TABLE_LIST*) sl->table_list.first;
tables;
tables= tables->next)
{
tables->table= 0; // safety - nasty init
tables->table_list= 0;
}
} }
/*
TODO: When the new table structure is ready, then have a status bit
to indicate the table is altered, and re-do the setup_*
and open the tables back.
*/
for (TABLE_LIST *tables= (TABLE_LIST*) stmt->lex->select_lex.table_list.first;
tables;
tables= tables->next)
tables->table= 0; // safety - nasty init
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (stmt->param_count && setup_params_data(stmt)) if (stmt->param_count && setup_params_data(stmt))
...@@ -1050,6 +1065,7 @@ void mysql_stmt_execute(THD *thd, char *packet) ...@@ -1050,6 +1065,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
cleanup_items(stmt->free_list); cleanup_items(stmt->free_list);
free_root(&thd->mem_root, MYF(0)); free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup); thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -327,8 +327,7 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -327,8 +327,7 @@ JOIN::prepare(Item ***rref_pointer_array,
// Is it subselect // Is it subselect
{ {
Item_subselect *subselect; Item_subselect *subselect;
if ((subselect= select_lex->master_unit()->item) && if ((subselect= select_lex->master_unit()->item))
select_lex->linkage != GLOBAL_OPTIONS_TYPE)
{ {
Item_subselect::trans_res res; Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) != if ((res= subselect->select_transformer(this)) !=
...@@ -1519,10 +1518,10 @@ JOIN::cleanup() ...@@ -1519,10 +1518,10 @@ JOIN::cleanup()
lock=0; // It's faster to unlock later lock=0; // It's faster to unlock later
join_free(1); join_free(1);
if (exec_tmp_table1) if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1); free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2) if (exec_tmp_table2)
free_tmp_table(thd, exec_tmp_table2); free_tmp_table(thd, exec_tmp_table2);
delete select; delete select;
delete_dynamic(&keyuse); delete_dynamic(&keyuse);
delete procedure; delete procedure;
......
...@@ -474,3 +474,9 @@ int st_select_lex_unit::cleanup() ...@@ -474,3 +474,9 @@ int st_select_lex_unit::cleanup()
} }
DBUG_RETURN(error); DBUG_RETURN(error);
} }
void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
}
...@@ -8095,6 +8095,85 @@ static void test_bug1946() ...@@ -8095,6 +8095,85 @@ static void test_bug1946()
rc= mysql_query(mysql,"DROP TABLE prepare_command"); rc= mysql_query(mysql,"DROP TABLE prepare_command");
} }
static void test_subqueries()
{
MYSQL_STMT *stmt;
int rc, i;
const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1";
myheader("test_subquery");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
myquery(rc);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);");
myquery(rc);
rc= mysql_query(mysql,
"insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5);");
myquery(rc);
rc= mysql_query(mysql,"create table t2 select * from t1;");
myquery(rc);
stmt= mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt);
for (i= 0; i < 3; i++)
{
rc= mysql_execute(stmt);
mystmt(stmt, rc);
assert(5 == my_process_stmt_result(stmt));
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1,t2");
myquery(rc);
}
static void test_bad_union()
{
MYSQL_STMT *stmt;
const char *query= "SELECT 1, 2 union SELECT 1";
myheader("test_bad_union");
stmt= mysql_prepare(mysql, query, strlen(query));
assert(stmt == 0);
myerror(NULL);
}
static void test_distinct()
{
MYSQL_STMT *stmt;
int rc, i;
const char *query= "SELECT count(distinct b), group_concat(a) FROM t1";
myheader("test_subquery");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int , b int);");
myquery(rc);
rc= mysql_query(mysql,
"insert into t1 values (1,1), (2, 2), (3,3), (4,4), (5,5);");
myquery(rc);
for (i= 0; i < 3; i++)
{
stmt= mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt);
rc= mysql_execute(stmt);
mystmt(stmt, rc);
assert(1 == my_process_stmt_result(stmt));
mysql_stmt_close(stmt);
}
rc= mysql_query(mysql, "DROP TABLE t1");
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
...@@ -8234,6 +8313,7 @@ int main(int argc, char **argv) ...@@ -8234,6 +8313,7 @@ int main(int argc, char **argv)
test_count= 1; test_count= 1;
start_time= time((time_t *)0); start_time= time((time_t *)0);
client_query(); /* simple client query test */ client_query(); /* simple client query test */
#if NOT_YET_WORKING #if NOT_YET_WORKING
/* Used for internal new development debugging */ /* Used for internal new development debugging */
...@@ -8340,6 +8420,10 @@ int main(int argc, char **argv) ...@@ -8340,6 +8420,10 @@ int main(int argc, char **argv)
test_bug1644(); /* BUG#1644 */ test_bug1644(); /* BUG#1644 */
test_bug1946(); /* test that placeholders are allowed only in test_bug1946(); /* test that placeholders are allowed only in
prepared queries */ prepared queries */
test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */
test_distinct(); /* distinct aggregate functions */
end_time= time((time_t *)0); end_time= time((time_t *)0);
total_time+= difftime(end_time, start_time); total_time+= difftime(end_time, start_time);
......
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