From: Roy Lyseng Date: January 5 2011 7:44am Subject: bzr commit into mysql-trunk branch (roy.lyseng:3321) Bug#56080 List-Archive: http://lists.mysql.com/commits/127945 X-Bug: 56080 Message-Id: <20110105074456.539791F2@tyr67.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3630222232102122235==" --===============3630222232102122235== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/rl136806/mysql/repo/mysql-work3/ based on revid:tor.didriksen@stripped 3321 Roy Lyseng 2011-01-05 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). mysql-test/r/optimizer_debug_sync.result Results for new test case. mysql-test/t/optimizer_debug_sync.test Test case for bug. Requires the debug sync facility, and often fails without the bug fix. 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(). added: mysql-test/r/optimizer_debug_sync.result mysql-test/t/optimizer_debug_sync.test 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 === added file 'mysql-test/r/optimizer_debug_sync.result' --- a/mysql-test/r/optimizer_debug_sync.result 1970-01-01 00:00:00 +0000 +++ b/mysql-test/r/optimizer_debug_sync.result 2011-01-05 07:44:06 +0000 @@ -0,0 +1,23 @@ + +BUG#56080 Assertion 'inited==INDEX' on SELECT MAX(...) + +CREATE TABLE t(i INT NOT NULL PRIMARY KEY, f INT) ENGINE = InnoDB; +INSERT INTO t VALUES (1,1),(2,2); +BEGIN; +UPDATE t SET f=100 WHERE i=2; +set optimizer_switch='semijoin=off'; +SET DEBUG_SYNC='before_index_end_in_subselect WAIT_FOR callit'; +SELECT f FROM t WHERE i IN ( SELECT i FROM t ); +SELECT MAX(i) FROM t FOR UPDATE; +SELECT MAX(i) FROM t FOR UPDATE; +SET DEBUG_SYNC='now SIGNAL callit'; +COMMIT; +f +1 +2 +SET DEBUG_SYNC='RESET'; +MAX(i) +2 +MAX(i) +2 +DROP TABLE t; === modified file 'mysql-test/r/union.result' --- a/mysql-test/r/union.result 2010-12-05 22:23:53 +0000 +++ b/mysql-test/r/union.result 2011-01-05 07:44:06 +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 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 === added file 'mysql-test/t/optimizer_debug_sync.test' --- a/mysql-test/t/optimizer_debug_sync.test 1970-01-01 00:00:00 +0000 +++ b/mysql-test/t/optimizer_debug_sync.test 2011-01-05 07:44:06 +0000 @@ -0,0 +1,60 @@ +# This test checks various optimizer-related functions using +# the debug-sync facility. + +--source include/have_debug_sync.inc +--source include/have_innodb.inc + +--echo +--echo BUG#56080 Assertion 'inited==INDEX' on SELECT MAX(...) +--echo + +CREATE TABLE t(i INT NOT NULL PRIMARY KEY, f INT) ENGINE = InnoDB; +INSERT INTO t VALUES (1,1),(2,2); + +BEGIN; +UPDATE t SET f=100 WHERE i=2; + +--connect (con1,localhost,root,,) + +set optimizer_switch='semijoin=off'; + +SET DEBUG_SYNC='before_index_end_in_subselect WAIT_FOR callit'; +--send SELECT f FROM t WHERE i IN ( SELECT i FROM t ) + +--connection default +let $show_statement= SHOW PROCESSLIST; +let $field= State; +let $condition= = 'debug sync point: before_index_end_in_subselect'; +--source include/wait_show_condition.inc + +--connect (con2,localhost,root,,) +--send SELECT MAX(i) FROM t FOR UPDATE + +--connect (con3,localhost,root,,) +--send SELECT MAX(i) FROM t FOR UPDATE + +--connection default + +let $wait_condition= + SELECT COUNT(*) = 2 FROM information_schema.processlist + WHERE state = 'Optimizing' and info = 'SELECT MAX(i) FROM t FOR UPDATE'; +--source include/wait_condition.inc + +SET DEBUG_SYNC='now SIGNAL callit'; +COMMIT; + +--connection con1 +--reap +SET DEBUG_SYNC='RESET'; + +--connection con2 +--reap + +--connection con3 +--reap + +DROP TABLE t; + +--exit + +--echo # End of BUG#56080 === modified file 'sql/ha_partition.cc' --- a/sql/ha_partition.cc 2010-12-17 11:28:59 +0000 +++ b/sql/ha_partition.cc 2011-01-05 07:44:06 +0000 @@ -3369,7 +3369,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-12-29 00:38:59 +0000 +++ b/sql/item_subselect.cc 2011-01-05 07:44:06 +0000 @@ -38,6 +38,7 @@ #include "set_var.h" #include "sql_select.h" #include "sql_parse.h" // check_stack_overrun +#include "debug_sync.h" inline Item * and_items(Item* cond, Item *item) { @@ -120,7 +121,10 @@ void Item_subselect::cleanup() if (old_engine) { if (engine) + { engine->cleanup(); + delete engine; + } engine= old_engine; old_engine= 0; } @@ -279,8 +283,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. @@ -295,7 +297,7 @@ bool Item_subselect::exec() */ DBUG_EXECUTE_IF("subselect_exec_fail", return 1;); - res= engine->exec(); + const bool res= engine->exec(); if (engine_changed) { @@ -1885,18 +1887,13 @@ void Item_in_subselect::fix_after_pullou /** - Try to create an engine to compute the subselect via materialization, - and if this fails, revert to execution via the IN=>EXISTS transformation. + Create an engine to compute the subquery via materialization. @details The purpose of this method is to hide the implementation details 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 @@ -1905,43 +1902,29 @@ 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); + /* The decision whether to materialize is already taken. */ + DBUG_ASSERT(exec_method == Item_exists_subselect::EXEC_MATERIALIZATION); - subselect_single_select_engine *old_engine= - static_cast(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(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(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); } /* @@ -1954,10 +1937,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); } @@ -2095,7 +2075,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; } @@ -2122,23 +2101,13 @@ bool subselect_union_engine::is_executed FALSE - Otherwise */ -bool subselect_union_engine::no_rows() +bool subselect_union_engine::no_rows() const { /* Check if we got any rows when reading UNION result from temp. table: */ return test(!unit->fake_select_lex->join->send_records); } -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) @@ -2175,7 +2144,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; @@ -2202,12 +2171,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); @@ -2230,7 +2201,7 @@ int subselect_uniquesubquery_engine::pre FALSE - Otherwise */ -bool subselect_single_select_engine::no_rows() +bool subselect_single_select_engine::no_rows() const { return !item->assigned(); } @@ -2300,7 +2271,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; @@ -2329,12 +2300,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)); } @@ -2399,10 +2365,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; } @@ -2426,7 +2392,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; @@ -2591,7 +2557,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; @@ -2694,7 +2660,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; @@ -2781,26 +2747,26 @@ int subselect_indexsubquery_engine::exec } -uint subselect_single_select_engine::cols() +uint subselect_single_select_engine::cols() const { return select_lex->item_list.elements; } -uint subselect_union_engine::cols() +uint subselect_union_engine::cols() const { DBUG_ASSERT(unit->is_prepared()); // should be called after fix_fields() return unit->types.elements; } -uint8 subselect_single_select_engine::uncacheable() +uint8 subselect_single_select_engine::uncacheable() const { return select_lex->uncacheable; } -uint8 subselect_union_engine::uncacheable() +uint8 subselect_union_engine::uncacheable() const { return unit->uncacheable; } @@ -2887,13 +2853,13 @@ subselect_single_select_engine::save_joi return FALSE; } -table_map subselect_single_select_engine::upper_select_const_tables() +table_map subselect_single_select_engine::upper_select_const_tables() const { return calc_const_tables(select_lex->outer_select()->leaf_tables); } -table_map subselect_union_engine::upper_select_const_tables() +table_map subselect_union_engine::upper_select_const_tables() const { return calc_const_tables(unit->outer_select()->leaf_tables); } @@ -3061,7 +3027,7 @@ bool subselect_uniquesubquery_engine::ch @retval FALSE there are some tables in subquery */ -bool subselect_single_select_engine::no_tables() +bool subselect_single_select_engine::no_tables() const { return(select_lex->table_list.elements == 0); } @@ -3077,7 +3043,7 @@ bool subselect_single_select_engine::no_ FALSE can guarantee that the subquery never return NULL TRUE otherwise */ -bool subselect_single_select_engine::may_be_null() +bool subselect_single_select_engine::may_be_null() const { return ((no_tables() && !join->conds && !join->having) ? maybe_null : 1); } @@ -3091,7 +3057,7 @@ bool subselect_single_select_engine::may @retval FALSE there are some tables in subquery */ -bool subselect_union_engine::no_tables() +bool subselect_union_engine::no_tables() const { for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) { @@ -3111,7 +3077,7 @@ bool subselect_union_engine::no_tables() FALSE there are some tables in subquery */ -bool subselect_uniquesubquery_engine::no_tables() +bool subselect_uniquesubquery_engine::no_tables() const { /* returning value is correct, but this method should never be called */ return 0; @@ -3124,8 +3090,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 @@ -3143,7 +3108,7 @@ bool subselect_uniquesubquery_engine::no @retval FALSE otherwise */ -bool subselect_hash_sj_engine::init_permanent(List *tmp_columns) +bool subselect_hash_sj_engine::setup(List *tmp_columns) { /* The result sink where we will materialize the subquery result. */ select_union *tmp_result_sink; @@ -3153,7 +3118,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. */ @@ -3199,8 +3164,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. */ @@ -3295,43 +3260,24 @@ 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() { + /* Assure that cleanup has been called for this engine. */ + DBUG_ASSERT(!tab); + delete result; - if (tab) - free_tmp_table(thd, tab->table); } @@ -3344,10 +3290,16 @@ 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. */ + DEBUG_SYNC(thd, "before_index_end_in_subselect"); + 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; } @@ -3362,7 +3314,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; @@ -3374,17 +3326,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-12-14 11:15:13 +0000 +++ b/sql/item_subselect.h 2011-01-05 07:44:06 +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; @@ -190,10 +191,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(); @@ -240,7 +241,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; } @@ -292,7 +293,7 @@ public: return RES_OK; } subs_type substype() { return EXISTS_SUBS; } - void reset() + virtual void reset() { value= 0; } @@ -380,9 +381,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; @@ -455,15 +456,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; /* @@ -471,8 +470,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 @@ -494,23 +493,23 @@ 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 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 bool exec()= 0; + virtual uint cols() const = 0; /* return number of columns in select */ + virtual uint8 uncacheable() const = 0; /* query is uncacheable */ + virtual enum Item_result type() const { return res_type; } + virtual 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; + virtual bool may_be_null() const { return maybe_null; }; + virtual table_map upper_select_const_tables() const = 0; static table_map calc_const_tables(TABLE_LIST *); virtual void print(String *str, enum_query_type query_type)= 0; virtual bool change_result(Item_subselect *si, select_result_interceptor *result)= 0; - virtual bool no_tables()= 0; + virtual bool no_tables() const = 0; virtual bool is_executed() const { return FALSE; } /* Check if subquery produced any rows during last query execution */ - virtual bool no_rows() = 0; - virtual enum_engine_type engine_type() { return ABSTRACT_ENGINE; } + virtual bool no_rows() const = 0; + virtual enum_engine_type engine_type() const { return ABSTRACT_ENGINE; } protected: void set_row(List &item_list, Item_cache **row); @@ -519,30 +518,31 @@ 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() const; + virtual uint8 uncacheable() const; + virtual void exclude(); + virtual table_map upper_select_const_tables() const; 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 enum_engine_type engine_type() { return SINGLE_SELECT_ENGINE; } + virtual bool change_result(Item_subselect *si, + select_result_interceptor *result); + virtual bool no_tables() const; + virtual bool may_be_null() const; + virtual bool is_executed() const { return executed; } + virtual bool no_rows() const; + virtual enum_engine_type engine_type() const { return SINGLE_SELECT_ENGINE; } bool save_join_if_explain(); friend class subselect_hash_sj_engine; @@ -552,25 +552,28 @@ public: class subselect_union_engine: public subselect_engine { - 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() const; + virtual uint8 uncacheable() const; + virtual void exclude(); + virtual table_map upper_select_const_tables() const; 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 enum_engine_type engine_type() { return UNION_ENGINE; } + virtual bool change_result(Item_subselect *si, + select_result_interceptor *result); + virtual bool no_tables() const; + virtual bool is_executed() const; + virtual bool no_rows() const; + virtual enum_engine_type engine_type() const { return UNION_ENGINE; } + +private: + st_select_lex_unit *unit; /* corresponding unit structure */ }; @@ -614,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() const { return 1; } + virtual uint8 uncacheable() const { return UNCACHEABLE_DEPENDENT; } + virtual void exclude(); + virtual table_map upper_select_const_tables() const { 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() const; + bool scan_table(); bool copy_ref_key(); - bool no_rows() { return empty_result_set; } - virtual enum_engine_type engine_type() { return UNIQUESUBQUERY_ENGINE; } + virtual bool no_rows() const { return empty_result_set; } + virtual enum_engine_type engine_type() const { return UNIQUESUBQUERY_ENGINE; } }; class subselect_indexsubquery_engine: public subselect_uniquesubquery_engine { +private: /* FALSE for 'ref', TRUE for 'ref-or-null'. */ bool check_null; /* @@ -676,9 +681,9 @@ 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; } + virtual enum_engine_type engine_type() const { return INDEXSUBQUERY_ENGINE; } }; /* @@ -711,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; @@ -734,23 +735,22 @@ 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 *tmp_columns); - bool init_runtime(); - void cleanup(); - int prepare() + bool setup(List *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() const { return materialize_engine->cols(); } - virtual enum_engine_type engine_type() { return HASH_SJ_ENGINE; } + virtual enum_engine_type engine_type() const { return HASH_SJ_ENGINE; } }; #endif /* ITEM_SUBSELECT_INCLUDED */ === modified file 'sql/sql_lex.h' --- a/sql/sql_lex.h 2010-12-14 11:15:13 +0000 +++ b/sql/sql_lex.h 2011-01-05 07:44:06 +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 *get_unit_column_types(); }; === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-12-29 00:38:59 +0000 +++ b/sql/sql_parse.cc 2011-01-05 07:44:06 +0000 @@ -5564,6 +5564,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-12-06 13:12:51 +0000 +++ b/sql/sql_plugin.cc 2011-01-05 07:44:06 +0000 @@ -1576,6 +1576,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-12-21 15:27:40 +0000 +++ b/sql/sql_plugin.h 2011-01-05 07:44:06 +0000 @@ -163,4 +163,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-12-29 00:38:59 +0000 +++ b/sql/sql_select.cc 2011-01-05 07:44:06 +0000 @@ -2637,10 +2637,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() : @@ -2691,7 +2695,7 @@ JOIN::reinit() if (!(select_options & SELECT_DESCRIBE)) init_ftfuncs(thd, select_lex, test(order)); - DBUG_RETURN(0); + DBUG_VOID_RETURN; } /** @@ -3360,14 +3364,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; @@ -3393,6 +3395,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); @@ -3409,7 +3416,7 @@ JOIN::destroy() delete_dynamic(&keyuse); delete procedure; - DBUG_RETURN(error); + DBUG_RETURN(test(error)); } @@ -3505,8 +3512,8 @@ mysql_select(THD *thd, Item ***rref_poin subselect execution. So we need to restore them. */ Item_subselect *subselect= select_lex->master_unit()->item; - if (subselect && subselect->is_uncacheable() && join->reinit()) - DBUG_RETURN(TRUE); + if (subselect && subselect->is_uncacheable()) + join->reset(); } else { @@ -3558,6 +3565,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) @@ -11261,7 +11270,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() @@ -23134,7 +23148,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-12-29 00:38:59 +0000 +++ b/sql/sql_select.h 2011-01-05 07:44:06 +0000 @@ -1918,9 +1918,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-11-11 09:40:06 +0000 +++ b/sql/sql_union.cc 2011-01-05 07:44:06 +0000 @@ -214,16 +214,16 @@ bool st_select_lex_unit::prepare(THD *th /* fast reinit for EXPLAIN */ for (sl= first_sl; sl; sl= sl->next_select()) { - sl->join->result= result; - select_limit_cnt= HA_POS_ERROR; - offset_limit_cnt= 0; - if (!sl->join->procedure && - result->prepare(sl->join->fields_list, this)) - { - DBUG_RETURN(TRUE); - } - sl->join->select_options|= SELECT_DESCRIBE; - sl->join->reinit(); + sl->join->result= result; + select_limit_cnt= HA_POS_ERROR; + offset_limit_cnt= 0; + if (!sl->join->procedure && + result->prepare(sl->join->fields_list, this)) + { + DBUG_RETURN(TRUE); + } + sl->join->select_options|= SELECT_DESCRIBE; + sl->join->reset(); } } DBUG_RETURN(FALSE); @@ -469,8 +469,8 @@ bool st_select_lex_unit::exec() DBUG_ENTER("st_select_lex_unit::exec"); if (executed && !uncacheable && !describe) - DBUG_RETURN(FALSE); - executed= 1; + DBUG_RETURN(false); + executed= true; if (uncacheable || !item || !item->assigned() || describe) { @@ -496,19 +496,22 @@ 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); - if (sl == global_parameters || describe) - { - offset_limit_cnt= 0; - /* - We can't use LIMIT at this stage if we are using ORDER BY for the - whole query - */ - if (sl->order_list.first || describe) - select_limit_cnt= HA_POS_ERROR; + if (sl == global_parameters || describe) + { + offset_limit_cnt= 0; + /* + We can't use LIMIT at this stage if we are using ORDER BY for the + whole query + */ + if (sl->order_list.first || describe) + select_limit_cnt= HA_POS_ERROR; } /* @@ -520,62 +523,62 @@ bool st_select_lex_unit::exec() (select_limit_cnt == HA_POS_ERROR || sl->braces) ? sl->options & ~OPTION_FOUND_ROWS : sl->options | found_rows_for_union; - saved_error= sl->join->optimize(); + saved_error= sl->join->optimize(); } if (!saved_error) { - records_at_start= table->file->stats.records; - sl->join->exec(); + records_at_start= table->file->stats.records; + sl->join->exec(); if (sl == union_distinct) - { - if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL)) - DBUG_RETURN(TRUE); - table->no_keyread=1; - } - saved_error= sl->join->error; - offset_limit_cnt= (ha_rows)(sl->offset_limit ? + { + if (table->file->ha_disable_indexes(HA_KEY_SWITCH_ALL)) + DBUG_RETURN(true); + table->no_keyread=1; + } + saved_error= sl->join->error; + offset_limit_cnt= (ha_rows)(sl->offset_limit ? sl->offset_limit->val_uint() : 0); - if (!saved_error) - { - examined_rows+= thd->examined_row_count; - if (union_result->flush()) - { - thd->lex->current_select= lex_select_save; - DBUG_RETURN(1); - } - } + if (!saved_error) + { + examined_rows+= thd->examined_row_count; + if (union_result->flush()) + { + thd->lex->current_select= lex_select_save; + DBUG_RETURN(true); + } + } } if (saved_error) { - thd->lex->current_select= lex_select_save; - DBUG_RETURN(saved_error); + thd->lex->current_select= lex_select_save; + DBUG_RETURN(saved_error); } /* Needed for the following test and for records_at_start in next loop */ int error= table->file->info(HA_STATUS_VARIABLE); if(error) { table->file->print_error(error, MYF(0)); - DBUG_RETURN(1); + DBUG_RETURN(true); } if (found_rows_for_union && !sl->braces && select_limit_cnt != HA_POS_ERROR) { - /* - This is a union without braces. Remember the number of rows that - could also have been part of the result set. - We get this from the difference of between total number of possible - rows and actual rows added to the temporary table. - */ - add_rows+= (ulonglong) (thd->limit_found_rows - (ulonglong) - ((table->file->stats.records - records_at_start))); + /* + This is a union without braces. Remember the number of rows that + could also have been part of the result set. + We get this from the difference of between total number of possible + rows and actual rows added to the temporary table. + */ + add_rows+= (ulonglong) (thd->limit_found_rows - + (ulonglong)(table->file->stats.records - records_at_start)); } } } - optimized= 1; + optimized= true; /* Send result to 'result' */ - saved_error= TRUE; + saved_error= true; { List empty_list; empty_list.empty(); @@ -587,27 +590,27 @@ bool st_select_lex_unit::exec() JOIN *join= fake_select_lex->join; if (!join) { - /* - allocate JOIN for fake select only once (prevent - mysql_select automatic allocation) + /* + allocate JOIN for fake select only once (prevent + mysql_select automatic allocation) TODO: The above is nonsense. mysql_select() will not allocate the join if one already exists. There must be some other reason why we don't let it allocate the join. Perhaps this is because we need some special parameter values passed to join constructor? */ - if (!(fake_select_lex->join= new JOIN(thd, item_list, - fake_select_lex->options, result))) + if (!(fake_select_lex->join= + new JOIN(thd, item_list, fake_select_lex->options, result))) { - fake_select_lex->table_list.empty(); - DBUG_RETURN(TRUE); + fake_select_lex->table_list.empty(); + DBUG_RETURN(true); } - fake_select_lex->join->no_const_tables= TRUE; + fake_select_lex->join->no_const_tables= true; - /* - Fake st_select_lex should have item list for correctref_array - allocation. - */ - fake_select_lex->item_list= item_list; + /* + Fake st_select_lex should have item list for correctref_array + allocation. + */ + fake_select_lex->item_list= item_list; saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, &result_table_list, 0, item_list, NULL, @@ -630,7 +633,7 @@ bool st_select_lex_unit::exec() subquery execution rather than EXPLAIN line production. In order to reset them back, we re-do all of the actions (yes it is ugly): */ - join->init(thd, item_list, fake_select_lex->options, result); + join->init(thd, item_list, fake_select_lex->options, result); saved_error= mysql_select(thd, &fake_select_lex->ref_pointer_array, &result_table_list, 0, item_list, NULL, @@ -643,7 +646,8 @@ bool st_select_lex_unit::exec() else { join->examined_rows= 0; - saved_error= join->reinit(); + saved_error= false; + join->reset(); join->exec(); } } @@ -655,8 +659,8 @@ bool st_select_lex_unit::exec() thd->examined_row_count+= examined_rows; } /* - Mark for slow query log if any of the union parts didn't use - indexes efficiently + Mark for slow query log if any of the union parts didn't use + indexes efficiently */ } } @@ -665,16 +669,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) { @@ -812,6 +825,13 @@ List *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; @@ -827,7 +847,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(); --===============3630222232102122235== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/roy.lyseng@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: roy.lyseng@stripped # target_branch: file:///home/rl136806/mysql/repo/mysql-work3/ # testament_sha1: 93a9268198026b676f4f7a025c69a674d5521296 # timestamp: 2011-01-05 08:44:56 +0100 # base_revision_id: tor.didriksen@stripped\ # sobe03mdz8nl567b # # Begin bundle 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 --===============3630222232102122235==--