Merge c-0409e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/bug19122

into  c-0409e253.1238-1-64736c10.cust.bredbandsbolaget.se:/home/pappa/bug19305
parents 334a28f9 44076b96
...@@ -925,6 +925,17 @@ create index inx1 on t1(a); ...@@ -925,6 +925,17 @@ create index inx1 on t1(a);
drop table t1; drop table t1;
create table t1 (a int) create table t1 (a int)
partition by key (a) 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); (partition p0 engine = MERGE);
ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables ERROR HY000: MyISAM Merge handler cannot be used in partitioned tables
create table t1 (a varchar(1)) create table t1 (a varchar(1))
......
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;
...@@ -387,3 +387,108 @@ ALTER TABLE t1 DROP PARTITION p0; ...@@ -387,3 +387,108 @@ ALTER TABLE t1 DROP PARTITION p0;
ALTER TABLE t1 DROP PARTITION p1; ALTER TABLE t1 DROP PARTITION p1;
ALTER TABLE t1 DROP PARTITION p2; ALTER TABLE t1 DROP PARTITION p2;
drop table t1; 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;
...@@ -1048,6 +1048,22 @@ show create table t1; ...@@ -1048,6 +1048,22 @@ show create table t1;
set session sql_mode=''; set session sql_mode='';
drop table t1; 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 # BUG 19304 Partitions: MERGE handler not allowed in partitioned tables
# #
......
-- 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
...@@ -416,3 +416,117 @@ ALTER TABLE t1 DROP PARTITION p0; ...@@ -416,3 +416,117 @@ ALTER TABLE t1 DROP PARTITION p0;
ALTER TABLE t1 DROP PARTITION p1; ALTER TABLE t1 DROP PARTITION p1;
ALTER TABLE t1 DROP PARTITION p2; ALTER TABLE t1 DROP PARTITION p2;
drop table t1; 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;
...@@ -828,7 +828,7 @@ int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list) ...@@ -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)) if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(1); DBUG_RETURN(1);
VOID(pthread_mutex_lock(&LOCK_open)); 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; goto end;
if (lock_retcode && wait_for_locked_table_names(thd, table_list)) if (lock_retcode && wait_for_locked_table_names(thd, table_list))
{ {
...@@ -851,6 +851,7 @@ end: ...@@ -851,6 +851,7 @@ end:
lock_table_name() lock_table_name()
thd Thread handler thd Thread handler
table_list Lock first table in this list table_list Lock first table in this list
check_in_use Do we need to check if table already in use by us
WARNING WARNING
If you are going to update the table, you should use If you are going to update the table, you should use
...@@ -870,7 +871,7 @@ end: ...@@ -870,7 +871,7 @@ end:
> 0 table locked, but someone is using it > 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; TABLE *table;
char key[MAX_DBKEY_LENGTH]; char key[MAX_DBKEY_LENGTH];
...@@ -882,17 +883,22 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list) ...@@ -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); key_length= create_table_def_key(thd, key, table_list, 0);
/* Only insert the table if we haven't insert it already */ if (check_in_use)
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 (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")); if (table->in_use == thd)
table->s->version= 0; // Ensure no one can use this {
table->locked_by_name= 1; DBUG_PRINT("info", ("Table is in use"));
DBUG_RETURN(0); 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) ...@@ -917,10 +923,10 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
my_free((gptr) table,MYF(0)); my_free((gptr) table,MYF(0));
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
/* Return 1 if table is in use */ /* Return 1 if table is in use */
DBUG_RETURN(test(remove_table_from_cache(thd, db, table_list->table_name, 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) ...@@ -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) for (lock_table= table_list; lock_table; lock_table= lock_table->next_local)
{ {
int got_lock; 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 goto end; // Fatal error
if (got_lock) if (got_lock)
got_all_locks=0; // Someone is using table got_all_locks=0; // Someone is using table
......
...@@ -1174,7 +1174,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -1174,7 +1174,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
TABLE_LIST *table_list, TABLE_LIST *table_list,
List<create_field> *create_list, List<create_field> *create_list,
List<Key> *key_list, const char *db, List<Key> *key_list, char *db,
const char *table_name, const char *table_name,
uint fast_alter_partition); uint fast_alter_partition);
uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info, uint prep_alter_part_table(THD *thd, TABLE *table, ALTER_INFO *alter_info,
...@@ -1204,6 +1204,7 @@ void create_subpartition_name(char *out, const char *in1, ...@@ -1204,6 +1204,7 @@ void create_subpartition_name(char *out, const char *in1,
typedef struct st_lock_param_type typedef struct st_lock_param_type
{ {
TABLE_LIST table_list;
ulonglong copied; ulonglong copied;
ulonglong deleted; ulonglong deleted;
THD *thd; THD *thd;
...@@ -1688,7 +1689,7 @@ void unset_protect_against_global_read_lock(void); ...@@ -1688,7 +1689,7 @@ void unset_protect_against_global_read_lock(void);
/* Lock based on name */ /* Lock based on name */
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list); 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); void unlock_table_name(THD *thd, TABLE_LIST *table_list);
bool wait_for_locked_table_names(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); bool lock_table_names(THD *thd, TABLE_LIST *table_list);
......
...@@ -2686,7 +2686,7 @@ retry: ...@@ -2686,7 +2686,7 @@ retry:
goto err; goto err;
// Code below is for repairing a crashed file // 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) if (error < 0)
goto err; goto err;
......
...@@ -5378,6 +5378,79 @@ static void release_log_entries(partition_info *part_info) ...@@ -5378,6 +5378,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 Handle errors for ALTER TABLE for partitioning
SYNOPSIS SYNOPSIS
...@@ -5528,7 +5601,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5528,7 +5601,7 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
TABLE_LIST *table_list, TABLE_LIST *table_list,
List<create_field> *create_list, List<create_field> *create_list,
List<Key> *key_list, const char *db, List<Key> *key_list, char *db,
const char *table_name, const char *table_name,
uint fast_alter_partition) uint fast_alter_partition)
{ {
...@@ -5669,8 +5742,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5669,8 +5742,17 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
2) Write the ddl log to ensure that the operation is completed 2) Write the ddl log to ensure that the operation is completed
even in the presence of a MySQL Server crash even in the presence of a MySQL Server crash
3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to 3) Lock the table in TL_WRITE_ONLY to ensure all other accesses to
the table have completed the table have completed. This ensures that other threads can not
4) Write the bin log 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 Unfortunately the writing of the binlog is not synchronised with
other logging activities. So no matter in which order the binlog other logging activities. So no matter in which order the binlog
is written compared to other activities there will always be cases is written compared to other activities there will always be cases
...@@ -5681,14 +5763,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5681,14 +5763,13 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
require writing the statement first in the ddl log and then require writing the statement first in the ddl log and then
when recovering from the crash read the binlog and insert it into when recovering from the crash read the binlog and insert it into
the binlog if not written already. the binlog if not written already.
5) Install the previously written shadow frm file 8) Install the previously written shadow frm file
6) Ensure that any users that has opened the table but not yet 9) Prepare handlers for drop of partitions
reached the abort lock do that before downgrading the lock. 10) Drop the partitions
7) Prepare MyISAM handlers for drop of partitions 11) Remove entries from ddl log
8) Drop the partitions 12) Release name lock so that all other threads can access the table
9) Remove entries from ddl log again.
10) Wait until all accesses using the old frm file has completed 13) Complete query
11) Complete query
We insert Error injections at all places where it could be interesting We insert Error injections at all places where it could be interesting
to test if recovery is properly done. to test if recovery is properly done.
...@@ -5701,22 +5782,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5701,22 +5782,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_drop_partition_3") || ERROR_INJECT_CRASH("crash_drop_partition_3") ||
(not_completed= FALSE) || (not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */ 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) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, (write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) || thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_drop_partition_4") || ERROR_INJECT_CRASH("crash_drop_partition_7") ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_5") ||
((frm_install= TRUE), FALSE) || ((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
((frm_install= FALSE), FALSE) || ((frm_install= FALSE), FALSE) ||
(close_open_tables_and_downgrade(lpt), FALSE) || ERROR_INJECT_CRASH("crash_drop_partition_8") ||
ERROR_INJECT_CRASH("crash_drop_partition_6") ||
mysql_drop_partitions(lpt) || mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_drop_partition_7") || ERROR_INJECT_CRASH("crash_drop_partition_9") ||
(write_log_completed(lpt, FALSE), FALSE) || (write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_drop_partition_8") || ERROR_INJECT_CRASH("crash_drop_partition_10") ||
(mysql_wait_completed_table(lpt, table), FALSE)) (release_name_lock(lpt), FALSE))
{ {
handle_alter_part_error(lpt, not_completed, TRUE, frm_install); handle_alter_part_error(lpt, not_completed, TRUE, frm_install);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -5742,15 +5825,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5742,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 3) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing. ongoing users have completed before progressing.
4) Write binlog 4) Get a name lock on the table. This ensures that we can release all
5) Now the change is completed except for the installation of the 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 new frm file. We thus write an action in the log to change to
the shadow frm file 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. added to the table.
7) Wait until all accesses using the old frm file has completed 10)Wait until all accesses using the old frm file has completed
8) Remove entries from ddl log 11)Remove entries from ddl log
9) Complete query 12)Release name lock
13)Complete query
*/ */
if (write_log_add_change_partition(lpt) || if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_1") || ERROR_INJECT_CRASH("crash_add_partition_1") ||
...@@ -5759,19 +5851,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5759,19 +5851,24 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
mysql_change_partitions(lpt) || mysql_change_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_add_partition_3") || ERROR_INJECT_CRASH("crash_add_partition_3") ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */ 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) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, (write_bin_log(thd, FALSE,
thd->query, thd->query_length), 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) || write_log_rename_frm(lpt) ||
(not_completed= FALSE) || (not_completed= FALSE) ||
ERROR_INJECT_CRASH("crash_add_partition_5") || ERROR_INJECT_CRASH("crash_add_partition_7") ||
((frm_install= TRUE), FALSE) || ((frm_install= TRUE), FALSE) ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_add_partition_6") || ERROR_INJECT_CRASH("crash_add_partition_8") ||
(close_open_tables_and_downgrade(lpt), FALSE) ||
(write_log_completed(lpt, FALSE), FALSE) || (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); handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -5821,16 +5918,20 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5821,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 5) Lock all partitions in TL_WRITE_ONLY to ensure that no users
are still using the old partitioning scheme. Wait until all are still using the old partitioning scheme. Wait until all
ongoing users have completed before progressing. ongoing users have completed before progressing.
6) Prepare MyISAM handlers for rename and delete of partitions 6) Get a name lock of the table
7) Rename the reorged partitions such that they are no longer 7) Close all tables opened but not yet locked, after this call we are
used and rename those added to their real new names. certain that no other thread is in the lock wait queue or has
8) Write bin log opened the table. The name lock will ensure that they are blocked
9) Install the shadow frm file on the open call. This is achieved also by get_name_lock call.
10) Wait until all accesses using the old frm file has completed 8) Close all partitions opened by this thread, but retain name lock.
11) Drop the reorganised partitions 9) Write bin log
12) Remove log entry 10) Prepare handlers for rename and delete of partitions
13)Wait until all accesses using the old frm file has completed 11) Rename and drop the reorged partitions such that they are no
14)Complete query 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) || if (write_log_add_change_partition(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_1") || ERROR_INJECT_CRASH("crash_change_partition_1") ||
...@@ -5842,24 +5943,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table, ...@@ -5842,24 +5943,25 @@ uint fast_alter_partition_table(THD *thd, TABLE *table,
ERROR_INJECT_CRASH("crash_change_partition_4") || ERROR_INJECT_CRASH("crash_change_partition_4") ||
(not_completed= FALSE) || (not_completed= FALSE) ||
abort_and_upgrade_lock(lpt) || /* Always returns 0 */ abort_and_upgrade_lock(lpt) || /* Always returns 0 */
ERROR_INJECT_CRASH("crash_change_partition_5") ||
get_name_lock(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_6") ||
alter_close_tables(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_7") ||
((!thd->lex->no_write_to_binlog) && ((!thd->lex->no_write_to_binlog) &&
(write_bin_log(thd, FALSE, (write_bin_log(thd, FALSE,
thd->query, thd->query_length), FALSE)) || thd->query, thd->query_length), FALSE)) ||
ERROR_INJECT_CRASH("crash_change_partition_5") || ERROR_INJECT_CRASH("crash_change_partition_8") ||
(table->file->extra(HA_EXTRA_PREPARE_FOR_DELETE), FALSE) || mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_6") || ERROR_INJECT_CRASH("crash_change_partition_9") ||
mysql_drop_partitions(lpt) || mysql_drop_partitions(lpt) ||
ERROR_INJECT_CRASH("crash_change_partition_61") || ERROR_INJECT_CRASH("crash_change_partition_10") ||
mysql_rename_partitions(lpt) || mysql_rename_partitions(lpt) ||
((frm_install= TRUE), FALSE) || ((frm_install= TRUE), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_7") || ERROR_INJECT_CRASH("crash_change_partition_11") ||
mysql_write_frm(lpt, WFRM_INSTALL_SHADOW) ||
ERROR_INJECT_CRASH("crash_change_partition_8") ||
(close_open_tables_and_downgrade(lpt), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_9") ||
(write_log_completed(lpt, FALSE), FALSE) || (write_log_completed(lpt, FALSE), FALSE) ||
ERROR_INJECT_CRASH("crash_change_partition_10") || ERROR_INJECT_CRASH("crash_change_partition_12") ||
(mysql_wait_completed_table(lpt, table), FALSE)) (release_name_lock(lpt), FALSE))
{ {
handle_alter_part_error(lpt, not_completed, FALSE, frm_install); handle_alter_part_error(lpt, not_completed, FALSE, frm_install);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment