From: Mattias Jonsson Date: March 15 2011 11:28am Subject: bzr commit into mysql-trunk branch (mattias.jonsson:3693) List-Archive: http://lists.mysql.com/commits/133003 Message-Id: <201103151128.p2FBSVSN031348@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============3214498114393350943==" --===============3214498114393350943== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///Users/mattiasj/mysql-bzr/wl4443-trunk/ based on revid:mattias.jonsson@stripped 3693 Mattias Jonsson 2011-03-15 Minor updates from Mikaels preliminary code review modified: mysql-test/r/wl4443.result mysql-test/t/wl4443.test sql/ha_partition.cc sql/sql_base.cc sql/sql_base.h sql/sql_delete.cc sql/sql_derived.cc sql/sql_insert.cc sql/sql_parse.cc sql/sql_select.cc sql/sql_union.cc sql/sql_update.cc === modified file 'mysql-test/r/wl4443.result' --- a/mysql-test/r/wl4443.result 2011-02-21 16:27:53 +0000 +++ b/mysql-test/r/wl4443.result 2011-03-15 11:27:59 +0000 @@ -804,6 +804,164 @@ a b 4 First row, p4 52 Fifth row, p0, updated 1 # Test CREATE SELECT +# Test Stored procedures +DROP PROCEDURE IF EXISTS sp_insert; +DROP PROCEDURE IF EXISTS sp_insert_partition; +DROP PROCEDURE IF EXISTS sp_select_all; +DROP PROCEDURE IF EXISTS sp_select_exact; +DROP PROCEDURE IF EXISTS sp_select_partition; +DROP PROCEDURE IF EXISTS sp_select_range; +CREATE PROCEDURE sp_insert(a INT, b CHAR(16)) +INSERT INTO test.t1 VALUES (a, b); +CREATE PROCEDURE sp_insert_partition(p CHAR(16), a INT, b CHAR(16)) +BEGIN +SET @str = concat("INSERT INTO test.t1 PARTITION(", p, ") VALUES (?, ?)"); +set @x = a, @y = b; +PREPARE stmt FROM @str; +EXECUTE stmt USING @x, @y; +END| +CREATE PROCEDURE sp_select_all() +SELECT * FROM test.t1; +CREATE PROCEDURE sp_select_exact(x INT) +SELECT * FROM test.t1 WHERE a = x; +CREATE PROCEDURE sp_select_partition(p CHAR(16)) +BEGIN +SET @str = concat("SELECT * FROM test.t1 PARTITION(", p, ")"); +PREPARE stmt FROM @str; +EXECUTE stmt; +END| +CREATE PROCEDURE sp_select_range(x INT, y INT) +SELECT * FROM test.t1 WHERE a between x and y; +FLUSH STATUS; +CALL sp_insert(313,"Test313"); +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 30 +HANDLER_READ_KEY 1 +HANDLER_WRITE 18 +FLUSH STATUS; +CALL sp_insert_partition("p7", 98, "Test98"); +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 6 +HANDLER_READ_KEY 1 +HANDLER_WRITE 18 +FLUSH STATUS; +CALL sp_insert_partition("p8", 111, "Test111"); +ERROR HY000: Found a row not matching the given partition set +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_EXTERNAL_LOCK 4 +HANDLER_ROLLBACK 1 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_insert_partition("p7,p8", 111, "Test111"); +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 6 +HANDLER_WRITE 18 +FLUSH STATUS; +CALL sp_select_all(); +a b +0 First row, p0 +1 First row, p1 +111 Test111 +113 Second row, p0, updated 1, updated 2 -> p8, updated 3, updated 4 -> p9 +2 First row, p2 +26 Third row, p0, updated 1 +3 First row, p3 +313 Test313 +39 Fourth row, p0, updated 1 +4 First row, p4 +52 Fifth row, p0, updated 1 +98 Test98 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 30 +HANDLER_READ_FIRST 13 +HANDLER_READ_KEY 27 +HANDLER_READ_NEXT 12 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_select_exact(98); +a b +98 Test98 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 6 +HANDLER_READ_KEY 3 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_select_partition("p7"); +a b +111 Test111 +98 Test98 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 6 +HANDLER_READ_FIRST 1 +HANDLER_READ_KEY 3 +HANDLER_READ_NEXT 2 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_select_partition("p8"); +a b +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 4 +HANDLER_READ_FIRST 1 +HANDLER_READ_KEY 2 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_select_partition("p7,p8"); +a b +111 Test111 +98 Test98 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 6 +HANDLER_READ_FIRST 2 +HANDLER_READ_KEY 4 +HANDLER_READ_NEXT 2 +HANDLER_WRITE 17 +FLUSH STATUS; +CALL sp_select_range(1,5); +a b +1 First row, p1 +2 First row, p2 +3 First row, p3 +4 First row, p4 +SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS +WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; +VARIABLE_NAME VARIABLE_VALUE +HANDLER_COMMIT 1 +HANDLER_EXTERNAL_LOCK 14 +HANDLER_READ_KEY 16 +HANDLER_READ_NEXT 4 +HANDLER_WRITE 17 +DROP PROCEDURE sp_insert; +DROP PROCEDURE sp_insert_partition; +DROP PROCEDURE sp_select_all; +DROP PROCEDURE sp_select_partition; +DROP PROCEDURE sp_select_range; +DROP PROCEDURE sp_select_exact; # TODO: Add variants for LOCK TABLES # TODO: add delayed locking/pruning for multi-table update # TODO: Document that functions in WHERE clause can now be evaluated === modified file 'mysql-test/t/wl4443.test' --- a/mysql-test/t/wl4443.test 2011-02-21 16:27:53 +0000 +++ b/mysql-test/t/wl4443.test 2011-03-15 11:27:59 +0000 @@ -257,6 +257,93 @@ eval $get_handler_status_counts; --sorted_result SELECT * FROM t1; --echo # Test CREATE SELECT + + +--echo # Test Stored procedures +--disable_warnings +DROP PROCEDURE IF EXISTS sp_insert; +DROP PROCEDURE IF EXISTS sp_insert_partition; +DROP PROCEDURE IF EXISTS sp_select_all; +DROP PROCEDURE IF EXISTS sp_select_exact; +DROP PROCEDURE IF EXISTS sp_select_partition; +DROP PROCEDURE IF EXISTS sp_select_range; +--enable_warnings +CREATE PROCEDURE sp_insert(a INT, b CHAR(16)) + INSERT INTO test.t1 VALUES (a, b); + +delimiter |; +CREATE PROCEDURE sp_insert_partition(p CHAR(16), a INT, b CHAR(16)) +BEGIN + SET @str = concat("INSERT INTO test.t1 PARTITION(", p, ") VALUES (?, ?)"); + set @x = a, @y = b; + PREPARE stmt FROM @str; + EXECUTE stmt USING @x, @y; +END| +delimiter ;| + +CREATE PROCEDURE sp_select_all() + SELECT * FROM test.t1; + +CREATE PROCEDURE sp_select_exact(x INT) + SELECT * FROM test.t1 WHERE a = x; + +delimiter |; +CREATE PROCEDURE sp_select_partition(p CHAR(16)) +BEGIN + SET @str = concat("SELECT * FROM test.t1 PARTITION(", p, ")"); + PREPARE stmt FROM @str; + EXECUTE stmt; +END| +delimiter ;| + + +CREATE PROCEDURE sp_select_range(x INT, y INT) + SELECT * FROM test.t1 WHERE a between x and y; + +FLUSH STATUS; +CALL sp_insert(313,"Test313"); +eval $get_handler_status_counts; +FLUSH STATUS; +CALL sp_insert_partition("p7", 98, "Test98"); +eval $get_handler_status_counts; +FLUSH STATUS; +--error ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET +CALL sp_insert_partition("p8", 111, "Test111"); +eval $get_handler_status_counts; +FLUSH STATUS; +CALL sp_insert_partition("p7,p8", 111, "Test111"); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_all(); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_exact(98); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_partition("p7"); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_partition("p8"); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_partition("p7,p8"); +eval $get_handler_status_counts; +FLUSH STATUS; +--sorted_result +CALL sp_select_range(1,5); +eval $get_handler_status_counts; +DROP PROCEDURE sp_insert; +DROP PROCEDURE sp_insert_partition; +DROP PROCEDURE sp_select_all; +DROP PROCEDURE sp_select_partition; +DROP PROCEDURE sp_select_range; +DROP PROCEDURE sp_select_exact; + --echo # TODO: Add variants for LOCK TABLES --echo # TODO: add delayed locking/pruning for multi-table update --echo # TODO: Document that functions in WHERE clause can now be evaluated === modified file 'sql/ha_partition.cc' --- a/sql/ha_partition.cc 2011-02-21 16:27:53 +0000 +++ b/sql/ha_partition.cc 2011-03-15 11:27:59 +0000 @@ -2943,6 +2943,7 @@ int ha_partition::external_lock(THD *thd used_partitions= &(m_part_info->lock_partitions); first_used_partition= bitmap_get_first_set(used_partitions); + DBUG_ASSERT(first_used_partition != MY_BIT_NONE); if (first_used_partition == MY_BIT_NONE) DBUG_RETURN(0); @@ -3044,6 +3045,7 @@ THR_LOCK_DATA **ha_partition::store_lock first_used_partition= bitmap_get_first_set(&(m_part_info->lock_partitions)); + DBUG_ASSERT(first_used_partition != MY_BIT_NONE); if (first_used_partition == MY_BIT_NONE) DBUG_RETURN(to); @@ -3083,6 +3085,7 @@ int ha_partition::start_stmt(THD *thd, t first_used_partition= bitmap_get_first_set(&(m_part_info->lock_partitions)); + DBUG_ASSERT(first_used_partition != MY_BIT_NONE); if (first_used_partition == MY_BIT_NONE) DBUG_RETURN(0); @@ -3198,6 +3201,8 @@ void ha_partition::try_semi_consistent_r first_used_partition= bitmap_get_first_set(&(m_part_info->read_partitions)); + DBUG_ASSERT(first_used_partition != MY_BIT_NONE); + for (i= first_used_partition; i < m_tot_parts; i++) { if (bitmap_is_set(&(m_part_info->read_partitions), i)) @@ -6081,22 +6086,18 @@ int ha_partition::reset(void) int tmp; uint first_used_partition; first_used_partition= bitmap_get_first_set(&m_part_info->lock_partitions); - if (first_used_partition == MY_BIT_NONE) - { - /* Be sure lock_partitions are set if no pruning in the next statement */ - m_part_info->set_partition_bitmaps(NULL); - DBUG_RETURN(result); - } - - file= m_file + first_used_partition; - do + if (first_used_partition != MY_BIT_NONE) { - if (bitmap_is_set(&(m_part_info->lock_partitions), file - m_file)) + file= m_file + first_used_partition; + do { - if ((tmp= (*file)->ha_reset())) - result= tmp; - } - } while (*(++file)); + if (bitmap_is_set(&(m_part_info->lock_partitions), file - m_file)) + { + if ((tmp= (*file)->ha_reset())) + result= tmp; + } + } while (*(++file)); + } /* Be sure lock_partitions are set if no pruning in the next statement */ m_part_info->set_partition_bitmaps(NULL); } @@ -6318,6 +6319,7 @@ void ha_partition::partitions_optimizer_ uint *check_min_num) { *first= bitmap_get_first_set(&(m_part_info->read_partitions)); + DBUG_ASSERT(*first != MY_BIT_NONE); *num_used_parts= bitmap_bits_set(&(m_part_info->read_partitions)); *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts); } === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_base.cc 2011-03-15 11:27:59 +0000 @@ -4974,6 +4974,7 @@ restart: #ifdef WITH_PARTITION_STORAGE_ENGINE /* TODO: move this to prune_partitions() when implementing WL#4443. */ + /* TODO: MOVE THIS TO ha_partition::store_lock/start_stmt ? */ /* Prune partitions to avoid unneccesary locks */ if (prune_partition_locks(*start)) { @@ -5448,6 +5449,68 @@ void open_or_lock_cleanup(THD *thd, cons /** + Open tables and open derived tables and prepares them. + + @param thd Thread context. + @param[in,out] tables List of tables to open/was opened. + @param[out] table_counter Number of tables opened. + + @return Operation status + @retval false OK + @retval true Error +*/ + +bool open_tables_and_prepare_derived(THD *thd, TABLE_LIST **tables, + uint *table_counter) +{ + DBUG_ENTER("open_tables_and_prepare_derived"); + + if (open_tables(thd, tables, table_counter, 0)) + DBUG_RETURN(true); + + if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || + (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_prepare_filling))) + DBUG_RETURN(true); + + DBUG_RETURN(false); +} + + +/** + Lock tables and execute derived tables. + + @param thd Thread context. + @param tables List of tables to lock. + @param num_tables_to_lock Number of tables to lock. + + @return Operation status + @retval false OK + @retval true Error +*/ + +bool lock_tables_and_execute_derived(THD *thd, TABLE_LIST *tables, + uint num_tables_to_lock) +{ + DBUG_ENTER("lock_tables_and_execute_derived"); + + if (lock_tables(thd, tables, num_tables_to_lock, 0)) + DBUG_RETURN(true); + + if (thd->fill_derived_tables() && + mysql_handle_derived(thd->lex, &mysql_derived_execute_filling)) + { + mysql_handle_derived(thd->lex, &mysql_derived_cleanup); + DBUG_RETURN(true); + } + if (!thd->lex->describe) + mysql_handle_derived(thd->lex, &mysql_derived_cleanup); + + DBUG_RETURN(false); +} + + +/** Open all tables in list, locks them and optionally process derived tables. @param thd Thread context. === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2011-02-21 16:27:53 +0000 +++ b/sql/sql_base.h 2011-03-15 11:27:59 +0000 @@ -247,6 +247,10 @@ bool lock_table_names(THD *thd, TABLE_LI bool open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags, Prelocking_strategy *prelocking_strategy); void open_or_lock_cleanup(THD *thd, const MDL_savepoint &mdl_savepoint); +bool open_tables_and_prepare_derived(THD *thd, TABLE_LIST **tables, + uint *table_counter); +bool lock_tables_and_execute_derived(THD *thd, TABLE_LIST *tables, + uint num_tables_to_lock); /* open_and_lock_tables with optional derived handling */ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables, bool derived, uint flags, === modified file 'sql/sql_delete.cc' --- a/sql/sql_delete.cc 2011-02-02 10:32:21 +0000 +++ b/sql/sql_delete.cc 2011-03-15 11:27:59 +0000 @@ -68,6 +68,7 @@ bool mysql_delete(THD *thd, TABLE_LIST * THD::enum_binlog_query_type query_type= THD::ROW_QUERY_TYPE; DBUG_ENTER("mysql_delete"); + /* TODO: delay locking to be able to prune partitioning locks */ if (open_and_lock_tables(thd, table_list, TRUE, 0)) DBUG_RETURN(TRUE); if (!(table= table_list->table)) @@ -141,6 +142,7 @@ bool mysql_delete(THD *thd, TABLE_LIST * (!thd->is_current_stmt_binlog_format_row() && !(table->triggers && table->triggers->has_delete_triggers()))) { + /* TODO: add locking here since no pruning will be possible anyway */ /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); ha_rows const maybe_deleted= table->file->stats.records; @@ -181,6 +183,7 @@ bool mysql_delete(THD *thd, TABLE_LIST * DBUG_RETURN(0); } #endif + /* TODO: add locking here */ /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); === modified file 'sql/sql_derived.cc' --- a/sql/sql_derived.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_derived.cc 2011-03-15 11:27:59 +0000 @@ -32,14 +32,12 @@ /* Call given derived table processor (preparing or filling tables) - SYNOPSIS - mysql_handle_derived() - lex LEX for this thread - processor procedure of derived table processing - - RETURN - FALSE OK - TRUE Error + @param lex LEX for this thread + @param processor procedure of derived table processing + + @return Operation status + @retval FALSE OK + @retval TRUE Error */ bool @@ -242,24 +240,23 @@ exit: /* prepare fill derived table - SYNOPSIS - mysql_derived_prepare_filling() - thd Thread handle - lex LEX for this thread - unit node that contains all SELECT's for derived tables - orig_table_list TABLE_LIST for the upper SELECT - - IMPLEMENTATION - Derived table is resolved with temporary table. It is created based on the - queries defined. After temporary table is filled, if this is not EXPLAIN, - then the entire unit / node is deleted. unit is deleted if UNION is used - for derived table and node is deleted is it is a simple SELECT. - If you use this function, make sure it's not called at prepare. - Due to evaluation of LIMIT clause it can not be used at prepared stage. - - RETURN - FALSE OK - TRUE Error + @param thd Thread handle + @param lex LEX for this thread + @param unit node that contains all SELECT's for derived tables + @param orig_table_list TABLE_LIST for the upper SELECT + + @details + + Derived table is resolved with temporary table. It is created based on the + queries defined. This is the prepare part of filling the derived table. + It calls prepare and optimize_before_locking on the unit or node + (UNION or JOIN/SELECT). This call must only use SE API calls where the table + is only opened, not yet locked! This to ensure that prune_partitions can be + called and also prune away locks not needed for the derived tables. + + @return Operation status + @retval FALSE OK + @retval TRUE Error */ bool mysql_derived_prepare_filling(THD *thd, LEX *lex, @@ -294,7 +291,7 @@ bool mysql_derived_prepare_filling(THD * { unit->set_limit(first_select); if (unit->select_limit_cnt == HA_POS_ERROR) - first_select->options&= ~OPTION_FOUND_ROWS; + first_select->options&= ~OPTION_FOUND_ROWS; lex->current_select= first_select; res= mysql_prepare_select(thd, &first_select->ref_pointer_array, @@ -332,24 +329,24 @@ bool mysql_derived_prepare_filling(THD * /* execute fill derived table - SYNOPSIS - mysql_derived_execute_filling() - thd Thread handle - lex LEX for this thread - unit node that contains all SELECT's for derived tables - orig_table_list TABLE_LIST for the upper SELECT - - IMPLEMENTATION - Derived table is resolved with temporary table. It is created based on the - queries defined. After temporary table is filled, if this is not EXPLAIN, - then the entire unit / node is deleted. unit is deleted if UNION is used - for derived table and node is deleted is it is a simple SELECT. - If you use this function, make sure it's not called at prepare. - Due to evaluation of LIMIT clause it can not be used at prepared stage. - - RETURN - FALSE OK - TRUE Error + @param thd Thread handle + @param lex LEX for this thread + @param unit node that contains all SELECT's for derived tables + @param orig_table_list TABLE_LIST for the upper SELECT + + @details + + Derived table is resolved with temporary table. It is created based on the + queries defined. This step executes the filling of the prepared derived + table. After temporary table is filled, if this is not EXPLAIN, + then the entire unit / node is deleted. unit is deleted if UNION is used + for derived table and node is deleted is it is a simple SELECT. + If you use this function, make sure it's not called at prepare. + Due to evaluation of LIMIT clause it can not be used at prepared stage. + + @return Operation status + @retval FALSE OK + @retval TRUE Error */ bool mysql_derived_execute_filling(THD *thd, LEX *lex, @@ -376,7 +373,7 @@ bool mysql_derived_execute_filling(THD * { unit->set_limit(first_select); if (unit->select_limit_cnt == HA_POS_ERROR) - first_select->options&= ~OPTION_FOUND_ROWS; + first_select->options&= ~OPTION_FOUND_ROWS; lex->current_select= first_select; res= mysql_execute_select(thd, first_select, @@ -403,77 +400,34 @@ bool mysql_derived_execute_filling(THD * /* fill derived table - SYNOPSIS - mysql_derived_filling() - thd Thread handle - lex LEX for this thread - unit node that contains all SELECT's for derived tables - orig_table_list TABLE_LIST for the upper SELECT - - IMPLEMENTATION - Derived table is resolved with temporary table. It is created based on the - queries defined. After temporary table is filled, if this is not EXPLAIN, - then the entire unit / node is deleted. unit is deleted if UNION is used - for derived table and node is deleted is it is a simple SELECT. - If you use this function, make sure it's not called at prepare. - Due to evaluation of LIMIT clause it can not be used at prepared stage. - - RETURN - FALSE OK - TRUE Error + @param thd Thread handle + @param lex LEX for this thread + @param unit node that contains all SELECT's for derived tables + @param orig_table_list TABLE_LIST for the upper SELECT + + @details + + Derived table is resolved with temporary table. It is created based on the + queries defined. After temporary table is filled, if this is not EXPLAIN, + then the entire unit / node is deleted. unit is deleted if UNION is used + for derived table and node is deleted is it is a simple SELECT. + If you use this function, make sure it's not called at prepare. + Due to evaluation of LIMIT clause it can not be used at prepared stage. + + @return Operation status + @retval FALSE OK + @retval TRUE Error */ bool mysql_derived_filling(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) { - TABLE *table= orig_table_list->table; - SELECT_LEX_UNIT *unit= orig_table_list->derived; bool res= FALSE; DBUG_ENTER("mysql_derived_filling"); - /*check that table creation pass without problem and it is derived table */ - if (table && unit) - { - SELECT_LEX *first_select= unit->first_select(); - select_union *derived_result= orig_table_list->derived_result; - SELECT_LEX *save_current_select= lex->current_select; - if (unit->is_union()) - { - // execute union without clean up - res= unit->exec(); - } - else - { - unit->set_limit(first_select); - if (unit->select_limit_cnt == HA_POS_ERROR) - first_select->options&= ~OPTION_FOUND_ROWS; - - lex->current_select= first_select; - res= mysql_select(thd, &first_select->ref_pointer_array, - first_select->table_list.first, - first_select->with_wild, - first_select->item_list, first_select->where, - (first_select->order_list.elements+ - first_select->group_list.elements), - first_select->order_list.first, - first_select->group_list.first, - first_select->having, (ORDER*) NULL, - (first_select->options | thd->variables.option_bits | - SELECT_NO_UNLOCK), - derived_result, unit, first_select, NULL, true, NULL, - NULL); - } - if (!res) - { - /* - Here we entirely fix both TABLE_LIST and list of SELECT's as - there were no derived tables - */ - if (derived_result->flush()) - res= TRUE; - } - lex->current_select= save_current_select; - } + res= mysql_derived_prepare_filling(thd, lex, orig_table_list); + if (!res) + res= mysql_derived_execute_filling(thd, lex, orig_table_list); DBUG_RETURN(res); } === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_insert.cc 2011-03-15 11:27:59 +0000 @@ -716,18 +716,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *t { used_table_counter= &table_counter; mdl_savepoint= thd->mdl_context.mdl_savepoint(); - if (open_tables(thd, &table_list, used_table_counter, 0)) + if (open_tables_and_prepare_derived(thd, &table_list, used_table_counter)) { open_or_lock_cleanup(thd, mdl_savepoint); DBUG_RETURN(TRUE); } - if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || - (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_prepare_filling))) - { - open_or_lock_cleanup(thd, mdl_savepoint); - DBUG_RETURN(true); - } } lock_type= table_list->lock_type; @@ -816,20 +809,11 @@ bool mysql_insert(THD *thd,TABLE_LIST *t if (used_table_counter) { /* lock the tables and handle derived tables */ - if (lock_tables(thd, table_list, *used_table_counter, 0)) + if (lock_tables_and_execute_derived(thd, table_list, *used_table_counter)) { open_or_lock_cleanup(thd, mdl_savepoint); DBUG_RETURN(true); } - /* Handle derived tables */ - if (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_execute_filling)) - { - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); - DBUG_RETURN(true); - } - if (!thd->lex->describe) - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); } /* === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_parse.cc 2011-03-15 11:27:59 +0000 @@ -2419,11 +2419,8 @@ case SQLCOM_PREPARE: } mdl_savepoint= thd->mdl_context.mdl_savepoint(); - if (!((res= open_tables(thd, &lex->query_tables, &counter, 0)) || - (res= mysql_handle_derived(lex, &mysql_derived_prepare)) || - (thd->fill_derived_tables() && - (res= mysql_handle_derived(lex, - &mysql_derived_prepare_filling))))) + if (!(res= open_tables_and_prepare_derived(thd, &lex->query_tables, + &counter))) { /* The table already exists */ if (create_table->table || create_table->view) @@ -2898,11 +2895,7 @@ end_with_restore_list: unit->set_limit(select_lex); mdl_savepoint= thd->mdl_context.mdl_savepoint(); - if (!((res= open_tables(thd, &all_tables, &counter, 0)) || - (res= mysql_handle_derived(lex, &mysql_derived_prepare)) || - (thd->fill_derived_tables() && - (res= mysql_handle_derived(lex, - &mysql_derived_prepare_filling))))) + if (!(res= open_tables_and_prepare_derived(thd, &all_tables, &counter))) { MYSQL_INSERT_SELECT_START(thd->query()); /* Skip first table, which is the table we are inserting in */ @@ -2991,10 +2984,7 @@ end_with_restore_list: thd_proc_info(thd, "init"); mdl_savepoint= thd->mdl_context.mdl_savepoint(); - if ((res= open_tables(thd, &all_tables, &counter, 0)) || - (res= mysql_handle_derived(lex, &mysql_derived_prepare)) || - (thd->fill_derived_tables() && - (res= mysql_handle_derived(lex, &mysql_derived_prepare_filling)))) + if ((res= open_tables_and_prepare_derived(thd, &all_tables, &counter))) { open_or_lock_cleanup(thd, mdl_savepoint); break; === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_select.cc 2011-03-15 11:27:59 +0000 @@ -325,10 +325,10 @@ bool handle_select(THD *thd, select_resu select_lex->order_list.first, select_lex->group_list.first, select_lex->having, - thd->lex->proc_list.first, - select_lex->options | thd->variables.option_bits | - setup_tables_done_option, - result, unit, select_lex, tables_to_open_and_lock, + thd->lex->proc_list.first, + (select_lex->options | thd->variables.option_bits | + setup_tables_done_option), + result, unit, select_lex, tables_to_open_and_lock, open_tables_is_done, tables_to_lock, open_mdl_savepoint); } DBUG_PRINT("info",("res: %d report_error: %d", res, @@ -3752,11 +3752,11 @@ err: bool mysql_select(THD *thd, Item ***rref_pointer_array, - TABLE_LIST *tables, uint wild_num, List &fields, - Item *conds, uint og_num, ORDER *order, ORDER *group, - Item *having, ORDER *proc_param, ulonglong select_options, - select_result *result, SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex, TABLE_LIST *tables_to_open_and_lock, + TABLE_LIST *tables, uint wild_num, List &fields, + Item *conds, uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc_param, ulonglong select_options, + select_result *result, SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex, TABLE_LIST *tables_to_open_and_lock, bool open_tables_is_done, uint *tables_to_lock, MDL_savepoint *open_mdl_savepoint) { @@ -3770,20 +3770,13 @@ mysql_select(THD *thd, Item ***rref_poin { DBUG_ASSERT(!tables_to_lock && !open_mdl_savepoint); mdl_savepoint= thd->mdl_context.mdl_savepoint(); - /* Open the tables */ - if (open_tables(thd, &tables_to_open_and_lock, &table_counter, 0)) + if (open_tables_and_prepare_derived(thd, &tables_to_open_and_lock, + &table_counter)) { open_or_lock_cleanup(thd, mdl_savepoint); DBUG_RETURN(true); } query_cache_store_query(thd, tables_to_open_and_lock); - if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || - (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_prepare_filling))) - { - open_or_lock_cleanup(thd, mdl_savepoint); - DBUG_RETURN(true); - } } else { @@ -3810,29 +3803,15 @@ mysql_select(THD *thd, Item ***rref_poin DBUG_RETURN(true); } - /* Lock all tables */ if (!open_tables_is_done || tables_to_lock) { if (open_tables_is_done) table_counter= *tables_to_lock; - /* Lock the tables */ - if (lock_tables(thd, tables_to_open_and_lock, table_counter, 0)) - { - if (free_join) - { - thd_proc_info(thd, "end"); - (void) select_lex->cleanup(); - } - open_or_lock_cleanup(thd, mdl_savepoint); - DBUG_RETURN(true); - } - /* Handle derived tables */ - if (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_execute_filling)) + if (lock_tables_and_execute_derived(thd, tables_to_open_and_lock, + table_counter)) { - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); if (free_join) { thd_proc_info(thd, "end"); @@ -3841,8 +3820,6 @@ mysql_select(THD *thd, Item ***rref_poin open_or_lock_cleanup(thd, mdl_savepoint); DBUG_RETURN(true); } - if (!thd->lex->describe) - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); } if (mysql_execute_select(thd, select_lex, free_join, join)) === modified file 'sql/sql_union.cc' --- a/sql/sql_union.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_union.cc 2011-03-15 11:27:59 +0000 @@ -44,19 +44,13 @@ bool mysql_union(THD *thd, select_result DBUG_ASSERT(!tables_to_lock && !open_mdl_savepoint); mdl_savepoint= thd->mdl_context.mdl_savepoint(); /* Open the tables */ - if (open_tables(thd, &tables_to_open_and_lock, &table_counter, 0)) + if (open_tables_and_prepare_derived(thd, &tables_to_open_and_lock, + &table_counter)) { open_or_lock_cleanup(thd, mdl_savepoint); DBUG_RETURN(true); } query_cache_store_query(thd, tables_to_open_and_lock); - if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) || - (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_prepare_filling))) - { - open_or_lock_cleanup(thd, mdl_savepoint); - DBUG_RETURN(true); - } } else { @@ -82,19 +76,9 @@ bool mysql_union(THD *thd, select_result if (open_tables_is_done) table_counter= *tables_to_lock; - /* Lock the tables */ - if (lock_tables(thd, tables_to_open_and_lock, table_counter, 0)) + if (lock_tables_and_execute_derived(thd, tables_to_open_and_lock, + table_counter)) goto err; - - /* Handle derived tables */ - if (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_execute_filling)) - { - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); - goto err; - } - if (!thd->lex->describe) - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); } res= unit->exec(); @@ -586,7 +570,7 @@ 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_after_locking(); + saved_error= sl->join->optimize_after_locking(); } if (!saved_error) { === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2011-02-21 16:27:53 +0000 +++ b/sql/sql_update.cc 2011-03-15 11:27:59 +0000 @@ -293,6 +293,7 @@ int mysql_update(THD *thd, /* convert to multiupdate */ DBUG_RETURN(2); } + /* TODO: Check if possible to use open_tables_and_prepare_derived */ if (mysql_handle_derived(thd->lex, &mysql_derived_prepare)) DBUG_RETURN(1); @@ -388,17 +389,9 @@ int mysql_update(THD *thd, } #endif - if (lock_tables(thd, table_list, table_count, 0)) + if (lock_tables_and_execute_derived(thd, table_list, table_count)) DBUG_RETURN(1); - if (thd->fill_derived_tables() && - mysql_handle_derived(thd->lex, &mysql_derived_filling)) - { - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); - DBUG_RETURN(1); - } - mysql_handle_derived(thd->lex, &mysql_derived_cleanup); - /* Update the table->file->stats.records number */ table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); @@ -1041,6 +1034,7 @@ int mysql_multi_update_prepare(THD *thd) keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE and global read lock. */ + /* TODO: Check if possible to use open_tables_and_prepare_derived */ if ((original_multiupdate && open_tables(thd, &table_list, &table_count, (thd->stmt_arena->is_stmt_prepare() ? @@ -1158,6 +1152,7 @@ int mysql_multi_update_prepare(THD *thd) } /* now lock and fill tables */ + /* TOOD: check if possible to use lock_tables_and_execute_derived */ if (!thd->stmt_arena->is_stmt_prepare() && lock_tables(thd, table_list, table_count, 0)) { @@ -1200,6 +1195,7 @@ int mysql_multi_update_prepare(THD *thd) */ lex->select_lex.exclude_from_table_unique_test= FALSE; + /* TOOD: check if possible to use lock_tables_and_execute_derived */ if (thd->fill_derived_tables() && mysql_handle_derived(lex, &mysql_derived_filling)) { --===============3214498114393350943== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/mattias.jonsson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: mattias.jonsson@stripped\ # 8xm6tym77f8qclhm # target_branch: file:///Users/mattiasj/mysql-bzr/wl4443-trunk/ # testament_sha1: 9ea62b95a10b42b3cbb6c145cf74f10af68210e0 # timestamp: 2011-03-15 12:28:27 +0100 # base_revision_id: mattias.jonsson@stripped\ # xewli7mr2zm72wfw # # Begin bundle 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 yhhBZg== --===============3214498114393350943==--