From: Dmitry Lenev Date: March 26 2011 10:56am Subject: bzr commit into mysql-trunk branch (Dmitry.Lenev:3532) Bug#11746602 List-Archive: http://lists.mysql.com/commits/133935 X-Bug: 11746602 Message-Id: <20110326105633.0F4717406EF@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1027859757==" --===============1027859757== 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-26 Patch for Bug#11746602 (27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). The problem was that user with CREATE TEMPORARY TABLES privilege which was able to create temporary table, needed additional privileges which also applied to non-temporary tables to do any useful work on it. As result it was impossible to allow user to work with temporary tables without also granting extra privileges on normal tables. 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 going 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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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, even by user without any privileges on tables. +########################################################################### + +# -- 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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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, even by user without any privileges on tables. +--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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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-26 10:56:27 +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 --===============1027859757== 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: 99cea2be7bfc366d06791ceab79f4132f132a9d3 # timestamp: 2011-03-26 13:56:32 +0300 # base_revision_id: alexander.nozdrin@stripped\ # v0qajienvv3fwctf # # Begin bundle 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 --===============1027859757==--