From: Alexander Nozdrin Date: March 24 2011 9:02am Subject: bzr commit into mysql-trunk branch (alexander.nozdrin:3532) Bug#11746602 List-Archive: http://lists.mysql.com/commits/133732 X-Bug: 11746602 Message-Id: <201103240902.p2O92ZvC010583@acsmt356.oracle.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============8994390456644936479==" --===============8994390456644936479== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/alik/MySQL/bzr/00/bug27480/mysql-trunk-bug27480/ based on revid:alexander.nozdrin@stripped 3532 Alexander Nozdrin 2011-03-24 Patch for Bug#11746602 (27480: Extend CREATE TEMPORARY TABLES privilege to allow temp table operations). The idea of this patch is to check CREATE TEMPORARY TABLES privilege for CREATE TEMPORARY TABLE statement only. Privileges are not checked for temporary tables for other statements. 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_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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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 table-level privileges for it. + Note that during creation of temporary table we still need to check + if user has CREATE_TMP_ACL, but this is not a table-level privilege. + */ + tl->grant.privilege|= 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_alter.cc' --- a/sql/sql_alter.cc 2010-10-05 09:15:51 +0000 +++ b/sql/sql_alter.cc 2011-03-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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-24 09:02:22 +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)) @@ -7081,6 +7114,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. === 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-24 09:02:22 +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-24 09:02:22 +0000 @@ -2062,14 +2062,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 +2140,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 --===============8994390456644936479== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/alexander.nozdrin@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: alexander.nozdrin@stripped\ # k29hmbp4mc45cqlx # target_branch: file:///home/alik/MySQL/bzr/00/bug27480/mysql-trunk-\ # bug27480/ # testament_sha1: 1de3ec68590ae68895feaae9a794acb0d3ea84f0 # timestamp: 2011-03-24 12:02:30 +0300 # source_branch: file:///home/alik/MySQL/bzr/mysql-trunk/ # base_revision_id: alexander.nozdrin@stripped\ # v0qajienvv3fwctf # # Begin bundle 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 RwnN/kldA9h6n/F3JFOFCQ/4Ng3Q --===============8994390456644936479==--