#At file:///home/rl136806/mysql/repo/mysql-work3/ based on revid:olav.sandstaa@stripped
3280 Roy Lyseng 2010-11-09
Bug#56080: Assertion 'inited=INDEX in sql/handler.h
The problem occurs because some TABLE objects are associated with
the optimizer execution structures even after close_thread_tables()
has been called. In turn, this means that final cleanup of some
TABLE objects is done from within THD::cleanup_after_query().
At this point in time, the TABLE objects may already have been
given to another session, meaning that we may end another session's
index or table scan.
The safest solution seems to be to always perform a thorough cleanup
of all execution data structures, including releasing the TABLE
objects, before close_thread_tables() is called. In other words,
this will have to be done at the end of each execution.
However, this is currently not possible in the implementation of
subquery materialization. This part of the optimizer assigns some
objects, including a TABLE object, for the lifetime of the
statement object, and not for each execution. This gives an odd
situation, where some parts of the data structures are set up for
reuse and others are not. Combine this with the fact that the
user may decide to use another strategy for a subsequent
subquery execution, the "permanent" data structures may not even
be used later.
It is therefore reasonable to allocate materialization execution
structures for the lifetime of one execution. It means that the
functions init_permanent() and init_runtime() of class
subselect_hash_sj_engine are combined into one setup() function.
In addition, the function Item_subselect::cleanup() will be called
when the cleanup() function for the underlying query expression
is called, and this function will cleanup and destroy the
materialization data structures, so that the subquery item object
is ready for a new optimization process in the next round of
execution.
However, the EXPLAIN functionality relies on these data
structures being present when explaining a query containing
a materialized subquery. Thus, we have two conflicting
requirements for query cleanup:
- For maximum efficiency we should release resources as early as
possible after execution.
- We cannot release resources that are needed for EXPLAIN queries.
One solution to this problem is to split resource cleanup in two:
1. Delete JOIN objects as soon as possible - this makes sense
because TABLE objects are associated with them through JOIN_TAB.
But notice that JOIN objects may be needed for EXPLAIN queries...
2. Cleanup query expression objects (ie st_select_lex and
st_select_lex_unit) later (in practice at end of query execution).
Because this bug was caused by a race condition, no simple test case
has been made.
mysql-test/r/union.result
Change in EXPLAIN EXTENDED output that shows an optimized predicate
in the two query specifications within a UNION in a subquery.
AFAIK, this is similar to how a non-subquery is reported, so the
change is an improvement.
sql/ha_partition.cc
Comment change.
sql/item_subselect.cc
In Item_subselect::cleanup(), "new" engine is always deleted after
an execution.
Item_in_subselect::setup_engine() now builds the materialization
engine for one execution only. Specific arena is no longer needed.
In subselect_union_engine::cleanup(), call to
unit->reinit_exec_mechanism is deleted because it is redundant.
Implementation of cleanup() functions for subclasses of
subselect_engine has been refactored.
subselect_hash_sj_engine::setup() replaces init_permanent() and
init_runtime().
For class subselect_hash_sj_engine, freeing of the temporary
result table is moved from the destructor to ::cleanup().
Some changes necessary because of interface changes.
sql/item_subselect.h
Some cleanup of the subselect_engine classes:
- All virtual functions now marked virtual in all derived classes.
- Functions that returned bool result are now declared accordingly.
- Slight cleanup of private/protected/public performed.
- Improved constructors.
sql/sql_lex.h
Change in friend declaration.
sql/sql_select.cc
Function JOIN::reinit() is renamed to JOIN::reset().
JOIN::destroy() will now delete connection to associated tables.
The st_select_lex_unit object is no longer cleaned up as early as
before, but instead relying on the general cleanup of lex->unit
in mysql_execute_command().
sql/sql_select.h
A few small interface changes.
sql/sql_union.cc
Cleaned up some confusing error handling in st_select_lex_unit::exec()
and st_select_lex::cleanup().
modified:
mysql-test/r/union.result
sql/ha_partition.cc
sql/item_subselect.cc
sql/item_subselect.h
sql/sql_lex.h
sql/sql_parse.cc
sql/sql_plugin.cc
sql/sql_plugin.h
sql/sql_select.cc
sql/sql_select.h
sql/sql_union.cc
=== modified file 'mysql-test/r/union.result'
--- a/mysql-test/r/union.result 2010-08-18 10:18:27 +0000
+++ b/mysql-test/r/union.result 2010-11-09 15:29:16 +0000
@@ -480,7 +480,7 @@ id select_type table type possible_keys
2 UNION t2 const PRIMARY PRIMARY 4 const 1 100.00
NULL UNION RESULT <union1,2> ALL NULL NULL NULL NULL NULL NULL
Warnings:
-Note 1003 (select '1' AS `a`,'1' AS `b` from `test`.`t1` where ('1' = 1)) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where ('1' = 1))
+Note 1003 (select '1' AS `a`,'1' AS `b` from `test`.`t1` where 1) union (select '1' AS `a`,'10' AS `b` from `test`.`t2` where 1)
(select * from t1 where a=5) union (select * from t2 where a=1);
a b
1 10
=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc 2010-10-21 11:34:17 +0000
+++ b/sql/ha_partition.cc 2010-11-09 15:29:16 +0000
@@ -3336,7 +3336,7 @@ int ha_partition::delete_row(const uchar
Called from item_sum.cc by Item_func_group_concat::clear(),
Item_sum_count_distinct::clear(), and Item_func_group_concat::clear().
Called from sql_delete.cc by mysql_delete().
- Called from sql_select.cc by JOIN::reinit().
+ Called from sql_select.cc by JOIN::reset().
Called from sql_union.cc by st_select_lex_unit::exec().
*/
=== modified file 'sql/item_subselect.cc'
--- a/sql/item_subselect.cc 2010-10-27 10:28:09 +0000
+++ b/sql/item_subselect.cc 2010-11-09 15:29:16 +0000
@@ -120,7 +120,10 @@ void Item_subselect::cleanup()
if (old_engine)
{
if (engine)
+ {
engine->cleanup();
+ delete engine;
+ }
engine= old_engine;
old_engine= 0;
}
@@ -293,8 +296,6 @@ bool Item_subselect::walk(Item_processor
bool Item_subselect::exec()
{
- int res;
-
/*
Do not execute subselect in case of a fatal error
or if the query has been killed.
@@ -308,7 +309,7 @@ bool Item_subselect::exec()
*/
DBUG_EXECUTE_IF("subselect_exec_fail", return 1;);
- res= engine->exec();
+ const bool res= engine->exec();
if (engine_changed)
{
@@ -1905,10 +1906,6 @@ void Item_in_subselect::fix_after_pullou
of this Item's execution. The method creates a new engine for
materialized execution, and initializes the engine.
- The initialization of the new engine is divided in two parts - a permanent
- one that lives across prepared statements, and one that is repeated for each
- execution.
-
@returns
@retval TRUE memory allocation error occurred, or was not able to create
temporary table
@@ -1917,43 +1914,30 @@ void Item_in_subselect::fix_after_pullou
bool Item_in_subselect::setup_engine()
{
- subselect_hash_sj_engine *hash_engine;
DBUG_ENTER("Item_in_subselect::setup_engine");
- if (engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE)
- {
- /* Create/initialize objects in permanent memory. */
- Query_arena *arena= thd->stmt_arena;
- Query_arena backup;
- if (arena->is_conventional())
- arena= 0;
- else
- thd->set_n_backup_active_arena(arena, &backup);
+ /* Currently, the decision whether to materialize is already taken. */
+ if (exec_method != Item_exists_subselect::EXEC_MATERIALIZATION)
+ DBUG_RETURN(FALSE);
- subselect_single_select_engine *old_engine=
- static_cast<subselect_single_select_engine*>(engine);
- if (!(hash_engine= new subselect_hash_sj_engine(thd, this,
- old_engine)) ||
- hash_engine->init_permanent(unit->get_unit_column_types()))
- {
- /*
- For some reason we cannot use materialization for this IN predicate.
- Delete all materialization-related objects, and return error.
- */
- delete hash_engine;
- if (arena)
- thd->restore_active_arena(arena, &backup);
- DBUG_RETURN(TRUE);
- }
- engine= hash_engine;
+ DBUG_ASSERT(engine->engine_type() == subselect_engine::SINGLE_SELECT_ENGINE);
- if (arena)
- thd->restore_active_arena(arena, &backup);
- }
- else
+ old_engine= engine;
+
+ if (!(engine= new subselect_hash_sj_engine(thd, this,
+ static_cast<subselect_single_select_engine*>(old_engine))))
+ DBUG_RETURN(TRUE);
+ if (((subselect_hash_sj_engine *) engine)
+ ->setup(unit->get_unit_column_types()))
{
- DBUG_ASSERT(engine->engine_type() == subselect_engine::HASH_SJ_ENGINE);
- hash_engine= static_cast<subselect_hash_sj_engine*>(engine);
+ /*
+ For some reason we cannot use materialization for this IN predicate.
+ Delete all materialization-related objects, and return error.
+ */
+ delete engine;
+ engine= old_engine;
+ old_engine= NULL;
+ DBUG_RETURN(TRUE);
}
/*
@@ -1966,10 +1950,7 @@ bool Item_in_subselect::setup_engine()
*/
unit->global_parameters->select_limit= NULL;
- /* Initializations done in runtime memory, repeated for each execution. */
- const bool res= hash_engine->init_runtime();
-
- DBUG_RETURN(res);
+ DBUG_RETURN(FALSE);
}
@@ -2106,7 +2087,6 @@ void subselect_single_select_engine::cle
void subselect_union_engine::cleanup()
{
DBUG_ENTER("subselect_union_engine::cleanup");
- unit->reinit_exec_mechanism();
result->cleanup();
DBUG_VOID_RETURN;
}
@@ -2140,16 +2120,6 @@ bool subselect_union_engine::no_rows()
}
-void subselect_uniquesubquery_engine::cleanup()
-{
- DBUG_ENTER("subselect_uniquesubquery_engine::cleanup");
- /* Tell handler we don't need the index anymore */
- if (tab->table->file->inited)
- tab->table->file->ha_index_end();
- DBUG_VOID_RETURN;
-}
-
-
subselect_union_engine::subselect_union_engine(st_select_lex_unit *u,
select_result_interceptor *result_arg,
Item_subselect *item_arg)
@@ -2186,7 +2156,7 @@ subselect_union_engine::subselect_union_
@retval 1 if error
*/
-int subselect_single_select_engine::prepare()
+bool subselect_single_select_engine::prepare()
{
if (prepared)
return 0;
@@ -2213,12 +2183,14 @@ int subselect_single_select_engine::prep
return 0;
}
-int subselect_union_engine::prepare()
+
+bool subselect_union_engine::prepare()
{
return unit->prepare(thd, result, SELECT_NO_UNLOCK);
}
-int subselect_uniquesubquery_engine::prepare()
+
+bool subselect_uniquesubquery_engine::prepare()
{
/* Should never be called. */
DBUG_ASSERT(FALSE);
@@ -2311,7 +2283,7 @@ int rr_sequential(READ_RECORD *info);
int join_read_always_key_or_null(JOIN_TAB *tab);
int join_read_next_same_or_null(READ_RECORD *info);
-int subselect_single_select_engine::exec()
+bool subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
char const *save_where= thd->where;
@@ -2340,12 +2312,7 @@ int subselect_single_select_engine::exec
select_lex->uncacheable != UNCACHEABLE_EXPLAIN
&& executed)
{
- if (join->reinit())
- {
- thd->where= save_where;
- thd->lex->current_select= save_select;
- DBUG_RETURN(1);
- }
+ join->reset();
item->reset();
item->assigned((executed= 0));
}
@@ -2410,10 +2377,10 @@ int subselect_single_select_engine::exec
DBUG_RETURN(0);
}
-int subselect_union_engine::exec()
+bool subselect_union_engine::exec()
{
char const *save_where= thd->where;
- int res= unit->exec();
+ const bool res= unit->exec();
thd->where= save_where;
return res;
}
@@ -2437,7 +2404,7 @@ int subselect_union_engine::exec()
TRUE - Error
*/
-int subselect_uniquesubquery_engine::scan_table()
+bool subselect_uniquesubquery_engine::scan_table()
{
int error;
TABLE *table= tab->table;
@@ -2602,7 +2569,7 @@ bool subselect_uniquesubquery_engine::co
TRUE - an error occured while scanning
*/
-int subselect_uniquesubquery_engine::exec()
+bool subselect_uniquesubquery_engine::exec()
{
DBUG_ENTER("subselect_uniquesubquery_engine::exec");
int error;
@@ -2705,7 +2672,7 @@ int subselect_uniquesubquery_engine::exe
1
*/
-int subselect_indexsubquery_engine::exec()
+bool subselect_indexsubquery_engine::exec()
{
DBUG_ENTER("subselect_indexsubquery_engine::exec");
int error;
@@ -3133,8 +3100,7 @@ bool subselect_uniquesubquery_engine::no
/**
- Create all structures needed for IN execution that can live between PS
- reexecution.
+ Create all structures needed for subquery execution using hash semijoin.
@detail
- Create a temporary table to store the result of the IN subquery. The
@@ -3152,7 +3118,7 @@ bool subselect_uniquesubquery_engine::no
@retval FALSE otherwise
*/
-bool subselect_hash_sj_engine::init_permanent(List<Item> *tmp_columns)
+bool subselect_hash_sj_engine::setup(List<Item> *tmp_columns)
{
/* The result sink where we will materialize the subquery result. */
select_union *tmp_result_sink;
@@ -3162,7 +3128,7 @@ bool subselect_hash_sj_engine::init_perm
uint tmp_key_parts; /* Number of keyparts in tmp_key. */
Item_in_subselect *item_in= (Item_in_subselect *) item;
- DBUG_ENTER("subselect_hash_sj_engine::init_permanent");
+ DBUG_ENTER("subselect_hash_sj_engine::setup");
/* 1. Create/initialize materialization related objects. */
@@ -3208,8 +3174,8 @@ bool subselect_hash_sj_engine::init_perm
Make sure there is only one index on the temp table, and it doesn't have
the extra key part created when s->uniques > 0.
*/
- DBUG_ASSERT(tmp_table->s->keys == 1 && tmp_columns->elements == tmp_key_parts);
-
+ DBUG_ASSERT(tmp_table->s->keys == 1 &&
+ tmp_columns->elements == tmp_key_parts);
/* 2. Create/initialize execution related objects. */
@@ -3304,43 +3270,22 @@ bool subselect_hash_sj_engine::init_perm
if (cond->fix_fields(thd, &cond))
DBUG_RETURN(TRUE);
- DBUG_RETURN(FALSE);
-}
-
-
-/**
- Initialize members of the engine that need to be re-initilized at each
- execution.
-
- @retval TRUE if a memory allocation error occurred
- @retval FALSE if success
-*/
-
-bool subselect_hash_sj_engine::init_runtime()
-{
/*
Create and optimize the JOIN that will be used to materialize
the subquery if not yet created.
*/
materialize_engine->prepare();
- /*
- Repeat name resolution for 'cond' since cond is not part of any
- clause of the query, and it is not 'fixed' during JOIN::prepare.
- */
- if (cond && !cond->fixed && cond->fix_fields(thd, &cond))
- return TRUE;
/* Let our engine reuse this query plan for materialization. */
- materialize_join= materialize_engine->join;
- materialize_join->change_result(result);
- return FALSE;
+ materialize_engine->join->change_result(result);
+
+ DBUG_RETURN(FALSE);
}
subselect_hash_sj_engine::~subselect_hash_sj_engine()
{
delete result;
- if (tab)
- free_tmp_table(thd, tab->table);
+ DBUG_ASSERT(!tab);
}
@@ -3353,10 +3298,15 @@ subselect_hash_sj_engine::~subselect_has
void subselect_hash_sj_engine::cleanup()
{
- is_materialized= FALSE;
+ DBUG_ENTER("subselect_hash_sj_engine::cleanup");
+ is_materialized= false;
result->cleanup(); /* Resets the temp table as well. */
+ if (tab->table->file->inited)
+ tab->table->file->ha_index_end(); // Close the scan over the index
+ free_tmp_table(thd, tab->table);
+ tab= NULL;
materialize_engine->cleanup();
- subselect_uniquesubquery_engine::cleanup();
+ DBUG_VOID_RETURN;
}
@@ -3371,7 +3321,7 @@ void subselect_hash_sj_engine::cleanup()
@retval FALSE otherwise
*/
-int subselect_hash_sj_engine::exec()
+bool subselect_hash_sj_engine::exec()
{
Item_in_subselect *item_in= (Item_in_subselect *) item;
@@ -3383,17 +3333,17 @@ int subselect_hash_sj_engine::exec()
*/
if (!is_materialized)
{
- int res= 0;
+ bool res= false;
SELECT_LEX *save_select= thd->lex->current_select;
thd->lex->current_select= materialize_engine->select_lex;
- if ((res= materialize_join->optimize()))
+ if ((res= materialize_engine->join->optimize()))
goto err; /* purecov: inspected */
if (materialize_engine->save_join_if_explain())
goto err;
- materialize_join->exec();
- if ((res= test(materialize_join->error || thd->is_fatal_error)))
+ materialize_engine->join->exec();
+ if ((res= test(materialize_engine->join->error || thd->is_fatal_error)))
goto err;
/*
=== modified file 'sql/item_subselect.h'
--- a/sql/item_subselect.h 2010-10-15 10:32:50 +0000
+++ b/sql/item_subselect.h 2010-11-09 15:29:16 +0000
@@ -44,7 +44,8 @@ typedef Comp_creator* (*chooser_compare_
class Item_subselect :public Item_result_field
{
- my_bool value_assigned; /* value already assigned to subselect */
+private:
+ bool value_assigned; /* value already assigned to subselect */
public:
/* thread handler, will be assigned in fix_fields only */
THD *thd;
@@ -109,7 +110,7 @@ public:
select_result_interceptor *result);
~Item_subselect();
- void cleanup();
+ virtual void cleanup();
virtual void reset()
{
null_value= 1;
@@ -191,10 +192,10 @@ public:
Item_singlerow_subselect(st_select_lex *select_lex);
Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {}
- void cleanup();
+ virtual void cleanup();
subs_type substype() { return SINGLEROW_SUBS; }
- void reset();
+ virtual void reset();
trans_res select_transformer(JOIN *join);
void store(uint i, Item* item);
double val_real();
@@ -241,7 +242,7 @@ public:
Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max);
virtual void print(String *str, enum_query_type query_type);
- void cleanup();
+ virtual void cleanup();
bool any_value() { return was_values; }
void register_value() { was_values= TRUE; }
void reset_value_registration() { was_values= FALSE; }
@@ -293,7 +294,7 @@ public:
return RES_OK;
}
subs_type substype() { return EXISTS_SUBS; }
- void reset()
+ virtual void reset()
{
value= 0;
}
@@ -381,9 +382,9 @@ public:
optimizer(NULL), was_null(FALSE), abort_on_null(FALSE),
pushed_cond_guards(NULL), upper_item(NULL)
{}
- void cleanup();
+ virtual void cleanup();
subs_type substype() { return IN_SUBS; }
- void reset()
+ virtual void reset()
{
value= 0;
null_value= 0;
@@ -456,15 +457,13 @@ public:
INDEXSUBQUERY_ENGINE, HASH_SJ_ENGINE};
subselect_engine(Item_subselect *si, select_result_interceptor *res)
- :thd(0)
- {
- result= res;
- item= si;
- res_type= STRING_RESULT;
- res_field_type= MYSQL_TYPE_VAR_STRING;
- maybe_null= 0;
- }
+ :result(res), thd(NULL), item(si), res_type(STRING_RESULT),
+ res_field_type(MYSQL_TYPE_VAR_STRING), maybe_null(FALSE)
+ {}
virtual ~subselect_engine() {}; // to satisfy compiler
+ /**
+ Cleanup engine after complete query execution, free all resources.
+ */
virtual void cleanup()= 0;
/*
@@ -472,8 +471,8 @@ public:
Should be called before prepare().
*/
void set_thd(THD *thd_arg);
- THD * get_thd() { return thd; }
- virtual int prepare()= 0;
+ THD * get_thd() const { return thd; }
+ virtual bool prepare()= 0;
virtual void fix_length_and_dec(Item_cache** row)= 0;
/*
Execute the engine
@@ -495,11 +494,11 @@ public:
1 - Either an execution error, or the engine was "changed", and the
caller should call exec() again for the new engine.
*/
- virtual int exec()= 0;
+ virtual bool exec()= 0;
virtual uint cols()= 0; /* return number of columns in select */
virtual uint8 uncacheable()= 0; /* query is uncacheable */
- enum Item_result type() { return res_type; }
- enum_field_types field_type() { return res_field_type; }
+ virtual const enum Item_result type() const { return res_type; }
+ virtual const enum_field_types field_type() const { return res_field_type; }
virtual void exclude()= 0;
virtual bool may_be_null() { return maybe_null; };
virtual table_map upper_select_const_tables()= 0;
@@ -520,29 +519,30 @@ protected:
class subselect_single_select_engine: public subselect_engine
{
- my_bool prepared; /* simple subselect is prepared */
- my_bool optimized; /* simple subselect is optimized */
- my_bool executed; /* simple subselect is executed */
+private:
+ bool prepared; /* simple subselect is prepared */
+ bool executed; /* simple subselect is executed */
st_select_lex *select_lex; /* corresponding select_lex */
JOIN * join; /* corresponding JOIN structure */
public:
subselect_single_select_engine(st_select_lex *select,
select_result_interceptor *result,
Item_subselect *item);
- void cleanup();
- int prepare();
- void fix_length_and_dec(Item_cache** row);
- int exec();
- uint cols();
- uint8 uncacheable();
- void exclude();
- table_map upper_select_const_tables();
+ virtual void cleanup();
+ virtual bool prepare();
+ virtual void fix_length_and_dec(Item_cache** row);
+ virtual bool exec();
+ virtual uint cols();
+ virtual uint8 uncacheable();
+ virtual void exclude();
+ virtual table_map upper_select_const_tables();
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_result_interceptor *result);
- bool no_tables();
- bool may_be_null();
- bool is_executed() const { return executed; }
- bool no_rows();
+ virtual bool change_result(Item_subselect *si,
+ select_result_interceptor *result);
+ virtual bool no_tables();
+ virtual bool may_be_null();
+ virtual bool is_executed() const { return executed; }
+ virtual bool no_rows();
virtual enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; }
bool save_join_if_explain();
@@ -553,24 +553,26 @@ public:
class subselect_union_engine: public subselect_engine
{
+private:
st_select_lex_unit *unit; /* corresponding unit structure */
public:
subselect_union_engine(st_select_lex_unit *u,
select_result_interceptor *result,
Item_subselect *item);
- void cleanup();
- int prepare();
- void fix_length_and_dec(Item_cache** row);
- int exec();
- uint cols();
- uint8 uncacheable();
- void exclude();
- table_map upper_select_const_tables();
+ virtual void cleanup();
+ virtual bool prepare();
+ virtual void fix_length_and_dec(Item_cache** row);
+ virtual bool exec();
+ virtual uint cols();
+ virtual uint8 uncacheable();
+ virtual void exclude();
+ virtual table_map upper_select_const_tables();
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_result_interceptor *result);
- bool no_tables();
- bool is_executed() const;
- bool no_rows();
+ virtual bool change_result(Item_subselect *si,
+ select_result_interceptor *result);
+ virtual bool no_tables();
+ virtual bool is_executed() const;
+ virtual bool no_rows();
virtual enum_engine_type engine_type() { return UNION_ENGINE; }
};
@@ -615,26 +617,28 @@ public:
{
set_thd(thd_arg);
}
- void cleanup();
- int prepare();
- void fix_length_and_dec(Item_cache** row);
- int exec();
- uint cols() { return 1; }
- uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
- void exclude();
- table_map upper_select_const_tables() { return 0; }
+ virtual void cleanup() {}
+ virtual bool prepare();
+ virtual void fix_length_and_dec(Item_cache** row);
+ virtual bool exec();
+ virtual uint cols() { return 1; }
+ virtual uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
+ virtual void exclude();
+ virtual table_map upper_select_const_tables() { return 0; }
virtual void print (String *str, enum_query_type query_type);
- bool change_result(Item_subselect *si, select_result_interceptor *result);
- bool no_tables();
- int scan_table();
+ virtual bool change_result(Item_subselect *si,
+ select_result_interceptor *result);
+ virtual bool no_tables();
+ bool scan_table();
bool copy_ref_key();
- bool no_rows() { return empty_result_set; }
+ virtual bool no_rows() { return empty_result_set; }
virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; }
};
class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine
{
+private:
/* FALSE for 'ref', TRUE for 'ref-or-null'. */
bool check_null;
/*
@@ -677,7 +681,7 @@ public:
check_null(chk_null),
having(having_arg)
{}
- int exec();
+ virtual bool exec();
virtual void print (String *str, enum_query_type query_type);
virtual enum_engine_type engine_type() { return INDEXSUBQUERY_ENGINE; }
};
@@ -712,21 +716,17 @@ inline bool Item_subselect::is_uncacheab
class subselect_hash_sj_engine: public subselect_uniquesubquery_engine
{
-protected:
+private:
/* TRUE if the subquery was materialized into a temp table. */
bool is_materialized;
/*
The old engine already chosen at parse time and stored in permanent memory.
- Through this member we can re-create and re-prepare materialize_join for
- each execution of a prepared statement. We also reuse the functionality
- of subselect_single_select_engine::[prepare | cols].
+ Through this member we can re-create and re-prepare the join object
+ used to materialize the subquery for each execution of a prepared
+ statement. We also reuse the functionality of
+ subselect_single_select_engine::[prepare | cols].
*/
subselect_single_select_engine *materialize_engine;
- /*
- QEP to execute the subquery and materialize its result into a
- temporary table. Created during the first call to exec().
- */
- JOIN *materialize_join;
/* Temp table context of the outer select's JOIN. */
TMP_TABLE_PARAM *tmp_param;
@@ -735,20 +735,19 @@ public:
subselect_single_select_engine *old_engine)
:subselect_uniquesubquery_engine(thd, NULL, in_predicate, NULL),
is_materialized(FALSE), materialize_engine(old_engine),
- materialize_join(NULL), tmp_param(NULL)
+ tmp_param(NULL)
{}
~subselect_hash_sj_engine();
- bool init_permanent(List<Item> *tmp_columns);
- bool init_runtime();
- void cleanup();
- int prepare()
+ bool setup(List<Item> *tmp_columns);
+ virtual void cleanup();
+ virtual bool prepare()
{
return materialize_engine->prepare();
}
- int exec();
- void print (String *str, enum_query_type query_type);
- uint cols()
+ virtual bool exec();
+ virtual void print (String *str, enum_query_type query_type);
+ virtual uint cols()
{
return materialize_engine->cols();
}
=== modified file 'sql/sql_lex.h'
--- a/sql/sql_lex.h 2010-10-25 16:07:05 +0000
+++ b/sql/sql_lex.h 2010-11-09 15:29:16 +0000
@@ -596,7 +596,7 @@ public:
inline bool is_union ();
friend void lex_start(THD *thd);
- friend int subselect_union_engine::exec();
+ friend bool subselect_union_engine::exec();
List<Item> *get_unit_column_types();
};
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2010-10-27 14:46:44 +0000
+++ b/sql/sql_parse.cc 2010-11-09 15:29:16 +0000
@@ -5551,6 +5551,8 @@ void mysql_parse(THD *thd, char *rawbuf,
thd->end_statement();
thd->cleanup_after_query();
DBUG_ASSERT(thd->change_list.is_empty());
+ //sql_print_error("Query: %*s", length, rawbuf);
+ //report_memory_plugin();
}
DBUG_VOID_RETURN;
=== modified file 'sql/sql_plugin.cc'
--- a/sql/sql_plugin.cc 2010-11-05 22:14:29 +0000
+++ b/sql/sql_plugin.cc 2010-11-09 15:29:16 +0000
@@ -1554,6 +1554,19 @@ error:
DBUG_RETURN(TRUE);
}
+void report_memory_plugin()
+
+{
+ struct st_plugin_int *p;
+
+ for (uint i= 0; i < plugin_array.elements; i++)
+ {
+ p= *dynamic_element(&plugin_array, i, struct st_plugin_int **);
+ if (!strcmp(p->name.str, "MEMORY"))
+ sql_print_error("Plugin '%s' has ref_count=%d",
+ p->name.str, p->ref_count);
+ }
+}
void plugin_shutdown(void)
{
=== modified file 'sql/sql_plugin.h'
--- a/sql/sql_plugin.h 2010-10-07 17:34:38 +0000
+++ b/sql/sql_plugin.h 2010-11-09 15:29:16 +0000
@@ -160,4 +160,5 @@ typedef my_bool (plugin_foreach_func)(TH
#define plugin_foreach(A,B,C,D) plugin_foreach_with_mask(A,B,C,PLUGIN_IS_READY,D)
extern bool plugin_foreach_with_mask(THD *thd, plugin_foreach_func *func,
int type, uint state_mask, void *arg);
+void report_memory_plugin();
#endif
=== modified file 'sql/sql_select.cc'
--- a/sql/sql_select.cc 2010-11-05 22:19:41 +0000
+++ b/sql/sql_select.cc 2010-11-09 15:29:16 +0000
@@ -2626,10 +2626,14 @@ void JOIN::restore_tmp()
}
-int
-JOIN::reinit()
+/**
+ Reset the state of this join object so that it is ready for a
+ new execution.
+*/
+
+void JOIN::reset()
{
- DBUG_ENTER("JOIN::reinit");
+ DBUG_ENTER("JOIN::reset");
unit->offset_limit_cnt= (ha_rows)(select_lex->offset_limit ?
select_lex->offset_limit->val_uint() :
@@ -2677,7 +2681,7 @@ JOIN::reinit()
func->clear();
}
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
/**
@@ -3309,14 +3313,12 @@ JOIN::exec()
/**
- Clean up join.
+ Clean up and destroy join object.
- @return
- Return error that hold JOIN.
+ @return false if previous execution was successful, and true otherwise
*/
-int
-JOIN::destroy()
+bool JOIN::destroy()
{
DBUG_ENTER("JOIN::destroy");
select_lex->join= 0;
@@ -3342,6 +3344,11 @@ JOIN::destroy()
cond_equal= 0;
cleanup(1);
+ if (join_tab)
+ {
+ for (JOIN_TAB *tab= join_tab; tab < join_tab+tables; tab++)
+ tab->table= NULL;
+ }
/* Cleanup items referencing temporary table columns */
cleanup_item_list(tmp_all_fields1);
cleanup_item_list(tmp_all_fields3);
@@ -3358,7 +3365,7 @@ JOIN::destroy()
delete_dynamic(&keyuse);
delete procedure;
- DBUG_RETURN(error);
+ DBUG_RETURN(test(error));
}
@@ -3500,6 +3507,8 @@ mysql_select(THD *thd, Item ***rref_poin
select_lex->where= join->conds_history;
select_lex->having= join->having_history;
}
+ if (select_options & SELECT_DESCRIBE)
+ free_join= 0;
err:
if (free_join)
@@ -4133,9 +4142,7 @@ bool JOIN::setup_subquery_materializatio
subquery_predicate->substype() == Item_subselect::IN_SUBS)
{
Item_in_subselect *in_subs= (Item_in_subselect*) subquery_predicate;
- if (in_subs->exec_method ==
- Item_exists_subselect::EXEC_MATERIALIZATION &&
- in_subs->setup_engine())
+ if (in_subs->setup_engine())
return TRUE;
}
}
@@ -11181,7 +11188,12 @@ bool error_if_full_join(JOIN *join)
/**
- cleanup JOIN_TAB.
+ Cleanup table of join operation.
+
+ @note
+ Notice that this is not a complete cleanup. In some situations, the
+ object may be reused after a cleanup operation, hence we cannot set
+ the table pointer to NULL in this function.
*/
void JOIN_TAB::cleanup()
@@ -23029,7 +23041,6 @@ bool mysql_explain_union(THD *thd, SELEC
unit->fake_select_lex->options|= SELECT_DESCRIBE;
if (!(res= unit->prepare(thd, result, SELECT_NO_UNLOCK | SELECT_DESCRIBE)))
res= unit->exec();
- res|= unit->cleanup();
}
else
{
=== modified file 'sql/sql_select.h'
--- a/sql/sql_select.h 2010-11-05 22:19:41 +0000
+++ b/sql/sql_select.h 2010-11-09 15:29:16 +0000
@@ -1916,9 +1916,9 @@ public:
Item *having, ORDER *proc_param, SELECT_LEX *select,
SELECT_LEX_UNIT *unit);
int optimize();
- int reinit();
+ void reset();
void exec();
- int destroy();
+ bool destroy();
void restore_tmp();
bool alloc_func_list();
bool flatten_subqueries();
=== modified file 'sql/sql_union.cc'
--- a/sql/sql_union.cc 2010-10-25 09:18:21 +0000
+++ b/sql/sql_union.cc 2010-11-09 15:29:16 +0000
@@ -223,7 +223,7 @@ bool st_select_lex_unit::prepare(THD *th
DBUG_RETURN(TRUE);
}
sl->join->select_options|= SELECT_DESCRIBE;
- sl->join->reinit();
+ sl->join->reset();
}
}
DBUG_RETURN(FALSE);
@@ -495,7 +495,10 @@ bool st_select_lex_unit::exec()
thd->lex->current_select= sl;
if (optimized)
- saved_error= sl->join->reinit();
+ {
+ saved_error= false;
+ sl->join->reset();
+ }
else
{
set_limit(sl);
@@ -642,7 +645,8 @@ bool st_select_lex_unit::exec()
else
{
join->examined_rows= 0;
- saved_error= join->reinit();
+ saved_error= false;
+ join->reset();
join->exec();
}
}
@@ -664,16 +668,25 @@ bool st_select_lex_unit::exec()
}
+/**
+ Cleanup this query expression object after preparation or one round
+ of execution. After the cleanup, the object can be reused for a
+ new round of execution, but a new optimization will be needed before
+ the execution.
+
+ @return false if previous execution was successful, and true otherwise
+*/
+
bool st_select_lex_unit::cleanup()
{
- int error= 0;
+ bool error= false;
DBUG_ENTER("st_select_lex_unit::cleanup");
if (cleaned)
{
DBUG_RETURN(FALSE);
}
- cleaned= 1;
+ cleaned= true;
if (union_result)
{
@@ -811,6 +824,13 @@ List<Item> *st_select_lex_unit::get_unit
return &sl->item_list;
}
+
+/**
+ Cleanup after preparation or one round of execution.
+
+ @return false if previous execution was successful, and true otherwise
+*/
+
bool st_select_lex::cleanup()
{
bool error= FALSE;
@@ -826,7 +846,7 @@ bool st_select_lex::cleanup()
for (SELECT_LEX_UNIT *lex_unit= first_inner_unit(); lex_unit ;
lex_unit= lex_unit->next_unit())
{
- error= (bool) ((uint) error | (uint) lex_unit->cleanup());
+ error|= lex_unit->cleanup();
}
non_agg_fields.empty();
inner_refs_list.empty();
Attachment: [text/bzr-bundle] bzr/roy.lyseng@oracle.com-20101109152916-0vdj2ymr3ujnsuu3.bundle