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

fixed subquery with PS (BUG#2462)

fixed UNION preparation
parent 8eb590a7
......@@ -966,8 +966,10 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
void Item_field::cleanup()
{
DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup();
field= result_field= 0;
DBUG_VOID_RETURN;
}
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)
void Item_ref::cleanup()
{
DBUG_ENTER("Item_ref::cleanup");
Item_ident::cleanup();
if (hook_ptr)
*hook_ptr= orig_item;
DBUG_VOID_RETURN;
}
......
......@@ -128,7 +128,13 @@ public:
virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length, CHARSET_INFO *cs);
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 bool fix_fields(THD *, struct st_table_list *, Item **);
virtual int save_in_field(Field *field, bool no_conversions);
......@@ -996,8 +1002,10 @@ public:
void bring_value();
void cleanup()
{
DBUG_ENTER("Item_cache_row::cleanup");
Item_cache::cleanup();
values= 0;
DBUG_VOID_RETURN;
}
};
......@@ -1023,8 +1031,10 @@ public:
Field *example() { return field_example; }
void cleanup()
{
DBUG_ENTER("Item_type_holder::cleanup");
Item::cleanup();
item_type= orig_type;
DBUG_VOID_RETURN;
}
};
......
......@@ -484,6 +484,14 @@ longlong Item_in_optimizer::val_int()
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()
{
cache->store(args[0]);
......
......@@ -105,6 +105,7 @@ public:
Item_in_optimizer return NULL, else it evaluate Item_in_subselect.
*/
longlong val_int();
void cleanup();
const char *func_name() const { return "<in_optimizer>"; }
Item_cache **get_cache() { return &cache; }
};
......@@ -207,9 +208,11 @@ public:
}
void cleanup()
{
DBUG_ENTER("Item_bool_rowready_func2::cleanup");
Item_bool_func2::cleanup();
tmp_arg[0]= orig_a;
tmp_arg[1]= orig_b;
DBUG_VOID_RETURN;
}
};
......@@ -718,10 +721,12 @@ class Item_func_in :public Item_int_func
void fix_length_and_dec();
void cleanup()
{
DBUG_ENTER("Item_func_in::cleanup");
delete array;
delete in_item;
array= 0;
in_item= 0;
DBUG_VOID_RETURN;
}
optimize_type select_optimize() const
{ return array ? OPTIMIZE_KEY : OPTIMIZE_NONE; }
......
......@@ -991,6 +991,7 @@ public:
join_key(0), ft_handler(0), table(0), master(0), concat(0) { }
void cleanup()
{
DBUG_ENTER("Item_func_match");
if (!master && ft_handler)
{
ft_handler->please->close_search(ft_handler);
......@@ -1001,6 +1002,7 @@ public:
}
if (concat)
delete concat;
DBUG_VOID_RETURN;
}
enum Functype functype() const { return FT_FUNC; }
const char *func_name() const { return "match"; }
......
This diff is collapsed.
......@@ -26,6 +26,7 @@ class JOIN;
class select_subselect;
class subselect_engine;
class Item_bool_func2;
class Statement;
/* base class for subselects */
......@@ -35,22 +36,30 @@ class Item_subselect :public Item_result_field
protected:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
/* prepared statement, or 0 */
Statement *stmt;
/* substitution instead of subselect in case of optimization */
Item *substitution;
/* unit of subquery */
st_select_lex_unit *unit;
/* engine that perform execution of subselect (single select or union) */
subselect_engine *engine;
/* old engine if engine was changed */
subselect_engine *old_engine;
/* cache of used external tables */
table_map used_tables_cache;
/* allowed number of columns (1 for single value subqueries) */
uint max_columns;
/* work with 'substitution' */
bool have_to_be_excluded;
/* cache of constante state */
/* cache of constant state */
bool const_item_cache;
public:
/* changed engine indicator */
bool engine_changed;
/* subquery is transformed */
bool changed;
enum trans_res {RES_OK, RES_REDUCE, RES_ERROR};
enum subs_type {UNKNOWN_SUBS, SINGLEROW_SUBS,
......@@ -94,6 +103,7 @@ public:
void print(String *str);
bool change_engine(subselect_engine *eng)
{
old_engine= engine;
engine= eng;
engine_changed= 1;
return eng == 0;
......@@ -116,6 +126,7 @@ public:
Item_singlerow_subselect(st_select_lex *select_lex);
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
void cleanup();
subs_type substype() { return SINGLEROW_SUBS; }
void reset();
......@@ -200,13 +211,6 @@ public:
{}
void cleanup()
{
Item_exists_subselect::cleanup();
abort_on_null= 0;
transformed= 0;
upper_not= 0;
}
subs_type substype() { return IN_SUBS; }
void reset()
{
......@@ -269,7 +273,7 @@ public:
maybe_null= 0;
}
virtual ~subselect_engine() {}; // to satisfy compiler
virtual void cleanup() {}
virtual void cleanup()= 0;
// set_thd should be called before prepare()
void set_thd(THD *thd_arg) { thd= thd_arg; }
......@@ -318,6 +322,7 @@ public:
subselect_union_engine(st_select_lex_unit *u,
select_subselect *result,
Item_subselect *item);
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
......@@ -345,6 +350,7 @@ public:
set_thd(thd_arg);
}
~subselect_uniquesubquery_engine();
void cleanup();
int prepare();
void fix_length_and_dec(Item_cache** row);
int exec();
......
......@@ -1084,6 +1084,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
void Item_sum_count_distinct::cleanup()
{
DBUG_ENTER("Item_sum_count_distinct::cleanup");
Item_sum_int::cleanup();
/*
Free table and tree if they belong to this item (if item have not pointer
......@@ -1099,6 +1100,7 @@ void Item_sum_count_distinct::cleanup()
table= 0;
use_tree= 0;
}
DBUG_VOID_RETURN;
}
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
......@@ -1666,6 +1668,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
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
to original item from which was made copy => it own its objects )
......@@ -1679,6 +1682,7 @@ void Item_func_group_concat::cleanup()
if (tree_mode)
delete_tree(tree);
}
DBUG_VOID_RETURN;
}
Item_func_group_concat::~Item_func_group_concat()
......
......@@ -60,8 +60,10 @@ public:
Item_sum(THD *thd, Item_sum *item);
void cleanup()
{
DBUG_ENTER("Item_sum::cleanup");
Item_result_field::cleanup();
result_field=0;
DBUG_VOID_RETURN;
}
enum Type type() const { return SUM_FUNC_ITEM; }
......
......@@ -83,7 +83,7 @@ extern "C" void free_user_var(user_var_entry *entry)
** 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),
insert_id_used(0), rand_used(0), in_lock_tables(0),
global_read_lock(0), bootstrap(0)
......@@ -1232,6 +1232,21 @@ void Statement::set_statement(Statement *stmt)
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()
{
......
......@@ -427,7 +427,7 @@ class Statement
public:
/* FIXME: must be private */
LEX main_lex;
public:
/*
Uniquely identifies each statement object in thread scope; change during
statement lifetime. FIXME: must be const
......@@ -476,7 +476,7 @@ public:
char *query;
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))
*/
Item *free_list;
......@@ -503,6 +503,15 @@ public:
void set_statement(Statement *stmt);
/* return class type */
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 @@ public:
#ifdef SIGNAL_WITH_VIO_CLOSE
Vio* active_vio;
#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
generated auto_increment value in handler.cc
......
......@@ -1561,7 +1561,11 @@ void st_select_lex::print_limit(THD *thd, String *str)
/*
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_unit::prepare, st_select_lex_unit::exec,
st_select_lex_unit::cleanup, st_select_lex_unit::reinit_exec_mechanism
are in sql_union.cc
*/
......@@ -354,6 +354,7 @@ public:
int prepare(THD *thd, select_result *result, ulong additional_options);
int exec();
int cleanup();
void reinit_exec_mechanism();
void print(String *str);
......
......@@ -753,14 +753,21 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
DBUG_RETURN(1);
}
JOIN *join= new JOIN(thd, fields, select_options, result);
thd->used_tables= 0; // Updated by setup_fields
if (join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*)select_lex->get_table_list(),
wild_num, conds, og_num, order, group, having, proc,
select_lex, unit))
Statement backup;
/*
we do not want to have in statement memory all that junk,
which will be created by preparation => substitute memory
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);
}
thd->restore_backup_item_arena(&backup);
if (send_prep_stmt(stmt, fields.elements) ||
thd->protocol_simple.send_fields(&fields, 0)
#ifndef EMBEDDED_LIBRARY
......@@ -768,7 +775,7 @@ static bool mysql_test_select_fields(Prepared_statement *stmt,
#endif
)
DBUG_RETURN(1);
join->cleanup();
unit->cleanup();
}
DBUG_RETURN(0);
}
......@@ -899,6 +906,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_statement= stmt;
if (alloc_query(thd, packet, packet_length))
goto alloc_query_err;
......@@ -929,6 +937,7 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length)
cleanup_items(thd->free_list);
stmt->set_statement(thd);
thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
if (init_param_items(stmt))
goto init_param_err;
......@@ -947,6 +956,7 @@ alloc_query_err:
thd->stmt_map.erase(stmt);
DBUG_RETURN(1);
insert_stmt_err:
thd->current_statement= 0;
delete stmt;
DBUG_RETURN(1);
}
......@@ -980,6 +990,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
stmt->query_id= thd->query_id;
thd->stmt_backup.set_statement(thd);
thd->set_statement(stmt);
thd->current_statement= stmt;
thd->free_list= 0;
/*
......@@ -1009,17 +1020,21 @@ void mysql_stmt_execute(THD *thd, char *packet)
order->item= (Item **)(order+1);
for (order=(ORDER *)sl->order_list.first ; order ; order=order->next)
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
if (stmt->param_count && setup_params_data(stmt))
......@@ -1049,6 +1064,7 @@ void mysql_stmt_execute(THD *thd, char *packet)
cleanup_items(stmt->free_list);
free_root(&thd->mem_root, MYF(0));
thd->set_statement(&thd->stmt_backup);
thd->current_statement= 0;
DBUG_VOID_RETURN;
}
......
......@@ -330,8 +330,7 @@ JOIN::prepare(Item ***rref_pointer_array,
// Is it subselect
{
Item_subselect *subselect;
if ((subselect= select_lex->master_unit()->item) &&
select_lex->linkage != GLOBAL_OPTIONS_TYPE)
if ((subselect= select_lex->master_unit()->item))
{
Item_subselect::trans_res res;
if ((res= subselect->select_transformer(this)) !=
......@@ -1527,10 +1526,10 @@ JOIN::cleanup()
lock=0; // It's faster to unlock later
join_free(1);
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
free_tmp_table(thd, exec_tmp_table2);
if (exec_tmp_table1)
free_tmp_table(thd, exec_tmp_table1);
if (exec_tmp_table2)
free_tmp_table(thd, exec_tmp_table2);
delete select;
delete_dynamic(&keyuse);
delete procedure;
......
......@@ -468,3 +468,9 @@ int st_select_lex_unit::cleanup()
}
DBUG_RETURN(error);
}
void st_select_lex_unit::reinit_exec_mechanism()
{
prepared= optimized= executed= 0;
}
......@@ -8095,6 +8095,53 @@ static void test_bug1946()
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));
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);
}
/*
Read and parse arguments and MySQL options from my.cnf
......@@ -8234,6 +8281,7 @@ int main(int argc, char **argv)
test_count= 1;
start_time= time((time_t *)0);
client_query(); /* simple client query test */
#if NOT_YET_WORKING
/* Used for internal new development debugging */
......@@ -8340,6 +8388,9 @@ int main(int argc, char **argv)
test_bug1644(); /* BUG#1644 */
test_bug1946(); /* test that placeholders are allowed only in
prepared queries */
test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */
end_time= time((time_t *)0);
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