Skip to content

Commit 8e4c36a

Browse files
author
ingo/istruewing@chilla.local
committed
Bug#18775 - Temporary table from alter table visible to other threads
Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
1 parent ddcb190 commit 8e4c36a

25 files changed

+503
-160
lines changed

mysql-test/r/alter_table.result

+60
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,63 @@ SELECT * FROM t1;
657657
v b
658658
abc 5
659659
DROP TABLE t1;
660+
DROP DATABASE IF EXISTS mysqltest;
661+
CREATE DATABASE mysqltest;
662+
use mysqltest;
663+
DROP TABLE IF EXISTS `t1_n�gel`, `t1_bl�ten`;
664+
CREATE TABLE `t1_n�gel` (c1 INT);
665+
ALTER TABLE `t1_n�gel` RENAME `t1_bl�ten`;
666+
CREATE TABLE `t1_n�gel` (c1 INT);
667+
ALTER TABLE `t1_n�gel` RENAME `t1_bl�ten`;
668+
ERROR 42S01: Table 't1_blЭten' already exists
669+
DROP TABLE `t1_n�gel`, `t1_bl�ten`;
670+
CREATE TEMPORARY TABLE `tt1_n�gel` (c1 INT);
671+
ALTER TABLE `tt1_n�gel` RENAME `tt1_bl�ten`;
672+
CREATE TEMPORARY TABLE `tt1_n�gel` (c1 INT);
673+
ALTER TABLE `tt1_n�gel` RENAME `tt1_bl�ten`;
674+
ERROR 42S01: Table 'tt1_blЭten' already exists
675+
SHOW CREATE TABLE `tt1_bl�ten`;
676+
Table Create Table
677+
tt1_bl�ten CREATE TEMPORARY TABLE `tt1_bl�ten` (
678+
`c1` int(11) DEFAULT NULL
679+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
680+
DROP TABLE `tt1_n�gel`, `tt1_bl�ten`;
681+
CREATE TABLE `#sql1` (c1 INT);
682+
CREATE TABLE `@0023sql2` (c1 INT);
683+
SHOW TABLES;
684+
Tables_in_mysqltest
685+
#sql1
686+
@0023sql2
687+
RENAME TABLE `#sql1` TO `@0023sql1`;
688+
RENAME TABLE `@0023sql2` TO `#sql2`;
689+
SHOW TABLES;
690+
Tables_in_mysqltest
691+
#sql2
692+
@0023sql1
693+
ALTER TABLE `@0023sql1` RENAME `#sql-1`;
694+
ALTER TABLE `#sql2` RENAME `@0023sql-2`;
695+
SHOW TABLES;
696+
Tables_in_mysqltest
697+
#sql-1
698+
@0023sql-2
699+
INSERT INTO `#sql-1` VALUES (1);
700+
INSERT INTO `@0023sql-2` VALUES (2);
701+
DROP TABLE `#sql-1`, `@0023sql-2`;
702+
CREATE TEMPORARY TABLE `#sql1` (c1 INT);
703+
CREATE TEMPORARY TABLE `@0023sql2` (c1 INT);
704+
SHOW TABLES;
705+
Tables_in_mysqltest
706+
ALTER TABLE `#sql1` RENAME `@0023sql1`;
707+
ALTER TABLE `@0023sql2` RENAME `#sql2`;
708+
SHOW TABLES;
709+
Tables_in_mysqltest
710+
INSERT INTO `#sql2` VALUES (1);
711+
INSERT INTO `@0023sql1` VALUES (2);
712+
SHOW CREATE TABLE `@0023sql1`;
713+
Table Create Table
714+
@0023sql1 CREATE TEMPORARY TABLE `@0023sql1` (
715+
`c1` int(11) DEFAULT NULL
716+
) ENGINE=MyISAM DEFAULT CHARSET=latin1
717+
DROP TABLE `#sql2`, `@0023sql1`;
718+
use test;
719+
DROP DATABASE mysqltest;

mysql-test/r/backup.result

+20
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,23 @@ test.t5 backup status OK
101101
Warnings:
102102
Warning 1541 The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
103103
drop table t5;
104+
DROP TABLE IF EXISTS `t-bl�ten`;
105+
CREATE TABLE `t-bl�ten` (c1 INT);
106+
INSERT INTO `t-bl�ten` VALUES (1), (2), (3);
107+
BACKUP TABLE `t-bl�ten` TO '../tmp';
108+
Table Op Msg_type Msg_text
109+
test.t-bl�ten backup status OK
110+
Warnings:
111+
Warning 1541 The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
112+
DROP TABLE `t-bl�ten`;
113+
RESTORE TABLE `t-bl�ten` FROM '../tmp';
114+
Table Op Msg_type Msg_text
115+
test.t-bl�ten restore status OK
116+
Warnings:
117+
Warning 1541 The syntax 'RESTORE TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead.
118+
SELECT * FROM `t-bl�ten`;
119+
c1
120+
1
121+
2
122+
3
123+
DROP TABLE `t-bl�ten`;

mysql-test/r/repair.result

+6
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,9 @@ Table Op Msg_type Msg_text
4141
test.t1 repair warning Number of rows changed from 0 to 1
4242
test.t1 repair status OK
4343
drop table t1;
44+
DROP TABLE IF EXISTS tt1;
45+
CREATE TEMPORARY TABLE tt1 (c1 INT);
46+
REPAIR TABLE tt1 USE_FRM;
47+
Table Op Msg_type Msg_text
48+
tt1 repair error Cannot repair temporary table from .frm file
49+
DROP TABLE tt1;

mysql-test/t/alter_table.test

+63
Original file line numberDiff line numberDiff line change
@@ -482,3 +482,66 @@ SELECT * FROM t1;
482482
ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4);
483483
SELECT * FROM t1;
484484
DROP TABLE t1;
485+
486+
# End of 5.0 tests
487+
488+
#
489+
# Bug#18775 - Temporary table from alter table visible to other threads
490+
#
491+
# Use a special database to avoid name clashes with user tables.
492+
--disable_warnings
493+
DROP DATABASE IF EXISTS mysqltest;
494+
--enable_warnings
495+
CREATE DATABASE mysqltest;
496+
use mysqltest;
497+
#
498+
# Check if non-ASCII alphabetic characters work and duplicates are detected.
499+
--disable_warnings
500+
DROP TABLE IF EXISTS `t1_n�gel`, `t1_bl�ten`;
501+
--enable_warnings
502+
CREATE TABLE `t1_n�gel` (c1 INT);
503+
ALTER TABLE `t1_n�gel` RENAME `t1_bl�ten`;
504+
CREATE TABLE `t1_n�gel` (c1 INT);
505+
--error ER_TABLE_EXISTS_ERROR
506+
ALTER TABLE `t1_n�gel` RENAME `t1_bl�ten`;
507+
DROP TABLE `t1_n�gel`, `t1_bl�ten`;
508+
#
509+
# Same for temporary tables though these names do not become file names.
510+
CREATE TEMPORARY TABLE `tt1_n�gel` (c1 INT);
511+
ALTER TABLE `tt1_n�gel` RENAME `tt1_bl�ten`;
512+
CREATE TEMPORARY TABLE `tt1_n�gel` (c1 INT);
513+
--error ER_TABLE_EXISTS_ERROR
514+
ALTER TABLE `tt1_n�gel` RENAME `tt1_bl�ten`;
515+
SHOW CREATE TABLE `tt1_bl�ten`;
516+
DROP TABLE `tt1_n�gel`, `tt1_bl�ten`;
517+
#
518+
# Check if special characters as in tmp_file_prefix work.
519+
CREATE TABLE `#sql1` (c1 INT);
520+
CREATE TABLE `@0023sql2` (c1 INT);
521+
SHOW TABLES;
522+
RENAME TABLE `#sql1` TO `@0023sql1`;
523+
RENAME TABLE `@0023sql2` TO `#sql2`;
524+
SHOW TABLES;
525+
ALTER TABLE `@0023sql1` RENAME `#sql-1`;
526+
ALTER TABLE `#sql2` RENAME `@0023sql-2`;
527+
SHOW TABLES;
528+
INSERT INTO `#sql-1` VALUES (1);
529+
INSERT INTO `@0023sql-2` VALUES (2);
530+
DROP TABLE `#sql-1`, `@0023sql-2`;
531+
#
532+
# Same for temporary tables though these names do not become file names.
533+
CREATE TEMPORARY TABLE `#sql1` (c1 INT);
534+
CREATE TEMPORARY TABLE `@0023sql2` (c1 INT);
535+
SHOW TABLES;
536+
ALTER TABLE `#sql1` RENAME `@0023sql1`;
537+
ALTER TABLE `@0023sql2` RENAME `#sql2`;
538+
SHOW TABLES;
539+
INSERT INTO `#sql2` VALUES (1);
540+
INSERT INTO `@0023sql1` VALUES (2);
541+
SHOW CREATE TABLE `@0023sql1`;
542+
DROP TABLE `#sql2`, `@0023sql1`;
543+
#
544+
# Cleanup
545+
use test;
546+
DROP DATABASE mysqltest;
547+

mysql-test/t/backup.test

+19
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,22 @@ drop table t5;
5858
--system rm $MYSQLTEST_VARDIR/tmp/t?.*
5959

6060
# End of 4.1 tests
61+
# End of 5.0 tests
62+
63+
#
64+
# Bug#18775 - Temporary table from alter table visible to other threads
65+
#
66+
# Backup did not encode table names.
67+
--disable_warnings
68+
DROP TABLE IF EXISTS `t-bl�ten`;
69+
--enable_warnings
70+
CREATE TABLE `t-bl�ten` (c1 INT);
71+
INSERT INTO `t-bl�ten` VALUES (1), (2), (3);
72+
BACKUP TABLE `t-bl�ten` TO '../tmp';
73+
DROP TABLE `t-bl�ten`;
74+
#
75+
# Same for restore.
76+
RESTORE TABLE `t-bl�ten` FROM '../tmp';
77+
SELECT * FROM `t-bl�ten`;
78+
DROP TABLE `t-bl�ten`;
79+

mysql-test/t/repair.test

+13
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,16 @@ repair table t1 use_frm;
3535
drop table t1;
3636

3737
# End of 4.1 tests
38+
# End of 5.0 tests
39+
40+
#
41+
# Bug#18775 - Temporary table from alter table visible to other threads
42+
#
43+
# REPAIR TABLE ... USE_FRM on temporary table crashed the table or server.
44+
--disable_warnings
45+
DROP TABLE IF EXISTS tt1;
46+
--enable_warnings
47+
CREATE TEMPORARY TABLE tt1 (c1 INT);
48+
REPAIR TABLE tt1 USE_FRM;
49+
DROP TABLE tt1;
50+

sql/ha_myisam.cc

+8-2
Original file line numberDiff line numberDiff line change
@@ -464,11 +464,14 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
464464
HA_CHECK_OPT tmp_check_opt;
465465
char *backup_dir= thd->lex->backup_dir;
466466
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
467-
const char *table_name= table->s->table_name.str;
467+
char table_name[FN_REFLEN];
468468
int error;
469469
const char* errmsg;
470470
DBUG_ENTER("restore");
471471

472+
VOID(tablename_to_filename(table->s->table_name.str, table_name,
473+
sizeof(table_name)));
474+
472475
if (fn_format_relative_to_data_home(src_path, table_name, backup_dir,
473476
MI_NAME_DEXT))
474477
DBUG_RETURN(HA_ADMIN_INVALID);
@@ -504,11 +507,14 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
504507
{
505508
char *backup_dir= thd->lex->backup_dir;
506509
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
507-
const char *table_name= table->s->table_name.str;
510+
char table_name[FN_REFLEN];
508511
int error;
509512
const char *errmsg;
510513
DBUG_ENTER("ha_myisam::backup");
511514

515+
VOID(tablename_to_filename(table->s->table_name.str, table_name,
516+
sizeof(table_name)));
517+
512518
if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir,
513519
reg_ext))
514520
{

sql/ha_myisammrg.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form,
473473
an embedded server without changing the paths in the .MRG file.
474474
*/
475475
uint length= build_table_filename(buff, sizeof(buff),
476-
tables->db, tables->table_name, "");
476+
tables->db, tables->table_name, "", 0);
477477
/*
478478
If a MyISAM table is in the same directory as the MERGE table,
479479
we use the table name without a path. This means that the

sql/ha_ndbcluster.cc

+7-7
Original file line numberDiff line numberDiff line change
@@ -5795,7 +5795,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name,
57955795
DBUG_RETURN(HA_ERR_NO_CONNECTION);
57965796
ndb->setDatabaseName(db);
57975797
NDBDICT* dict= ndb->getDictionary();
5798-
build_table_filename(key, sizeof(key), db, name, "");
5798+
build_table_filename(key, sizeof(key), db, name, "", 0);
57995799
NDB_SHARE *share= get_share(key, 0, false);
58005800
if (share && get_ndb_share_state(share) == NSS_ALTERED)
58015801
{
@@ -5938,7 +5938,7 @@ int ndbcluster_drop_database_impl(const char *path)
59385938
// Drop any tables belonging to database
59395939
char full_path[FN_REFLEN];
59405940
char *tmp= full_path +
5941-
build_table_filename(full_path, sizeof(full_path), dbname, "", "");
5941+
build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0);
59425942

59435943
ndb->setDatabaseName(dbname);
59445944
List_iterator_fast<char> it(drop_list);
@@ -6061,7 +6061,7 @@ int ndbcluster_find_all_files(THD *thd)
60616061

60626062
/* check if database exists */
60636063
char *end= key +
6064-
build_table_filename(key, sizeof(key), elmt.database, "", "");
6064+
build_table_filename(key, sizeof(key), elmt.database, "", "", 0);
60656065
if (my_access(key, F_OK))
60666066
{
60676067
/* no such database defined, skip table */
@@ -6204,7 +6204,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
62046204
}
62056205

62066206
// File is not in NDB, check for .ndb file with this name
6207-
build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext);
6207+
build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext, 0);
62086208
DBUG_PRINT("info", ("Check access for %s", name));
62096209
if (my_access(name, F_OK))
62106210
{
@@ -6229,7 +6229,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
62296229
/* setup logging to binlog for all discovered tables */
62306230
{
62316231
char *end, *end1= name +
6232-
build_table_filename(name, sizeof(name), db, "", "");
6232+
build_table_filename(name, sizeof(name), db, "", "", 0);
62336233
for (i= 0; i < ok_tables.records; i++)
62346234
{
62356235
file_name= (char*)hash_element(&ok_tables, i);
@@ -6251,7 +6251,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path,
62516251
file_name= hash_element(&ndb_tables, i);
62526252
if (!hash_search(&ok_tables, file_name, strlen(file_name)))
62536253
{
6254-
build_table_filename(name, sizeof(name), db, file_name, reg_ext);
6254+
build_table_filename(name, sizeof(name), db, file_name, reg_ext, 0);
62556255
if (my_access(name, F_OK))
62566256
{
62576257
DBUG_PRINT("info", ("%s must be discovered", file_name));
@@ -6802,7 +6802,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname,
68026802
NDB_SHARE *share;
68036803
DBUG_ENTER("ndb_get_commitcount");
68046804

6805-
build_table_filename(name, sizeof(name), dbname, tabname, "");
6805+
build_table_filename(name, sizeof(name), dbname, tabname, "", 0);
68066806
DBUG_PRINT("enter", ("name: %s", name));
68076807
pthread_mutex_lock(&ndbcluster_mutex);
68086808
if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables,

sql/ha_ndbcluster_binlog.cc

+7-6
Original file line numberDiff line numberDiff line change
@@ -737,7 +737,7 @@ static int ndbcluster_create_apply_status_table(THD *thd)
737737
*/
738738
{
739739
build_table_filename(buf, sizeof(buf),
740-
NDB_REP_DB, NDB_APPLY_TABLE, reg_ext);
740+
NDB_REP_DB, NDB_APPLY_TABLE, reg_ext, 0);
741741
my_delete(buf, MYF(0));
742742
}
743743

@@ -786,7 +786,7 @@ static int ndbcluster_create_schema_table(THD *thd)
786786
*/
787787
{
788788
build_table_filename(buf, sizeof(buf),
789-
NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext);
789+
NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext, 0);
790790
my_delete(buf, MYF(0));
791791
}
792792

@@ -1247,7 +1247,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share,
12471247
NDB_SCHEMA_OBJECT *ndb_schema_object;
12481248
{
12491249
char key[FN_REFLEN];
1250-
build_table_filename(key, sizeof(key), db, table_name, "");
1250+
build_table_filename(key, sizeof(key), db, table_name, "", 0);
12511251
ndb_schema_object= ndb_get_schema_object(key, TRUE, FALSE);
12521252
}
12531253

@@ -1577,7 +1577,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp,
15771577

15781578
DBUG_PRINT("info", ("Detected frm change of table %s.%s",
15791579
dbname, tabname));
1580-
build_table_filename(key, FN_LEN-1, dbname, tabname, NullS);
1580+
build_table_filename(key, FN_LEN-1, dbname, tabname, NullS, 0);
15811581
/*
15821582
If the frm of the altered table is different than the one on
15831583
disk then overwrite it with the new table definition
@@ -1775,7 +1775,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb,
17751775
case SOT_TRUNCATE_TABLE:
17761776
{
17771777
char key[FN_REFLEN];
1778-
build_table_filename(key, sizeof(key), schema->db, schema->name, "");
1778+
build_table_filename(key, sizeof(key),
1779+
schema->db, schema->name, "", 0);
17791780
NDB_SHARE *share= get_share(key, 0, FALSE, FALSE);
17801781
// invalidation already handled by binlog thread
17811782
if (!share || !share->op)
@@ -1979,7 +1980,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd,
19791980
{
19801981
enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type;
19811982
char key[FN_REFLEN];
1982-
build_table_filename(key, sizeof(key), schema->db, schema->name, "");
1983+
build_table_filename(key, sizeof(key), schema->db, schema->name, "", 0);
19831984
if (schema_type == SOT_CLEAR_SLOCK)
19841985
{
19851986
pthread_mutex_lock(&ndbcluster_mutex);

sql/ha_ndbcluster_binlog.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ typedef NdbDictionary::Index NDBINDEX;
2323
typedef NdbDictionary::Dictionary NDBDICT;
2424
typedef NdbDictionary::Event NDBEVENT;
2525

26-
#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix) || is_prefix(A, "@0023sql"))
26+
#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix))
2727

2828
extern ulong ndb_extra_logging;
2929

0 commit comments

Comments
 (0)