List:Commits« Previous MessageNext Message »
From:Mattias Jonsson Date:June 3 2010 9:02pm
Subject:bzr push into mysql-next-mr branch (mattias.jonsson:3151 to 3152)
WL#4445
View as plain text  
 3152 Mattias Jonsson	2010-06-03
      WL#4445: EXCHANGE PARTITION WITH TABLE
      
      Changes according to Davi's review.
      (not including object orienting alter table command).
     @ mysql-test/r/partition_error.result
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        updated result
     @ mysql-test/r/partition_exchange.result
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        updated result
     @ mysql-test/r/partition_symlink.result
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        updated result
     @ mysql-test/suite/parts/inc/partition_crash.inc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        cleaned up test
     @ mysql-test/t/partition_error.test
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added test.
     @ mysql-test/t/partition_exchange.test
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added test.
     @ mysql-test/t/partition_symlink.test
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added test.
     @ sql/ha_partition.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        changed to more strict type.
     @ sql/handler.h
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Removed duplicate define (original is in sql_partition.h)
     @ sql/opt_range.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added comment about include file.
     @ sql/partition_info.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added comment about include file.
     @ sql/sql_partition.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Fixed wrong error message.
        Added result value to function header.
        compacted compare_partition_options function.
     @ sql/sql_partition.h
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Reused constant definition.
     @ sql/sql_table.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Updated according to reviewers comments.
     @ sql/sql_table.h
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added enum for EXCHANGE PARTITION phases.

    modified:
      mysql-test/r/partition_error.result
      mysql-test/r/partition_exchange.result
      mysql-test/r/partition_symlink.result
      mysql-test/suite/parts/inc/partition_crash.inc
      mysql-test/t/partition_error.test
      mysql-test/t/partition_exchange.test
      mysql-test/t/partition_symlink.test
      sql/ha_partition.cc
      sql/handler.h
      sql/opt_range.cc
      sql/partition_info.cc
      sql/sql_partition.cc
      sql/sql_partition.h
      sql/sql_table.cc
      sql/sql_table.h
 3151 Mattias Jonsson	2010-05-28
      WL#4445: EXCHANGE PARTITION WITH TABLE
      
      (Minor fix)
      
      updated error message which included table_name
      
      Failed on windows 64 bit.
     @ mysql-test/r/partition_exchange.result
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        updated results
     @ mysql-test/t/partition_exchange.test
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Added test for EXCHANGING PARTITION with an already
        partitioned table.
        
        changed case of sql commands
     @ sql/sql_table.cc
        WL#4445: EXCHANGE PARTITION WITH TABLE
        
        Using the correct string for the error message.

    modified:
      mysql-test/r/partition_exchange.result
      mysql-test/t/partition_exchange.test
      sql/sql_table.cc
=== modified file 'mysql-test/r/partition_error.result'
--- a/mysql-test/r/partition_error.result	2010-03-20 20:23:42 +0000
+++ b/mysql-test/r/partition_error.result	2010-06-03 21:00:55 +0000
@@ -132,6 +132,19 @@ a int not null,
 b int not null,
 c int not null,
 primary key(a,b))
+partition by range columns (a,d)
+(partition x1 VALUES LESS THAN (1,1),
+partition x2 VALUES LESS THAN (2,2),
+partition x3 VALUES LESS THAN (3,3));
+ERROR HY000: Field in list of fields for partition function not found in table
+select load_file('$MYSQLD_DATADIR/test/t1.par');
+load_file('$MYSQLD_DATADIR/test/t1.par')
+NULL
+CREATE TABLE t1 (
+a int not null,
+b int not null,
+c int not null,
+primary key(a,b))
 partition by key (a,d)
 partitions 3
 (partition x1 tablespace ts1,

=== modified file 'mysql-test/r/partition_exchange.result'
--- a/mysql-test/r/partition_exchange.result	2010-05-28 15:53:05 +0000
+++ b/mysql-test/r/partition_exchange.result	2010-06-03 21:00:55 +0000
@@ -556,6 +556,36 @@ ALTER TABLE t CHARACTER SET = koi8r COLL
 ALTER TABLE tp EXCHANGE PARTITION p0 WITH TABLE t IGNORE;
 ERROR HY000: Non matching attribute 'CHARACTER SET' between partition and table
 DROP TABLE t;
+# Test multiple different table options
+CREATE TABLE t (a INT,
+b VARCHAR(55),
+PRIMARY KEY (a))
+ENGINE = MyISAM MAX_ROWS = 100000 MIN_ROWS = 1000;
+INSERT INTO t SELECT * FROM tmp2;
+SHOW CREATE TABLE t;
+Table	Create Table
+t	CREATE TABLE `t` (
+  `a` int(11) NOT NULL DEFAULT '0',
+  `b` varchar(55) DEFAULT NULL,
+  PRIMARY KEY (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 MIN_ROWS=1000 MAX_ROWS=100000
+SHOW CREATE TABLE tp;
+Table	Create Table
+tp	CREATE TABLE `tp` (
+  `a` int(11) NOT NULL DEFAULT '0',
+  `b` varchar(55) DEFAULT NULL,
+  PRIMARY KEY (`a`)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY RANGE (a)
+(PARTITION p0 VALUES LESS THAN (100) ENGINE = MyISAM,
+ PARTITION p1 VALUES LESS THAN MAXVALUE ENGINE = MyISAM) */
+ALTER TABLE tp EXCHANGE PARTITION p0 WITH TABLE t IGNORE;
+ERROR HY000: Non matching attribute 'MAX_ROWS' between partition and table
+SHOW WARNINGS;
+Level	Code	Message
+Error	1696	Non matching attribute 'MAX_ROWS' between partition and table
+Error	1696	Non matching attribute 'MIN_ROWS' between partition and table
+DROP TABLE t;
 RENAME TABLE tmp2 TO t;
 ALTER TABLE t ADD KEY ba_key (b, a);
 ALTER TABLE tp ADD KEY ba_key (b, a);

=== modified file 'mysql-test/r/partition_symlink.result'
--- a/mysql-test/r/partition_symlink.result	2009-10-21 11:59:11 +0000
+++ b/mysql-test/r/partition_symlink.result	2010-06-03 21:00:55 +0000
@@ -1,5 +1,42 @@
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
 DROP DATABASE IF EXISTS mysqltest2;
+#
+# Test for WL#4445: EXCHANGE PARTITION
+#
+CREATE TABLE t1 (a INT)
+PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN (0)
+DATA DIRECTORY 'MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY 'MYSQLTEST_VARDIR/tmp',
+PARTITION p1 VALUES IN (1)
+DATA DIRECTORY 'MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY 'MYSQLTEST_VARDIR/tmp',
+PARTITION p2 VALUES IN (2));
+CREATE TABLE t2 (a INT)
+DATA DIRECTORY 'MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY 'MYSQLTEST_VARDIR/tmp';
+SHOW CREATE TABLE t1;
+Table	Create Table
+t1	CREATE TABLE `t1` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1
+/*!50100 PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN (0) DATA DIRECTORY = 'MYSQLTEST_VARDIR/tmp' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/tmp' ENGINE = MyISAM,
+ PARTITION p1 VALUES IN (1) DATA DIRECTORY = 'MYSQLTEST_VARDIR/tmp' INDEX DIRECTORY = 'MYSQLTEST_VARDIR/tmp' ENGINE = MyISAM,
+ PARTITION p2 VALUES IN (2) ENGINE = MyISAM) */
+SHOW CREATE TABLE t2;
+Table	Create Table
+t2	CREATE TABLE `t2` (
+  `a` int(11) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 DATA DIRECTORY='MYSQLTEST_VARDIR/tmp/' INDEX DIRECTORY='MYSQLTEST_VARDIR/tmp/'
+INSERT INTO t1 VALUES (0), (1), (2);
+ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2;
+ERROR HY000: Tables have different definitions
+ALTER TABLE t1 EXCHANGE PARTITION p2 WITH TABLE t2;
+ERROR HY000: Tables have different definitions
+SELECT * FROM t2;
+a
+DROP TABLE t1, t2;
 # Creating two non colliding tables mysqltest2.t1 and test.t1
 # test.t1 have partitions in mysqltest2-directory!
 # user root:

=== modified file 'mysql-test/suite/parts/inc/partition_crash.inc'
--- a/mysql-test/suite/parts/inc/partition_crash.inc	2010-05-18 20:40:51 +0000
+++ b/mysql-test/suite/parts/inc/partition_crash.inc	2010-06-03 21:00:55 +0000
@@ -10,6 +10,7 @@ SELECT * FROM t1;
 --write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
 wait
 EOF
+# CR_SERVER_LOST
 --error 2013
 --eval $crash_statement
 --echo # State after crash (before recovery)
@@ -29,11 +30,6 @@ open(FH, ">", $ENV{'EXPECT_FILE'}) or di
 print FH "restart";
 close(FH);
 EOF
-#--remove_file $MYSQLTEST_VARDIR/tmp/ls_of_crash.txt
-#--remove_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-#--write_file $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-#restart
-#EOF
 --enable_reconnect
 --source include/wait_until_connected_again.inc
 --echo # State after crash recovery

=== modified file 'mysql-test/t/partition_error.test'
--- a/mysql-test/t/partition_error.test	2010-03-20 20:23:42 +0000
+++ b/mysql-test/t/partition_error.test	2010-06-03 21:00:55 +0000
@@ -144,6 +144,23 @@ partitions 3
  partition x3 tablespace ts3);
 
 #
+# Partition by range columns, invalid field in field list
+#
+--error ER_FIELD_NOT_FOUND_PART_ERROR
+CREATE TABLE t1 (
+a int not null,
+b int not null,
+c int not null,
+primary key(a,b))
+partition by range columns (a,d)
+(partition x1 VALUES LESS THAN (1,1),
+ partition x2 VALUES LESS THAN (2,2),
+ partition x3 VALUES LESS THAN (3,3));
+
+let $MYSQLD_DATADIR= `select @@datadir`;
+select load_file('$MYSQLD_DATADIR/test/t1.par');
+
+#
 # Partition by key, invalid field in field list
 #
 --error ER_FIELD_NOT_FOUND_PART_ERROR

=== modified file 'mysql-test/t/partition_exchange.test'
--- a/mysql-test/t/partition_exchange.test	2010-05-28 15:53:05 +0000
+++ b/mysql-test/t/partition_exchange.test	2010-06-03 21:00:55 +0000
@@ -152,6 +152,18 @@ ALTER TABLE t CHARACTER SET = koi8r COLL
 --error ER_PARTITION_EXCHANGE_DIFFERENT_OPTION
 ALTER TABLE tp EXCHANGE PARTITION p0 WITH TABLE t IGNORE;
 DROP TABLE t;
+--echo # Test multiple different table options
+CREATE TABLE t (a INT,
+  b VARCHAR(55),
+  PRIMARY KEY (a))
+ENGINE = MyISAM MAX_ROWS = 100000 MIN_ROWS = 1000;
+INSERT INTO t SELECT * FROM tmp2;
+SHOW CREATE TABLE t;
+SHOW CREATE TABLE tp;
+--error ER_PARTITION_EXCHANGE_DIFFERENT_OPTION
+ALTER TABLE tp EXCHANGE PARTITION p0 WITH TABLE t IGNORE;
+SHOW WARNINGS;
+DROP TABLE t;
 RENAME TABLE tmp2 TO t;
 # test different keys
 ALTER TABLE t ADD KEY ba_key (b, a);

=== modified file 'mysql-test/t/partition_symlink.test'
--- a/mysql-test/t/partition_symlink.test	2008-09-06 00:51:17 +0000
+++ b/mysql-test/t/partition_symlink.test	2010-06-03 21:00:55 +0000
@@ -7,10 +7,50 @@
 # as in --skip-symbolic-links
 -- source include/not_windows.inc
 -- disable_warnings
-DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t1, t2;
 DROP DATABASE IF EXISTS mysqltest2;
 -- enable_warnings
 
+--echo #
+--echo # Test for WL#4445: EXCHANGE PARTITION
+--echo #
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval CREATE TABLE t1 (a INT)
+PARTITION BY LIST (a)
+(PARTITION p0 VALUES IN (0)
+  DATA DIRECTORY '$MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY '$MYSQLTEST_VARDIR/tmp',
+ PARTITION p1 VALUES IN (1)
+  DATA DIRECTORY '$MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY '$MYSQLTEST_VARDIR/tmp',
+ PARTITION p2 VALUES IN (2));
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval CREATE TABLE t2 (a INT)
+  DATA DIRECTORY '$MYSQLTEST_VARDIR/tmp'
+  INDEX DIRECTORY '$MYSQLTEST_VARDIR/tmp';
+
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+SHOW CREATE TABLE t1;
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+SHOW CREATE TABLE t2;
+INSERT INTO t1 VALUES (0), (1), (2);
+--error ER_TABLES_DIFFERENT_METADATA
+ALTER TABLE t1 EXCHANGE PARTITION p0 WITH TABLE t2;
+--error ER_TABLES_DIFFERENT_METADATA
+ALTER TABLE t1 EXCHANGE PARTITION p2 WITH TABLE t2;
+--sorted_result
+SELECT * FROM t2;
+DROP TABLE t1, t2;
+# skipped because of bug#52354
+#CREATE TABLE t1 LIKE t2;
+#ALTER TABLE t1 PARTITION BY LIST (a)
+#(PARTITION p0 VALUES in (0));
+#--error ER_TABLES_DIFFERENT_METADATA
+#ALTER TABLE t1 EXCHANGE PARTITION p2 WITH TABLE t2;
+#SELECT * FROM t2;
+#DROP TABLE t1, t2;
+ 
 #
 # Bug 32091: Security breach via directory changes
 #

=== modified file 'sql/ha_partition.cc'
--- a/sql/ha_partition.cc	2010-04-13 00:07:15 +0000
+++ b/sql/ha_partition.cc	2010-06-03 21:00:55 +0000
@@ -147,7 +147,7 @@ static uint alter_table_flags(uint flags
           HA_FAST_CHANGE_PARTITION);
 }
 
-const uint ha_partition::NO_CURRENT_PART_ID= NOT_A_PARTITION_ID;
+const uint32 ha_partition::NO_CURRENT_PART_ID= NOT_A_PARTITION_ID;
 
 /*
   Constructor method

=== modified file 'sql/handler.h'
--- a/sql/handler.h	2010-03-31 14:05:33 +0000
+++ b/sql/handler.h	2010-06-03 21:00:55 +0000
@@ -970,7 +970,6 @@ struct st_table_log_memory_entry;
 class partition_info;
 
 struct st_partition_iter;
-#define NOT_A_PARTITION_ID ((uint32)-1)
 
 enum enum_ha_unused { HA_CHOICE_UNDEF, HA_CHOICE_NO, HA_CHOICE_YES };
 

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2010-03-31 14:05:33 +0000
+++ b/sql/opt_range.cc	2010-06-03 21:00:55 +0000
@@ -69,7 +69,7 @@
 #include "key.h"        // is_key_used, key_copy, key_cmp, key_restore
 #include "sql_parse.h"                          // check_stack_overrun
 #include "sql_partition.h"    // get_part_id_func, PARTITION_ITERATOR,
-                              // struct partition_info
+                              // struct partition_info, NOT_A_PARTITION_ID
 #include "sql_base.h"         // free_io_cache
 #include "records.h"          // init_read_record, end_read_record
 #include <m_ctype.h>

=== modified file 'sql/partition_info.cc'
--- a/sql/partition_info.cc	2010-04-13 00:07:15 +0000
+++ b/sql/partition_info.cc	2010-06-03 21:00:55 +0000
@@ -22,7 +22,8 @@
 #include "sql_priv.h"
 // Required to get server definitions for mysql/plugin.h right
 #include "sql_plugin.h"
-#include "sql_partition.h"     /* partition_info.h: LIST_PART_ENTRY */
+#include "sql_partition.h"                 // partition_info.h: LIST_PART_ENTRY
+                                           // NOT_A_PARTITION_ID
 #include "partition_info.h"
 #include "sql_parse.h"                        // test_if_data_home_dir
 #include "sql_acl.h"                          // *_ACL

=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc	2010-05-20 12:43:20 +0000
+++ b/sql/sql_partition.cc	2010-06-03 21:00:55 +0000
@@ -572,8 +572,13 @@ static bool set_up_field_array(TABLE *ta
           } while (++inx < num_fields);
           if (inx == num_fields)
           {
-            /* TODO: Set to correct error message! */
-            mem_alloc_error(1);
+            /*
+              Should not occur since it should already been checked in either
+              add_column_list_values, handle_list_of_fields,
+              check_partition_info etc.
+            */
+            DBUG_ASSERT(0);
+            my_error(ER_FIELD_NOT_FOUND_PART_ERROR, MYF(0));
             result= TRUE;
             continue;
           }
@@ -3900,6 +3905,10 @@ void get_full_part_id_from_key(const TAB
                     it is matching the partition definition.
   @param part_table Partitioned table containing the partition to check.
   @param part_id    Which partition to match with.
+
+  @return Operation status
+    @retval TRUE                Not all rows match the given partition
+    @retval FALSE               OK
 */
 bool verify_data_with_partition(TABLE *table, TABLE *part_table,
                                 uint32 part_id)
@@ -3911,8 +3920,8 @@ bool verify_data_with_partition(TABLE *t
   uchar *old_rec;
   partition_info *part_info;
   DBUG_ENTER("verify_data_with_partition");
-  DBUG_ASSERT (table && table->file && part_table && part_table->part_info &&
-               part_table->file);
+  DBUG_ASSERT(table && table->file && part_table && part_table->part_info &&
+              part_table->file);
 
   /*
     Verify all table rows.
@@ -4618,7 +4627,9 @@ uint set_part_state(Alter_info *alter_in
 bool compare_partition_options(HA_CREATE_INFO *table_create_info,
                                partition_element *part_elem)
 {
-  bool error= FALSE;
+#define MAX_COMPARE_PARTITION_OPTION_ERRORS 5
+  const char *option_diffs[MAX_COMPARE_PARTITION_OPTION_ERRORS + 1];
+  int i, errors= 0;
   DBUG_ENTER("compare_partition_options");
   DBUG_ASSERT(!part_elem->tablespace_name &&
               !table_create_info->tablespace);
@@ -4628,37 +4639,20 @@ bool compare_partition_options(HA_CREATE
     with partitioning. TODO: when there are, add compare.
   */
   if (part_elem->tablespace_name || table_create_info->tablespace)
-  {
-    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
-             "TABLESPACE");
-    error= TRUE;
-  }
+    option_diffs[errors++]= "TABLESPACE";
   if (part_elem->part_max_rows != table_create_info->max_rows)
-  {
-    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
-             "MAX_ROWS");
-    error= TRUE;
-  }
+    option_diffs[errors++]= "MAX_ROWS";
   if (part_elem->part_min_rows != table_create_info->min_rows)
-  {
-    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
-             "MIN_ROWS");
-    error= TRUE;
-  }
+    option_diffs[errors++]= "MIN_ROWS";
   if (part_elem->data_file_name || table_create_info->data_file_name)
-  {
-    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
-             "DATA DIRECTORY");
-    error= TRUE;
-  }
+    option_diffs[errors++]= "DATA DIRECTORY";
   if (part_elem->index_file_name || table_create_info->index_file_name)
-  {
-    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
-             "INDEX DIRECTORY");
-    error= TRUE;
-  }
+    option_diffs[errors++]= "INDEX DIRECTORY";
 
-  DBUG_RETURN(error);
+  for (i= 0; i < errors; i++)
+    my_error(ER_PARTITION_EXCHANGE_DIFFERENT_OPTION, MYF(0),
+             option_diffs[i]);
+  DBUG_RETURN(errors != 0);
 }
 
 

=== modified file 'sql/sql_partition.h'
--- a/sql/sql_partition.h	2010-04-13 00:07:15 +0000
+++ b/sql/sql_partition.h	2010-06-03 21:00:55 +0000
@@ -76,7 +76,7 @@ typedef struct {
 } part_id_range;
 
 struct st_partition_iter;
-#define NOT_A_PARTITION_ID ((uint32)-1)
+#define NOT_A_PARTITION_ID UINT_MAX32
 
 bool is_partition_in_list(char *part_name, List<char> list_part_names);
 char *are_partitions_in_table(partition_info *new_part_info,

=== modified file 'sql/sql_table.cc'
--- a/sql/sql_table.cc	2010-05-28 15:53:05 +0000
+++ b/sql/sql_table.cc	2010-06-03 21:00:55 +0000
@@ -32,6 +32,7 @@
 #include "sql_partition.h"                      // mem_alloc_error,
                                                 // generate_partition_syntax,
                                                 // partition_info
+                                                // NOT_A_PARTITION_ID
 #include "sql_db.h" // load_db_opt_by_name, lock_db_cache, creating_database
 #include "sql_time.h"                  // make_truncated_value_warning
 #include "records.h"             // init_read_record, end_read_record
@@ -612,11 +613,9 @@ uint build_tmptable_filename(THD* thd, c
 
    History:
    First version written in 2006 by Mikael Ronstrom
-   Updated 2010 by Mattias Jonsson, added EXCHANGE action + refactoring
 --------------------------------------------------------------------------
 */
 
-
 struct st_global_ddl_log
 {
   /*
@@ -694,11 +693,11 @@ static bool write_ddl_log_file_entry(uin
 {
   bool error= FALSE;
   File file_id= global_ddl_log.file_id;
-  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
+  uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
   DBUG_ENTER("write_ddl_log_file_entry");
 
   mysql_mutex_assert_owner(&LOCK_gdl);
-  if (mysql_file_pwrite(file_id, (uchar*)file_entry_buf,
+  if (mysql_file_pwrite(file_id, file_entry_buf,
                         IO_SIZE, IO_SIZE * entry_no, MYF(MY_WME)) != IO_SIZE)
     error= TRUE;
   DBUG_RETURN(error);
@@ -715,15 +714,8 @@ static bool write_ddl_log_file_entry(uin
 
 static bool sync_ddl_log_file()
 {
-  bool error= FALSE;
   DBUG_ENTER("sync_ddl_log_file");
-  if (mysql_file_sync(global_ddl_log.file_id, MYF(0)))
-  {
-    /* Write to error log */
-    sql_print_error("Failed to sync ddl log file");
-    error= TRUE;
-  }
-  DBUG_RETURN(error);
+  DBUG_RETURN(mysql_file_sync(global_ddl_log.file_id, MYF(MY_WME)));
 }
 
 
@@ -738,7 +730,6 @@ static bool sync_ddl_log_file()
 static bool write_ddl_log_header()
 {
   uint16 const_var;
-  bool error= FALSE;
   DBUG_ENTER("write_ddl_log_header");
 
   int4store(&global_ddl_log.file_entry_buf[DDL_LOG_NUM_ENTRY_POS],
@@ -754,8 +745,7 @@ static bool write_ddl_log_header()
     sql_print_error("Error writing ddl log header");
     DBUG_RETURN(TRUE);
   }
-  (void) sync_ddl_log_file();
-  DBUG_RETURN(error);
+  DBUG_RETURN(sync_ddl_log_file());
 }
 
 
@@ -782,13 +772,13 @@ static inline void create_ddl_log_file_n
 
 static uint read_ddl_log_header()
 {
-  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
+  uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
   char file_name[FN_REFLEN];
   uint entry_no;
   bool successful_open= FALSE;
   DBUG_ENTER("read_ddl_log_header");
 
-  mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_FAST);
+  mysql_mutex_init(key_LOCK_gdl, &LOCK_gdl, MY_MUTEX_INIT_SLOW);
   mysql_mutex_lock(&LOCK_gdl);
   create_ddl_log_file_name(file_name);
   if ((global_ddl_log.file_id= mysql_file_open(key_file_global_ddl_log,
@@ -871,12 +861,15 @@ static void set_global_from_ddl_log_entr
   Convert from file_entry_buf binary blob to ddl_log_entry struct.
 
   @param[out] ddl_log_entry   struct to fill in.
+
+  @note Strings (names) are pointing to the global_ddl_log structure,
+  so LOCK_gdl needs to be hold until they are read or copied.
 */
 
 static void set_ddl_log_entry_from_global(DDL_LOG_ENTRY *ddl_log_entry,
                                           const uint read_entry)
 {
-  char *file_entry_buf= (char*)&global_ddl_log.file_entry_buf;
+  char *file_entry_buf= (char*) global_ddl_log.file_entry_buf;
   uint inx;
   uchar single_char;
 
@@ -981,7 +974,6 @@ end:
 
 static bool sync_ddl_log_no_lock()
 {
-  bool error= FALSE;
   DBUG_ENTER("sync_ddl_log_no_lock");
 
   mysql_mutex_assert_owner(&LOCK_gdl);
@@ -1023,7 +1015,7 @@ static bool sync_ddl_log_no_lock()
 
 static bool deactivate_ddl_log_entry_no_lock(uint entry_no)
 {
-  char *file_entry_buf= (char*)global_ddl_log.file_entry_buf;
+  uchar *file_entry_buf= (uchar*)global_ddl_log.file_entry_buf;
   DBUG_ENTER("deactivate_ddl_log_entry_no_lock");
 
   mysql_mutex_assert_owner(&LOCK_gdl);
@@ -1031,12 +1023,16 @@ static bool deactivate_ddl_log_entry_no_
   {
     if (file_entry_buf[DDL_LOG_ENTRY_TYPE_POS] == DDL_LOG_ENTRY_CODE)
     {
+      /*
+        Log entry, if complete mark it done (IGNORE).
+        Otherwise increase the phase by one.
+      */
       if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_DELETE_ACTION ||
           file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_RENAME_ACTION ||
           (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION &&
            file_entry_buf[DDL_LOG_PHASE_POS] == 1) ||
           (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION &&
-           file_entry_buf[DDL_LOG_PHASE_POS] > 1))
+           file_entry_buf[DDL_LOG_PHASE_POS] >= EXCH_PHASE_TEMP_TO_FROM))
         file_entry_buf[DDL_LOG_ENTRY_TYPE_POS]= DDL_IGNORE_LOG_ENTRY_CODE;
       else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_REPLACE_ACTION)
       {
@@ -1045,7 +1041,8 @@ static bool deactivate_ddl_log_entry_no_
       }
       else if (file_entry_buf[DDL_LOG_ACTION_TYPE_POS] == DDL_LOG_EXCHANGE_ACTION)
       {
-        DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] <= 1);
+        DBUG_ASSERT(file_entry_buf[DDL_LOG_PHASE_POS] <=
+                                                 EXCH_PHASE_FROM_TO_NAME);
         file_entry_buf[DDL_LOG_PHASE_POS]++;
       }
       else
@@ -1088,7 +1085,6 @@ static int execute_ddl_log_action(THD *t
   int error= TRUE;
   char to_path[FN_REFLEN];
   char from_path[FN_REFLEN];
-  char tmp_path[FN_REFLEN];
 #ifdef WITH_PARTITION_STORAGE_ENGINE
   char *par_ext= (char*)".par";
 #endif
@@ -1210,7 +1206,7 @@ static int execute_ddl_log_action(THD *t
         since it will fall through until the first phase is undone.
       */
       switch (ddl_log_entry->phase) {
-        case 2:
+        case EXCH_PHASE_TEMP_TO_FROM:
           /* tmp_name -> from_name possibly done */
           (void) file->ha_rename_table(ddl_log_entry->from_name,
                                        ddl_log_entry->tmp_name);
@@ -1221,7 +1217,7 @@ static int execute_ddl_log_action(THD *t
           if (sync_ddl_log_no_lock())
             break;
           /* fall through */
-        case 1:
+        case EXCH_PHASE_FROM_TO_NAME:
           /* from_name -> name possibly done */
           (void) file->ha_rename_table(ddl_log_entry->name,
                                        ddl_log_entry->from_name);
@@ -1232,7 +1228,7 @@ static int execute_ddl_log_action(THD *t
           if (sync_ddl_log_no_lock())
             break;
           /* fall through */
-        case 0:
+        case EXCH_PHASE_NAME_TO_TEMP:
           /* name -> tmp_name possibly done */
           (void) file->ha_rename_table(ddl_log_entry->tmp_name,
                                        ddl_log_entry->name);
@@ -1647,9 +1643,7 @@ void execute_ddl_log_recovery()
   thd->thread_stack= (char*) &thd;
   thd->store_globals();
 
-  /* Needed for InnoDB, since it checks for DROP FOREIGN KEY */
-  thd->query_string.str= recover_query_string;
-  thd->query_string.length= strlen(recover_query_string);
+  thd->set_query(recover_query_string, strlen(recover_query_string));
 
   /* this also initialize LOCK_gdl */
   num_entries= read_ddl_log_header();
@@ -6675,6 +6669,8 @@ static bool compare_table_with_partition
   /*
     NOTE: ha_blackhole does not support check_if_compatible_data,
     so this always fail for blackhole tables.
+    ha_myisam compares pointers to verify that DATA/INDEX DIRECTORY is
+    the same, so any table using data/index_file_name will fail.
   */
   if (compare_tables(table, &part_alter_info, &part_create_info,
                      0, &alter_change_level, &key_info_buffer,
@@ -6779,7 +6775,7 @@ static bool exchange_name_with_ddl_log(T
   handler *file= NULL;
   DBUG_ENTER("exchange_name_with_ddl_log");
 
-  if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, ht)))
+  if (!(file= get_new_handler(NULL, thd->mem_root, ht)))
   {
     mem_alloc_error(sizeof(handler));
     DBUG_RETURN(TRUE);
@@ -6793,6 +6789,7 @@ static bool exchange_name_with_ddl_log(T
   exchange_entry.from_name=    from_name;
   exchange_entry.tmp_name=     tmp_name;
   exchange_entry.handler_name= ha_resolve_storage_engine_name(ht);
+  exchange_entry.phase=        EXCH_PHASE_NAME_TO_TEMP;
 
   mysql_mutex_lock(&LOCK_gdl);
   /*
@@ -6947,6 +6944,8 @@ bool mysql_exchange_partition(THD *thd,
   uint swap_part_id;
   uint part_file_name_len;
   Alter_table_prelocking_strategy alter_prelocking_strategy(alter_info);
+  MDL_ticket *swap_table_mdl_ticket= NULL;
+  MDL_ticket *part_table_mdl_ticket= NULL;
   DBUG_ENTER("mysql_exchange_partition");
   DBUG_ASSERT(alter_info->flags & ALTER_EXCHANGE_PARTITION);
 
@@ -6978,7 +6977,7 @@ bool mysql_exchange_partition(THD *thd,
 
   /*
     NOTE: It is not possible to exchange a crashed partition/table since
-    we need som info from the engine, which we can only access after open,
+    we need some info from the engine, which we can only access after open,
     to be able to verify the structure/metadata.
   */
   if (open_and_lock_tables(thd, table_list, FALSE,
@@ -7046,8 +7045,10 @@ bool mysql_exchange_partition(THD *thd,
 
   /*
     Get exclusive mdl lock on both tables, alway the non partitioned table
-    first.
+    first. Remember the tickets for downgrading locks later.
   */
+  swap_table_mdl_ticket= swap_table->mdl_ticket;
+  part_table_mdl_ticket= part_table->mdl_ticket;
 
   /*
     No need to set used_partitions to only propagate
@@ -7069,22 +7070,29 @@ bool mysql_exchange_partition(THD *thd,
     goto err;
   /* Skip ha_binlog_log_query since this function is not supported by NDB */
 
-  /* Reopen tables under LOCK TABLES */
-  if (thd->locked_tables_list.reopen_tables(thd))
-    goto err;
+  /*
+    Reopen tables under LOCK TABLES. Ignore the return value for now. It's
+    better to keep master/slave in consistent state. Alternative would be to
+    try to revert the exchange operation and issue error.
+  */
+  (void) thd->locked_tables_list.reopen_tables(thd);
 
   if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
   {
     /*
-      Should we only report failure, even if the operation was successful,
-      or should we also revert the operation? We continue and only report the
-      failed bin log call.
+      The error is reported in write_bin_log().
+      We try to revert to make it easier to keep the master/slave in sync.
     */
-    sql_print_error("Failed to write to binlog in mysql_exchange_partition:"
-                    " ALTER TABLE ... EXCHANGE PARTITION ... WITH TABLE ..."
-                    " (Part 'file name' '%s' Exchange table 'file name' '%s')",
-                    part_file_name, swap_file_name);
-                    
+    (void) exchange_name_with_ddl_log(thd, part_file_name, swap_file_name,
+                                      temp_file_name, table_hton);
+    goto err;
+  }
+  if (thd->locked_tables_mode)
+  {
+    if (swap_table_mdl_ticket)
+      swap_table_mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+    if (part_table_mdl_ticket)
+      part_table_mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
   }
   my_ok(thd);
   table_list->table= NULL;			// For query cache
@@ -7092,6 +7100,14 @@ bool mysql_exchange_partition(THD *thd,
   query_cache_invalidate3(thd, table_list, 0);
   DBUG_RETURN(FALSE);
 err:
+  if (thd->locked_tables_mode)
+  {
+    if (swap_table_mdl_ticket)
+      swap_table_mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+    if (part_table_mdl_ticket)
+      part_table_mdl_ticket->downgrade_exclusive_lock(MDL_SHARED_NO_READ_WRITE);
+  }
+
   DBUG_RETURN(TRUE);
 }
 #endif

=== modified file 'sql/sql_table.h'
--- a/sql/sql_table.h	2010-05-18 16:27:18 +0000
+++ b/sql/sql_table.h	2010-06-03 21:00:55 +0000
@@ -73,6 +73,12 @@ enum ddl_log_action_code
   DDL_LOG_EXCHANGE_ACTION = 'e'
 };
 
+enum enum_ddl_log_exchange_phase {
+  EXCH_PHASE_NAME_TO_TEMP= 0,
+  EXCH_PHASE_FROM_TO_NAME= 1,
+  EXCH_PHASE_TEMP_TO_FROM= 2
+};
+
 
 typedef struct st_ddl_log_entry
 {


Attachment: [text/bzr-bundle]
Thread
bzr push into mysql-next-mr branch (mattias.jonsson:3151 to 3152)WL#4445Mattias Jonsson3 Jun