Bug #22633 partitioned tables with DATA DIRECTORY option fail to change engine
Submitted: 23 Sep 2006 22:52 Modified: 16 Oct 2007 13:14
Reporter: Giuseppe Maxia Email Updates:
Status: Not a Bug Impact on me:
None 
Category:MySQL Server: Partitions Severity:S2 (Serious)
Version:5.1.12 OS:Linux (Linux)
Assigned to: Mikael Ronström CPU Architecture:Any
Tags: data directory, partitioning

[23 Sep 2006 22:52] Giuseppe Maxia
Description:
Using the "DATA DIRECTORY" option on a partitioned table may cause a conversion error when changing to a different storage engine, if the source table was not MyISAM or ARCHIVE.
The documentation is vague about the applicability of the "DATA|INDEX DIRECTORY" option. In practice, it applies to both MyISAM and Archive engines, but other storage engines accept the option without complaining.
The trouble happens when converting the table to a storage engine that actually supports this option.

For example, defining a non-existant date directory for a InnoDB table 
will create the table. The only complain happens if the data directory difinition does not start with a '/'.

Given a system where the data directory is '/usr/local/mysql/data' and the paths '/usr/local/mysql/data/test/x0' and '/usr/local/mysql/data/test/x1' actually exist, a Innodb partitioned table referring to '/usr/local/mysql/data/test/x1' will be converted to MyISAM without errors. 
If the data directory option refers to '/not_existing/usr/local/mysql/data/test/x1', then the conversion will fail.

--------------
select version()
--------------

+-------------------+
| version()         |
+-------------------+
| 5.1.12-beta-debug |
+-------------------+
1 row in set (0.00 sec)

--------------
create schema if not exists test
--------------

Query OK, 0 rows affected, 1 warning (0.00 sec)

Note (Code 1007): Can't create database 'test'; database exists
--------------
drop table if exists t1, t2, t3
--------------

Query OK, 0 rows affected, 1 warning (0.07 sec)

Note (Code 1051): Unknown table 't3'
--------------
create table t1 (id int not null primary key) engine = innodb partition by range (id)
(
    partition p0 values less than (1000)
        data directory =  '/not_existing/usr/local/mysql/data/test/',
    partition p1 values less than (2000)
        data directory =  '/not_existing/usr/local/mysql/data/test/',
    partition p2 values less than (MAXVALUE)
)
--------------

Query OK, 0 rows affected (0.35 sec)

--------------
create table t2 (id int not null primary key) engine = innodb partition by range (id)
(
    partition p0 values less than (1000)
        data directory =  '/usr/local/mysql/data/test/x0',
    partition p1 values less than (2000)
        data directory =  '/usr/local/mysql/data/test/x1',
    partition p2 values less than (MAXVALUE)
)
--------------

Query OK, 0 rows affected (0.38 sec)

--------------
show tables
--------------

+----------------+
| Tables_in_test |
+----------------+
| t1             |
| t2             |
+----------------+
2 rows in set (0.00 sec)

--------------
show create table t1
--------------

*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (1000) DATA DIRECTORY = '/not_existing/usr/local/mysql/data/test/' ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (2000) DATA DIRECTORY = '/not_existing/usr/local/mysql/data/test/' ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.01 sec)

--------------
show create table t2
--------------

*************************** 1. row ***************************
       Table: t2
Create Table: CREATE TABLE `t2` (
  `id` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 /*!50100 PARTITION BY RANGE (id) (PARTITION p0 VALUES LESS THAN (1000) DATA DIRECTORY = '/usr/local/mysql/data/test/x0' ENGINE = InnoDB, PARTITION p1 VALUES LESS THAN (2000) DATA DIRECTORY = '/usr/local/mysql/data/test/x1' ENGINE = InnoDB, PARTITION p2 VALUES LESS THAN MAXVALUE ENGINE = InnoDB) */
1 row in set (0.00 sec)

--------------
alter table t2 engine=archive
--------------

ERROR 1005 (HY000) at line 30: Can't create table 'test.#sql-4a4c_17' (errno: 1)
--------------
alter table t1 engine=myisam
--------------

ERROR 1 (HY000) at line 31: Can't create/write to file '/not_existing/usr/local/mysql/data/test/#sql-4a4c_17#P#p0.MYD' (Errcode: 2)

How to repeat:
select version();
create schema if not exists test;
use test;

drop table if exists t1, t2, t3;

create table t1 (id int not null primary key) engine = innodb partition by range (id)
(
    partition p0 values less than (1000)
        data directory =  '/not_existing/usr/local/mysql/data/test/',
    partition p1 values less than (2000)
        data directory =  '/not_existing/usr/local/mysql/data/test/',
    partition p2 values less than (MAXVALUE)
)
;
create table t2 (id int not null primary key) engine = innodb partition by range (id)
(
    partition p0 values less than (1000)
        data directory =  '/usr/local/mysql/data/test/x0',
    partition p1 values less than (2000)
        data directory =  '/usr/local/mysql/data/test/x1',
    partition p2 values less than (MAXVALUE)
)
;

show tables;
show create table t1\G
show create table t2\G

alter table t2 engine=archive;
alter table t1 engine=myisam;
show create table t1\G
show create table t2\G

Suggested fix:
Storage engines that don't use the 'DATA|INDEX DIRECTORY' option should not accept it when the table is created.
Check for DATA|INDEX DIRECTORY names should be more robust than just looking for the first character.
[25 Sep 2006 10:05] Valeriy Kravchuk
Thank you for a bug report. Verified just as described with 5.1.12-BK (ChangeSet@1.1810.1697.161, 2006-09-25 01:32:55+02:00) on Linux.
[15 Oct 2007 14:03] Mikael Ronström
What's the bug?
If you have a DATA DIRECTORY this is ignored a la so many other things in MySQL if not
supported by the storage engine.
If you need to change to a storage engine that supports DATA DIRECTORY but don't want the
DATA DIRECTORY to have effect then you simply have to do a proper ALTER TABLE.
[15 Oct 2007 14:37] Giuseppe Maxia
The bug is that an engine is storing the (wrong) information that it should ignore.
If the engine were ignoring it, there would be no bug when converting from InnoDB to MyIsam or Archive. 
So the bad information should either be checked for correctness or discarded. Storing it and waiting for trouble to happen is not the right thing to do.
[2 Dec 2007 22:56] Baron Schwartz
This limitation should at least be noted in the manual section on partitioning limitations.  It is mentioned elsewhere (http://dev.mysql.com/doc/refman/5.1/en/partitioning-overview.html) but isn't easy to find if you click on the "limitations" link, where you'd expect it to be:

"The DATA DIRECTORY and INDEX DIRECTORY options have no effect when defining partitions for tables using the InnoDB  storage engine."