From: Dmitry Lenev Date: March 25 2011 12:51pm Subject: bzr commit into mysql-trunk branch (Dmitry.Lenev:3532) Bug#11746602 List-Archive: http://lists.mysql.com/commits/133873 X-Bug: 11746602 Message-Id: <20110325125108.BE893740646@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============2023830936==" --===============2023830936== 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-bug27480-2/ based on revid:alexander.nozdrin@stripped 3532 Dmitry Lenev 2011-03-25 Patch for Bug#11746602 (27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). The idea of this patch is to allow any relevant operation on a temporary table which already exists. Creation of temporary table still requires CREATE TEMPORARY TABLES privilege on database in which this table to be created. @ mysql-test/include/handler.inc Adjusted test case to the fact that now HANDLER OPEN pre-opens temporary tables first and only after that checks if it is called under LOCK TABLES. @ mysql-test/r/flush_read_lock.result Adjusted test case to the fact that DROP TABLE no longer acquires metadata locks if it is going to drop temporary table and thus doesn't conflict with global read lock in this case. @ mysql-test/r/grant2.result Added test coverage for privilege handling for temporary tables (i.e. for bug#11746602 "27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations"). @ mysql-test/r/handler_innodb.result Adjusted test case to the fact that now HANDLER OPEN pre-opens temporary tables first and only after that checks if it is called under LOCK TABLES. @ mysql-test/r/handler_myisam.result Adjusted test case to the fact that now HANDLER OPEN pre-opens temporary tables first and only after that checks if it is called under LOCK TABLES. @ mysql-test/r/merge.result Since ALTER TABLE now pre-opens temporary table for UNION clause, ALTER TABLE temp_table UNION=(..., temp_table) is no longer legal. Adjusted test case to avoid using this construct. @ mysql-test/t/flush_read_lock.test Adjusted test case to the fact that DROP TABLE no longer acquires metadata locks if it is going to drop temporary table and thus doesn't conflict with global read lock in this case. @ mysql-test/t/grant2.test Added test coverage for privilege handling for temporary tables (i.e. for bug#11746602 "27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations"). @ mysql-test/t/merge.test Since ALTER TABLE now pre-opens temporary table for UNION clause, ALTER TABLE temp_table UNION=(..., temp_table) is no longer legal. Adjusted test case to avoid using this construct. @ sql/sql_acl.cc Changed check_grant() to skip its and further privilege checks on pre-opened temporary tables. This is achieved by automatically adding all relevant table-level privileges to the set of granted privileges for every temporary table. @ sql/sql_acl.h Added define for set of table-level privileges which are relevant for temporary tables. @ sql/sql_alter.cc Changed code checking privileges for tables from UNION clause of ALTER TABLE. Now we pre-open temporary tables for this clause in order properly check privileges for them (or rather skip privilege checking). @ sql/sql_base.cc Now drop_temporary_table() assumes that temporary table to be dropped was pre-opened using table list element which it gets as parameter. Adjusted code accordingly. @ sql/sql_base.h Adjusted is_temporary_table() function to ignore views and schema tables so it can properly differentiate real temporary tables from ones used in view and information schema implementation. @ sql/sql_handler.cc Removed comment which is no longer relevant. @ sql/sql_insert.cc Since drop_temporary_table() function now expects that table to be dropped is pre-opened we can no longer use it to drop temporary table which we have created but failed to open. Replaced call to this function with assert since such situation should not be possible anyway. @ sql/sql_parse.cc - Now we pre-open temporary tables for DROP TABLE and HANDLER OPEN statements. This allows correctly handle (i.e. ignore) privilege checks in cases when we are goign to drop or open handler for temporary table. As a consequence DROP TABLE now needs to close open handlers for tables to be dropped before this pre-opening happens. - Moved handling of privilege checks for UNION clause of CREATE TABLE statement inside of create_table_precheck() function. Adjusted the latter to correctly handle privilege checking in cases when UNION clause contains temporary tables. Also we no longer require INSERT privilege for CREATE TEMPORARY TABLE ... SELECT statement. It is enough to have CREATE TEMPORARY privilege for it. - Introduced lock_tables_precheck() function which allows to skip temporary tables when checking privileges for LOCK TABLES statement (we can't handle LOCK TABLES privilege in the same way as other privileges for temporary tables as it is a db-level privilege). - Changed code in check_show_access() to take into account temporary tables when checking privileges for SHOW FIELDS and SHOW KEYS statements. - Adjusted code in multi_delete_precheck() to update elements of auxiliary table list from corresponding elements of main table list. This allows to correctly distinguish temporary tables when auxiliary table list is used for privilege checking. @ sql/sql_prepare.cc Checking of privileges on tables from UNION clause of CREATE TABLE statement has been moved into create_table_precheck() function. @ sql/sql_table.cc Changed DROP TABLES implementation to rely on the fact that temporary tables to be dropped are pre-opened. Pre-opening has to be done in any case in order to correctly skip those tables during privilege check for this statement. modified: mysql-test/include/handler.inc mysql-test/r/flush_read_lock.result mysql-test/r/grant2.result mysql-test/r/handler_innodb.result mysql-test/r/handler_myisam.result mysql-test/r/merge.result mysql-test/t/flush_read_lock.test mysql-test/t/grant2.test mysql-test/t/merge.test sql/sql_acl.cc sql/sql_acl.h sql/sql_alter.cc sql/sql_base.cc sql/sql_base.h sql/sql_handler.cc sql/sql_insert.cc sql/sql_parse.cc sql/sql_prepare.cc sql/sql_table.cc === modified file 'mysql-test/include/handler.inc' --- a/mysql-test/include/handler.inc 2010-11-18 16:34:56 +0000 +++ b/mysql-test/include/handler.inc 2011-03-25 12:51:00 +0000 @@ -804,6 +804,7 @@ create table t1 (a int, key a (a)); insert into t1 (a) values (1), (2), (3), (4), (5); create table t2 (a int, key a (a)) select * from t1; create temporary table t3 (a int, key a (a)) select * from t2; +create temporary table t4 like t3; handler t1 open; handler t2 open; handler t3 open; @@ -818,8 +819,10 @@ handler t1 open; handler t1 read next; --error ER_LOCK_OR_ACTIVE_TRANSACTION handler t2 close; ---error ER_LOCK_OR_ACTIVE_TRANSACTION +--error ER_CANT_REOPEN_TABLE handler t3 open; +--error ER_LOCK_OR_ACTIVE_TRANSACTION +handler t4 open; --echo # After UNLOCK TABLES handlers should be around and --echo # we should be able to continue reading through them. unlock tables; @@ -829,7 +832,7 @@ handler t2 read next; handler t2 close; handler t3 read next; handler t3 close; -drop temporary table t3; +drop temporary tables t3, t4; --echo # --echo # Other operations that implicitly close handler: --echo # === modified file 'mysql-test/r/flush_read_lock.result' --- a/mysql-test/r/flush_read_lock.result 2010-11-11 17:11:05 +0000 +++ b/mysql-test/r/flush_read_lock.result 2011-03-25 12:51:00 +0000 @@ -543,11 +543,10 @@ Success: Was not able to run 'drop table Success: 'drop table t2_base' is blocked by FTWRL active in another connection. Success: FTWRL is blocked when 'drop table t2_base' is active in another connection. # 13.1.b) DROP TABLES which affects only temporary tables -# in theory can be compatible with FTWRL. -# In practice it is not yet. -Success: Was not able to run 'drop table t2_temp' under FTWRL. -Success: 'drop table t2_temp' is blocked by FTWRL active in another connection. -Success: FTWRL is blocked when 'drop table t2_temp' is active in another connection. +# is compatible with FTWRL. +Success: Was able to run 'drop table t2_temp' under FTWRL. +Success: Was able to run 'drop table t2_temp' with FTWRL active in another connection. +Success: Was able to run FTWRL while 'drop table t2_temp' was active in another connection. # # 13.1.c) DROP TEMPORARY TABLES should be compatible with FTWRL. Success: Was able to run 'drop temporary table t2_temp' under FTWRL. === modified file 'mysql-test/r/grant2.result' --- a/mysql-test/r/grant2.result 2010-08-09 08:32:50 +0000 +++ b/mysql-test/r/grant2.result 2011-03-25 12:51:00 +0000 @@ -472,3 +472,330 @@ root localhost Y FLUSH PRIVILEGES; USE test; End of 5.1 tests + +# -- +# -- Bug#11746602: 27480 - Extend CREATE TEMPORARY TABLES privilege to +# -- allow temp table operations +# -- + +############################################################################ +# Setup environment. +########################################################################### +DROP DATABASE IF EXISTS mysqltest_db1; +CREATE DATABASE mysqltest_db1; +# mysqltest_u1@localhost has CREATE_TMP_ACL, FILE_ACL and EXECUTE_ACL only +# (EXECUTE_ACL is needed to call p0, and FILE_ACL is needed for SELECT +# OUTFILE/LOAD DATA INFILE). +GRANT FILE ON *.* TO mysqltest_u1@localhost; +GRANT CREATE TEMPORARY TABLES, EXECUTE ON mysqltest_db1.* TO mysqltest_u1@localhost; +# mysqltest_u2@localhost has all privileges but CREATE_TMP_ACL. +GRANT ALL PRIVILEGES ON mysqltest_db1.* TO mysqltest_u2@localhost; +REVOKE CREATE TEMPORARY TABLES ON mysqltest_db1.* FROM mysqltest_u2@localhost; +# mysqltest_u3@localhost has CREATE_TMP_ACL & EXECUTE_ACL. +# This user is required to check SUID-stored-routines. +GRANT CREATE TEMPORARY TABLES ON mysqltest_db1.* TO mysqltest_u3@localhost; +GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u3@localhost; +# mysqltest_u4@localhost has only EXECUTE_ACL. +# We need this user to check that once created temporary tables +# are accessible by anyone. +GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u4@localhost; +# Create stored routine to test how privilege checking is done for its +# arguments. +CREATE PROCEDURE mysqltest_db1.p0(i INT) SELECT i; +# Create SUID-stored-routines. +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p1() +CREATE TEMPORARY TABLE t4(x INT); +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p2() +INSERT INTO t4 VALUES (1), (2), (3); +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p3() +SELECT * FROM t4 ORDER BY x; +# We need separate key cache to test CACHE INDEX and LOAD INDEX. +SET GLOBAL keycache1.key_buffer_size = 128 * 1024; +########################################################################### +# Check that CREATE_TMP_ACL is enough to issue any supported SQL-statement +# against temporary tables (loosely follow order in sql_command enum). +########################################################################### + +# -- connect con1, mysqltest_u1@localhost, mysqltest_db1 +# +# Variants of CREATE TABLE. +# +CREATE TEMPORARY TABLE t1(a INT); +CREATE TEMPORARY TABLE t2 LIKE t1; +CREATE TEMPORARY TABLE t3(a INT, b INT, PRIMARY KEY (a)); +CREATE TEMPORARY TABLE t4 SELECT * FROM t1; +# Also check that we allow creation of MERGE table with underlying +# temporary table without additional privileges. +CREATE TEMPORARY TABLE t5(a INT) ENGINE = MyISAM; +CREATE TEMPORARY TABLE t6(a INT) ENGINE = MERGE UNION = (t5); +# +# SELECT. +# +INSERT INTO t1 VALUES (1), (2), (3); +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +# +# CREATE/DROP INDEX. +# +CREATE INDEX idx1 ON t3(b); +DROP INDEX idx1 ON t3; +# +# ALTER TABLE. +# +ALTER TABLE t4 ADD COLUMN b INT; +# Check that we allow altering of MERGE table with underlying +# temporary table without additional privileges. +ALTER TABLE t6 UNION = (); +ALTER TABLE t6 UNION = (t5); +# +# Simple INSERT and INSERT ... SELECT. +# +INSERT INTO t1 VALUES (4); +INSERT INTO t2 SELECT a FROM t1; +SELECT * FROM t1 ORDER BY a; +a +1 +2 +3 +4 +SELECT * FROM t2 ORDER BY a; +a +1 +2 +3 +4 +# +# UPDATE and multi-UPDATE. +# +UPDATE t1 SET a = a * 10; +UPDATE t1 SET a = 100 WHERE a = 10; +UPDATE t1, t2 SET t1.a = 200 WHERE t1.a = t2.a * 10 AND t1.a = 20; +SELECT * FROM t1 ORDER BY a; +a +30 +40 +100 +200 +# +# DELETE and multi-DELETE. +# +DELETE FROM t1 WHERE a = 100; +DELETE t1 FROM t1, t2 WHERE t1.a = t2.a * 100 AND t1.a = 200; +SELECT * FROM t1 ORDER BY a; +a +30 +40 +# +# TRUNCATE TABLE. +# +TRUNCATE TABLE t1; +SELECT * FROM t1 ORDER BY a; +a +# +# SHOW COLUMNS/DESCRIBE and SHOW KEYS. +# +SHOW COLUMNS FROM t1; +Field Type Null Key Default Extra +SHOW KEYS FROM t3; +Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment +t3 0 PRIMARY 1 a A 0 NULL NULL BTREE +# +# SHOW CREATE TABLE. +# +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TEMPORARY TABLE `t1` ( + `a` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +# +# LOAD DATA INFILE (also SELECT INTO OUTFILE). +# +INSERT INTO t1 VALUES (1), (2), (3); +SELECT a INTO OUTFILE 'MYSQLTEST_VARDIR/tmp/bug27480.txt' FROM t1 ; +LOAD DATA INFILE 'MYSQLTEST_VARDIR/tmp/bug27480.txt' INTO TABLE t1; +SELECT * FROM t1 ORDER BY a; +a +1 +1 +2 +2 +3 +3 +# +# SET. +# +SET @a := (SELECT COUNT(*) FROM t1); +SELECT @a; +@a +6 +# +# LOCK TABLES. +# +LOCK TABLES t1 READ; +UNLOCK TABLES; +# +# CHECK/REPAIR/ANALYZE/OPTIMIZE and CHECKSUM. +# +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +mysqltest_db1.t1 analyze status OK +CHECK TABLE t1; +Table Op Msg_type Msg_text +mysqltest_db1.t1 check status OK +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +mysqltest_db1.t1 optimize status Table is already up to date +REPAIR TABLE t1; +Table Op Msg_type Msg_text +mysqltest_db1.t1 repair status OK +# +# REPLACE and REPLACE ... SELECT. +# +INSERT INTO t3 VALUES (1, 111), (2, 222), (3, 333); +REPLACE INTO t3 VALUES (1, 1111), (4, 444), (0, 001); +REPLACE INTO t2 SELECT b FROM t3; +SELECT * FROM t2 ORDER BY a; +a +1 +1 +2 +3 +4 +222 +333 +444 +1111 +SELECT * FROM t3 ORDER BY a; +a b +0 1 +1 1111 +2 222 +3 333 +4 444 +# +# CACHE and LOAD INDEX. +# +CACHE INDEX t3 IN keycache1; +Table Op Msg_type Msg_text +mysqltest_db1.t3 assign_to_keycache status OK +LOAD INDEX INTO CACHE t3; +Table Op Msg_type Msg_text +mysqltest_db1.t3 preload_keys status OK +# +# RENAME (doesn't work for temporary tables, thus should fail). +# +RENAME TABLE t3 TO t3_1; +ERROR 42000: DROP, ALTER command denied to user 'mysqltest_u1'@'localhost' for table 't3' +# +# HANDLER OPEN/READ/CLOSE. +# +HANDLER t1 OPEN; +HANDLER t1 READ NEXT; +a +1 +HANDLER t1 CLOSE; +# +# DO. +# +DO (SELECT COUNT(*) FROM t1); +# +# CHECKSUM TABLE. +# +DELETE FROM t1; +CHECKSUM TABLE t1; +Table Checksum +mysqltest_db1.t1 0 +# +# CALL. +# +CALL p0((SELECT COUNT(*) FROM t1)); +i +0 +# +# PREPARE, EXECUTE and DEALLOCATE. +# +PREPARE stmt1 FROM 'SELECT * FROM t1 ORDER BY a'; +PREPARE stmt2 FROM 'SELECT * FROM t2 ORDER BY a'; +EXECUTE stmt1; +a +EXECUTE stmt2; +a +1 +1 +2 +3 +4 +222 +333 +444 +1111 +DEALLOCATE PREPARE stmt1; +DEALLOCATE PREPARE stmt2; +# +# DROP TABLE and DROP TEMPORARY TABLE. +# +DROP TABLE t1; +CREATE TEMPORARY TABLE t1(a INT); +DROP TEMPORARY TABLE t1; +########################################################################### +# - Check that even having all privileges but CREATE_TMP_ACL is not enough +# to create temporary tables. +# - Check that creation/working with temporary tables is possible via +# SUID-stored-routines. +# - Check that even outside of SUID context we can access temporary +# table once it is created. +########################################################################### + +# -- connect con2, mysqltest_u2@localhost, mysqltest_db1 +CREATE TEMPORARY TABLE t2(a INT); +ERROR 42000: Access denied for user 'mysqltest_u2'@'localhost' to database 'mysqltest_db1' +CALL p1(); +CALL p2(); +CALL p3(); +x +1 +2 +3 +# Check that once table is created it can be accessed even +# outside of such a SUID context. +INSERT INTO t4 VALUES (4); +UPDATE t4 SET x = 10 WHERE x = 1; +DELETE FROM t4 WHERE x < 3; +SELECT * FROM t4 ORDER BY x; +x +3 +4 +10 +DROP TEMPORARY TABLE t4; +########################################################################### +# - Check that once table is created it can be accessed from within any +# context. +########################################################################### + +# -- connect con3, mysqltest_u4@localhost, mysqltest_db1 +CALL p1(); +INSERT INTO t4 VALUES (4); +UPDATE t4 SET x = 10 WHERE x = 1; +DELETE FROM t4 WHERE x < 3; +SELECT * FROM t4 ORDER BY x; +x +4 +DROP TEMPORARY TABLE t4; +########################################################################### +# That's all. Cleanup. +########################################################################### + +# -- connection: default +# -- disconnect con1 +# All remaining temporary tables are automatically dropped. +# -- disconnect con2 +# -- disconnect con3 +SET GLOBAL keycache1.key_buffer_size = 0; +DROP DATABASE mysqltest_db1; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; +DROP USER mysqltest_u3@localhost; +DROP USER mysqltest_u4@localhost; === modified file 'mysql-test/r/handler_innodb.result' --- a/mysql-test/r/handler_innodb.result 2010-11-18 16:34:56 +0000 +++ b/mysql-test/r/handler_innodb.result 2011-03-25 12:51:00 +0000 @@ -784,6 +784,7 @@ create table t1 (a int, key a (a)); insert into t1 (a) values (1), (2), (3), (4), (5); create table t2 (a int, key a (a)) select * from t1; create temporary table t3 (a int, key a (a)) select * from t2; +create temporary table t4 like t3; handler t1 open; handler t2 open; handler t3 open; @@ -799,6 +800,8 @@ ERROR HY000: Can't execute the given com handler t2 close; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction handler t3 open; +ERROR HY000: Can't reopen table: 't3' +handler t4 open; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction # After UNLOCK TABLES handlers should be around and # we should be able to continue reading through them. @@ -815,7 +818,7 @@ handler t3 read next; a 1 handler t3 close; -drop temporary table t3; +drop temporary tables t3, t4; # # Other operations that implicitly close handler: # === modified file 'mysql-test/r/handler_myisam.result' --- a/mysql-test/r/handler_myisam.result 2011-01-17 16:27:07 +0000 +++ b/mysql-test/r/handler_myisam.result 2011-03-25 12:51:00 +0000 @@ -782,6 +782,7 @@ create table t1 (a int, key a (a)); insert into t1 (a) values (1), (2), (3), (4), (5); create table t2 (a int, key a (a)) select * from t1; create temporary table t3 (a int, key a (a)) select * from t2; +create temporary table t4 like t3; handler t1 open; handler t2 open; handler t3 open; @@ -797,6 +798,8 @@ ERROR HY000: Can't execute the given com handler t2 close; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction handler t3 open; +ERROR HY000: Can't reopen table: 't3' +handler t4 open; ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction # After UNLOCK TABLES handlers should be around and # we should be able to continue reading through them. @@ -813,7 +816,7 @@ handler t3 read next; a 1 handler t3 close; -drop temporary table t3; +drop temporary tables t3, t4; # # Other operations that implicitly close handler: # === modified file 'mysql-test/r/merge.result' --- a/mysql-test/r/merge.result 2011-02-15 18:21:37 +0000 +++ b/mysql-test/r/merge.result 2011-03-25 12:51:00 +0000 @@ -2716,13 +2716,14 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; # Bug#47633 - assert in ha_myisammrg::info during OPTIMIZE # CREATE TEMPORARY TABLE t1 (c1 INT); -ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); +CREATE TEMPORARY TABLE t2 (c1 INT); +ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists, t2); OPTIMIZE 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; +DROP TABLE t1, t2; # # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine # More tests with TEMPORARY MERGE table and permanent children. === modified file 'mysql-test/t/flush_read_lock.test' --- a/mysql-test/t/flush_read_lock.test 2010-11-12 13:57:08 +0000 +++ b/mysql-test/t/flush_read_lock.test 2011-03-25 12:51:00 +0000 @@ -706,11 +706,10 @@ let $cleanup_stmt1= create table t2_base --source include/check_ftwrl_incompatible.inc --echo # 13.1.b) DROP TABLES which affects only temporary tables ---echo # in theory can be compatible with FTWRL. ---echo # In practice it is not yet. +--echo # is compatible with FTWRL. let $statement= drop table t2_temp; -let $cleanup_stmt1= create temporary table t2_temp(j int); ---source include/check_ftwrl_incompatible.inc +let $cleanup_stmt= create temporary table t2_temp(j int); +--source include/check_ftwrl_compatible.inc --echo # --echo # 13.1.c) DROP TEMPORARY TABLES should be compatible with FTWRL. === modified file 'mysql-test/t/grant2.test' --- a/mysql-test/t/grant2.test 2010-08-09 08:32:50 +0000 +++ b/mysql-test/t/grant2.test 2011-03-25 12:51:00 +0000 @@ -667,5 +667,308 @@ USE test; --echo End of 5.1 tests + +--echo +--echo # -- +--echo # -- Bug#11746602: 27480 - Extend CREATE TEMPORARY TABLES privilege to +--echo # -- allow temp table operations +--echo # -- +--echo + +--echo ############################################################################ +--echo # Setup environment. +--echo ########################################################################### + +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +--enable_warnings + +CREATE DATABASE mysqltest_db1; + +--echo # mysqltest_u1@localhost has CREATE_TMP_ACL, FILE_ACL and EXECUTE_ACL only +--echo # (EXECUTE_ACL is needed to call p0, and FILE_ACL is needed for SELECT +--echo # OUTFILE/LOAD DATA INFILE). +GRANT FILE ON *.* TO mysqltest_u1@localhost; +GRANT CREATE TEMPORARY TABLES, EXECUTE ON mysqltest_db1.* TO mysqltest_u1@localhost; + +--echo # mysqltest_u2@localhost has all privileges but CREATE_TMP_ACL. +GRANT ALL PRIVILEGES ON mysqltest_db1.* TO mysqltest_u2@localhost; +REVOKE CREATE TEMPORARY TABLES ON mysqltest_db1.* FROM mysqltest_u2@localhost; + +--echo # mysqltest_u3@localhost has CREATE_TMP_ACL & EXECUTE_ACL. +--echo # This user is required to check SUID-stored-routines. +GRANT CREATE TEMPORARY TABLES ON mysqltest_db1.* TO mysqltest_u3@localhost; +GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u3@localhost; + +--echo # mysqltest_u4@localhost has only EXECUTE_ACL. +--echo # We need this user to check that once created temporary tables +--echo # are accessible by anyone. +GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u4@localhost; + +--echo # Create stored routine to test how privilege checking is done for its +--echo # arguments. +CREATE PROCEDURE mysqltest_db1.p0(i INT) SELECT i; + +--echo # Create SUID-stored-routines. +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p1() + CREATE TEMPORARY TABLE t4(x INT); + +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p2() + INSERT INTO t4 VALUES (1), (2), (3); + +CREATE DEFINER = mysqltest_u3@localhost PROCEDURE mysqltest_db1.p3() + SELECT * FROM t4 ORDER BY x; + +--echo # We need separate key cache to test CACHE INDEX and LOAD INDEX. +SET GLOBAL keycache1.key_buffer_size = 128 * 1024; + +--echo ########################################################################### +--echo # Check that CREATE_TMP_ACL is enough to issue any supported SQL-statement +--echo # against temporary tables (loosely follow order in sql_command enum). +--echo ########################################################################### + +--echo +--echo # -- connect con1, mysqltest_u1@localhost, mysqltest_db1 +--connect (con1,localhost,mysqltest_u1,,mysqltest_db1) + +--echo # +--echo # Variants of CREATE TABLE. +--echo # +CREATE TEMPORARY TABLE t1(a INT); +CREATE TEMPORARY TABLE t2 LIKE t1; +CREATE TEMPORARY TABLE t3(a INT, b INT, PRIMARY KEY (a)); +CREATE TEMPORARY TABLE t4 SELECT * FROM t1; +--echo # Also check that we allow creation of MERGE table with underlying +--echo # temporary table without additional privileges. +CREATE TEMPORARY TABLE t5(a INT) ENGINE = MyISAM; +CREATE TEMPORARY TABLE t6(a INT) ENGINE = MERGE UNION = (t5); + +--echo # +--echo # SELECT. +--echo # +INSERT INTO t1 VALUES (1), (2), (3); +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # CREATE/DROP INDEX. +--echo # +CREATE INDEX idx1 ON t3(b); +DROP INDEX idx1 ON t3; + +--echo # +--echo # ALTER TABLE. +--echo # +ALTER TABLE t4 ADD COLUMN b INT; +--echo # Check that we allow altering of MERGE table with underlying +--echo # temporary table without additional privileges. +ALTER TABLE t6 UNION = (); +ALTER TABLE t6 UNION = (t5); + +--echo # +--echo # Simple INSERT and INSERT ... SELECT. +--echo # +INSERT INTO t1 VALUES (4); +INSERT INTO t2 SELECT a FROM t1; +SELECT * FROM t1 ORDER BY a; +SELECT * FROM t2 ORDER BY a; + +--echo # +--echo # UPDATE and multi-UPDATE. +--echo # +UPDATE t1 SET a = a * 10; +UPDATE t1 SET a = 100 WHERE a = 10; +UPDATE t1, t2 SET t1.a = 200 WHERE t1.a = t2.a * 10 AND t1.a = 20; +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # DELETE and multi-DELETE. +--echo # +DELETE FROM t1 WHERE a = 100; +DELETE t1 FROM t1, t2 WHERE t1.a = t2.a * 100 AND t1.a = 200; +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # TRUNCATE TABLE. +--echo # +TRUNCATE TABLE t1; +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # SHOW COLUMNS/DESCRIBE and SHOW KEYS. +--echo # +SHOW COLUMNS FROM t1; +SHOW KEYS FROM t3; + +--echo # +--echo # SHOW CREATE TABLE. +--echo # +SHOW CREATE TABLE t1; + +--echo # +--echo # LOAD DATA INFILE (also SELECT INTO OUTFILE). +--echo # +INSERT INTO t1 VALUES (1), (2), (3); +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval SELECT a INTO OUTFILE '$MYSQLTEST_VARDIR/tmp/bug27480.txt' FROM t1 +--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR +--eval LOAD DATA INFILE '$MYSQLTEST_VARDIR/tmp/bug27480.txt' INTO TABLE t1 +--remove_file $MYSQLTEST_VARDIR/tmp/bug27480.txt +SELECT * FROM t1 ORDER BY a; + +--echo # +--echo # SET. +--echo # +SET @a := (SELECT COUNT(*) FROM t1); +SELECT @a; + +--echo # +--echo # LOCK TABLES. +--echo # +LOCK TABLES t1 READ; +UNLOCK TABLES; + +--echo # +--echo # CHECK/REPAIR/ANALYZE/OPTIMIZE and CHECKSUM. +--echo # +ANALYZE TABLE t1; +CHECK TABLE t1; +OPTIMIZE TABLE t1; +REPAIR TABLE t1; + +--echo # +--echo # REPLACE and REPLACE ... SELECT. +--echo # +INSERT INTO t3 VALUES (1, 111), (2, 222), (3, 333); +REPLACE INTO t3 VALUES (1, 1111), (4, 444), (0, 001); +REPLACE INTO t2 SELECT b FROM t3; +SELECT * FROM t2 ORDER BY a; +SELECT * FROM t3 ORDER BY a; + +--echo # +--echo # CACHE and LOAD INDEX. +--echo # +CACHE INDEX t3 IN keycache1; +LOAD INDEX INTO CACHE t3; + +--echo # +--echo # RENAME (doesn't work for temporary tables, thus should fail). +--echo # +--error ER_TABLEACCESS_DENIED_ERROR +RENAME TABLE t3 TO t3_1; + +--echo # +--echo # HANDLER OPEN/READ/CLOSE. +--echo # +HANDLER t1 OPEN; +HANDLER t1 READ NEXT; +HANDLER t1 CLOSE; + +--echo # +--echo # DO. +--echo # +DO (SELECT COUNT(*) FROM t1); + +--echo # +--echo # CHECKSUM TABLE. +--echo # +DELETE FROM t1; +CHECKSUM TABLE t1; + +--echo # +--echo # CALL. +--echo # +CALL p0((SELECT COUNT(*) FROM t1)); + +--echo # +--echo # PREPARE, EXECUTE and DEALLOCATE. +--echo # +PREPARE stmt1 FROM 'SELECT * FROM t1 ORDER BY a'; +PREPARE stmt2 FROM 'SELECT * FROM t2 ORDER BY a'; +EXECUTE stmt1; +EXECUTE stmt2; +DEALLOCATE PREPARE stmt1; +DEALLOCATE PREPARE stmt2; + +--echo # +--echo # DROP TABLE and DROP TEMPORARY TABLE. +--echo # +DROP TABLE t1; + +CREATE TEMPORARY TABLE t1(a INT); +DROP TEMPORARY TABLE t1; + + +--echo ########################################################################### +--echo # - Check that even having all privileges but CREATE_TMP_ACL is not enough +--echo # to create temporary tables. +--echo # - Check that creation/working with temporary tables is possible via +--echo # SUID-stored-routines. +--echo # - Check that even outside of SUID context we can access temporary +--echo # table once it is created. +--echo ########################################################################### + +--echo +--echo # -- connect con2, mysqltest_u2@localhost, mysqltest_db1 +--connect (con2,localhost,mysqltest_u2,,mysqltest_db1) + +--error ER_DBACCESS_DENIED_ERROR +CREATE TEMPORARY TABLE t2(a INT); + +CALL p1(); + +CALL p2(); + +CALL p3(); + +--echo # Check that once table is created it can be accessed even +--echo # outside of such a SUID context. +INSERT INTO t4 VALUES (4); +UPDATE t4 SET x = 10 WHERE x = 1; +DELETE FROM t4 WHERE x < 3; +SELECT * FROM t4 ORDER BY x; +DROP TEMPORARY TABLE t4; + +--echo ########################################################################### +--echo # - Check that once table is created it can be accessed from within any +--echo # context. +--echo ########################################################################### + +--echo +--echo # -- connect con3, mysqltest_u4@localhost, mysqltest_db1 +--connect (con3,localhost,mysqltest_u4,,mysqltest_db1) + +CALL p1(); +INSERT INTO t4 VALUES (4); +UPDATE t4 SET x = 10 WHERE x = 1; +DELETE FROM t4 WHERE x < 3; +SELECT * FROM t4 ORDER BY x; +DROP TEMPORARY TABLE t4; + +--echo ########################################################################### +--echo # That's all. Cleanup. +--echo ########################################################################### + +--echo +--echo # -- connection: default +--connection default + +--echo # -- disconnect con1 +--echo # All remaining temporary tables are automatically dropped. +--disconnect con1 + +--echo # -- disconnect con2 +--disconnect con2 + +--echo # -- disconnect con3 +--disconnect con3 + +SET GLOBAL keycache1.key_buffer_size = 0; +DROP DATABASE mysqltest_db1; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; +DROP USER mysqltest_u3@localhost; +DROP USER mysqltest_u4@localhost; + + # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc === modified file 'mysql-test/t/merge.test' --- a/mysql-test/t/merge.test 2011-02-15 18:21:37 +0000 +++ b/mysql-test/t/merge.test 2011-03-25 12:51:00 +0000 @@ -2194,9 +2194,10 @@ DROP TABLE tm1, t1, t2, t3, t4, t5; --echo # Bug#47633 - assert in ha_myisammrg::info during OPTIMIZE --echo # CREATE TEMPORARY TABLE t1 (c1 INT); -ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists,t1); +CREATE TEMPORARY TABLE t2 (c1 INT); +ALTER TABLE t1 ENGINE=MERGE UNION(t_not_exists, t2); OPTIMIZE TABLE t1; -DROP TABLE t1; +DROP TABLE t1, t2; --echo # --echo # Bug#36171 - CREATE TEMPORARY TABLE and MERGE engine === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2011-02-18 09:56:51 +0000 +++ b/sql/sql_acl.cc 2011-03-25 12:51:00 +0000 @@ -4617,6 +4617,20 @@ bool check_grant(THD *thd, ulong want_ac } continue; } + + if (is_temporary_table(tl)) + { + /* + If this table list element corresponds to a pre-opened temporary + table skip checking of all relevant table-level privileges for it. + Note that during creation of temporary table we still need to check + if user has CREATE_TMP_ACL. + */ + tl->grant.privilege|= TMP_TABLE_ACLS; + tl->grant.want_privilege= 0; + continue; + } + GRANT_TABLE *grant_table= table_hash_search(sctx->host, sctx->ip, tl->get_db_name(), sctx->priv_user, === modified file 'sql/sql_acl.h' --- a/sql/sql_acl.h 2010-10-21 09:49:16 +0000 +++ b/sql/sql_acl.h 2011-03-25 12:51:00 +0000 @@ -95,6 +95,14 @@ CREATE_ACL | DROP_ACL | ALTER_ACL | INDEX_ACL | \ TRIGGER_ACL | REFERENCES_ACL | GRANT_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL) +/** + Table-level privileges which are automatically "granted" to everyone on + existing temporary tables (CREATE_ACL is necessary for ALTER ... RENAME). +*/ +#define TMP_TABLE_ACLS \ +(SELECT_ACL | INSERT_ACL | UPDATE_ACL | DELETE_ACL | CREATE_ACL | DROP_ACL | \ + INDEX_ACL | ALTER_ACL) + /* Defines to change the above bits to how things are stored in tables This is needed as the 'host' and 'db' table is missing a few privileges === modified file 'sql/sql_alter.cc' --- a/sql/sql_alter.cc 2010-10-05 09:15:51 +0000 +++ b/sql/sql_alter.cc 2011-03-25 12:51:00 +0000 @@ -16,6 +16,7 @@ #include "sql_parse.h" // check_access #include "sql_table.h" // mysql_alter_table, // mysql_exchange_partition +#include "sql_base.h" // open_temporary_tables #include "sql_alter.h" bool Sql_cmd_alter_table::execute(THD *thd) @@ -64,10 +65,31 @@ bool Sql_cmd_alter_table::execute(THD *t DBUG_RETURN(TRUE); /* purecov: inspected */ /* If it is a merge table, check privileges for merge children. */ - if (create_info.merge_list.first && - check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - create_info.merge_list.first, FALSE, UINT_MAX, FALSE)) - DBUG_RETURN(TRUE); + if (create_info.merge_list.first) + { + /* Pre-open underlying temporary tables to simplify privilege checking. */ + if (open_temporary_tables(thd, create_info.merge_list.first)) + DBUG_RETURN(TRUE); + + if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, + create_info.merge_list.first, FALSE, UINT_MAX, FALSE)) + DBUG_RETURN(TRUE); + + /* + Since one of tables in UNION clause might be already used by table being + altered we need to close all tables opened for UNION checking to allow + normal open of table being altered. + To do this we simply close all tables and then open only tables from the + main statement's table list. + */ + close_thread_tables(thd); + + for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global) + tl->table= NULL; + + if (open_temporary_tables(thd, lex->query_tables)) + DBUG_RETURN(TRUE); + } if (check_grant(thd, priv_needed, first_table, FALSE, UINT_MAX, FALSE)) DBUG_RETURN(TRUE); /* purecov: inspected */ === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_base.cc 2011-03-25 12:51:00 +0000 @@ -2059,10 +2059,13 @@ TABLE *find_temporary_table(THD *thd, thd->temporary_tables list, it's impossible to tell here whether we're dealing with an internal or a user temporary table. - If is_trans is not null, we return the type of the table: + In is_trans out-parameter, we return the type of the table: either transactional (e.g. innodb) as TRUE or non-transactional (e.g. myisam) as FALSE. + This function assumes that table to be dropped was pre-opened + using table list provided. + @retval 0 the table was found and dropped successfully. @retval 1 the table was not found in the list of temporary tables of this thread @@ -2071,14 +2074,15 @@ TABLE *find_temporary_table(THD *thd, int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans) { - TABLE *table; DBUG_ENTER("drop_temporary_table"); DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", table_list->db, table_list->table_name)); - if (!(table= find_temporary_table(thd, table_list))) + if (!is_temporary_table(table_list)) DBUG_RETURN(1); + TABLE *table= table_list->table; + /* Table might be in use by some outer statement. */ if (table->query_id && table->query_id != thd->query_id) { @@ -2086,8 +2090,7 @@ int drop_temporary_table(THD *thd, TABLE DBUG_RETURN(-1); } - if (is_trans != NULL) - *is_trans= table->file->has_transactions(); + *is_trans= table->file->has_transactions(); /* If LOCK TABLES list is not empty and contains this table, @@ -2095,6 +2098,7 @@ int drop_temporary_table(THD *thd, TABLE */ mysql_lock_remove(thd, thd->lock, table); close_temporary_table(thd, table, 1, 1); + table_list->table= NULL; DBUG_RETURN(0); } === modified file 'sql/sql_base.h' --- a/sql/sql_base.h 2011-03-09 12:24:36 +0000 +++ b/sql/sql_base.h 2011-03-25 12:51:00 +0000 @@ -577,7 +577,21 @@ private: inline bool is_temporary_table(TABLE_LIST *tl) { - return tl->table ? (tl->table->s->tmp_table != NO_TMP_TABLE) : FALSE; + if (tl->view || tl->schema_table) + return FALSE; + + if (!tl->table) + return FALSE; + + /* + NOTE: 'table->s' might be NULL for specially constructed TABLE + instances. See SHOW TRIGGERS for example. + */ + + if (!tl->table->s) + return FALSE; + + return tl->table->s->tmp_table != NO_TMP_TABLE; } === modified file 'sql/sql_handler.cc' --- a/sql/sql_handler.cc 2011-01-17 16:27:07 +0000 +++ b/sql/sql_handler.cc 2011-03-25 12:51:00 +0000 @@ -287,10 +287,6 @@ bool mysql_ha_open(THD *thd, TABLE_LIST */ DBUG_ASSERT(! hash_tables->table); - /* - TODO/FIXME: In the upcoming patch we somehow should handle - situation with privilege check for temporary table. - */ error= open_temporary_tables(thd, hash_tables); if (!error) === modified file 'sql/sql_insert.cc' --- a/sql/sql_insert.cc 2011-02-15 17:36:23 +0000 +++ b/sql/sql_insert.cc 2011-03-25 12:51:00 +0000 @@ -3799,10 +3799,10 @@ static TABLE *create_table_from_items(TH { /* This shouldn't happen as creation of temporary table should make - it preparable for open. But let us do close_temporary_table() here - just in case. + it preparable for open. Anyway we can't drop temporary table if + we are unable to fint it. */ - drop_temporary_table(thd, create_table, NULL); + DBUG_ASSERT(0); } else { === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_parse.cc 2011-03-25 12:51:00 +0000 @@ -114,6 +114,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables); static void sql_kill(THD *thd, ulong id, bool only_kill_query); +static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables); const char *any_db="*any*"; // Special symbol for check_access @@ -455,6 +456,7 @@ void init_update_queries(void) pre-opening temporary tables for those statements is somewhat custom. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_DROP_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CREATE_INDEX]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_TRUNCATE]|= CF_PREOPEN_TMP_TABLES; @@ -472,6 +474,7 @@ void init_update_queries(void) sql_command_flags[SQLCOM_SELECT]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_SET_OPTION]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_DO]|= CF_PREOPEN_TMP_TABLES; + sql_command_flags[SQLCOM_HA_OPEN]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CALL]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_CHECKSUM]|= CF_PREOPEN_TMP_TABLES; sql_command_flags[SQLCOM_ANALYZE]|= CF_PREOPEN_TMP_TABLES; @@ -488,6 +491,7 @@ void init_update_queries(void) have to be closed before emporary tables are pre-opened. */ sql_command_flags[SQLCOM_CREATE_TABLE]|= CF_HA_CLOSE; + sql_command_flags[SQLCOM_DROP_TABLE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_ALTER_TABLE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_TRUNCATE]|= CF_HA_CLOSE; sql_command_flags[SQLCOM_REPAIR]|= CF_HA_CLOSE; @@ -2396,19 +2400,6 @@ case SQLCOM_PREPARE: goto end_with_restore_list; } - /* - Pre-open temporary tables from UNION clause to simplify privilege - checking for them. - */ - if (lex->create_info.merge_list.elements) - { - if (open_temporary_tables(thd, lex->create_info.merge_list.first)) - { - res= 1; - goto end_with_restore_list; - } - } - if ((res= create_table_precheck(thd, select_tables, create_table))) goto end_with_restore_list; @@ -3259,8 +3250,7 @@ end_with_restore_list: if (open_temporary_tables(thd, all_tables)) goto error; - if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, - FALSE, UINT_MAX, FALSE)) + if (lock_tables_precheck(thd, all_tables)) goto error; thd->variables.option_bits|= OPTION_TABLE_LOCK; @@ -3757,6 +3747,9 @@ end_with_restore_list: DBUG_ASSERT(first_table == all_tables && first_table != 0); if (check_table_access(thd, SELECT_ACL, all_tables, FALSE, UINT_MAX, FALSE)) goto error; + /* Close temporary tables which were pre-opened for privilege checking. */ + close_thread_tables(thd); + all_tables->table= NULL; res= mysql_ha_open(thd, first_table, 0); break; case SQLCOM_HA_CLOSE: @@ -4998,10 +4991,10 @@ static bool check_show_access(THD *thd, DBUG_ASSERT(dst_table); /* - TODO/FIXME: In the upcoming patch we somehow should handle - situation when table in question is a temporary - table. + Open temporary tables to be able to detect them during privilege check. */ + if (open_temporary_tables(thd, dst_table)) + return TRUE; if (check_access(thd, SELECT_ACL, dst_table->db, &dst_table->grant.privilege, @@ -5016,6 +5009,9 @@ static bool check_show_access(THD *thd, if (check_grant(thd, SELECT_ACL, dst_table, TRUE, UINT_MAX, FALSE)) return TRUE; /* Access denied */ + close_thread_tables(thd); + dst_table->table= NULL; + /* Access granted */ return FALSE; } @@ -6773,6 +6769,19 @@ bool multi_delete_precheck(THD *thd, TAB TABLE_LIST **save_query_tables_own_last= thd->lex->query_tables_own_last; DBUG_ENTER("multi_delete_precheck"); + /* + Temporary tables are pre-opened in 'tables' list only. Here we need to + initialize TABLE instances in 'aux_tables' list. + */ + for (TABLE_LIST *tl= aux_tables; tl; tl= tl->next_global) + { + if (tl->table) + continue; + + if (tl->correspondent_table) + tl->table= tl->correspondent_table->table; + } + /* sql_yacc guarantees that tables and aux_tables are not zero */ DBUG_ASSERT(aux_tables != 0); if (check_table_access(thd, SELECT_ACL, tables, FALSE, UINT_MAX, FALSE)) @@ -7041,9 +7050,9 @@ bool create_table_precheck(THD *thd, TAB CREATE TABLE ... SELECT, also require INSERT. */ - want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? - CREATE_TMP_ACL : CREATE_ACL) | - (select_lex->item_list.elements ? INSERT_ACL : 0); + want_priv= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ? + CREATE_TMP_ACL : + (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0)); if (check_access(thd, want_priv, create_table->db, &create_table->grant.privilege, @@ -7052,11 +7061,35 @@ bool create_table_precheck(THD *thd, TAB goto err; /* If it is a merge table, check privileges for merge children. */ - if (lex->create_info.merge_list.first && - check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, - lex->create_info.merge_list.first, - FALSE, UINT_MAX, FALSE)) - goto err; + if (lex->create_info.merge_list.first) + { + /* + Pre-open temporary tables from UNION clause to simplify privilege + checking for them. + */ + if (open_temporary_tables(thd, lex->create_info.merge_list.first)) + goto err; + + if (check_table_access(thd, SELECT_ACL | UPDATE_ACL | DELETE_ACL, + lex->create_info.merge_list.first, + FALSE, UINT_MAX, FALSE)) + goto err; + + /* + Since the MERGE table in question might already exist with exactly + the same definition we need to close all tables opened for underlying + checking to allow normal open of table being created. + To do this we simply close all tables and then open only tables from + the main statement's table list. + */ + close_thread_tables(thd); + + for (TABLE_LIST *tl= lex->query_tables; tl; tl= tl->next_global) + tl->table= NULL; + + if (open_temporary_tables(thd, lex->query_tables)) + DBUG_RETURN(TRUE); + } if (want_priv != CREATE_TMP_ACL && check_grant(thd, want_priv, create_table, FALSE, 1, FALSE)) @@ -7082,6 +7115,35 @@ err: /** + Check privileges for LOCK TABLES statement. + + @param thd Thread context. + @param tables List of tables to be locked. + + @retval FALSE - Success. + @retval TRUE - Failure. +*/ + +static bool lock_tables_precheck(THD *thd, TABLE_LIST *tables) +{ + TABLE_LIST *first_not_own_table= thd->lex->first_not_own_table(); + + for (TABLE_LIST *table= tables; table != first_not_own_table && table; + table= table->next_global) + { + if (is_temporary_table(table)) + continue; + + if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, table, + FALSE, 1, FALSE)) + return TRUE; + } + + return FALSE; +} + + +/** negate given expression. @param thd thread handler === modified file 'sql/sql_prepare.cc' --- a/sql/sql_prepare.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_prepare.cc 2011-03-25 12:51:00 +0000 @@ -1716,14 +1716,6 @@ static bool mysql_test_create_table(Prep TABLE_LIST *create_table= lex->query_tables; TABLE_LIST *tables= lex->create_last_non_select_table->next_global; - if (lex->create_info.merge_list.elements) - { - if (open_temporary_tables(thd, lex->create_info.merge_list.first)) - { - DBUG_RETURN(TRUE); - } - } - if (create_table_precheck(thd, tables, create_table)) DBUG_RETURN(TRUE); === modified file 'sql/sql_table.cc' --- a/sql/sql_table.cc 2011-03-09 12:24:36 +0000 +++ b/sql/sql_table.cc 2011-03-25 12:51:00 +0000 @@ -2052,8 +2052,6 @@ bool mysql_rm_table(THD *thd,TABLE_LIST } } - mysql_ha_rm_tables(thd, tables); - if (!drop_temporary) { if (!thd->locked_tables_mode) @@ -2062,14 +2060,18 @@ bool mysql_rm_table(THD *thd,TABLE_LIST thd->variables.lock_wait_timeout, 0)) DBUG_RETURN(true); for (table= tables; table; table= table->next_local) + { + if (is_temporary_table(table)) + continue; + tdc_remove_table(thd, TDC_RT_REMOVE_ALL, table->db, table->table_name, false); + } } else { for (table= tables; table; table= table->next_local) - if (table->open_type != OT_BASE_ONLY && - find_temporary_table(thd, table)) + if (is_temporary_table(table)) { /* A temporary table. @@ -2136,6 +2138,9 @@ bool mysql_rm_table(THD *thd,TABLE_LIST @note This function assumes that metadata locks have already been taken. It is also assumed that the tables have been removed from TDC. + @note This function assumes that temporary tables to be dropped have + been pre-opened using corresponding table list elements. + @todo When logging to the binary log, we should log tmp_tables and transactional tables as separate statements if we are in a transaction; This is needed to get these tables into the --===============2023830936== 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-bug27480-2/ # testament_sha1: aa67ea5bcc856cd88e6a00f9c7e778e770d44397 # timestamp: 2011-03-25 15:51:08 +0300 # base_revision_id: alexander.nozdrin@stripped\ # v0qajienvv3fwctf # # Begin bundle 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 4vaH6Pp4zR/r/5axNnLMf/F3JFOFCQJR3/Hg --===============2023830936==--