MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Alexander Nozdrin Date:August 24 2009 5:54pm
Subject:bzr commit into mysql-5.4 branch (alik:2875)
View as plain text  
#At file:///mnt/raid/alik/MySQL/bzr/mysql-next-bugfixing/ based on revid:alik@stripped

 2875 Alexander Nozdrin	2009-08-24 [merge]
      Pull from mysql-next-bugfixing

    modified:
      mysql-test/r/lock_multi.result
      mysql-test/r/mdl_sync.result
      mysql-test/r/merge.result
      mysql-test/r/ps_ddl.result
      mysql-test/t/lock_multi.test
      mysql-test/t/mdl_sync.test
      mysql-test/t/merge.test
      mysql-test/t/ps_ddl.test
      sql/mdl.cc
      sql/mysql_priv.h
      sql/sql_acl.cc
      sql/sql_base.cc
      sql/sql_insert.cc
      sql/sql_parse.cc
      sql/sql_partition.cc
      sql/sql_prepare.cc
      sql/sql_table.cc
      sql/sql_trigger.cc
      sql/sql_view.cc
      sql/sql_yacc.yy
      sql/table.h
=== modified file 'mysql-test/r/lock_multi.result'
--- a/mysql-test/r/lock_multi.result	2009-07-28 14:16:37 +0000
+++ b/mysql-test/r/lock_multi.result	2009-08-24 09:56:29 +0000
@@ -72,9 +72,10 @@ CREATE TABLE t1 (c1 int);
 LOCK TABLE t1 WRITE;
 FLUSH TABLES WITH READ LOCK;
 CREATE TABLE t2 (c1 int);
+ERROR HY000: Table 't2' was not locked with LOCK TABLES
 UNLOCK TABLES;
 UNLOCK TABLES;
-DROP TABLE t1, t2;
+DROP TABLE t1;
 CREATE TABLE t1 (c1 int);
 LOCK TABLE t1 WRITE;
 FLUSH TABLES WITH READ LOCK;

=== modified file 'mysql-test/r/mdl_sync.result'
--- a/mysql-test/r/mdl_sync.result	2009-08-21 14:17:02 +0000
+++ b/mysql-test/r/mdl_sync.result	2009-08-24 09:56:29 +0000
@@ -62,3 +62,63 @@ unlock tables;
 # Reap INSERT.
 # Clean-up.
 drop tables t1, t2, t3, t5;
+#
+# Bug#42546 - Backup: RESTORE fails, thinking it finds an existing table
+#
+DROP TABLE IF EXISTS t1;
+set @save_log_output=@@global.log_output;
+set global log_output=file;
+#
+# Test 1: CREATE TABLE
+#
+# Connection 2 
+# Start insert on the not-yet existing table
+# Wait after taking the MDL lock
+SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
+INSERT INTO t1 VALUES(1,"def");
+# Connection 1
+SET DEBUG_SYNC= 'now WAIT_FOR locked';
+# Now INSERT has a MDL on the non-existent table t1.
+#
+# Continue the INSERT once CREATE waits for exclusive lock
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
+# Try to create that table.
+CREATE TABLE t1 (c1 INT, c2 VARCHAR(100), KEY(c1));
+# Connection 2
+# Insert fails
+ERROR 42S02: Table 'test.t1' doesn't exist
+# Connection 1
+SET DEBUG_SYNC= 'RESET';
+SHOW TABLES;
+Tables_in_test
+t1
+DROP TABLE IF EXISTS t1;
+#
+# Test 2: CREATE TABLE LIKE
+#
+CREATE TABLE t2 (c1 INT, c2 VARCHAR(100), KEY(c1));
+# Connection 2 
+# Start insert on the not-yet existing table
+# Wait after taking the MDL
+SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
+INSERT INTO t1 VALUES(1,"def");
+# Connection 1
+SET DEBUG_SYNC= 'now WAIT_FOR locked';
+# Now INSERT has a MDL on the non-existent table t1.
+#
+# Continue the INSERT once CREATE waits for exclusive lock
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
+# Try to create that table.
+CREATE TABLE t1 LIKE t2;
+# Connection 2
+# Insert fails
+ERROR 42S02: Table 'test.t1' doesn't exist
+# Connection 1
+SET DEBUG_SYNC= 'RESET';
+SHOW TABLES;
+Tables_in_test
+t1
+t2
+DROP TABLE t2;
+DROP TABLE IF EXISTS t1;
+set global log_output=@save_log_output;

=== modified file 'mysql-test/r/merge.result'
--- a/mysql-test/r/merge.result	2009-08-05 09:49:45 +0000
+++ b/mysql-test/r/merge.result	2009-08-24 09:56:29 +0000
@@ -1140,7 +1140,8 @@ SHOW CREATE TABLE t3;
 ERROR 42S02: Table 'test.t3' doesn't exist
 DROP TABLE t1, t2;
 #
-# CREATE ... LIKE
+# Bug#37371 "CREATE TABLE LIKE merge loses UNION parameter"
+# Demonstrate that this is no longer the case.
 #
 # 1. Create like.
 CREATE TABLE t1 (c1 INT);
@@ -1155,26 +1156,26 @@ SHOW CREATE TABLE t4;
 Table	Create Table
 t4	CREATE TABLE `t4` (
   `c1` int(11) DEFAULT NULL
-) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1
+) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 INSERT_METHOD=LAST UNION=(`t1`,`t2`)
 INSERT INTO t4 VALUES (4);
-ERROR HY000: Table 't4' is read only
 DROP TABLE t4;
 #
 # 1. Create like with locked tables.
 LOCK TABLES t3 WRITE, t2 WRITE, t1 WRITE;
 CREATE TABLE t4 LIKE t3;
+ERROR HY000: Table 't4' was not locked with LOCK TABLES
 SHOW CREATE TABLE t4;
 ERROR HY000: Table 't4' was not locked with LOCK TABLES
 INSERT INTO t4 VALUES (4);
 ERROR HY000: Table 't4' was not locked with LOCK TABLES
-UNLOCK TABLES;
+CREATE TEMPORARY TABLE t4 LIKE t3;
 SHOW CREATE TABLE t4;
-Table	Create Table
-t4	CREATE TABLE `t4` (
-  `c1` int(11) DEFAULT NULL
-) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1
+ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 INSERT INTO t4 VALUES (4);
-ERROR HY000: Table 't4' is read only
+ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
+UNLOCK TABLES;
+INSERT INTO t4 VALUES (4);
+ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
 DROP TABLE t4;
 #
 # Rename child.
@@ -1201,6 +1202,7 @@ c1
 1
 2
 3
+4
 RENAME TABLE t2 TO t5;
 SELECT * FROM t3 ORDER BY c1;
 ERROR HY000: Unable to open underlying table which is differently defined or of non-MyISAM type or doesn't exist
@@ -1210,6 +1212,7 @@ c1
 1
 2
 3
+4
 #
 # 3. Normal rename with locked tables.
 LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE;
@@ -1218,6 +1221,7 @@ c1
 1
 2
 3
+4
 RENAME TABLE t2 TO t5;
 ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
 SELECT * FROM t3 ORDER BY c1;
@@ -1225,6 +1229,7 @@ c1
 1
 2
 3
+4
 RENAME TABLE t5 TO t2;
 ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
 SELECT * FROM t3 ORDER BY c1;
@@ -1232,6 +1237,7 @@ c1
 1
 2
 3
+4
 UNLOCK TABLES;
 #
 # 4. Alter table rename.
@@ -1244,6 +1250,7 @@ c1
 1
 2
 3
+4
 #
 # 5. Alter table rename with locked tables.
 LOCK TABLES t1 WRITE, t2 WRITE, t3 WRITE;
@@ -1259,6 +1266,7 @@ c1
 1
 2
 3
+4
 #
 # Rename parent.
 #
@@ -1269,6 +1277,7 @@ c1
 1
 2
 3
+4
 RENAME TABLE t3 TO t5;
 ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
 SELECT * FROM t3 ORDER BY c1;
@@ -1276,6 +1285,7 @@ c1
 1
 2
 3
+4
 RENAME TABLE t5 TO t3;
 ERROR HY000: Can't execute the given command because you have active locked tables or an active transaction
 SELECT * FROM t3 ORDER BY c1;
@@ -1283,6 +1293,7 @@ c1
 1
 2
 3
+4
 #
 # 5. Alter table rename with locked tables.
 ALTER TABLE t3 RENAME TO t5;
@@ -1297,6 +1308,7 @@ c1
 1
 2
 3
+4
 DROP TABLE t1, t2, t3;
 #
 # Drop locked tables.

=== modified file 'mysql-test/r/ps_ddl.result'
--- a/mysql-test/r/ps_ddl.result	2008-09-13 14:16:20 +0000
+++ b/mysql-test/r/ps_ddl.result	2009-08-24 09:56:29 +0000
@@ -1755,21 +1755,21 @@ SUCCESS
 
 drop table t1;
 deallocate prepare stmt;
-# XXX: no validation of the first table in case of
-# CREATE TEMPORARY TABLE. This is a shortcoming of the current code,
-# but since validation is not strictly necessary, nothing is done
-# about it.
-# Will be fixed as part of work on Bug#21431 "Incomplete support of
-# temporary tables"
 create table t1 (a int);
 insert into t1 (a) values (1);
 prepare stmt from "create temporary table if not exists t2 as select * from t1";
 execute stmt;
 drop table t2;
 execute stmt;
+call p_verify_reprepare_count(0);
+SUCCESS
+
 execute stmt;
 Warnings:
 Note	1050	Table 't2' already exists
+call p_verify_reprepare_count(1);
+SUCCESS
+
 select * from t2;
 a
 1
@@ -1777,6 +1777,9 @@ a
 execute stmt;
 Warnings:
 Note	1050	Table 't2' already exists
+call p_verify_reprepare_count(0);
+SUCCESS
+
 select * from t2;
 a
 1
@@ -1790,7 +1793,7 @@ Note	1050	Table 't2' already exists
 select * from t2;
 a
 1
-call p_verify_reprepare_count(0);
+call p_verify_reprepare_count(1);
 SUCCESS
 
 drop table t1;

=== modified file 'mysql-test/t/lock_multi.test'
--- a/mysql-test/t/lock_multi.test	2009-07-28 14:16:37 +0000
+++ b/mysql-test/t/lock_multi.test	2009-08-24 09:56:29 +0000
@@ -201,6 +201,7 @@ let $wait_condition=
   where state = "Waiting for table" and info = "FLUSH TABLES WITH READ LOCK";
 --source include/wait_condition.inc
 # This must not block.
+--error ER_TABLE_NOT_LOCKED
 CREATE TABLE t2 (c1 int);
 UNLOCK TABLES;
 #
@@ -210,7 +211,7 @@ reap;
 UNLOCK TABLES;
 #
 connection default;
-DROP TABLE t1, t2;
+DROP TABLE t1;
 #
 # Test if CREATE TABLE SELECT with LOCK TABLE deadlocks.
 #

=== modified file 'mysql-test/t/mdl_sync.test'
--- a/mysql-test/t/mdl_sync.test	2009-08-21 14:17:02 +0000
+++ b/mysql-test/t/mdl_sync.test	2009-08-24 09:56:29 +0000
@@ -141,6 +141,102 @@ disconnect con2root;
 drop tables t1, t2, t3, t5;
 
 
+--echo #
+--echo # Bug#42546 - Backup: RESTORE fails, thinking it finds an existing table
+--echo #
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+set @save_log_output=@@global.log_output;
+set global log_output=file;
+
+connect(con2, localhost, root,,);
+
+--echo #
+--echo # Test 1: CREATE TABLE
+--echo #
+
+--echo # Connection 2 
+connection con2;
+--echo # Start insert on the not-yet existing table
+--echo # Wait after taking the MDL lock
+SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
+--send INSERT INTO t1 VALUES(1,"def")
+
+--echo # Connection 1
+connection default;
+SET DEBUG_SYNC= 'now WAIT_FOR locked';
+--echo # Now INSERT has a MDL on the non-existent table t1.
+
+--echo #
+--echo # Continue the INSERT once CREATE waits for exclusive lock
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
+--echo # Try to create that table.
+--send CREATE TABLE t1 (c1 INT, c2 VARCHAR(100), KEY(c1))
+
+--echo # Connection 2
+--echo # Insert fails
+connection con2;
+--error ER_NO_SUCH_TABLE
+--reap
+
+--echo # Connection 1
+connection default;
+--reap;
+SET DEBUG_SYNC= 'RESET';
+SHOW TABLES;
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+--echo #
+--echo # Test 2: CREATE TABLE LIKE
+--echo #
+
+CREATE TABLE t2 (c1 INT, c2 VARCHAR(100), KEY(c1));
+
+--echo # Connection 2 
+connection con2;
+--echo # Start insert on the not-yet existing table
+--echo # Wait after taking the MDL
+SET DEBUG_SYNC= 'after_open_table_mdl_shared SIGNAL locked WAIT_FOR finish';
+--send INSERT INTO t1 VALUES(1,"def")
+
+--echo # Connection 1
+connection default;
+SET DEBUG_SYNC= 'now WAIT_FOR locked';
+--echo # Now INSERT has a MDL on the non-existent table t1.
+
+--echo #
+--echo # Continue the INSERT once CREATE waits for exclusive lock
+SET DEBUG_SYNC= 'mdl_acquire_exclusive_locks_wait SIGNAL finish';
+--echo # Try to create that table.
+--send CREATE TABLE t1 LIKE t2
+
+--echo # Connection 2
+--echo # Insert fails
+connection con2;
+--error ER_NO_SUCH_TABLE
+--reap
+
+--echo # Connection 1
+connection default;
+--reap
+SET DEBUG_SYNC= 'RESET';
+SHOW TABLES;
+
+DROP TABLE t2;
+disconnect con2;
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+set global log_output=@save_log_output;
+
+
+
 # Check that all connections opened by test cases in this file are really
 # gone so execution of other tests won't be affected by their presence.
 --source include/wait_until_count_sessions.inc

=== modified file 'mysql-test/t/merge.test'
--- a/mysql-test/t/merge.test	2009-08-05 09:49:45 +0000
+++ b/mysql-test/t/merge.test	2009-08-24 09:56:29 +0000
@@ -760,7 +760,8 @@ SHOW CREATE TABLE t3;
 DROP TABLE t1, t2;
 #
 --echo #
---echo # CREATE ... LIKE
+--echo # Bug#37371 "CREATE TABLE LIKE merge loses UNION parameter"
+--echo # Demonstrate that this is no longer the case.
 --echo #
 --echo # 1. Create like.
 CREATE TABLE t1 (c1 INT);
@@ -772,20 +773,24 @@ INSERT INTO t2 VALUES (2);
 INSERT INTO t3 VALUES (3);
 CREATE TABLE t4 LIKE t3;
 SHOW CREATE TABLE t4;
---error ER_OPEN_AS_READONLY
 INSERT INTO t4 VALUES (4);
 DROP TABLE t4;
 --echo #
 --echo # 1. Create like with locked tables.
 LOCK TABLES t3 WRITE, t2 WRITE, t1 WRITE;
+--error ER_TABLE_NOT_LOCKED
 CREATE TABLE t4 LIKE t3;
 --error ER_TABLE_NOT_LOCKED
 SHOW CREATE TABLE t4;
 --error ER_TABLE_NOT_LOCKED
 INSERT INTO t4 VALUES (4);
-UNLOCK TABLES;
+CREATE TEMPORARY TABLE t4 LIKE t3;
+--error ER_WRONG_MRG_TABLE
 SHOW CREATE TABLE t4;
---error ER_OPEN_AS_READONLY
+--error ER_WRONG_MRG_TABLE
+INSERT INTO t4 VALUES (4);
+UNLOCK TABLES;
+--error ER_WRONG_MRG_TABLE
 INSERT INTO t4 VALUES (4);
 DROP TABLE t4;
 #

=== modified file 'mysql-test/t/ps_ddl.test'
--- a/mysql-test/t/ps_ddl.test	2008-09-13 14:16:20 +0000
+++ b/mysql-test/t/ps_ddl.test	2009-08-24 09:56:29 +0000
@@ -1493,27 +1493,24 @@ execute stmt;
 call p_verify_reprepare_count(0);
 drop table t1;
 deallocate prepare stmt;
---echo # XXX: no validation of the first table in case of
---echo # CREATE TEMPORARY TABLE. This is a shortcoming of the current code,
---echo # but since validation is not strictly necessary, nothing is done
---echo # about it.
---echo # Will be fixed as part of work on Bug#21431 "Incomplete support of
---echo # temporary tables"
 create table t1 (a int);
 insert into t1 (a) values (1);
 prepare stmt from "create temporary table if not exists t2 as select * from t1";
 execute stmt;
 drop table t2;
 execute stmt;
+call p_verify_reprepare_count(0);
 execute stmt;
+call p_verify_reprepare_count(1);
 select * from t2;
 execute stmt;
+call p_verify_reprepare_count(0);
 select * from t2;
 drop table t2;
 create temporary table t2 (a varchar(10));
 execute stmt;
 select * from t2;
-call p_verify_reprepare_count(0);
+call p_verify_reprepare_count(1);
 drop table t1;
 create table t1 (x int);
 execute stmt;

=== modified file 'sql/mdl.cc'
--- a/sql/mdl.cc	2009-08-13 14:29:55 +0000
+++ b/sql/mdl.cc	2009-08-24 09:56:29 +0000
@@ -1034,6 +1034,9 @@ MDL_ticket::upgrade_shared_lock_to_exclu
         signalled|= notify_shared_lock(thd, conflicting_ticket);
     }
 
+    /* There is a shared or exclusive lock on the object. */
+    DEBUG_SYNC(thd, "mdl_upgrade_shared_lock_to_exclusive_wait");
+
     if (signalled)
       pthread_cond_wait(&COND_mdl, &LOCK_mdl);
     else

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-08-14 19:52:00 +0000
+++ b/sql/mysql_priv.h	2009-08-24 09:56:29 +0000
@@ -1052,6 +1052,7 @@ bool mysql_new_select(LEX *lex, bool mov
 void create_select_for_variable(const char *var_name);
 void mysql_init_multi_delete(LEX *lex);
 bool multi_delete_set_locks_and_link_aux_tables(LEX *lex);
+void create_table_set_open_action_and_adjust_tables(LEX *lex);
 void init_max_user_conn(void);
 void init_update_queries(void);
 void free_max_user_conn(void);
@@ -1188,10 +1189,9 @@ int prepare_create_field(Create_field *s
 			 uint *blob_columns, 
 			 int *timestamps, int *timestamps_with_niladic,
 			 longlong table_flags);
-bool mysql_create_table(THD *thd,const char *db, const char *table_name,
+bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
                         HA_CREATE_INFO *create_info,
-                        Alter_info *alter_info,
-                        bool tmp_table, uint select_field_count);
+                        Alter_info *alter_info);
 bool mysql_create_table_no_lock(THD *thd, const char *db,
                                 const char *table_name,
                                 HA_CREATE_INFO *create_info,

=== modified file 'sql/sql_acl.cc'
--- a/sql/sql_acl.cc	2009-08-13 14:29:55 +0000
+++ b/sql/sql_acl.cc	2009-08-24 09:56:29 +0000
@@ -699,8 +699,7 @@ my_bool acl_reload(THD *thd)
   tables[0].next_local= tables[0].next_global= tables+1;
   tables[1].next_local= tables[1].next_global= tables+2;
   tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
-  tables[0].skip_temporary= tables[1].skip_temporary=
-    tables[2].skip_temporary= TRUE;
+  tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
   init_mdl_requests(tables);
 
   if (simple_open_n_lock_tables(thd, tables))
@@ -3800,7 +3799,7 @@ static my_bool grant_reload_procs_priv(T
   table.init_one_table("mysql", 5, "procs_priv",
                        strlen("procs_priv"), "procs_priv",
                        TL_READ);
-  table.skip_temporary= 1;
+  table.open_type= OT_BASE_ONLY;
 
   if (simple_open_n_lock_tables(thd, &table))
   {
@@ -3866,7 +3865,7 @@ my_bool grant_reload(THD *thd)
   tables[0].db= tables[1].db= (char *) "mysql";
   tables[0].next_local= tables[0].next_global= tables+1;
   tables[0].lock_type= tables[1].lock_type= TL_READ;
-  tables[0].skip_temporary= tables[1].skip_temporary= TRUE;
+  tables[0].open_type= tables[1].open_type= OT_BASE_ONLY;
   init_mdl_requests(tables);
 
   /*

=== modified file 'sql/sql_base.cc'
--- a/sql/sql_base.cc	2009-08-21 14:17:02 +0000
+++ b/sql/sql_base.cc	2009-08-24 09:56:29 +0000
@@ -2416,7 +2416,8 @@ bool open_table(THD *thd, TABLE_LIST *ta
     same name. This block implements the behaviour.
     TODO: move this block into a separate function.
   */
-  if (!table_list->skip_temporary && ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
+  if (table_list->open_type != OT_BASE_ONLY &&
+      ! (flags & MYSQL_OPEN_SKIP_TEMPORARY))
   {
     for (table= thd->temporary_tables; table ; table=table->next)
     {
@@ -2448,10 +2449,16 @@ bool open_table(THD *thd, TABLE_LIST *ta
     }
   }
 
-  if (flags & MYSQL_OPEN_TEMPORARY_ONLY)
+  if (table_list->open_type == OT_TEMPORARY_ONLY ||
+      (flags & MYSQL_OPEN_TEMPORARY_ONLY))
   {
-    my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
-    DBUG_RETURN(TRUE);
+    if (table_list->open_strategy == TABLE_LIST::OPEN_NORMAL)
+    {
+      my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->table_name);
+      DBUG_RETURN(TRUE);
+    }
+    else
+      DBUG_RETURN(FALSE);
   }
 
   /*
@@ -2580,6 +2587,7 @@ bool open_table(THD *thd, TABLE_LIST *ta
       DEBUG_SYNC(thd, "before_open_table_wait_refresh");
       DBUG_RETURN(TRUE);
     }
+    DEBUG_SYNC(thd, "after_open_table_mdl_shared");
   }
 
   /*

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2009-08-19 14:51:21 +0000
+++ b/sql/sql_insert.cc	2009-08-24 09:56:29 +0000
@@ -3428,46 +3428,43 @@ void select_insert::abort() {
   CREATE TABLE (SELECT) ...
 ***************************************************************************/
 
-/*
+/**
   Create table from lists of fields and items (or just return TABLE
   object for pre-opened existing table).
 
-  SYNOPSIS
-    create_table_from_items()
-      thd          in     Thread object
-      create_info  in     Create information (like MAX_ROWS, ENGINE or
-                          temporary table flag)
-      create_table in     Pointer to TABLE_LIST object providing database
-                          and name for table to be created or to be open
-      alter_info   in/out Initial list of columns and indexes for the table
-                          to be created
-      items        in     List of items which should be used to produce rest
-                          of fields for the table (corresponding fields will
-                          be added to the end of alter_info->create_list)
-      lock         out    Pointer to the MYSQL_LOCK object for table created
-                          (or open temporary table) will be returned in this
-                          parameter. Since this table is not included in
-                          THD::lock caller is responsible for explicitly
-                          unlocking this table.
-      hooks
-
-  NOTES
-    This function behaves differently for base and temporary tables:
-    - For base table we assume that either table exists and was pre-opened
-      and locked at open_and_lock_tables() stage (and in this case we just
-      emit error or warning and return pre-opened TABLE object) or special
-      placeholder was put in table cache that guarantees that this table
-      won't be created or opened until the placeholder will be removed
-      (so there is an exclusive lock on this table).
-    - We don't pre-open existing temporary table, instead we either open
-      or create and then open table in this function.
+  @param thd           [in]     Thread object
+  @param create_info   [in]     Create information (like MAX_ROWS, ENGINE or
+                                temporary table flag)
+  @param create_table  [in]     Pointer to TABLE_LIST object providing database
+                                and name for table to be created or to be open
+  @param alter_info    [in/out] Initial list of columns and indexes for the
+                                table to be created
+  @param items         [in]     List of items which should be used to produce
+                                rest of fields for the table (corresponding
+                                fields will be added to the end of
+                                alter_info->create_list)
+  @param lock          [out]    Pointer to the MYSQL_LOCK object for table
+                                created will be returned in this parameter.
+                                Since this table is not included in THD::lock
+                                caller is responsible for explicitly unlocking
+                                this table.
+  @param hooks         [in]     Hooks to be invoked before and after obtaining
+                                table lock on the table being created.
+
+  @note
+    This function assumes that either table exists and was pre-opened and
+    locked at open_and_lock_tables() stage (and in this case we just emit
+    error or warning and return pre-opened TABLE object) or an exclusive
+    metadata lock was acquired on table so we can safely create, open and
+    lock table in it (we don't acquire metadata lock if this create is
+    for temporary table).
 
+  @note
     Since this function contains some logic specific to CREATE TABLE ...
     SELECT it should be changed before it can be used in other contexts.
 
-  RETURN VALUES
-    non-zero  Pointer to TABLE object for table created or opened
-    0         Error
+  @retval non-zero  Pointer to TABLE object for table created or opened
+  @retval 0         Error
 */
 
 static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
@@ -3490,7 +3487,7 @@ static TABLE *create_table_from_items(TH
 
   DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
 
-  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&  create_table->table)
+  if (create_table->table)
   {
     /* Table already exists and was open at open_and_lock_tables() stage. */
     if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
@@ -3560,14 +3557,12 @@ static TABLE *create_table_from_items(TH
     open_table().
   */
   {
-    tmp_disable_binlog(thd);
     if (!mysql_create_table_no_lock(thd, create_table->db,
                                     create_table->table_name,
                                     create_info, alter_info, 0,
                                     select_field_count))
     {
-      if (create_info->table_existed &&
-          !(create_info->options & HA_LEX_CREATE_TMP_TABLE))
+      if (create_info->table_existed)
       {
         /*
           This means that someone created table underneath server
@@ -3603,8 +3598,7 @@ static TABLE *create_table_from_items(TH
       {
         Open_table_context ot_ctx_unused(thd);
         if (open_table(thd, create_table, thd->mem_root, &ot_ctx_unused,
-                       MYSQL_OPEN_TEMPORARY_ONLY) &&
-            !create_info->table_existed)
+                       MYSQL_OPEN_TEMPORARY_ONLY))
         {
           /*
             This shouldn't happen as creation of temporary table should make
@@ -3617,7 +3611,6 @@ static TABLE *create_table_from_items(TH
           table= create_table->table;
       }
     }
-    reenable_binlog(thd);
     if (!table)                                   // open failed
       DBUG_RETURN(0);
   }
@@ -3647,9 +3640,7 @@ static TABLE *create_table_from_items(TH
       mysql_unlock_tables(thd, *lock);
       *lock= 0;
     }
-
-    if (!create_info->table_existed)
-      drop_open_table(thd, table, create_table->db, create_table->table_name);
+    drop_open_table(thd, table, create_table->db, create_table->table_name);
     DBUG_RETURN(0);
     /* purecov: end */
   }

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-08-20 12:03:37 +0000
+++ b/sql/sql_parse.cc	2009-08-24 09:56:29 +0000
@@ -2520,9 +2520,9 @@ mysql_execute_command(THD *thd)
   {
     DBUG_ASSERT(first_table == all_tables && first_table != 0);
     bool link_to_local;
-    // Skip first table, which is the table we are creating
-    TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
-    TABLE_LIST *select_tables= lex->query_tables;
+    TABLE_LIST *create_table= first_table;
+    TABLE_LIST *select_tables= lex->create_last_non_select_table->next_global;
+
     /*
       Code below (especially in mysql_create_table() and select_create
       methods) may modify HA_CREATE_INFO structure in LEX, so we have to
@@ -2602,6 +2602,11 @@ mysql_execute_command(THD *thd)
       thd->work_part_info= part_info;
     }
 #endif
+
+    /* Set strategies: reset default or 'prepared' values. */
+    create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+    create_table->lock_strategy= TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL;
+
     if (select_lex->item_list.elements)		// With select
     {
       select_result *result;
@@ -2623,17 +2628,12 @@ mysql_execute_command(THD *thd)
         goto end_with_restore_list;
       }
 
-      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
-      {
-        lex->link_first_table_back(create_table, link_to_local);
-        /* Set strategies: reset default or 'prepared' values. */
-        create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
-        create_table->lock_strategy= TABLE_LIST::EXCLUSIVE_DOWNGRADABLE_MDL;
-        if (!thd->locked_tables_mode)
-          global_schema_lock_guard.lock();
-      }
+      if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+          !thd->locked_tables_mode)
+        global_schema_lock_guard.lock();
 
-      if (!(res= open_and_lock_tables(thd, lex->query_tables)))
+      if (!(res= open_and_lock_tables_derived(thd, lex->query_tables, TRUE,
+                                              MYSQL_OPEN_TAKE_UPGRADABLE_MDL)))
       {
         /*
           Is table which we are changing used somewhere in other parts
@@ -2642,7 +2642,6 @@ mysql_execute_command(THD *thd)
         if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
         {
           TABLE_LIST *duplicate;
-          create_table= lex->unlink_first_table(&link_to_local);
           if ((duplicate= unique_table(thd, create_table, select_tables, 0)))
           {
             update_non_unique_table_error(create_table, "CREATE", duplicate);
@@ -2669,6 +2668,13 @@ mysql_execute_command(THD *thd)
         }
 
         /*
+          Remove target table from main select and name resolution
+          context. This can't be done earlier as it will break view merging in
+          statements like "CREATE TABLE IF NOT EXISTS existing_view SELECT".
+        */
+        lex->unlink_first_table(&link_to_local);
+
+        /*
           select_create is currently not re-execution friendly and
           needs to be created for every execution of a PS/SP.
         */
@@ -2687,33 +2693,32 @@ mysql_execute_command(THD *thd)
           res= handle_select(thd, lex, result, 0);
           delete result;
         }
+        
+        lex->link_first_table_back(create_table, link_to_local);
       }
-      else if (!(create_info.options & HA_LEX_CREATE_TMP_TABLE))
-        create_table= lex->unlink_first_table(&link_to_local);
-
     }
     else
     {
       /* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
       if (create_info.options & HA_LEX_CREATE_TMP_TABLE)
         thd->options|= OPTION_KEEP_LOG;
-      /* regular create */
       if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+      {
+        /* CREATE TABLE ... LIKE ... */
         res= mysql_create_like_table(thd, create_table, select_tables,
                                      &create_info);
+      }
       else
       {
-        res= mysql_create_table(thd, create_table->db,
-                                create_table->table_name, &create_info,
-                                &alter_info, 0, 0);
+        /* Regular CREATE TABLE */
+        res= mysql_create_table(thd, create_table,
+                                &create_info, &alter_info);
       }
       if (!res)
-	my_ok(thd);
+        my_ok(thd);
     }
 
-    /* put tables back for PS rexecuting */
 end_with_restore_list:
-    lex->link_first_table_back(create_table, link_to_local);
     break;
   }
   case SQLCOM_CREATE_INDEX:
@@ -2944,7 +2949,7 @@ end_with_restore_list:
         }
 
         /* Ignore temporary tables if this is "SHOW CREATE VIEW" */
-        first_table->skip_temporary= 1;
+        first_table->open_type= OT_BASE_ONLY;
 
       }
       else
@@ -7487,6 +7492,34 @@ bool insert_precheck(THD *thd, TABLE_LIS
 
 
 /**
+   Set proper open mode and table type for element representing target table
+   of CREATE TABLE statement, also adjust statement table list if necessary.
+*/
+
+void create_table_set_open_action_and_adjust_tables(LEX *lex)
+{
+  TABLE_LIST *create_table= lex->query_tables;
+
+  if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
+    create_table->open_type= OT_TEMPORARY_ONLY;
+  else if (!lex->select_lex.item_list.elements)
+    create_table->open_type= OT_BASE_ONLY;
+
+  if (!lex->select_lex.item_list.elements)
+  {
+    /*
+      Avoid opening and locking target table for ordinary CREATE TABLE
+      or CREATE TABLE LIKE for write (unlike in CREATE ... SELECT we
+      won't do any insertions in it anyway). Not doing this causes
+      problems when running CREATE TABLE IF NOT EXISTS for already
+      existing log table.
+    */
+    create_table->lock_type= TL_READ;
+  }
+}
+
+
+/**
   CREATE TABLE query pre-check.
 
   @param thd			Thread handler

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2009-08-05 12:22:27 +0000
+++ b/sql/sql_partition.cc	2009-08-24 09:56:29 +0000
@@ -3869,39 +3869,22 @@ bool mysql_unpack_partition(THD *thd,
              ha_resolve_storage_engine_name(default_db_type)));
   if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
   {
-    if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
-    {
-      /*
-        This code is executed when we create table in CREATE TABLE t1 LIKE t2.
-        old_lex->query_tables contains table list element for t2 and the table
-        we are opening has name t1.
-      */
-      if (partition_default_handling(table, part_info, FALSE,
-                                     old_lex->query_tables->table->s->path.str))
-      {
-        result= TRUE;
-        goto end;
-      }
-    }
-    else
-    {
-      /*
-        When we come here we are doing a create table. In this case we
-        have already done some preparatory work on the old part_info
-        object. We don't really need this new partition_info object.
-        Thus we go back to the old partition info object.
-        We need to free any memory objects allocated on item_free_list
-        by the parser since we are keeping the old info from the first
-        parser call in CREATE TABLE.
-        We'll ensure that this object isn't put into table cache also
-        just to ensure we don't get into strange situations with the
-        item objects.
-      */
-      thd->free_items();
-      part_info= thd->work_part_info;
-      table->s->version= 0UL;
-      *work_part_info_used= true;
-    }
+    /*
+      When we come here we are doing a create table. In this case we
+      have already done some preparatory work on the old part_info
+      object. We don't really need this new partition_info object.
+      Thus we go back to the old partition info object.
+      We need to free any memory objects allocated on item_free_list
+      by the parser since we are keeping the old info from the first
+      parser call in CREATE TABLE.
+      We'll ensure that this object isn't put into table cache also
+      just to ensure we don't get into strange situations with the
+      item objects.
+    */
+    thd->free_items();
+    part_info= thd->work_part_info;
+    table->s->version= 0UL;
+    *work_part_info_used= true;
   }
   table->part_info= part_info;
   part_info->table= table;

=== modified file 'sql/sql_prepare.cc'
--- a/sql/sql_prepare.cc	2009-08-19 10:39:26 +0000
+++ b/sql/sql_prepare.cc	2009-08-24 09:56:29 +0000
@@ -1660,39 +1660,35 @@ static bool mysql_test_create_table(Prep
   LEX *lex= stmt->lex;
   SELECT_LEX *select_lex= &lex->select_lex;
   bool res= FALSE;
-  /* Skip first table, which is the table we are creating */
   bool link_to_local;
-  TABLE_LIST *create_table= lex->unlink_first_table(&link_to_local);
-  TABLE_LIST *tables= lex->query_tables;
+  TABLE_LIST *create_table= lex->query_tables;
+  TABLE_LIST *tables= lex->create_last_non_select_table->next_global;
 
   if (create_table_precheck(thd, tables, create_table))
     DBUG_RETURN(TRUE);
 
+   /*
+     The open and lock strategies will be set again once the
+     statement is executed. These values are only meaningful
+     for the prepare phase.
+   */
+  create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
+  create_table->lock_strategy= TABLE_LIST::SHARED_MDL;
+
   if (select_lex->item_list.elements)
   {
-    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
-    {
-      lex->link_first_table_back(create_table, link_to_local);
-      /*
-        The open and lock strategies will be set again once the
-        statement is executed. These values are only meaningful
-        for the prepare phase.
-      */
-      create_table->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
-      create_table->lock_strategy= TABLE_LIST::SHARED_MDL;
-    }
-
     if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
       DBUG_RETURN(TRUE);
 
-    if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))
-      create_table= lex->unlink_first_table(&link_to_local);
-
     select_lex->context.resolve_in_select_list= TRUE;
 
+    lex->unlink_first_table(&link_to_local);
+
     res= select_like_stmt_test(stmt, 0, 0);
+
+    lex->link_first_table_back(create_table, &link_to_local);
   }
-  else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
+  else
   {
     /*
       Check that the source table exist, and also record
@@ -1704,8 +1700,6 @@ static bool mysql_test_create_table(Prep
       DBUG_RETURN(TRUE);
   }
 
-  /* put tables back for PS rexecuting */
-  lex->link_first_table_back(create_table, link_to_local);
   DBUG_RETURN(res);
 }
 

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2009-08-18 20:05:37 +0000
+++ b/sql/sql_table.cc	2009-08-24 09:56:29 +0000
@@ -4012,18 +4012,6 @@ bool mysql_create_table_no_lock(THD *thd
     thd->thread_specific_used= TRUE;
   }
 
-  /*
-    Don't write statement if:
-    - It is an internal temporary table,
-    - Row-based logging is used and it we are creating a temporary table, or
-    - The binary log is not open.
-    Otherwise, the statement shall be binlogged.
-   */
-  if (!internal_tmp_table &&
-      (!thd->current_stmt_binlog_row_based ||
-       (thd->current_stmt_binlog_row_based &&
-        !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
-    write_bin_log(thd, TRUE, thd->query, thd->query_length);
   error= FALSE;
 unlock_and_end:
   pthread_mutex_unlock(&LOCK_open);
@@ -4047,27 +4035,22 @@ warn:
   Database locking aware wrapper for mysql_create_table_no_lock(),
 */
 
-bool mysql_create_table(THD *thd, const char *db, const char *table_name,
+bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
                         HA_CREATE_INFO *create_info,
-                        Alter_info *alter_info,
-                        bool internal_tmp_table,
-                        uint select_field_count)
+                        Alter_info *alter_info)
 {
-  MDL_request target_mdl_request;
-  bool has_target_mdl_lock= FALSE;
   bool result;
   Ha_global_schema_lock_guard global_schema_lock_guard(thd);
   DBUG_ENTER("mysql_create_table");
 
-  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
-      !create_info->frm_only &&
-      !internal_tmp_table)
+  if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
     global_schema_lock_guard.lock();
 
   /* Wait for any database locks */
   pthread_mutex_lock(&LOCK_lock_db);
   while (!thd->killed &&
-         my_hash_search(&lock_db_cache,(uchar*) db, strlen(db)))
+         my_hash_search(&lock_db_cache, (uchar*)create_table->db,
+                        create_table->db_length))
   {
     wait_for_condition(thd, &LOCK_lock_db, &COND_refresh);
     pthread_mutex_lock(&LOCK_lock_db);
@@ -4081,45 +4064,47 @@ bool mysql_create_table(THD *thd, const 
   creating_table++;
   pthread_mutex_unlock(&LOCK_lock_db);
 
+  /*
+    Open or obtain an exclusive metadata lock on table being created.
+  */
+  if (open_and_lock_tables_derived(thd, thd->lex->query_tables, FALSE,
+                                   MYSQL_OPEN_TAKE_UPGRADABLE_MDL))
+  {
+    result= TRUE;
+    goto unlock;
+  }
+
+  /* Got lock. */
+  DEBUG_SYNC(thd, "locked_table_name");
+
+  result= mysql_create_table_no_lock(thd, create_table->db,
+                                     create_table->table_name, create_info,
+                                     alter_info, FALSE, 0);
+
+  /*
+    Don't write statement if:
+    - Table creation has failed
+    - Table has already existed
+    - Row-based logging is used and we are creating a temporary table
+    Otherwise, the statement shall be binlogged.
+  */
+  if (!result &&
+      !create_info->table_existed &&
+      (!thd->current_stmt_binlog_row_based ||
+       (thd->current_stmt_binlog_row_based &&
+        !(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
+    write_bin_log(thd, TRUE, thd->query, thd->query_length);
+
   if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
   {
-    target_mdl_request.init(0, db, table_name, MDL_EXCLUSIVE);
-    if (thd->mdl_context.try_acquire_exclusive_lock(&target_mdl_request))
-    {
-      result= TRUE;
-      goto unlock;
-    }
-    if (target_mdl_request.ticket == NULL)
-    {
-      /* Table exists and is locked by some other thread. */
-      if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
-      {
-        push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-                            ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
-                            table_name);
-        create_info->table_existed= 1;
-        result= FALSE;
-      }
-      else
-      {
-        my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name);
-        result= TRUE;
-      }
-      goto unlock;
-    }
-    /* Got lock. */
-    DEBUG_SYNC(thd, "locked_table_name");
-    has_target_mdl_lock= TRUE;
-  }
-  result= mysql_create_table_no_lock(thd, db, table_name, create_info,
-                                     alter_info,
-                                     internal_tmp_table,
-                                     select_field_count);
+    /*
+      close_thread_tables() takes care about both closing open tables (which
+      might be still around in case of error) and releasing metadata locks.
+    */
+    close_thread_tables(thd);
+  }
 
 unlock:
-  if (has_target_mdl_lock)
-    thd->mdl_context.release_lock(target_mdl_request.ticket);
-
   pthread_mutex_lock(&LOCK_lock_db);
   if (!--creating_table && creating_database)
     pthread_cond_signal(&COND_refresh);
@@ -5088,55 +5073,6 @@ bool mysql_preload_keys(THD* thd, TABLE_
 }
 
 
-
-/**
-  @brief          Create frm file based on I_S table
-
-  @param[in]      thd                      thread handler
-  @param[in]      schema_table             I_S table           
-  @param[in]      dst_path                 path where frm should be created
-  @param[in]      create_info              Create info
-
-  @return         Operation status
-    @retval       0                        success
-    @retval       1                        error
-*/
-
-
-bool mysql_create_like_schema_frm(THD* thd, TABLE_LIST* schema_table,
-                                  char *dst_path, HA_CREATE_INFO *create_info)
-{
-  HA_CREATE_INFO local_create_info;
-  Alter_info alter_info;
-  bool tmp_table= (create_info->options & HA_LEX_CREATE_TMP_TABLE);
-  uint keys= schema_table->table->s->keys;
-  uint db_options= 0;
-  DBUG_ENTER("mysql_create_like_schema_frm");
-
-  bzero((char*) &local_create_info, sizeof(local_create_info));
-  local_create_info.db_type= schema_table->table->s->db_type();
-  local_create_info.row_type= schema_table->table->s->row_type;
-  local_create_info.default_table_charset=default_charset_info;
-  alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE);
-  schema_table->table->use_all_columns();
-  if (mysql_prepare_alter_table(thd, schema_table->table,
-                                &local_create_info, &alter_info))
-    DBUG_RETURN(1);
-  if (mysql_prepare_create_table(thd, &local_create_info, &alter_info,
-                                 tmp_table, &db_options,
-                                 schema_table->table->file,
-                                 &schema_table->table->s->key_info, &keys, 0))
-    DBUG_RETURN(1);
-  local_create_info.max_rows= 0;
-  if (mysql_create_frm(thd, dst_path, NullS, NullS,
-                       &local_create_info, alter_info.create_list,
-                       keys, schema_table->table->s->key_info,
-                       schema_table->table->file))
-    DBUG_RETURN(1);
-  DBUG_RETURN(0);
-}
-
-
 /*
   Create a table identical to the specified table
 
@@ -5155,12 +5091,8 @@ bool mysql_create_like_schema_frm(THD* t
 bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
                              HA_CREATE_INFO *create_info)
 {
-  char src_path[FN_REFLEN + 1], dst_path[FN_REFLEN + 1];
-  uint dst_path_length;
-  bool has_mdl_lock= FALSE;
-  char *db= table->db;
-  char *table_name= table->table_name;
-  int  err;
+  HA_CREATE_INFO local_create_info;
+  Alter_info local_alter_info;
   bool res= TRUE;
   uint not_used;
 #ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -5169,133 +5101,67 @@ bool mysql_create_like_table(THD* thd, T
   Ha_global_schema_lock_guard global_schema_lock_guard(thd);
   DBUG_ENTER("mysql_create_like_table");
 
-
   if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
     global_schema_lock_guard.lock();
 
   /*
-    By opening source table and thus acquiring shared metadata lock on it
-    we guarantee that it exists and no concurrent DDL operation will mess
-    with it. Later we also take an exclusive metadata lock on target table
-    name, which makes copying of .frm file, call to ha_create_table() and
-    binlogging atomic against concurrent DML and DDL operations on target
-    table. Thus by holding both these "locks" we ensure that our statement
-    is properly isolated from all concurrent operations which matter.
+    We the open source table to get its description in HA_CREATE_INFO
+    and Alter_info objects. This also acquires a shared metadata lock
+    on this table which ensures that no concurrent DDL operation will
+    mess with it.
+    Also in case when we create non-temporary table open_tables()
+    call obtains an exclusive metadata lock on target table ensuring
+    that we can safely perform table creation.
+    Thus by holding both these locks we ensure that our statement is
+    properly isolated from all concurrent operations which matter.
   */
-  if (open_tables(thd, &src_table, &not_used, 0))
-    DBUG_RETURN(TRUE);
-
-  strxmov(src_path, src_table->table->s->path.str, reg_ext, NullS);
-
-  DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
-
-  /* 
-    Check that destination tables does not exist. Note that its name
-    was already checked when it was added to the table list.
-  */
-  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
-  {
-    if (find_temporary_table(thd, db, table_name))
-      goto table_exists;
-    dst_path_length= build_tmptable_filename(thd, dst_path, sizeof(dst_path));
-    create_info->table_options|= HA_CREATE_DELAY_KEY_WRITE;
-  }
-  else
-  {
-    table->mdl_request.init(0, db, table_name, MDL_EXCLUSIVE);
-    if (thd->mdl_context.try_acquire_exclusive_lock(&table->mdl_request))
-      DBUG_RETURN(TRUE);
-
-    if (table->mdl_request.ticket == NULL)
-      goto table_exists;
-
-    DEBUG_SYNC(thd, "locked_table_name");
-    has_mdl_lock= TRUE;
-
-    dst_path_length= build_table_filename(dst_path, sizeof(dst_path) - 1,
-                                          db, table_name, reg_ext, 0);
-    if (!access(dst_path, F_OK))
-      goto table_exists;
-  }
+  if (open_tables(thd, &thd->lex->query_tables, &not_used, 0))
+    goto err;
+  src_table->table->use_all_columns();
 
-  DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
+  /* Fill HA_CREATE_INFO and Alter_info with description of source table. */
+  bzero((char*) &local_create_info, sizeof(local_create_info));
+  local_create_info.db_type= src_table->table->s->db_type();
+  local_create_info.row_type= src_table->table->s->row_type;
+  if (mysql_prepare_alter_table(thd, src_table->table, &local_create_info,
+                                &local_alter_info))
+    goto err;
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+  /* Partition info is not handled by mysql_prepare_alter_table() call. */
+  if (src_table->table->part_info)
+    thd->work_part_info= src_table->table->part_info->get_clone();
+#endif
 
   /*
-    Create a new table by copying from source table
+    Adjust description of source table before using it for creation of
+    target table.
 
-    TODO: Obtaining LOCK_open mutex here is actually a legacy from the
-          times when some operations (e.g. I_S implementation) ignored
-          exclusive metadata lock on target table. Also some engines
-          (e.g. NDB cluster) require that LOCK_open should be held
-          during the call to ha_create_table() (See bug #28614 for more
-          info). So we should double check and probably fix this code
-          to not acquire this mutex.
+    Similarly to SHOW CREATE TABLE we ignore MAX_ROWS attribute of
+    temporary table which represents I_S table.
   */
-  pthread_mutex_lock(&LOCK_open);
   if (src_table->schema_table)
-  {
-    if (mysql_create_like_schema_frm(thd, src_table, dst_path, create_info))
-    {
-      pthread_mutex_unlock(&LOCK_open);
-      goto err;
-    }
-  }
-  else if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
-  {
-    if (my_errno == ENOENT)
-      my_error(ER_BAD_DB_ERROR,MYF(0),db);
-    else
-      my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
-    pthread_mutex_unlock(&LOCK_open);
+    local_create_info.max_rows= 0;
+  /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
+  local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS;
+  /* Replace type of source table with one specified in the statement. */
+  local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
+  local_create_info.options|= create_info->options & HA_LEX_CREATE_TMP_TABLE;
+  /* Reset auto-increment counter for the new table. */
+  local_create_info.auto_increment_value= 0;
+
+  if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
+                                       &local_create_info, &local_alter_info,
+                                       FALSE, 0)) ||
+      local_create_info.table_existed)
     goto err;
-  }
 
   /*
-    As mysql_truncate don't work on a new table at this stage of
-    creation, instead create the table directly (for both normal
-    and temporary tables).
+    Ensure that we have an exclusive lock on target table if we are creating
+    non-temporary table.
   */
-#ifdef WITH_PARTITION_STORAGE_ENGINE
-  /*
-    For partitioned tables we need to copy the .par file as well since
-    it is used in open_table_def to even be able to create a new handler.
-    There is no way to find out here if the original table is a
-    partitioned table so we copy the file and ignore any errors.
-  */
-  fn_format(tmp_path, dst_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
-  strmov(dst_path, tmp_path);
-  fn_format(tmp_path, src_path, reg_ext, ".par", MYF(MY_REPLACE_EXT));
-  strmov(src_path, tmp_path);
-  my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE));
-#endif
-
-  DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
-
-  dst_path[dst_path_length - reg_ext_length]= '\0';  // Remove .frm
-  if (thd->variables.keep_files_on_create)
-    create_info->options|= HA_CREATE_KEEP_FILES;
-  err= ha_create_table(thd, dst_path, db, table_name, create_info, 1);
-  pthread_mutex_unlock(&LOCK_open);
-
-  if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
-  {
-    if (err || !open_temporary_table(thd, dst_path, db, table_name, 1,
-                                     OTM_OPEN))
-    {
-      (void) rm_temporary_table(create_info->db_type,
-				dst_path, false); /* purecov: inspected */
-      goto err;     /* purecov: inspected */
-    }
-    thd->thread_specific_used= TRUE;
-  }
-  else if (err)
-  {
-    (void) quick_rm_table(create_info->db_type, db,
-			  table_name, 0); /* purecov: inspected */
-    goto err;	    /* purecov: inspected */
-  }
-
-  DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000););
+  DBUG_ASSERT((create_info->options & HA_LEX_CREATE_TMP_TABLE) ||
+              thd->mdl_context.is_exclusive_lock_owner(0, table->db,
+                                                       table->table_name));
 
   /*
     We have to write the query before we unlock the tables.
@@ -5362,26 +5228,7 @@ bool mysql_create_like_table(THD* thd, T
   else
     write_bin_log(thd, TRUE, thd->query, thd->query_length);
 
-  res= FALSE;
-  goto err;
-
-table_exists:
-  if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
-  {
-    char warn_buff[MYSQL_ERRMSG_SIZE];
-    my_snprintf(warn_buff, sizeof(warn_buff),
-		ER(ER_TABLE_EXISTS_ERROR), table_name);
-    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-		 ER_TABLE_EXISTS_ERROR,warn_buff);
-    res= FALSE;
-  }
-  else
-    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
-
 err:
-  if (has_mdl_lock)
-    thd->mdl_context.release_lock(table->mdl_request.ticket);
-
   DBUG_RETURN(res);
 }
 
@@ -7103,7 +6950,7 @@ view_err:
       else
       {
         target_mdl_request.init(0, new_db, new_name, MDL_EXCLUSIVE);
-        if (thd->mdl_context.try_acquire_exclusive_lock(&target_mdl_request))
+        if (thd->mdl_context.try_acquire_exclusive_lock(&target_mdl_request)) // JOH: HER
           DBUG_RETURN(TRUE);
         if (target_mdl_request.ticket == NULL)
         {

=== modified file 'sql/sql_trigger.cc'
--- a/sql/sql_trigger.cc	2009-08-19 14:12:27 +0000
+++ b/sql/sql_trigger.cc	2009-08-24 09:56:29 +0000
@@ -447,7 +447,7 @@ bool mysql_create_or_drop_trigger(THD *t
     Also prevent DROP TRIGGER from opening temporary table which might
     shadow base table on which trigger to be dropped is defined.
   */
-  tables->skip_temporary= TRUE;
+  tables->open_type= OT_BASE_ONLY;
 
   /* Keep consistent with respect to other DDL statements */
   mysql_ha_rm_tables(thd, tables);

=== modified file 'sql/sql_view.cc'
--- a/sql/sql_view.cc	2009-06-19 09:28:44 +0000
+++ b/sql/sql_view.cc	2009-08-24 09:56:29 +0000
@@ -1260,7 +1260,7 @@ bool mysql_make_view(THD *thd, File_pars
          tbl;
          tbl= (view_tables_tail= tbl)->next_global)
     {
-      tbl->skip_temporary= 1;
+      tbl->open_type= OT_BASE_ONLY;
       tbl->belong_to_view= top_view;
       tbl->referencing_view= table;
       tbl->prelocking_placeholder= table->prelocking_placeholder;

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2009-08-18 20:05:37 +0000
+++ b/sql/sql_yacc.yy	2009-08-24 09:56:29 +0000
@@ -1911,6 +1911,7 @@ create:
                                   hton_name(lex->create_info.db_type)->str,
                                   $5->table.str);
             }
+            create_table_set_open_action_and_adjust_tables(lex);
           }
         | CREATE build_method opt_unique_or_fulltext INDEX_SYM ident key_alg 
           ON table_ident
@@ -4037,7 +4038,7 @@ size_number:
 create2:
           '(' create2a {}
         | opt_create_table_options
-          opt_partitioning
+          opt_create_partitioning
           create3 {}
         | LIKE table_ident
           {
@@ -4071,9 +4072,9 @@ create2:
 
 create2a:
           create_field_list ')' opt_create_table_options
-          opt_partitioning
+          opt_create_partitioning
           create3 {}
-        |  opt_partitioning
+        |  opt_create_partitioning
            create_select ')'
            { Select->set_braces(1);}
            union_opt {}
@@ -4089,6 +4090,19 @@ create3:
           union_opt {}
         ;
 
+opt_create_partitioning:
+          opt_partitioning
+          {
+            /*
+              Remove all tables used in PARTITION clause from the global table
+              list. Partitioning with subqueries is not allowed anyway.
+            */
+            TABLE_LIST *last_non_sel_table= Lex->create_last_non_select_table;
+            last_non_sel_table->next_global= 0;
+            Lex->query_tables_last= &last_non_sel_table->next_global;
+          }
+        ;
+
 /*
  This part of the parser is about handling of the partition information.
 

=== modified file 'sql/table.h'
--- a/sql/table.h	2009-08-13 16:13:55 +0000
+++ b/sql/table.h	2009-08-24 09:56:29 +0000
@@ -1007,6 +1007,16 @@ public:
 };
 
 
+/**
+   Type of table which can be open for an element of table list.
+*/
+
+enum enum_open_type
+{
+  OT_TEMPORARY_OR_BASE= 0, OT_TEMPORARY_ONLY, OT_BASE_ONLY
+};
+
+
 class SJ_MATERIALIZATION_INFO;
 class Index_hint;
 class Item_in_subselect;
@@ -1287,7 +1297,11 @@ struct TABLE_LIST
   bool		cacheable_table;	/* stop PS caching */
   /* used in multi-upd/views privilege check */
   bool		table_in_first_from_clause;
-  bool		skip_temporary;		/* this table shouldn't be temporary */
+  /**
+     Specifies which kind of table should be open for this element
+     of table list.
+  */
+  enum enum_open_type open_type;
   /* TRUE if this merged view contain auto_increment field */
   bool          contain_auto_increment;
   bool          multitable_view;        /* TRUE iff this is multitable view */


Attachment: [text/bzr-bundle] bzr/alik@sun.com-20090824175401-h7iew561rp9a3h1e.bundle
Thread
bzr commit into mysql-5.4 branch (alik:2875)Alexander Nozdrin24 Aug