From: Dmitry Lenev Date: December 14 2010 9:15am Subject: bzr commit into mysql-trunk-bugfixing branch (Dmitry.Lenev:3400) Bug#27480 List-Archive: http://lists.mysql.com/commits/126728 X-Bug: 27480 Message-Id: <20101214091558.56E231E5243@mockturtle> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0857940572==" --===============0857940572== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/dlenev/src/bzr/mysql-trunk-bugfixing-bug27480/ based on revid:dmitry.lenev@stripped 3400 Dmitry Lenev 2010-12-14 Prerequisite patch for Bug#27480 (Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). Review fixes in progress. Simplify opening of temporary tables. Get rid of duplicated code. modified: mysql-test/r/merge.result mysql-test/t/merge.test sql/sp_head.cc sql/sql_admin.cc sql/sql_base.cc sql/sql_base.h sql/sql_handler.cc sql/sql_parse.cc sql/sql_prepare.cc sql/sql_show.cc sql/sql_table.cc sql/sql_update.cc === modified file 'mysql-test/r/merge.result' --- a/mysql-test/r/merge.result 2010-12-02 08:07:11 +0000 +++ b/mysql-test/r/merge.result 2010-12-14 09:15:37 +0000 @@ -2718,7 +2718,10 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; CREATE TEMPORARY TABLE t1 (c1 INT); ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); OPTIMIZE TABLE t1; -ERROR HY000: Can't reopen table: 't1' +Table Op Msg_type Msg_text +test.t1 optimize Error Table 'test.t_not_exists' doesn't exist +test.t1 optimize Error Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist +test.t1 optimize error Corrupt DROP TABLE t1; # # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine @@ -3673,4 +3676,78 @@ ALTER TABLE t1 engine=myisam; ERROR HY000: Table 't1' was locked with a READ lock and can't be updated UNLOCK TABLES; DROP TABLE m1, t1; +# +# Additional coverage for refactoring which is made as part +# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +# to allow temp table operations". +# +# Check that prelocking works correctly for various variants of +# merge tables. +drop table if exists t1, t2, m1; +drop function if exists f1; +create table t1 (j int); +insert into t1 values (1); +create function f1() returns int return (select count(*) from m1); +create temporary table t2 (a int) engine=myisam; +insert into t2 values (1); +create temporary table m1 (a int) engine=merge union=(t2); +select f1() from t1; +f1() +1 +drop tables t2, m1; +create table t2 (a int) engine=myisam; +insert into t2 values (1); +create table m1 (a int) engine=merge union=(t2); +select f1() from t1; +f1() +1 +drop table m1; +create temporary table m1 (a int) engine=merge union=(t2); +select f1() from t1; +f1() +1 +drop tables t1, t2, m1; +drop function f1; +# +# Check that REPAIR/CHECK and CHECKSUM statements work correctly +# for various variants of merge tables. +create table t1 (a int) engine=myisam; +insert into t1 values (1); +create table m1 (a int) engine=merge union=(t1); +check table m1; +Table Op Msg_type Msg_text +test.m1 check status OK +repair table m1; +Table Op Msg_type Msg_text +test.m1 repair note The storage engine for the table doesn't support repair +checksum table m1; +Table Checksum +test.m1 3459908756 +drop tables t1, m1; +create temporary table t1 (a int) engine=myisam; +insert into t1 values (1); +create temporary table m1 (a int) engine=merge union=(t1); +check table m1; +Table Op Msg_type Msg_text +test.m1 check status OK +repair table m1; +Table Op Msg_type Msg_text +test.m1 repair note The storage engine for the table doesn't support repair +checksum table m1; +Table Checksum +test.m1 3459908756 +drop tables t1, m1; +create table t1 (a int) engine=myisam; +insert into t1 values (1); +create temporary table m1 (a int) engine=merge union=(t1); +check table m1; +Table Op Msg_type Msg_text +test.m1 check status OK +repair table m1; +Table Op Msg_type Msg_text +test.m1 repair note The storage engine for the table doesn't support repair +checksum table m1; +Table Checksum +test.m1 3459908756 +drop tables t1, m1; End of 6.0 tests === modified file 'mysql-test/t/merge.test' --- a/mysql-test/t/merge.test 2010-11-29 14:13:07 +0000 +++ b/mysql-test/t/merge.test 2010-12-14 09:15:37 +0000 @@ -2195,7 +2195,6 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; --echo # CREATE TEMPORARY TABLE t1 (c1 INT); ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); ---error ER_CANT_REOPEN_TABLE OPTIMIZE TABLE t1; DROP TABLE t1; @@ -2799,6 +2798,60 @@ UNLOCK TABLES; DROP TABLE m1, t1; +--echo # +--echo # Additional coverage for refactoring which is made as part +--echo # of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege +--echo # to allow temp table operations". +--echo # +--echo # Check that prelocking works correctly for various variants of +--echo # merge tables. +--disable_warnings +drop table if exists t1, t2, m1; +drop function if exists f1; +--enable_warnings +create table t1 (j int); +insert into t1 values (1); +create function f1() returns int return (select count(*) from m1); +create temporary table t2 (a int) engine=myisam; +insert into t2 values (1); +create temporary table m1 (a int) engine=merge union=(t2); +select f1() from t1; +drop tables t2, m1; +create table t2 (a int) engine=myisam; +insert into t2 values (1); +create table m1 (a int) engine=merge union=(t2); +select f1() from t1; +drop table m1; +create temporary table m1 (a int) engine=merge union=(t2); +select f1() from t1; +drop tables t1, t2, m1; +drop function f1; +--echo # +--echo # Check that REPAIR/CHECK and CHECKSUM statements work correctly +--echo # for various variants of merge tables. +create table t1 (a int) engine=myisam; +insert into t1 values (1); +create table m1 (a int) engine=merge union=(t1); +check table m1; +repair table m1; +checksum table m1; +drop tables t1, m1; +create temporary table t1 (a int) engine=myisam; +insert into t1 values (1); +create temporary table m1 (a int) engine=merge union=(t1); +check table m1; +repair table m1; +checksum table m1; +drop tables t1, m1; +create table t1 (a int) engine=myisam; +insert into t1 values (1); +create temporary table m1 (a int) engine=merge union=(t1); +check table m1; +repair table m1; +checksum table m1; +drop tables t1, m1; + + --echo End of 6.0 tests --disable_result_log === modified file 'sql/sp_head.cc' --- a/sql/sp_head.cc 2010-12-02 08:07:11 +0000 +++ b/sql/sp_head.cc 2010-12-14 09:15:37 +0000 @@ -3041,7 +3041,7 @@ int sp_instr::exec_open_and_lock_tables( Check whenever we have access to tables for this statement and open and lock them before executing instructions core function. */ - if (open_and_process_temporary_table_list(thd, tables) || + if (open_temporary_table_list(thd, tables) || check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE) || open_and_lock_tables(thd, tables, TRUE, 0)) result= -1; === modified file 'sql/sql_admin.cc' --- a/sql/sql_admin.cc 2010-12-06 10:36:38 +0000 +++ b/sql/sql_admin.cc 2010-12-14 09:15:37 +0000 @@ -346,7 +346,7 @@ static bool mysql_admin_table(THD* thd, if (view_operator_func == NULL) table->required_type=FRMTYPE_TABLE; - open_error= open_and_process_temporary_table_list(thd, table); + open_error= open_temporary_table_list(thd, table); if (! open_error) open_error= open_and_lock_tables(thd, table, TRUE, 0); === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2010-12-06 10:36:38 +0000 +++ b/sql/sql_base.cc 2010-12-14 09:15:37 +0000 @@ -4299,7 +4299,7 @@ open_and_process_table(THD *thd, LEX *le if (tables->table) { DBUG_ASSERT(is_temporary_table(tables->table)); - DBUG_RETURN(FALSE); + goto process_table; } /* @@ -4328,7 +4328,7 @@ open_and_process_table(THD *thd, LEX *le temporary tabletill the execution of substatement for several reasons: - Temporary table can be a MERGE table with base underlying tables, so its underlying tables has to be properly open and locked at - prelocking stage. TODO/FIXME: Add test case for this scenario. + prelocking stage. - Temporary table can be a MERGE table and we might be in PREPARE phase for a prepared statement. In this case it is important to call HA_ATTACH_CHILDREN for all merge children. @@ -4341,11 +4341,14 @@ open_and_process_table(THD *thd, LEX *le The problem is that since those attributes are not set in merge children, another round of PREPARE will not help. */ - error= open_and_process_temporary_table(thd, tables); + error= open_temporary_table(thd, tables); - if (error || tables->table) + if (error) goto end; + if (tables->table) + goto process_table; + /* For the tables added by the pre-locking code, attempt to open the table but fail silently if the table does not exist. @@ -4359,7 +4362,24 @@ open_and_process_table(THD *thd, LEX *le safe_to_ignore_table= no_such_table_handler.safely_trapped_errors(); } else + { + /* + Even if we are opening table not from the prelocking list we + still might need to look for a temporary table if this table + list element corresponds to underlying table of a merge table. + */ + if (tables->parent_l) + { + error= open_temporary_table(thd, tables); + + if (error) + goto end; + + if (tables->table) + goto process_table; + } error= open_table(thd, tables, new_frm_mem, ot_ctx); + } free_root(new_frm_mem, MYF(MY_KEEP_PREALLOC)); @@ -4407,6 +4427,7 @@ open_and_process_table(THD *thd, LEX *le goto process_view_routines; } +process_table: /* Special types of open can succeed but still don't set TABLE_LIST::table to anything. @@ -4832,7 +4853,7 @@ restart: goto err; /* Re-open temporary tables after close_tables_for_reopen(). */ - if (open_and_process_temporary_table_list(thd, *start)) + if (open_temporary_table_list(thd, *start)) goto err; error= FALSE; @@ -4882,7 +4903,7 @@ restart: goto err; /* Re-open temporary tables after close_tables_for_reopen(). */ - if (open_and_process_temporary_table_list(thd, *start)) + if (open_temporary_table_list(thd, *start)) goto err; error= FALSE; @@ -5957,14 +5978,13 @@ static void update_field_dependencies(TH of this thread. Temporary tables are thread-local and "shadow" base tables with the same name. - open_temporary_table() should be considered as an internal function. - Usually, open_and_process_temporary_table() should be used instead to - open temporary table completely. The only case where - open_temporary_table() is used directly is implementation of INSERT INTO - statement (sql_insert.cc). + @note One should finalize process of opening temporary table for table + list element by calling open_and_process_table(). This function + is responsible for table version checking and handling of merge + tables. - Note: we used to check global_read_lock before opening temporary tables. - However, that limitation was artificial and is removed now. + @note We used to check global_read_lock before opening temporary tables. + However, that limitation was artificial and is removed now. @return Error status. @retval FALSE On success. If a temporary table exists for the given @@ -5977,11 +5997,15 @@ bool open_temporary_table(THD *thd, TABL DBUG_ENTER("open_temporary_table"); DBUG_PRINT("enter", ("table: '%s'.'%s'", tl->db, tl->table_name)); + /* + Code in open_table() assumes that TABLE_LIST::table can + be non-zero only for pre-opened temporary tables. + */ + DBUG_ASSERT(tl->table == NULL); + if (tl->open_type == OT_BASE_ONLY) { DBUG_PRINT("info", ("skip_temporary is set")); - - tl->table= NULL; DBUG_RETURN(FALSE); } @@ -5992,7 +6016,6 @@ bool open_temporary_table(THD *thd, TABL if (!table) { - tl->table= NULL; DBUG_RETURN(FALSE); } @@ -6026,13 +6049,13 @@ bool open_temporary_table(THD *thd, TABL } -bool open_and_process_temporary_table_list(THD *thd, TABLE_LIST *tl_list) +bool open_temporary_table_list(THD *thd, TABLE_LIST *tl_list) { - DBUG_ENTER("open_and_process_temporary_table_list"); + DBUG_ENTER("open_temporary_table_list"); for (TABLE_LIST *tl= tl_list; tl; tl= tl->next_global) { - if (open_and_process_temporary_table(thd, tl)) + if (open_temporary_table(thd, tl)) DBUG_RETURN(TRUE); } @@ -6040,62 +6063,6 @@ bool open_and_process_temporary_table_li } -/** - Open a temporary table specified by TABLE_LIST instance. - - @return Error status. - @retval FALSE On success. Opened temporary table is returned in - TABLE_LIST::table member. If TABLE_LIST::table is NULL, - the specified temporary table does not exist. - @retval TRUE On error. my_error() has been called. -*/ - -bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl) -{ - DBUG_ENTER("open_and_process_temporary_table"); - - if (tl->schema_table || tl->derived) - DBUG_RETURN(FALSE); - - if (tl->table) - DBUG_RETURN(FALSE); // The table is already open. - - if (open_temporary_table(thd, tl)) - DBUG_RETURN(TRUE); - - /* - If 'tl->table' is NULL, that means there is no temporary table for the - table specified by 'tl'. This is not an error. - */ - if (!tl->table) - DBUG_RETURN(FALSE); - - /* Set appropriate TABLE::lock_type. */ - if (tl->lock_type != TL_UNLOCK && !thd->locked_tables_mode) - { - if (tl->lock_type == TL_WRITE_DEFAULT) - tl->table->reginfo.lock_type= thd->update_lock_default; - else if (tl->lock_type == TL_READ_DEFAULT) - tl->table->reginfo.lock_type= read_lock_type_for_table(thd, thd->lex, tl); - else - tl->table->reginfo.lock_type= tl->lock_type; - } - - /* Check and update metadata version of a base table. */ - if (check_and_update_table_version(thd, tl, tl->table->s)) - DBUG_RETURN(TRUE); - - /* MERGE tables need to access parent and child TABLE_LISTs. */ - DBUG_ASSERT(tl->table->pos_in_table_list == tl); - - /* Non-MERGE tables ignore this call. */ - if (tl->table->file->extra(HA_EXTRA_ADD_CHILDREN_LIST)) - DBUG_RETURN(TRUE); - - DBUG_RETURN(FALSE); -} - - /* Find a field by name in a view that uses merge algorithm. === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2010-11-29 14:13:07 +0000 +++ b/sql/sql_base.h 2010-12-14 09:15:37 +0000 @@ -267,8 +267,7 @@ void close_temporary_table(THD *thd, TAB void close_temporary(TABLE *table, bool free_share, bool delete_table); bool rename_temporary_table(THD* thd, TABLE *table, const char *new_db, const char *table_name); -bool open_and_process_temporary_table_list(THD *thd, TABLE_LIST *tl_list); -bool open_and_process_temporary_table(THD *thd, TABLE_LIST *tl); +bool open_temporary_table_list(THD *thd, TABLE_LIST *tl_list); bool open_temporary_table(THD *thd, TABLE_LIST *tl); bool is_equal(const LEX_STRING *a, const LEX_STRING *b); === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2010-11-29 14:13:07 +0000 +++ b/sql/sql_handler.cc 2010-12-14 09:15:37 +0000 @@ -287,12 +287,9 @@ bool mysql_ha_open(THD *thd, TABLE_LIST */ DBUG_ASSERT(! hash_tables->table); - error= open_and_process_temporary_table(thd, hash_tables); + error= open_temporary_table(thd, hash_tables); - if (is_temporary_table(hash_tables)) - hash_tables->table->grant= hash_tables->grant; - - if (!error && !hash_tables->table) + if (!error) error= open_tables(thd, &hash_tables, &counter, 0); if (! error && === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-12-06 10:36:38 +0000 +++ b/sql/sql_parse.cc 2010-12-14 09:15:37 +0000 @@ -1252,7 +1252,7 @@ bool dispatch_command(enum enum_server_c thd->set_query(fields, query_length); general_log_print(thd, command, "%s %s", table_list.table_name, fields); - if (open_and_process_temporary_table(thd, &table_list)) + if (open_temporary_table(thd, &table_list)) break; if (check_table_access(thd, SELECT_ACL, &table_list, @@ -2077,7 +2077,7 @@ mysql_execute_command(THD *thd) if (sql_command_flags[lex->sql_command] & CF_PREOPEN_TMP_TABLES) { - if (open_and_process_temporary_table_list(thd, all_tables)) + if (open_temporary_table_list(thd, all_tables)) goto error; } @@ -2384,7 +2384,7 @@ case SQLCOM_PREPARE: if (lex->create_info.merge_list.elements) { - if (open_and_process_temporary_table_list( + if (open_temporary_table_list( thd, lex->create_info.merge_list.first)) { res= 1; @@ -2736,7 +2736,7 @@ end_with_restore_list: Temporary tables should be opened for SHOW CREATE TABLE, but not for SHOW CREATE VIEW. */ - if (open_and_process_temporary_table_list(thd, all_tables)) + if (open_temporary_table_list(thd, all_tables)) goto error; /* @@ -3226,7 +3226,7 @@ end_with_restore_list: usual way, they would be closed by close_thread_tables(). */ - if (open_and_process_temporary_table_list(thd, all_tables)) + if (open_temporary_table_list(thd, all_tables)) goto error; if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, @@ -4630,10 +4630,6 @@ bool check_single_table_access(THD *thd, &all_tables->grant.m_internal, 0, no_errors)) goto deny; - - if (is_temporary_table(all_tables)) - all_tables->table->grant= all_tables->grant; - /* Show only 1 table for check_grant */ if (!(all_tables->belong_to_view && (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) && @@ -5066,9 +5062,6 @@ check_table_access(THD *thd, ulong requi &tables->grant.m_internal, 0, no_errors)) goto deny; - - if (is_temporary_table(tables)) - tables->table->grant= tables->grant; } thd->security_ctx= backup_ctx; return check_grant(thd,requirements,org_tables, === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2010-12-06 10:36:38 +0000 +++ b/sql/sql_prepare.cc 2010-12-14 09:15:37 +0000 @@ -1718,8 +1718,7 @@ static bool mysql_test_create_table(Prep if (lex->create_info.merge_list.elements) { - if (open_and_process_temporary_table_list( - thd, lex->create_info.merge_list.first)) + if (open_temporary_table_list(thd, lex->create_info.merge_list.first)) { DBUG_RETURN(TRUE); } @@ -1788,12 +1787,6 @@ static bool mysql_test_create_view(Prepa if (create_view_precheck(thd, tables, view, lex->create_view_mode)) goto err; - for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) - { - if (is_temporary_table(tl)) - tl->table->grant= tl->grant; - } - if (open_normal_and_derived_tables(thd, tables, MYSQL_OPEN_FORCE_SHARED_MDL)) goto err; @@ -1989,7 +1982,7 @@ static bool check_prepared_statement(Pre */ if (sql_command_flags[sql_command] & CF_PREOPEN_TMP_TABLES) { - if (open_and_process_temporary_table_list(thd, tables)) + if (open_temporary_table_list(thd, tables)) goto error; } === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2010-12-02 08:07:11 +0000 +++ b/sql/sql_show.cc 2010-12-14 09:15:37 +0000 @@ -3020,7 +3020,7 @@ fill_schema_show_cols_or_idxs(THD *thd, */ lex->sql_command= SQLCOM_SHOW_FIELDS; - res= open_and_process_temporary_table_list(thd, show_table_list); + res= open_temporary_table_list(thd, show_table_list); if (!res) { @@ -3635,7 +3635,7 @@ int get_all_tables(THD *thd, TABLE_LIST show_table_list->i_s_requested_object= schema_table->i_s_requested_object; DEBUG_SYNC(thd, "before_open_in_get_all_tables"); - if (open_and_process_temporary_table_list(thd, show_table_list)) + if (open_temporary_table_list(thd, show_table_list)) goto err; res= open_normal_and_derived_tables(thd, show_table_list, (MYSQL_OPEN_IGNORE_FLUSH | === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2010-12-02 08:07:11 +0000 +++ b/sql/sql_table.cc 2010-12-14 09:15:37 +0000 @@ -7304,19 +7304,40 @@ bool mysql_checksum_table(THD *thd, TABL Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); + /* + Close all temporary tables which were pre-open to simplify + privilege checking. Clear all references to closed tables. + */ + close_thread_tables(thd); + for (table= tables; table; table= table->next_local) + table->table= NULL; + /* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local) { - TABLE *t= table->table; char table_name[NAME_LEN*2+2]; + TABLE *t; + TABLE_LIST *save_next_global; strxmov(table_name, table->db ,".", table->table_name, NullS); - if (!table->table) + /* Remember old 'next' pointer and break the list. */ + save_next_global= table->next_global; + table->next_global= NULL; + table->lock_type= TL_READ; + /* Allow to open real tables only. */ + table->required_type= FRMTYPE_TABLE; + + if (open_temporary_table(thd, table) || + open_and_lock_tables(thd, table, FALSE, 0)) { - t= table->table= open_n_lock_single_table(thd, table, TL_READ, 0); - thd->clear_error(); // these errors shouldn't get client + t= NULL; + thd->clear_error(); // these errors shouldn't get client } + else + t= table->table; + + table->next_global= save_next_global; protocol->prepare_for_resend(); protocol->store(table_name, system_charset_info); @@ -7414,9 +7435,6 @@ bool mysql_checksum_table(THD *thd, TABL if (! thd->in_sub_stmt) trans_rollback_stmt(thd); close_thread_tables(thd); - - if (open_and_process_temporary_table_list(thd, tables)) - goto err; } if (protocol->write()) goto err; === modified file 'sql/sql_update.cc' --- a/sql/sql_update.cc 2010-12-02 09:21:50 +0000 +++ b/sql/sql_update.cc 2010-12-14 09:15:37 +0000 @@ -1130,10 +1130,6 @@ int mysql_multi_update_prepare(THD *thd) 0, 0) || check_grant(thd, want_privilege, tl, FALSE, 1, FALSE)) DBUG_RETURN(TRUE); - - if (is_temporary_table(tl)) - tl->table->grant= tl->grant; - } } --===============0857940572== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.lenev@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.lenev@stripped # target_branch: file:///home/dlenev/src/bzr/mysql-trunk-bugfixing-\ # bug27480/ # testament_sha1: 020ab4e7134a6d2c2e956a9ac44f7439f1d7be0f # timestamp: 2010-12-14 12:15:57 +0300 # source_branch: file:///home/dlenev/src/bzr/mysql-trunk-bugfixing/ # base_revision_id: dmitry.lenev@stripped\ # 1kt8j9f29yixq4b1 # # Begin bundle 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 --===============0857940572==--