summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/partition.result22
-rw-r--r--mysql-test/r/partition_innodb.result94
-rw-r--r--mysql-test/r/partition_mgm.result26
-rw-r--r--mysql-test/r/partition_range.result105
-rw-r--r--mysql-test/t/partition.test28
-rw-r--r--mysql-test/t/partition_innodb.test68
-rw-r--r--mysql-test/t/partition_mgm.test15
-rw-r--r--mysql-test/t/partition_range.test114
-rw-r--r--sql/ha_partition.cc6
-rw-r--r--sql/lock.cc34
-rw-r--r--sql/mysql_priv.h6
-rw-r--r--sql/sql_base.cc2
-rw-r--r--sql/sql_partition.cc232
-rw-r--r--sql/sql_partition.h3
-rw-r--r--sql/sql_show.cc5
-rw-r--r--sql/sql_table.cc4
-rw-r--r--storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp35
-rw-r--r--storage/ndb/test/ndbapi/test_event.cpp43
-rw-r--r--storage/ndb/test/run-test/daily-devel-tests.txt5
19 files changed, 757 insertions, 90 deletions
diff --git a/mysql-test/r/partition.result b/mysql-test/r/partition.result
index 7551be81c1d..310a10cb102 100644
--- a/mysql-test/r/partition.result
+++ b/mysql-test/r/partition.result
@@ -913,6 +913,28 @@ insert into t1 values (1);
create index inx1 on t1(a);
drop table t1;
create table t1 (a int)
+PARTITION BY KEY (a)
+(PARTITION p0);
+set session sql_mode='no_table_options';
+show create table t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `a` int(11) DEFAULT NULL
+) PARTITION BY KEY (a) (PARTITION p0)
+set session sql_mode='';
+drop table t1;
+create table t1 (a int)
+partition by key (a)
+(partition p1 engine = innodb);
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+drop table t1;
+create table t1 (a int)
partition by key (a)
(partition p0 engine = MERGE);
ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables
diff --git a/mysql-test/r/partition_innodb.result b/mysql-test/r/partition_innodb.result
new file mode 100644
index 00000000000..5b1221dd64c
--- /dev/null
+++ b/mysql-test/r/partition_innodb.result
@@ -0,0 +1,94 @@
+SET @max_row = 20;
+DROP TABLE IF EXISTS t0_template;
+CREATE TABLE t0_template (
+f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000) ,
+PRIMARY KEY(f_int1))
+ENGINE = MEMORY;
+INSERT INTO t0_template
+SET f_int1 = 20, f_int2 = 20, f_char1 = '20', f_char2 = '20',
+f_charbig = '===20===';
+INSERT INTO t0_template
+SET f_int1 = 19, f_int2 = 19, f_char1 = '19', f_char2 = '19',
+f_charbig = '===19===';
+INSERT INTO t0_template
+SET f_int1 = 18, f_int2 = 18, f_char1 = '18', f_char2 = '18',
+f_charbig = '===18===';
+INSERT INTO t0_template
+SET f_int1 = 17, f_int2 = 17, f_char1 = '17', f_char2 = '17',
+f_charbig = '===17===';
+INSERT INTO t0_template
+SET f_int1 = 16, f_int2 = 16, f_char1 = '16', f_char2 = '16',
+f_charbig = '===16===';
+INSERT INTO t0_template
+SET f_int1 = 15, f_int2 = 15, f_char1 = '15', f_char2 = '15',
+f_charbig = '===15===';
+INSERT INTO t0_template
+SET f_int1 = 14, f_int2 = 14, f_char1 = '14', f_char2 = '14',
+f_charbig = '===14===';
+INSERT INTO t0_template
+SET f_int1 = 13, f_int2 = 13, f_char1 = '13', f_char2 = '13',
+f_charbig = '===13===';
+INSERT INTO t0_template
+SET f_int1 = 12, f_int2 = 12, f_char1 = '12', f_char2 = '12',
+f_charbig = '===12===';
+INSERT INTO t0_template
+SET f_int1 = 11, f_int2 = 11, f_char1 = '11', f_char2 = '11',
+f_charbig = '===11===';
+INSERT INTO t0_template
+SET f_int1 = 10, f_int2 = 10, f_char1 = '10', f_char2 = '10',
+f_charbig = '===10===';
+INSERT INTO t0_template
+SET f_int1 = 9, f_int2 = 9, f_char1 = '9', f_char2 = '9',
+f_charbig = '===9===';
+INSERT INTO t0_template
+SET f_int1 = 8, f_int2 = 8, f_char1 = '8', f_char2 = '8',
+f_charbig = '===8===';
+INSERT INTO t0_template
+SET f_int1 = 7, f_int2 = 7, f_char1 = '7', f_char2 = '7',
+f_charbig = '===7===';
+INSERT INTO t0_template
+SET f_int1 = 6, f_int2 = 6, f_char1 = '6', f_char2 = '6',
+f_charbig = '===6===';
+INSERT INTO t0_template
+SET f_int1 = 5, f_int2 = 5, f_char1 = '5', f_char2 = '5',
+f_charbig = '===5===';
+INSERT INTO t0_template
+SET f_int1 = 4, f_int2 = 4, f_char1 = '4', f_char2 = '4',
+f_charbig = '===4===';
+INSERT INTO t0_template
+SET f_int1 = 3, f_int2 = 3, f_char1 = '3', f_char2 = '3',
+f_charbig = '===3===';
+INSERT INTO t0_template
+SET f_int1 = 2, f_int2 = 2, f_char1 = '2', f_char2 = '2',
+f_charbig = '===2===';
+INSERT INTO t0_template
+SET f_int1 = 1, f_int2 = 1, f_char1 = '1', f_char2 = '1',
+f_charbig = '===1===';
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30)) engine='InnoDB';
+INSERT INTO t1 (f_date, f_varchar)
+SELECT CONCAT(CAST((f_int1 + 999) AS CHAR),'-02-10'), CAST(f_char1 AS CHAR)
+FROM t0_template
+WHERE f_int1 + 999 BETWEEN 1000 AND 9999;
+SELECT IF(9999 - 1000 + 1 > @max_row, @max_row , 9999 - 1000 + 1)
+INTO @exp_row_count;
+ALTER TABLE t1 PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER));
+# 1.1.5 Add two named partitions + test
+ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
+drop table t1;
+CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30))
+ENGINE=InnoDB
+PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER));
+# This statement crashes the server.
+# CREATE partitioned table with three partitions in one step
+# would be harmless.
+ALTER TABLE t1 ADD PARTITION PARTITIONS 1;
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t0_aux;
+DROP TABLE IF EXISTS t0_definition;
+DROP TABLE IF EXISTS t0_template;
diff --git a/mysql-test/r/partition_mgm.result b/mysql-test/r/partition_mgm.result
new file mode 100644
index 00000000000..7b7b5729112
--- /dev/null
+++ b/mysql-test/r/partition_mgm.result
@@ -0,0 +1,26 @@
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30))
+PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_date` date DEFAULT NULL,
+ `f_varchar` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p0.MYD
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p0.MYI
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p1.MYD
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p1.MYI
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1.frm
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1.par
+ALTER TABLE t1 COALESCE PARTITION 1;
+SHOW CREATE TABLE t1;
+Table Create Table
+t1 CREATE TABLE `t1` (
+ `f_date` date DEFAULT NULL,
+ `f_varchar` varchar(30) DEFAULT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 PARTITION BY HASH (CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 1
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p0.MYD
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1#P#p0.MYI
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1.frm
+/home/pappa/bug19305/mysql-test/var/master-data/test/t1.par
diff --git a/mysql-test/r/partition_range.result b/mysql-test/r/partition_range.result
index 75702c48cc0..0ff219657b0 100644
--- a/mysql-test/r/partition_range.result
+++ b/mysql-test/r/partition_range.result
@@ -387,3 +387,108 @@ ALTER TABLE t1 DROP PARTITION p0;
ALTER TABLE t1 DROP PARTITION p1;
ALTER TABLE t1 DROP PARTITION p2;
drop table t1;
+create table t1 (a int DEFAULT NULL,
+b varchar(30) DEFAULT NULL,
+c date DEFAULT NULL)
+ENGINE=MYISAM DEFAULT CHARSET=latin1;
+insert into t1 values (1, 'abc', '1995-01-01');
+insert into t1 values (1, 'abc', '1995-01-02');
+insert into t1 values (1, 'abc', '1995-01-03');
+insert into t1 values (1, 'abc', '1995-01-04');
+insert into t1 values (1, 'abc', '1995-01-05');
+insert into t1 values (1, 'abc', '1995-01-06');
+insert into t1 values (1, 'abc', '1995-01-07');
+insert into t1 values (1, 'abc', '1995-01-08');
+insert into t1 values (1, 'abc', '1995-01-09');
+insert into t1 values (1, 'abc', '1995-01-10');
+insert into t1 values (1, 'abc', '1995-01-11');
+insert into t1 values (1, 'abc', '1995-01-12');
+insert into t1 values (1, 'abc', '1995-01-13');
+insert into t1 values (1, 'abc', '1995-01-14');
+insert into t1 values (1, 'abc', '1995-01-15');
+insert into t1 values (1, 'abc', '1997-01-01');
+insert into t1 values (1, 'abc', '1997-01-02');
+insert into t1 values (1, 'abc', '1997-01-03');
+insert into t1 values (1, 'abc', '1997-01-04');
+insert into t1 values (1, 'abc', '1997-01-05');
+insert into t1 values (1, 'abc', '1997-01-06');
+insert into t1 values (1, 'abc', '1997-01-07');
+insert into t1 values (1, 'abc', '1997-01-08');
+insert into t1 values (1, 'abc', '1997-01-09');
+insert into t1 values (1, 'abc', '1997-01-10');
+insert into t1 values (1, 'abc', '1997-01-11');
+insert into t1 values (1, 'abc', '1997-01-12');
+insert into t1 values (1, 'abc', '1997-01-13');
+insert into t1 values (1, 'abc', '1997-01-14');
+insert into t1 values (1, 'abc', '1997-01-15');
+insert into t1 values (1, 'abc', '1998-01-01');
+insert into t1 values (1, 'abc', '1998-01-02');
+insert into t1 values (1, 'abc', '1998-01-03');
+insert into t1 values (1, 'abc', '1998-01-04');
+insert into t1 values (1, 'abc', '1998-01-05');
+insert into t1 values (1, 'abc', '1998-01-06');
+insert into t1 values (1, 'abc', '1998-01-07');
+insert into t1 values (1, 'abc', '1998-01-08');
+insert into t1 values (1, 'abc', '1998-01-09');
+insert into t1 values (1, 'abc', '1998-01-10');
+insert into t1 values (1, 'abc', '1998-01-11');
+insert into t1 values (1, 'abc', '1998-01-12');
+insert into t1 values (1, 'abc', '1998-01-13');
+insert into t1 values (1, 'abc', '1998-01-14');
+insert into t1 values (1, 'abc', '1998-01-15');
+insert into t1 values (1, 'abc', '1999-01-01');
+insert into t1 values (1, 'abc', '1999-01-02');
+insert into t1 values (1, 'abc', '1999-01-03');
+insert into t1 values (1, 'abc', '1999-01-04');
+insert into t1 values (1, 'abc', '1999-01-05');
+insert into t1 values (1, 'abc', '1999-01-06');
+insert into t1 values (1, 'abc', '1999-01-07');
+insert into t1 values (1, 'abc', '1999-01-08');
+insert into t1 values (1, 'abc', '1999-01-09');
+insert into t1 values (1, 'abc', '1999-01-10');
+insert into t1 values (1, 'abc', '1999-01-11');
+insert into t1 values (1, 'abc', '1999-01-12');
+insert into t1 values (1, 'abc', '1999-01-13');
+insert into t1 values (1, 'abc', '1999-01-14');
+insert into t1 values (1, 'abc', '1999-01-15');
+insert into t1 values (1, 'abc', '2000-01-01');
+insert into t1 values (1, 'abc', '2000-01-02');
+insert into t1 values (1, 'abc', '2000-01-03');
+insert into t1 values (1, 'abc', '2000-01-04');
+insert into t1 values (1, 'abc', '2000-01-05');
+insert into t1 values (1, 'abc', '2000-01-06');
+insert into t1 values (1, 'abc', '2000-01-07');
+insert into t1 values (1, 'abc', '2000-01-08');
+insert into t1 values (1, 'abc', '2000-01-09');
+insert into t1 values (1, 'abc', '2000-01-15');
+insert into t1 values (1, 'abc', '2000-01-11');
+insert into t1 values (1, 'abc', '2000-01-12');
+insert into t1 values (1, 'abc', '2000-01-13');
+insert into t1 values (1, 'abc', '2000-01-14');
+insert into t1 values (1, 'abc', '2000-01-15');
+insert into t1 values (1, 'abc', '2001-01-01');
+insert into t1 values (1, 'abc', '2001-01-02');
+insert into t1 values (1, 'abc', '2001-01-03');
+insert into t1 values (1, 'abc', '2001-01-04');
+insert into t1 values (1, 'abc', '2001-01-05');
+insert into t1 values (1, 'abc', '2001-01-06');
+insert into t1 values (1, 'abc', '2001-01-07');
+insert into t1 values (1, 'abc', '2001-01-08');
+insert into t1 values (1, 'abc', '2001-01-09');
+insert into t1 values (1, 'abc', '2001-01-15');
+insert into t1 values (1, 'abc', '2001-01-11');
+insert into t1 values (1, 'abc', '2001-01-12');
+insert into t1 values (1, 'abc', '2001-01-13');
+insert into t1 values (1, 'abc', '2001-01-14');
+insert into t1 values (1, 'abc', '2001-01-15');
+alter table t1
+partition by range (year(c))
+(partition p5 values less than (2000), partition p10 values less than (2010));
+alter table t1
+reorganize partition p5 into
+(partition p1 values less than (1996),
+partition p2 values less than (1997),
+partition p3 values less than (1998),
+partition p4 values less than (1999),
+partition p5 values less than (2000));
+drop table t1;
diff --git a/mysql-test/t/partition.test b/mysql-test/t/partition.test
index be4fc1081f3..05adb6866db 100644
--- a/mysql-test/t/partition.test
+++ b/mysql-test/t/partition.test
@@ -1037,6 +1037,34 @@ create index inx1 on t1(a);
drop table t1;
#
+# Bug 19695 Partitions: SHOW CREATE TABLE shows table options even when it
+# shouldn't
+#
+create table t1 (a int)
+PARTITION BY KEY (a)
+(PARTITION p0);
+set session sql_mode='no_table_options';
+show create table t1;
+set session sql_mode='';
+drop table t1;
+
+#
+# BUG 19122 Crash after ALTER TABLE t1 REBUILD PARTITION p1
+#
+create table t1 (a int)
+partition by key (a)
+(partition p1 engine = innodb);
+
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+alter table t1 rebuild partition p1;
+drop table t1;
+
+#
# BUG 19304 Partitions: MERGE handler not allowed in partitioned tables
#
--error ER_PARTITION_MERGE_ERROR
diff --git a/mysql-test/t/partition_innodb.test b/mysql-test/t/partition_innodb.test
new file mode 100644
index 00000000000..6a95dd7c8b0
--- /dev/null
+++ b/mysql-test/t/partition_innodb.test
@@ -0,0 +1,68 @@
+-- source include/have_innodb.inc
+
+SET @max_row = 20;
+let $engine= 'InnoDB';
+let $MAX_VALUE= (2147483646);
+
+let $max_row= `SELECT @max_row`;
+
+# Column list with definition for all tables to be checked
+let $column_list= f_int1 INTEGER,
+f_int2 INTEGER,
+f_char1 CHAR(20),
+f_char2 CHAR(20),
+f_charbig VARCHAR(1000);
+
+let $sub_part_no= 3;
+--disable_warnings
+DROP TABLE IF EXISTS t0_template;
+--enable_warnings
+eval CREATE TABLE t0_template (
+$column_list ,
+PRIMARY KEY(f_int1))
+ENGINE = MEMORY;
+let $num= `SELECT @max_row`;
+while ($num)
+{
+ eval INSERT INTO t0_template
+SET f_int1 = $num, f_int2 = $num, f_char1 = '$num', f_char2 = '$num',
+f_charbig = '===$num===';
+ dec $num;
+}
+# 1. Create the table
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+eval CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30)) engine=$engine;
+# 2. Fill the table t1 with records
+INSERT INTO t1 (f_date, f_varchar)
+SELECT CONCAT(CAST((f_int1 + 999) AS CHAR),'-02-10'), CAST(f_char1 AS CHAR)
+FROM t0_template
+WHERE f_int1 + 999 BETWEEN 1000 AND 9999;
+# 3. Calculate the number of inserted records.
+SELECT IF(9999 - 1000 + 1 > @max_row, @max_row , 9999 - 1000 + 1)
+ INTO @exp_row_count;
+# DEBUG SELECT @exp_row_count;
+# 4. Print the layout, check Readability
+ALTER TABLE t1 PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER));
+--echo # 1.1.5 Add two named partitions + test
+ALTER TABLE t1 ADD PARTITION (PARTITION part1, PARTITION part7);
+drop table t1;
+
+CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30))
+ENGINE=InnoDB
+PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER));
+
+--echo # This statement crashes the server.
+--echo # CREATE partitioned table with three partitions in one step
+--echo # would be harmless.
+ALTER TABLE t1 ADD PARTITION PARTITIONS 1;
+
+--disable_warnings
+DROP VIEW IF EXISTS v1;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t0_aux;
+DROP TABLE IF EXISTS t0_definition;
+DROP TABLE IF EXISTS t0_template;
+--enable_warnings
+
diff --git a/mysql-test/t/partition_mgm.test b/mysql-test/t/partition_mgm.test
new file mode 100644
index 00000000000..aa9a6459a1a
--- /dev/null
+++ b/mysql-test/t/partition_mgm.test
@@ -0,0 +1,15 @@
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+CREATE TABLE t1 (f_date DATE, f_varchar VARCHAR(30))
+PARTITION BY HASH(CAST(YEAR(f_date) AS SIGNED INTEGER)) PARTITIONS 2;
+SHOW CREATE TABLE t1;
+
+--exec ls $MYSQLTEST_VARDIR/master-data/test/t1*
+ALTER TABLE t1 COALESCE PARTITION 1;
+SHOW CREATE TABLE t1;
+--exec ls $MYSQLTEST_VARDIR/master-data/test/t1*
+
+
+
+
diff --git a/mysql-test/t/partition_range.test b/mysql-test/t/partition_range.test
index ef539e2001f..42ce4e0d879 100644
--- a/mysql-test/t/partition_range.test
+++ b/mysql-test/t/partition_range.test
@@ -416,3 +416,117 @@ ALTER TABLE t1 DROP PARTITION p0;
ALTER TABLE t1 DROP PARTITION p1;
ALTER TABLE t1 DROP PARTITION p2;
drop table t1;
+
+#
+# Bug 19830: ALTER TABLE t1 REORGANIZE PARTITION crashes
+#
+create table t1 (a int DEFAULT NULL,
+ b varchar(30) DEFAULT NULL,
+ c date DEFAULT NULL)
+ENGINE=MYISAM DEFAULT CHARSET=latin1;
+
+insert into t1 values (1, 'abc', '1995-01-01');
+insert into t1 values (1, 'abc', '1995-01-02');
+insert into t1 values (1, 'abc', '1995-01-03');
+insert into t1 values (1, 'abc', '1995-01-04');
+insert into t1 values (1, 'abc', '1995-01-05');
+insert into t1 values (1, 'abc', '1995-01-06');
+insert into t1 values (1, 'abc', '1995-01-07');
+insert into t1 values (1, 'abc', '1995-01-08');
+insert into t1 values (1, 'abc', '1995-01-09');
+insert into t1 values (1, 'abc', '1995-01-10');
+insert into t1 values (1, 'abc', '1995-01-11');
+insert into t1 values (1, 'abc', '1995-01-12');
+insert into t1 values (1, 'abc', '1995-01-13');
+insert into t1 values (1, 'abc', '1995-01-14');
+insert into t1 values (1, 'abc', '1995-01-15');
+insert into t1 values (1, 'abc', '1997-01-01');
+insert into t1 values (1, 'abc', '1997-01-02');
+insert into t1 values (1, 'abc', '1997-01-03');
+insert into t1 values (1, 'abc', '1997-01-04');
+insert into t1 values (1, 'abc', '1997-01-05');
+insert into t1 values (1, 'abc', '1997-01-06');
+insert into t1 values (1, 'abc', '1997-01-07');
+insert into t1 values (1, 'abc', '1997-01-08');
+insert into t1 values (1, 'abc', '1997-01-09');
+insert into t1 values (1, 'abc', '1997-01-10');
+insert into t1 values (1, 'abc', '1997-01-11');
+insert into t1 values (1, 'abc', '1997-01-12');
+insert into t1 values (1, 'abc', '1997-01-13');
+insert into t1 values (1, 'abc', '1997-01-14');
+insert into t1 values (1, 'abc', '1997-01-15');
+insert into t1 values (1, 'abc', '1998-01-01');
+insert into t1 values (1, 'abc', '1998-01-02');
+insert into t1 values (1, 'abc', '1998-01-03');
+insert into t1 values (1, 'abc', '1998-01-04');
+insert into t1 values (1, 'abc', '1998-01-05');
+insert into t1 values (1, 'abc', '1998-01-06');
+insert into t1 values (1, 'abc', '1998-01-07');
+insert into t1 values (1, 'abc', '1998-01-08');
+insert into t1 values (1, 'abc', '1998-01-09');
+insert into t1 values (1, 'abc', '1998-01-10');
+insert into t1 values (1, 'abc', '1998-01-11');
+insert into t1 values (1, 'abc', '1998-01-12');
+insert into t1 values (1, 'abc', '1998-01-13');
+insert into t1 values (1, 'abc', '1998-01-14');
+insert into t1 values (1, 'abc', '1998-01-15');
+insert into t1 values (1, 'abc', '1999-01-01');
+insert into t1 values (1, 'abc', '1999-01-02');
+insert into t1 values (1, 'abc', '1999-01-03');
+insert into t1 values (1, 'abc', '1999-01-04');
+insert into t1 values (1, 'abc', '1999-01-05');
+insert into t1 values (1, 'abc', '1999-01-06');
+insert into t1 values (1, 'abc', '1999-01-07');
+insert into t1 values (1, 'abc', '1999-01-08');
+insert into t1 values (1, 'abc', '1999-01-09');
+insert into t1 values (1, 'abc', '1999-01-10');
+insert into t1 values (1, 'abc', '1999-01-11');
+insert into t1 values (1, 'abc', '1999-01-12');
+insert into t1 values (1, 'abc', '1999-01-13');
+insert into t1 values (1, 'abc', '1999-01-14');
+insert into t1 values (1, 'abc', '1999-01-15');
+insert into t1 values (1, 'abc', '2000-01-01');
+insert into t1 values (1, 'abc', '2000-01-02');
+insert into t1 values (1, 'abc', '2000-01-03');
+insert into t1 values (1, 'abc', '2000-01-04');
+insert into t1 values (1, 'abc', '2000-01-05');
+insert into t1 values (1, 'abc', '2000-01-06');
+insert into t1 values (1, 'abc', '2000-01-07');
+insert into t1 values (1, 'abc', '2000-01-08');
+insert into t1 values (1, 'abc', '2000-01-09');
+insert into t1 values (1, 'abc', '2000-01-15');
+insert into t1 values (1, 'abc', '2000-01-11');
+insert into t1 values (1, 'abc', '2000-01-12');
+insert into t1 values (1, 'abc', '2000-01-13');
+insert into t1 values (1, 'abc', '2000-01-14');
+insert into t1 values (1, 'abc', '2000-01-15');
+insert into t1 values (1, 'abc', '2001-01-01');
+insert into t1 values (1, 'abc', '2001-01-02');
+insert into t1 values (1, 'abc', '2001-01-03');
+insert into t1 values (1, 'abc', '2001-01-04');
+insert into t1 values (1, 'abc', '2001-01-05');
+insert into t1 values (1, 'abc', '2001-01-06');
+insert into t1 values (1, 'abc', '2001-01-07');
+insert into t1 values (1, 'abc', '2001-01-08');
+insert into t1 values (1, 'abc', '2001-01-09');
+insert into t1 values (1, 'abc', '2001-01-15');
+insert into t1 values (1, 'abc', '2001-01-11');
+insert into t1 values (1, 'abc', '2001-01-12');
+insert into t1 values (1, 'abc', '2001-01-13');
+insert into t1 values (1, 'abc', '2001-01-14');
+insert into t1 values (1, 'abc', '2001-01-15');
+
+alter table t1
+partition by range (year(c))
+(partition p5 values less than (2000), partition p10 values less than (2010));
+
+alter table t1
+reorganize partition p5 into
+(partition p1 values less than (1996),
+ partition p2 values less than (1997),
+ partition p3 values less than (1998),
+ partition p4 values less than (1999),
+ partition p5 values less than (2000));
+
+drop table t1;
+
diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc
index 77a150994ad..f151d89bb1a 100644
--- a/sql/ha_partition.cc
+++ b/sql/ha_partition.cc
@@ -611,6 +611,8 @@ int ha_partition::drop_partitions(const char *path)
DBUG_PRINT("info", ("Drop subpartition %s", part_name_buff));
if ((ret_error= file->delete_table((const char *) part_name_buff)))
error= ret_error;
+ if (deactivate_ddl_log_entry(sub_elem->log_entry->entry_pos))
+ error= 1;
} while (++j < no_subparts);
}
else
@@ -622,6 +624,8 @@ int ha_partition::drop_partitions(const char *path)
DBUG_PRINT("info", ("Drop partition %s", part_name_buff));
if ((ret_error= file->delete_table((const char *) part_name_buff)))
error= ret_error;
+ if (deactivate_ddl_log_entry(part_elem->log_entry->entry_pos))
+ error= 1;
}
if (part_elem->part_state == PART_IS_CHANGED)
part_elem->part_state= PART_NORMAL;
@@ -629,6 +633,7 @@ int ha_partition::drop_partitions(const char *path)
part_elem->part_state= PART_IS_DROPPED;
}
} while (++i < no_parts);
+ VOID(sync_ddl_log());
DBUG_RETURN(error);
}
@@ -745,6 +750,7 @@ int ha_partition::rename_partitions(const char *path)
*/
part_elem= part_it++;
if (part_elem->part_state == PART_IS_CHANGED ||
+ part_elem->part_state == PART_TO_BE_DROPPED ||
(part_elem->part_state == PART_IS_ADDED && temp_partitions))
{
if (m_is_sub_partitioned)
diff --git a/sql/lock.cc b/sql/lock.cc
index 80861e3beb5..e5003325df6 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -828,7 +828,7 @@ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list)
if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(1);
VOID(pthread_mutex_lock(&LOCK_open));
- if ((lock_retcode = lock_table_name(thd, table_list)) < 0)
+ if ((lock_retcode = lock_table_name(thd, table_list, TRUE)) < 0)
goto end;
if (lock_retcode && wait_for_locked_table_names(thd, table_list))
{
@@ -851,6 +851,7 @@ end:
lock_table_name()
thd Thread handler
table_list Lock first table in this list
+ check_in_use Do we need to check if table already in use by us
WARNING
If you are going to update the table, you should use
@@ -870,7 +871,7 @@ end:
> 0 table locked, but someone is using it
*/
-int lock_table_name(THD *thd, TABLE_LIST *table_list)
+int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
{
TABLE *table;
char key[MAX_DBKEY_LENGTH];
@@ -882,17 +883,22 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
key_length= create_table_def_key(thd, key, table_list, 0);
- /* Only insert the table if we haven't insert it already */
- for (table=(TABLE*) hash_first(&open_cache, (byte*)key, key_length, &state);
- table ;
- table = (TABLE*) hash_next(&open_cache,(byte*) key,key_length, &state))
+ if (check_in_use)
{
- if (table->in_use == thd)
+ /* Only insert the table if we haven't insert it already */
+ for (table=(TABLE*) hash_first(&open_cache, (byte*)key,
+ key_length, &state);
+ table ;
+ table = (TABLE*) hash_next(&open_cache,(byte*) key,
+ key_length, &state))
{
- DBUG_PRINT("info", ("Table is in use"));
- table->s->version= 0; // Ensure no one can use this
- table->locked_by_name= 1;
- DBUG_RETURN(0);
+ if (table->in_use == thd)
+ {
+ DBUG_PRINT("info", ("Table is in use"));
+ table->s->version= 0; // Ensure no one can use this
+ table->locked_by_name= 1;
+ DBUG_RETURN(0);
+ }
}
}
/*
@@ -917,10 +923,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
my_free((gptr) table,MYF(0));
DBUG_RETURN(-1);
}
-
+
/* Return 1 if table is in use */
DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name,
- RTFC_NO_FLAG)));
+ check_in_use ? RTFC_NO_FLAG : RTFC_WAIT_OTHER_THREAD_FLAG)));
}
@@ -1003,7 +1009,7 @@ bool lock_table_names(THD *thd, TABLE_LIST *table_list)
for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
{
int got_lock;
- if ((got_lock=lock_table_name(thd,lock_table)) < 0)
+ if ((got_lock=lock_table_name(thd,lock_table, TRUE)) < 0)
goto end; // Fatal error
if (got_lock)
got_all_locks=0; // Someone is using table
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 76d8aa18f59..3d499b67519 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -1174,7 +1174,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> *create_list,
- List<Key> *key_list, const char *db,
+ List<Key> *key_list, char *db,
const char *table_name,
uint fast_alter_partition);
uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
@@ -1204,10 +1204,12 @@ void create_subpartition_name(char *out, const char *in1,
typedef struct st_lock_param_type
{
+ TABLE_LIST table_list;
ulonglong copied;
ulonglong deleted;
THD *thd;
HA_CREATE_INFO *create_info;
+ ALTER_INFO *alter_info;
List<create_field> *create_list;
List<create_field> new_create_list;
List<Key> *key_list;
@@ -1687,7 +1689,7 @@ void unset_protect_against_global_read_lock(void);
/* Lock based on name */
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
-int lock_table_name(THD *thd, TABLE_LIST *table_list);
+int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use);
void unlock_table_name(THD *thd, TABLE_LIST *table_list);
bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list);
bool lock_table_names(THD *thd, TABLE_LIST *table_list);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 2298de7eeb5..9b7d46119b7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -2686,7 +2686,7 @@ retry:
goto err;
// Code below is for repairing a crashed file
- if ((error= lock_table_name(thd, table_list)))
+ if ((error= lock_table_name(thd, table_list, TRUE)))
{
if (error < 0)
goto err;
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index a10a04ba9f9..2f79da7edf4 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -1675,6 +1675,7 @@ static int add_partition_options(File fptr, partition_element *p_elem)
{
int err= 0;
+ err+= add_space(fptr);
if (p_elem->tablespace_name)
err+= add_keyword_string(fptr,"TABLESPACE", FALSE,
p_elem->tablespace_name);
@@ -1702,7 +1703,7 @@ static int add_partition_values(File fptr, partition_info *part_info,
if (part_info->part_type == RANGE_PARTITION)
{
- err+= add_string(fptr, "VALUES LESS THAN ");
+ err+= add_string(fptr, " VALUES LESS THAN ");
if (p_elem->range_value != LONGLONG_MAX)
{
err+= add_begin_parenthesis(fptr);
@@ -1716,7 +1717,7 @@ static int add_partition_values(File fptr, partition_info *part_info,
{
uint i;
List_iterator<longlong> list_val_it(p_elem->list_val_list);
- err+= add_string(fptr, "VALUES IN ");
+ err+= add_string(fptr, " VALUES IN ");
uint no_items= p_elem->list_val_list.elements;
err+= add_begin_parenthesis(fptr);
if (p_elem->has_null_value)
@@ -1740,7 +1741,7 @@ static int add_partition_values(File fptr, partition_info *part_info,
err+= add_end_parenthesis(fptr);
}
end:
- return err + add_space(fptr);
+ return err;
}
/*
@@ -1754,6 +1755,7 @@ end:
buf_length A pointer to the returned buffer length
use_sql_alloc Allocate buffer from sql_alloc if true
otherwise use my_malloc
+ show_partition_options Should we display partition options
RETURN VALUES
NULL error
@@ -1781,7 +1783,8 @@ end:
char *generate_partition_syntax(partition_info *part_info,
uint *buf_length,
- bool use_sql_alloc)
+ bool use_sql_alloc,
+ bool show_partition_options)
{
uint i,j, tot_no_parts, no_subparts, no_parts;
partition_element *part_elem;
@@ -1882,12 +1885,12 @@ char *generate_partition_syntax(partition_info *part_info,
first= FALSE;
err+= add_partition(fptr);
err+= add_name_string(fptr, part_elem->partition_name);
- err+= add_space(fptr);
err+= add_partition_values(fptr, part_info, part_elem);
if (!part_info->is_sub_partitioned() ||
part_info->use_default_subpartitions)
{
- err+= add_partition_options(fptr, part_elem);
+ if (show_partition_options)
+ err+= add_partition_options(fptr, part_elem);
}
else
{
@@ -1900,8 +1903,8 @@ char *generate_partition_syntax(partition_info *part_info,
part_elem= sub_it++;
err+= add_subpartition(fptr);
err+= add_name_string(fptr, part_elem->partition_name);
- err+= add_space(fptr);
- err+= add_partition_options(fptr, part_elem);
+ if (show_partition_options)
+ err+= add_partition_options(fptr, part_elem);
if (j != (no_subparts-1))
{
err+= add_comma(fptr);
@@ -4996,8 +4999,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
DBUG_RETURN(TRUE);
}
*next_entry= log_entry->entry_pos;
- if (temp_list)
- sub_elem->log_entry= log_entry;
+ sub_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
} while (++j < no_subparts);
}
@@ -5015,8 +5017,7 @@ static bool write_log_dropped_partitions(ALTER_PARTITION_PARAM_TYPE *lpt,
DBUG_RETURN(TRUE);
}
*next_entry= log_entry->entry_pos;
- if (temp_list)
- part_elem->log_entry= log_entry;
+ part_elem->log_entry= log_entry;
insert_part_info_log_entry_list(part_info, log_entry);
}
}
@@ -5290,7 +5291,7 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt)
lpt->table_name, "#");
pthread_mutex_lock(&LOCK_gdl);
if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path,
- TRUE))
+ lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION))
goto error;
if (write_log_changed_partitions(lpt, &next_entry, (const char*)path))
goto error;
@@ -5378,6 +5379,79 @@ static void release_log_entries(partition_info *part_info)
/*
+ Get a lock on table name to avoid that anyone can open the table in
+ a critical part of the ALTER TABLE.
+ SYNOPSIS
+ get_name_lock()
+ lpt Struct carrying parameters
+ RETURN VALUES
+ FALSE Success
+ TRUE Failure
+*/
+
+static int get_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ int error= 0;
+ DBUG_ENTER("get_name_lock");
+
+ bzero(&lpt->table_list, sizeof(lpt->table_list));
+ lpt->table_list.db= (char*)lpt->db;
+ lpt->table_list.table= lpt->table;
+ lpt->table_list.table_name= (char*)lpt->table_name;
+ pthread_mutex_lock(&LOCK_open);
+ error= lock_table_name(lpt->thd, &lpt->table_list, FALSE);
+ pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(error);
+}
+
+
+/*
+ Unlock and close table before renaming and dropping partitions
+ SYNOPSIS
+ alter_close_tables()
+ lpt Struct carrying parameters
+ RETURN VALUES
+ 0
+*/
+
+static int alter_close_tables(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ THD *thd= lpt->thd;
+ TABLE *table= lpt->table;
+ DBUG_ENTER("alter_close_tables");
+ /*
+ We need to also unlock tables and close all handlers.
+ We set lock to zero to ensure we don't do this twice
+ and we set db_stat to zero to ensure we don't close twice.
+ */
+ mysql_unlock_tables(thd, thd->lock);
+ thd->lock= 0;
+ table->file->close();
+ table->db_stat= 0;
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Release a lock name
+ SYNOPSIS
+ release_name_lock()
+ lpt
+ RETURN VALUES
+ 0
+*/
+
+static int release_name_lock(ALTER_PARTITION_PARAM_TYPE *lpt)
+{
+ DBUG_ENTER("release_name_lock");
+ pthread_mutex_lock(&LOCK_open);
+ unlock_table_name(lpt->thd, &lpt->table_list);
+ pthread_mutex_unlock(&LOCK_open);
+ DBUG_RETURN(0);
+}
+
+
+/*
Handle errors for ALTER TABLE for partitioning
SYNOPSIS
handle_alter_part_error()
@@ -5527,7 +5601,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info,
TABLE_LIST *table_list,
List<create_field> *create_list,
- List<Key> *key_list, const char *db,
+ List<Key> *key_list, char *db,
const char *table_name,
uint fast_alter_partition)
{
@@ -5544,6 +5618,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
lpt->thd= thd;
lpt->part_info= part_info;
+ lpt->alter_info= alter_info;
lpt->create_info= create_info;
lpt->create_list= create_list;
lpt->key_list= key_list;
@@ -5667,8 +5742,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
2) Write the ddl log to ensure that the operation is completed
even in the presence of a MySQL Server crash
3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to
- the table have completed
- 4) Write the bin log
+ the table have completed. This ensures that other threads can not
+ execute on the table in parallel.
+ 4) Get a name lock on the table. This ensures that we can release all
+ locks on the table and since no one can open the table, there can
+ be no new threads accessing the table. They will be hanging on the
+ name lock.
+ 5) Close all tables that have already been opened but didn't stumble on
+ the abort locked previously. This is done as part of the
+ get_name_lock call.
+ 6) We are now ready to release all locks we got in this thread.
+ 7) Write the bin log
Unfortunately the writing of the binlog is not synchronised with
other logging activities. So no matter in which order the binlog
is written compared to other activities there will always be cases
@@ -5679,14 +5763,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
require writing the statement first in the ddl log and then
when recovering from the crash read the binlog and insert it into
the binlog if not written already.
- 5) Install the previously written shadow frm file
- 6) Ensure that any users that has opened the table but not yet
- reached the abort lock do that before downgrading the lock.
- 7) Prepare MyISAM handlers for drop of partitions
- 8) Drop the partitions
- 9) Remove entries from ddl log
- 10) Wait until all accesses using the old frm file has completed
- 11) Complete query
+ 8) Install the previously written shadow frm file
+ 9) Prepare handlers for drop of partitions
+ 10) Drop the partitions
+ 11) Remove entries from ddl log
+ 12) Release name lock so that all other threads can access the table
+ again.
+ 13) Complete query
We insert Error injections at all places where it could be interesting
to test if recovery is properly done.
@@ -5699,22 +5782,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_drop_partition_3") ||
(not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
+ ERROR_INJECT_CRASH("crash_drop_partition_4") ||
+ get_name_lock(lpt) ||
+ ERROR_INJECT_CRASH("crash_drop_partition_5") ||
+ alter_close_tables(lpt) ||
+ ERROR_INJECT_CRASH("crash_drop_partition_6") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) ||
- ERROR_INJECT_CRASH("crash_drop_partition_4") ||
- (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) ||
- ERROR_INJECT_CRASH("crash_drop_partition_5") ||
+ ERROR_INJECT_CRASH("crash_drop_partition_7") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
((frm_install= FALSE), FALSE) ||
- (close_open_tables_and_downgrade(lpt), FALSE) ||
- ERROR_INJECT_CRASH("crash_drop_partition_6") ||
+ ERROR_INJECT_CRASH("crash_drop_partition_8") ||
mysql_drop_partitions(lpt) ||
- ERROR_INJECT_CRASH("crash_drop_partition_7") ||
+ ERROR_INJECT_CRASH("crash_drop_partition_9") ||
(write_log_completed(lpt, FALSE), FALSE) ||
- ERROR_INJECT_CRASH("crash_drop_partition_8") ||
- (mysql_wait_completed_table(lpt, table), FALSE))
+ ERROR_INJECT_CRASH("crash_drop_partition_10") ||
+ (release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, TRUE, frm_install);
DBUG_RETURN(TRUE);
@@ -5740,15 +5825,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing.
- 4) Write binlog
- 5) Now the change is completed except for the installation of the
+ 4) Get a name lock on the table. This ensures that we can release all
+ locks on the table and since no one can open the table, there can
+ be no new threads accessing the table. They will be hanging on the
+ name lock.
+ 5) Close all tables that have already been opened but didn't stumble on
+ the abort locked previously. This is done as part of the
+ get_name_lock call.
+ 6) Close all table handlers and unlock all handlers but retain name lock
+ 7) Write binlog
+ 8) Now the change is completed except for the installation of the
new frm file. We thus write an action in the log to change to
the shadow frm file
- 6) Install the new frm file of the table where the partitions are
+ 9) Install the new frm file of the table where the partitions are
added to the table.
- 7) Wait until all accesses using the old frm file has completed
- 8) Remove entries from ddl log
- 9) Complete query
+ 10)Wait until all accesses using the old frm file has completed
+ 11)Remove entries from ddl log
+ 12)Release name lock
+ 13)Complete query
*/
if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_1") ||
@@ -5757,19 +5851,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_3") ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
+ ERROR_INJECT_CRASH("crash_add_partition_3") ||
+ get_name_lock(lpt) ||
+ ERROR_INJECT_CRASH("crash_add_partition_4") ||
+ alter_close_tables(lpt) ||
+ ERROR_INJECT_CRASH("crash_add_partition_5") ||
((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) ||
- ERROR_INJECT_CRASH("crash_add_partition_4") ||
+ ERROR_INJECT_CRASH("crash_add_partition_6") ||
write_log_rename_frm(lpt) ||
(not_completed= FALSE) ||
- ERROR_INJECT_CRASH("crash_add_partition_5") ||
+ ERROR_INJECT_CRASH("crash_add_partition_7") ||
((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
- ERROR_INJECT_CRASH("crash_add_partition_6") ||
- (close_open_tables_and_downgrade(lpt), FALSE) ||
+ ERROR_INJECT_CRASH("crash_add_partition_8") ||
(write_log_completed(lpt, FALSE), FALSE) ||
- ERROR_INJECT_CRASH("crash_add_partition_7"))
+ ERROR_INJECT_CRASH("crash_add_partition_9") ||
+ (release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE);
@@ -5819,16 +5918,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
5) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing.
- 6) Prepare MyISAM handlers for rename and delete of partitions
- 7) Rename the reorged partitions such that they are no longer
- used and rename those added to their real new names.
- 8) Write bin log
- 9) Install the shadow frm file
- 10) Wait until all accesses using the old frm file has completed
- 11) Drop the reorganised partitions
- 12) Remove log entry
- 13)Wait until all accesses using the old frm file has completed
- 14)Complete query
+ 6) Get a name lock of the table
+ 7) Close all tables opened but not yet locked, after this call we are
+ certain that no other thread is in the lock wait queue or has
+ opened the table. The name lock will ensure that they are blocked
+ on the open call. This is achieved also by get_name_lock call.
+ 8) Close all partitions opened by this thread, but retain name lock.
+ 9) Write bin log
+ 10) Prepare handlers for rename and delete of partitions
+ 11) Rename and drop the reorged partitions such that they are no
+ longer used and rename those added to their real new names.
+ 12) Install the shadow frm file
+ 13) Release the name lock to enable other threads to start using the
+ table again.
+ 14) Complete query
*/
if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_1") ||
@@ -5840,22 +5943,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_change_partition_4") ||
(not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */
- ((!thd->lex->no_write_to_binlog) &&
- (write_bin_log(thd, FALSE,
- thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_5") ||
- (table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) ||
+ get_name_lock(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
- mysql_rename_partitions(lpt) ||
- ((frm_install= TRUE), FALSE) ||
+ alter_close_tables(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
- mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
+ ((!thd->lex->no_write_to_binlog) &&
+ (write_bin_log(thd, FALSE,
+ thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
- (close_open_tables_and_downgrade(lpt), FALSE) ||
+ mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_9") ||
- (write_log_completed(lpt, FALSE), FALSE) ||
+ mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_10") ||
- (mysql_wait_completed_table(lpt, table), FALSE))
+ mysql_rename_partitions(lpt) ||
+ ((frm_install= TRUE), FALSE) ||
+ ERROR_INJECT_CRASH("crash_change_partition_11") ||
+ (write_log_completed(lpt, FALSE), FALSE) ||
+ ERROR_INJECT_CRASH("crash_change_partition_12") ||
+ (release_name_lock(lpt), FALSE))
{
handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE);
diff --git a/sql/sql_partition.h b/sql/sql_partition.h
index 87f9a751ca3..7b07fd2eb53 100644
--- a/sql/sql_partition.h
+++ b/sql/sql_partition.h
@@ -69,7 +69,8 @@ bool check_partition_info(partition_info *part_info,handlerton **eng_type,
bool fix_partition_func(THD *thd, const char *name, TABLE *table,
bool create_table_ind);
char *generate_partition_syntax(partition_info *part_info,
- uint *buf_length, bool use_sql_alloc);
+ uint *buf_length, bool use_sql_alloc,
+ bool show_partition_options);
bool partition_key_modified(TABLE *table, List<Item> &fields);
void get_partition_set(const TABLE *table, byte *buf, const uint index,
const key_range *key_spec,
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 28282929b88..439f95f06be 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -970,6 +970,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
handler *file= table->file;
TABLE_SHARE *share= table->s;
HA_CREATE_INFO create_info;
+ bool show_table_options= FALSE;
bool foreign_db_mode= (thd->variables.sql_mode & (MODE_POSTGRESQL |
MODE_ORACLE |
MODE_MSSQL |
@@ -1195,6 +1196,7 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
packet->append(STRING_WITH_LEN("\n)"));
if (!(thd->variables.sql_mode & MODE_NO_TABLE_OPTIONS) && !foreign_db_mode)
{
+ show_table_options= TRUE;
/*
Get possible table space definitions and append them
to the CREATE TABLE statement
@@ -1335,7 +1337,8 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
(!table->part_info->is_auto_partitioned) &&
((part_syntax= generate_partition_syntax(table->part_info,
&part_syntax_len,
- FALSE))))
+ FALSE,
+ show_table_options))))
{
packet->append(STRING_WITH_LEN(" /*!50100"));
packet->append(part_syntax, part_syntax_len);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index e9c89b4983d..a49b7a2cc42 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1233,7 +1233,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
{
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE)))
+ TRUE, TRUE)))
{
DBUG_RETURN(TRUE);
}
@@ -3155,7 +3155,7 @@ bool mysql_create_table_internal(THD *thd,
*/
if (!(part_syntax_buf= generate_partition_syntax(part_info,
&syntax_len,
- TRUE)))
+ TRUE, TRUE)))
goto err;
part_info->part_info_string= part_syntax_buf;
part_info->part_info_len= syntax_len;
diff --git a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
index a5fbd84e5b0..c8f05f3a96c 100644
--- a/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
+++ b/storage/ndb/src/ndbapi/NdbEventOperationImpl.cpp
@@ -1933,15 +1933,16 @@ static struct Ev_t {
enum_DEL = NdbDictionary::Event::_TE_DELETE,
enum_UPD = NdbDictionary::Event::_TE_UPDATE,
enum_NUL = NdbDictionary::Event::_TE_NUL,
- enum_ERR = 255
+ enum_IDM = 254, // idempotent op possibly allowed on NF
+ enum_ERR = 255 // always impossible
};
int t1, t2, t3;
} ev_t[] = {
- { Ev_t::enum_INS, Ev_t::enum_INS, Ev_t::enum_ERR },
+ { Ev_t::enum_INS, Ev_t::enum_INS, Ev_t::enum_IDM },
{ Ev_t::enum_INS, Ev_t::enum_DEL, Ev_t::enum_NUL }, //ok
{ Ev_t::enum_INS, Ev_t::enum_UPD, Ev_t::enum_INS }, //ok
{ Ev_t::enum_DEL, Ev_t::enum_INS, Ev_t::enum_UPD }, //ok
- { Ev_t::enum_DEL, Ev_t::enum_DEL, Ev_t::enum_ERR },
+ { Ev_t::enum_DEL, Ev_t::enum_DEL, Ev_t::enum_IDM },
{ Ev_t::enum_DEL, Ev_t::enum_UPD, Ev_t::enum_ERR },
{ Ev_t::enum_UPD, Ev_t::enum_INS, Ev_t::enum_ERR },
{ Ev_t::enum_UPD, Ev_t::enum_DEL, Ev_t::enum_DEL }, //ok
@@ -2010,6 +2011,34 @@ NdbEventBuffer::merge_data(const SubTableData * const sdata,
}
assert(tp != 0 && tp->t3 != Ev_t::enum_ERR);
+ if (tp->t3 == Ev_t::enum_IDM) {
+ LinearSectionPtr (&ptr1)[3] = data->ptr;
+
+ /*
+ * TODO
+ * - can get data in INS ptr2[2] which is supposed to be empty
+ * - can get extra data in DEL ptr2[2]
+ * - why does DBUG_PRINT not work in this file ???
+ *
+ * replication + bug#19872 can ignore this since merge is on
+ * only for tables with explicit PK and before data is not used
+ */
+ const int maxsec = 1; // ignore section 2
+
+ int i;
+ for (i = 0; i <= maxsec; i++) {
+ if (ptr1[i].sz != ptr2[i].sz ||
+ memcmp(ptr1[i].p, ptr2[i].p, ptr1[i].sz << 2) != 0) {
+ DBUG_PRINT("info", ("idempotent op %d*%d data differs in sec %d",
+ tp->t1, tp->t2, i));
+ assert(false);
+ DBUG_RETURN_EVENT(-1);
+ }
+ }
+ DBUG_PRINT("info", ("idempotent op %d*%d data ok", tp->t1, tp->t2));
+ DBUG_RETURN_EVENT(0);
+ }
+
// save old data
EventBufData olddata = *data;
data->memory = 0;
diff --git a/storage/ndb/test/ndbapi/test_event.cpp b/storage/ndb/test/ndbapi/test_event.cpp
index 2f2a28fbff2..d8939f06b14 100644
--- a/storage/ndb/test/ndbapi/test_event.cpp
+++ b/storage/ndb/test/ndbapi/test_event.cpp
@@ -25,7 +25,8 @@
#define GETNDB(ps) ((NDBT_NdbApiStep*)ps)->getNdb()
-static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab)
+static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab,
+ bool merge_events = false)
{
char eventName[1024];
sprintf(eventName,"%s_EVENT",tab.getName());
@@ -45,6 +46,7 @@ static int createEvent(Ndb *pNdb, const NdbDictionary::Table &tab)
for(int a = 0; a < tab.getNoOfColumns(); a++){
myEvent.addEventColumn(a);
}
+ myEvent.mergeEvents(merge_events);
int res = myDict->createEvent(myEvent); // Add event to database
@@ -137,7 +139,8 @@ NdbEventOperation *createEventOperation(Ndb *ndb,
static int runCreateEvent(NDBT_Context* ctx, NDBT_Step* step)
{
- if (createEvent(GETNDB(step),* ctx->getTab()) != 0){
+ bool merge_events = ctx->getProperty("MergeEvents");
+ if (createEvent(GETNDB(step),* ctx->getTab(), merge_events) != 0){
return NDBT_FAILED;
}
return NDBT_OK;
@@ -584,6 +587,8 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step)
g_err << "Event operation creation failed on %s" << buf << endl;
DBUG_RETURN(NDBT_FAILED);
}
+ bool merge_events = ctx->getProperty("MergeEvents");
+ pOp->mergeEvents(merge_events);
int i;
int n_columns= table->getNoOfColumns();
@@ -616,6 +621,11 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step)
while ((pOp= ndb->nextEvent()) != 0)
{
assert(pOp == pCreate);
+
+ if (pOp->getEventType() >=
+ NdbDictionary::Event::TE_FIRST_NON_DATA_EVENT)
+ continue;
+
int noRetries= 0;
do
{
@@ -640,7 +650,7 @@ int runEventApplier(NDBT_Context* ctx, NDBT_Step* step)
goto end;
}
-
+
switch (pOp->getEventType()) {
case NdbDictionary::Event::TE_INSERT:
if (op->writeTuple())
@@ -1607,6 +1617,33 @@ TESTCASE("EventOperationApplier_NR",
FINALIZER(runVerify);
FINALIZER(runDropShadowTable);
}
+TESTCASE("MergeEventOperationApplier",
+ "Verify that if we apply the data we get from merged event "
+ "operation is the same as the original table"
+ "NOTE! No errors are allowed!" ){
+ TC_PROPERTY("MergeEvents", 1);
+ INITIALIZER(runCreateEvent);
+ INITIALIZER(runCreateShadowTable);
+ STEP(runEventApplier);
+ STEP(runEventMixedLoad);
+ FINALIZER(runDropEvent);
+ FINALIZER(runVerify);
+ FINALIZER(runDropShadowTable);
+}
+TESTCASE("MergeEventOperationApplier_NR",
+ "Verify that if we apply the data we get from merged event "
+ "operation is the same as the original table"
+ "NOTE! No errors are allowed!" ){
+ TC_PROPERTY("MergeEvents", 1);
+ INITIALIZER(runCreateEvent);
+ INITIALIZER(runCreateShadowTable);
+ STEP(runEventApplier);
+ STEP(runEventMixedLoad);
+ STEP(runRestarter);
+ FINALIZER(runDropEvent);
+ FINALIZER(runVerify);
+ FINALIZER(runDropShadowTable);
+}
TESTCASE("Multi",
"Verify that we can work with all tables in parallell"
"NOTE! HugoOperations::startTransaction, pTrans != NULL errors, "
diff --git a/storage/ndb/test/run-test/daily-devel-tests.txt b/storage/ndb/test/run-test/daily-devel-tests.txt
index 1a3a87fbc6e..75b85ebb1d2 100644
--- a/storage/ndb/test/run-test/daily-devel-tests.txt
+++ b/storage/ndb/test/run-test/daily-devel-tests.txt
@@ -216,6 +216,11 @@ args: -n EventOperationApplier_NR -l 2
#
max-time: 2500
cmd: test_event
+args: -n MergeEventOperationApplier_NR -l 2
+
+#
+max-time: 2500
+cmd: test_event
args: -n Multi
#