BUG#48265 - MRG_MYISAM problem (works in 5.0.85, does't
work in 5.1.40) MERGE engine fails to open child table from a different database if child table/database name contains characters that are subject for table name to filename encoding (WL1324). Another problem is that MERGE engine didn't properly open child table from the same database if child table name contains characters like '/', '#'. The problem was that table name to file name encoding was applied inconsistently: * On CREATE: encode table name + database name if child table is in different database; do not encode table name if child table is in the same database; * No decoding on open. With this fix child table/database names are always encoded on CREATE and decoded on open. Compatibility with older tables preserved. Along with this patch comes fix for SHOW CREATE TABLE, which used to show child table/database path instead of child table/database names.
This commit is contained in:
parent
29b7338736
commit
1a9c3717f1
@ -2219,4 +2219,71 @@ Trigger sql_mode SQL Original Statement character_set_client collation_connectio
|
|||||||
tr1 CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo() latin1 latin1_swedish_ci latin1_swedish_ci
|
tr1 CREATE DEFINER=`root`@`localhost` TRIGGER tr1 AFTER INSERT ON t3 FOR EACH ROW CALL foo() latin1 latin1_swedish_ci latin1_swedish_ci
|
||||||
DROP TRIGGER tr1;
|
DROP TRIGGER tr1;
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
#
|
||||||
|
# BUG#48265 - MRG_MYISAM problem (works in 5.0.85, does't work in 5.1.40)
|
||||||
|
#
|
||||||
|
CREATE DATABASE `test/1`;
|
||||||
|
CREATE TABLE `test/1`.`t/1`(a INT);
|
||||||
|
CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`test/1`.`t/1`)
|
||||||
|
DROP TABLE m1;
|
||||||
|
CREATE TABLE `test/1`.m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM `test/1`.m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE `test/1`.m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t/1`)
|
||||||
|
DROP TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.`t/1`;
|
||||||
|
CREATE TEMPORARY TABLE `test/1`.`t/1`(a INT);
|
||||||
|
CREATE TEMPORARY TABLE m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TEMPORARY TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`test/1`.`t/1`)
|
||||||
|
DROP TABLE m1;
|
||||||
|
CREATE TEMPORARY TABLE `test/1`.m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM `test/1`.m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE `test/1`.m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TEMPORARY TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t/1`)
|
||||||
|
DROP TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.`t/1`;
|
||||||
|
DROP DATABASE `test/1`;
|
||||||
|
CREATE TABLE `t@1`(a INT);
|
||||||
|
SELECT * FROM m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`t@1`)
|
||||||
|
DROP TABLE `t@1`;
|
||||||
|
CREATE DATABASE `test@1`;
|
||||||
|
CREATE TABLE `test@1`.`t@1`(a INT);
|
||||||
|
FLUSH TABLE m1;
|
||||||
|
SELECT * FROM m1;
|
||||||
|
a
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
Table Create Table
|
||||||
|
m1 CREATE TABLE `m1` (
|
||||||
|
`a` int(11) DEFAULT NULL
|
||||||
|
) ENGINE=MRG_MyISAM DEFAULT CHARSET=latin1 UNION=(`test@1`.`t@1`)
|
||||||
|
DROP TABLE m1;
|
||||||
|
DROP TABLE `test@1`.`t@1`;
|
||||||
|
DROP DATABASE `test@1`;
|
||||||
End of 5.1 tests
|
End of 5.1 tests
|
||||||
|
BIN
mysql-test/std_data/bug48265.frm
Normal file
BIN
mysql-test/std_data/bug48265.frm
Normal file
Binary file not shown.
@ -7,6 +7,8 @@ drop table if exists t1,t2,t3,t4,t5,t6;
|
|||||||
drop database if exists mysqltest;
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||||
|
|
||||||
create table t1 (a int not null primary key auto_increment, message char(20));
|
create table t1 (a int not null primary key auto_increment, message char(20));
|
||||||
create table t2 (a int not null primary key auto_increment, message char(20));
|
create table t2 (a int not null primary key auto_increment, message char(20));
|
||||||
INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
|
INSERT INTO t1 (message) VALUES ("Testing"),("table"),("t1");
|
||||||
@ -1633,4 +1635,59 @@ SHOW CREATE TRIGGER tr1;
|
|||||||
DROP TRIGGER tr1;
|
DROP TRIGGER tr1;
|
||||||
DROP TABLE t1, t2, t3;
|
DROP TABLE t1, t2, t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # BUG#48265 - MRG_MYISAM problem (works in 5.0.85, does't work in 5.1.40)
|
||||||
|
--echo #
|
||||||
|
CREATE DATABASE `test/1`;
|
||||||
|
|
||||||
|
CREATE TABLE `test/1`.`t/1`(a INT);
|
||||||
|
CREATE TABLE m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM m1;
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
DROP TABLE m1;
|
||||||
|
|
||||||
|
CREATE TABLE `test/1`.m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM `test/1`.m1;
|
||||||
|
SHOW CREATE TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.`t/1`;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE `test/1`.`t/1`(a INT);
|
||||||
|
CREATE TEMPORARY TABLE m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM m1;
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
DROP TABLE m1;
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE `test/1`.m1(a INT) ENGINE=MERGE UNION=(`test/1`.`t/1`);
|
||||||
|
SELECT * FROM `test/1`.m1;
|
||||||
|
SHOW CREATE TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.m1;
|
||||||
|
DROP TABLE `test/1`.`t/1`;
|
||||||
|
|
||||||
|
DROP DATABASE `test/1`;
|
||||||
|
|
||||||
|
# Test compatibility. Use '@' instead of '/' (was not allowed in 5.0)
|
||||||
|
|
||||||
|
CREATE TABLE `t@1`(a INT);
|
||||||
|
copy_file std_data/bug48265.frm $MYSQLD_DATADIR/test/m1.frm;
|
||||||
|
write_file $MYSQLD_DATADIR/test/m1.MRG;
|
||||||
|
t@1
|
||||||
|
EOF
|
||||||
|
SELECT * FROM m1;
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
DROP TABLE `t@1`;
|
||||||
|
|
||||||
|
CREATE DATABASE `test@1`;
|
||||||
|
CREATE TABLE `test@1`.`t@1`(a INT);
|
||||||
|
FLUSH TABLE m1;
|
||||||
|
remove_file $MYSQLD_DATADIR/test/m1.MRG;
|
||||||
|
write_file $MYSQLD_DATADIR/test/m1.MRG;
|
||||||
|
./test@1/t@1
|
||||||
|
EOF
|
||||||
|
SELECT * FROM m1;
|
||||||
|
SHOW CREATE TABLE m1;
|
||||||
|
DROP TABLE m1;
|
||||||
|
DROP TABLE `test@1`.`t@1`;
|
||||||
|
DROP DATABASE `test@1`;
|
||||||
|
|
||||||
--echo End of 5.1 tests
|
--echo End of 5.1 tests
|
||||||
|
@ -214,36 +214,14 @@ const char *ha_myisammrg::index_type(uint key_number)
|
|||||||
static int myisammrg_parent_open_callback(void *callback_param,
|
static int myisammrg_parent_open_callback(void *callback_param,
|
||||||
const char *filename)
|
const char *filename)
|
||||||
{
|
{
|
||||||
ha_myisammrg *ha_myrg;
|
ha_myisammrg *ha_myrg= (ha_myisammrg*) callback_param;
|
||||||
TABLE *parent;
|
TABLE *parent= ha_myrg->table_ptr();
|
||||||
TABLE_LIST *child_l;
|
TABLE_LIST *child_l;
|
||||||
const char *db;
|
|
||||||
const char *table_name;
|
|
||||||
size_t dirlen;
|
size_t dirlen;
|
||||||
char dir_path[FN_REFLEN];
|
char dir_path[FN_REFLEN];
|
||||||
|
char name_buf[NAME_LEN];
|
||||||
DBUG_ENTER("myisammrg_parent_open_callback");
|
DBUG_ENTER("myisammrg_parent_open_callback");
|
||||||
|
|
||||||
/* Extract child table name and database name from filename. */
|
|
||||||
dirlen= dirname_length(filename);
|
|
||||||
if (dirlen >= FN_REFLEN)
|
|
||||||
{
|
|
||||||
/* purecov: begin inspected */
|
|
||||||
DBUG_PRINT("error", ("name too long: '%.64s'", filename));
|
|
||||||
my_errno= ENAMETOOLONG;
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
/* purecov: end */
|
|
||||||
}
|
|
||||||
table_name= filename + dirlen;
|
|
||||||
dirlen--; /* Strip off trailing '/'. */
|
|
||||||
memcpy(dir_path, filename, dirlen);
|
|
||||||
dir_path[dirlen]= '\0';
|
|
||||||
db= base_name(dir_path);
|
|
||||||
dirlen-= db - dir_path; /* This is now the length of 'db'. */
|
|
||||||
DBUG_PRINT("myrg", ("open: '%s'.'%s'", db, table_name));
|
|
||||||
|
|
||||||
ha_myrg= (ha_myisammrg*) callback_param;
|
|
||||||
parent= ha_myrg->table_ptr();
|
|
||||||
|
|
||||||
/* Get a TABLE_LIST object. */
|
/* Get a TABLE_LIST object. */
|
||||||
if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root,
|
if (!(child_l= (TABLE_LIST*) alloc_root(&parent->mem_root,
|
||||||
sizeof(TABLE_LIST))))
|
sizeof(TABLE_LIST))))
|
||||||
@ -255,13 +233,69 @@ static int myisammrg_parent_open_callback(void *callback_param,
|
|||||||
}
|
}
|
||||||
bzero((char*) child_l, sizeof(TABLE_LIST));
|
bzero((char*) child_l, sizeof(TABLE_LIST));
|
||||||
|
|
||||||
/* Set database (schema) name. */
|
/*
|
||||||
child_l->db_length= dirlen;
|
Depending on MySQL version, filename may be encoded by table name to
|
||||||
child_l->db= strmake_root(&parent->mem_root, db, dirlen);
|
file name encoding or not. Always encoded if parent table is created
|
||||||
/* Set table name. */
|
by 5.1.46+. Encoded if parent is created by 5.1.6+ and child table is
|
||||||
child_l->table_name_length= strlen(table_name);
|
in different database.
|
||||||
child_l->table_name= strmake_root(&parent->mem_root, table_name,
|
*/
|
||||||
child_l->table_name_length);
|
if (!has_path(filename))
|
||||||
|
{
|
||||||
|
/* Child is in the same database as parent. */
|
||||||
|
child_l->db_length= parent->s->db.length;
|
||||||
|
child_l->db= strmake_root(&parent->mem_root, parent->s->db.str,
|
||||||
|
child_l->db_length);
|
||||||
|
/* Child table name is encoded in parent dot-MRG starting with 5.1.46. */
|
||||||
|
if (parent->s->mysql_version >= 50146)
|
||||||
|
{
|
||||||
|
child_l->table_name_length= filename_to_tablename(filename, name_buf,
|
||||||
|
sizeof(name_buf));
|
||||||
|
child_l->table_name= strmake_root(&parent->mem_root, name_buf,
|
||||||
|
child_l->table_name_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child_l->table_name_length= strlen(filename);
|
||||||
|
child_l->table_name= strmake_root(&parent->mem_root, filename,
|
||||||
|
child_l->table_name_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(strlen(filename) < sizeof(dir_path));
|
||||||
|
fn_format(dir_path, filename, "", "", 0);
|
||||||
|
/* Extract child table name and database name from filename. */
|
||||||
|
dirlen= dirname_length(dir_path);
|
||||||
|
/* Child db/table name is encoded in parent dot-MRG starting with 5.1.6. */
|
||||||
|
if (parent->s->mysql_version >= 50106)
|
||||||
|
{
|
||||||
|
child_l->table_name_length= filename_to_tablename(dir_path + dirlen,
|
||||||
|
name_buf,
|
||||||
|
sizeof(name_buf));
|
||||||
|
child_l->table_name= strmake_root(&parent->mem_root, name_buf,
|
||||||
|
child_l->table_name_length);
|
||||||
|
dir_path[dirlen - 1]= 0;
|
||||||
|
dirlen= dirname_length(dir_path);
|
||||||
|
child_l->db_length= filename_to_tablename(dir_path + dirlen, name_buf,
|
||||||
|
sizeof(name_buf));
|
||||||
|
child_l->db= strmake_root(&parent->mem_root, name_buf, child_l->db_length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
child_l->table_name_length= strlen(dir_path + dirlen);
|
||||||
|
child_l->table_name= strmake_root(&parent->mem_root, dir_path + dirlen,
|
||||||
|
child_l->table_name_length);
|
||||||
|
dir_path[dirlen - 1]= 0;
|
||||||
|
dirlen= dirname_length(dir_path);
|
||||||
|
child_l->db_length= strlen(dir_path + dirlen);
|
||||||
|
child_l->db= strmake_root(&parent->mem_root, dir_path + dirlen,
|
||||||
|
child_l->db_length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT("myrg", ("open: '%.*s'.'%.*s'", child_l->db_length, child_l->db,
|
||||||
|
child_l->table_name_length, child_l->table_name));
|
||||||
|
|
||||||
/* Convert to lowercase if required. */
|
/* Convert to lowercase if required. */
|
||||||
if (lower_case_table_names && child_l->table_name_length)
|
if (lower_case_table_names && child_l->table_name_length)
|
||||||
child_l->table_name_length= my_casedn_str(files_charset_info,
|
child_l->table_name_length= my_casedn_str(files_charset_info,
|
||||||
@ -1132,7 +1166,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
|
|||||||
/* Create child path names. */
|
/* Create child path names. */
|
||||||
for (pos= table_names; tables; tables= tables->next_local)
|
for (pos= table_names; tables; tables= tables->next_local)
|
||||||
{
|
{
|
||||||
const char *table_name;
|
const char *table_name= buff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Construct the path to the MyISAM table. Try to meet two conditions:
|
Construct the path to the MyISAM table. Try to meet two conditions:
|
||||||
@ -1158,10 +1192,12 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
|
|||||||
as the MyISAM tables are from the same database as the MERGE table.
|
as the MyISAM tables are from the same database as the MERGE table.
|
||||||
*/
|
*/
|
||||||
if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
|
if ((dirname_length(buff) == dirlgt) && ! memcmp(buff, name, dirlgt))
|
||||||
table_name= tables->table_name;
|
{
|
||||||
else
|
table_name+= dirlgt;
|
||||||
if (! (table_name= thd->strmake(buff, length)))
|
length-= dirlgt;
|
||||||
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
|
}
|
||||||
|
if (!(table_name= thd->strmake(table_name, length)))
|
||||||
|
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
|
||||||
|
|
||||||
*pos++= table_name;
|
*pos++= table_name;
|
||||||
}
|
}
|
||||||
@ -1182,7 +1218,7 @@ void ha_myisammrg::append_create_info(String *packet)
|
|||||||
const char *current_db;
|
const char *current_db;
|
||||||
size_t db_length;
|
size_t db_length;
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
MYRG_TABLE *open_table, *first;
|
TABLE_LIST *open_table, *first;
|
||||||
|
|
||||||
if (file->merge_insert_method != MERGE_INSERT_DISABLED)
|
if (file->merge_insert_method != MERGE_INSERT_DISABLED)
|
||||||
{
|
{
|
||||||
@ -1200,14 +1236,11 @@ void ha_myisammrg::append_create_info(String *packet)
|
|||||||
current_db= table->s->db.str;
|
current_db= table->s->db.str;
|
||||||
db_length= table->s->db.length;
|
db_length= table->s->db.length;
|
||||||
|
|
||||||
for (first=open_table=file->open_tables ;
|
for (first= open_table= table->child_l;;
|
||||||
open_table != file->end_table ;
|
open_table= open_table->next_global)
|
||||||
open_table++)
|
|
||||||
{
|
{
|
||||||
LEX_STRING db, name;
|
LEX_STRING db= { open_table->db, open_table->db_length };
|
||||||
LINT_INIT(db.str);
|
|
||||||
|
|
||||||
split_file_name(open_table->table->filename, &db, &name);
|
|
||||||
if (open_table != first)
|
if (open_table != first)
|
||||||
packet->append(',');
|
packet->append(',');
|
||||||
/* Report database for mapped table if it isn't in current database */
|
/* Report database for mapped table if it isn't in current database */
|
||||||
@ -1218,7 +1251,10 @@ void ha_myisammrg::append_create_info(String *packet)
|
|||||||
append_identifier(thd, packet, db.str, db.length);
|
append_identifier(thd, packet, db.str, db.length);
|
||||||
packet->append('.');
|
packet->append('.');
|
||||||
}
|
}
|
||||||
append_identifier(thd, packet, name.str, name.length);
|
append_identifier(thd, packet, open_table->table_name,
|
||||||
|
open_table->table_name_length);
|
||||||
|
if (&open_table->next_global == table->child_last_l)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
packet->append(')');
|
packet->append(')');
|
||||||
}
|
}
|
||||||
|
@ -311,14 +311,6 @@ MYRG_INFO *myrg_parent_open(const char *parent_name,
|
|||||||
if (!child_name_buff[0] || (child_name_buff[0] == '#'))
|
if (!child_name_buff[0] || (child_name_buff[0] == '#'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!has_path(child_name_buff))
|
|
||||||
{
|
|
||||||
VOID(strmake(parent_name_buff + dir_length, child_name_buff,
|
|
||||||
sizeof(parent_name_buff) - 1 - dir_length));
|
|
||||||
VOID(cleanup_dirname(child_name_buff, parent_name_buff));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
fn_format(child_name_buff, child_name_buff, "", "", 0);
|
|
||||||
DBUG_PRINT("info", ("child: '%s'", child_name_buff));
|
DBUG_PRINT("info", ("child: '%s'", child_name_buff));
|
||||||
|
|
||||||
/* Callback registers child with handler table. */
|
/* Callback registers child with handler table. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user