diff options
author | unknown <patg@govinda.patg.net> | 2006-08-10 14:28:39 -0700 |
---|---|---|
committer | unknown <patg@govinda.patg.net> | 2006-08-10 14:28:39 -0700 |
commit | 58590b3a53e641fab894e754298732d5cd1ed954 (patch) | |
tree | 92c83b7c1575acee956bf483c14ac7fddb177aa9 | |
parent | 6c086377d8d1ea5b53a25f4dc3e1189e98c08a08 (diff) | |
parent | 375692973df6b71826a11f470cb6d521bfa16cc9 (diff) | |
download | mariadb-git-58590b3a53e641fab894e754298732d5cd1ed954.tar.gz |
Merge pgalbraith@bk-internal.mysql.com:/home/bk/mysql-5.1
into govinda.patg.net:/home/patg/mysql-build/mysql-5.1-engines-merge
sql/ha_myisam.cc:
Auto merged
sql/ha_myisammrg.cc:
Auto merged
sql/ha_ndbcluster.cc:
Auto merged
sql/mysql_priv.h:
Auto merged
sql/sql_acl.cc:
Auto merged
sql/sql_base.cc:
Auto merged
sql/sql_delete.cc:
Auto merged
sql/sql_insert.cc:
Auto merged
sql/sql_partition.cc:
Auto merged
sql/sql_show.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/sql_trigger.cc:
Auto merged
sql/sql_view.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
sql/table.cc:
Auto merged
storage/innobase/row/row0mysql.c:
Auto merged
32 files changed, 676 insertions, 192 deletions
diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index f4332ea9888..d3657d84678 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -657,3 +657,68 @@ SELECT * FROM t1; v b abc 5 DROP TABLE t1; +DROP TABLE IF EXISTS `t+1`, `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +ERROR 42S01: Table 't+2' already exists +DROP TABLE `t+1`, `t+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +ERROR 42S01: Table 'tt+2' already exists +SHOW CREATE TABLE `tt+1`; +Table Create Table +tt+1 CREATE TEMPORARY TABLE `tt+1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `tt+2`; +Table Create Table +tt+2 CREATE TEMPORARY TABLE `tt+2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `tt+1`, `tt+2`; +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +#sql1 +@0023sql2 +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +Tables_in_test +#sql2 +@0023sql1 +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +Tables_in_test +#sql-1 +@0023sql-2 +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +Tables_in_test +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +Tables_in_test +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +Table Create Table +#sql2 CREATE TEMPORARY TABLE `#sql2` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +SHOW CREATE TABLE `@0023sql1`; +Table Create Table +@0023sql1 CREATE TEMPORARY TABLE `@0023sql1` ( + `c1` int(11) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP TABLE `#sql2`, `@0023sql1`; diff --git a/mysql-test/r/backup.result b/mysql-test/r/backup.result index a65808bbdd6..a4d1b18fe61 100644 --- a/mysql-test/r/backup.result +++ b/mysql-test/r/backup.result @@ -101,3 +101,23 @@ test.t5 backup status OK Warnings: Warning 1541 The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead. drop table t5; +DROP TABLE IF EXISTS `t+1`; +CREATE TABLE `t+1` (c1 INT); +INSERT INTO `t+1` VALUES (1), (2), (3); +BACKUP TABLE `t+1` TO '../tmp'; +Table Op Msg_type Msg_text +test.t+1 backup status OK +Warnings: +Warning 1541 The syntax 'BACKUP TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead. +DROP TABLE `t+1`; +RESTORE TABLE `t+1` FROM '../tmp'; +Table Op Msg_type Msg_text +test.t+1 restore status OK +Warnings: +Warning 1541 The syntax 'RESTORE TABLE' is deprecated and will be removed in MySQL 5.2. Please use MySQL Administrator (mysqldump, mysql) instead. +SELECT * FROM `t+1`; +c1 +1 +2 +3 +DROP TABLE `t+1`; diff --git a/mysql-test/r/federated_transactions.result b/mysql-test/r/federated_transactions.result index 403b65b5484..e6714210ded 100644 --- a/mysql-test/r/federated_transactions.result +++ b/mysql-test/r/federated_transactions.result @@ -16,7 +16,7 @@ CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) -DEFAULT CHARSET=latin1 ENGINE=BerkeleyDB; +DEFAULT CHARSET=latin1 ENGINE=InnoDB; DROP TABLE IF EXISTS federated.t1; Warnings: Note 1051 Unknown table 't1' diff --git a/mysql-test/r/keywords.result b/mysql-test/r/keywords.result index 88a0ab8abd5..597983dab7e 100644 --- a/mysql-test/r/keywords.result +++ b/mysql-test/r/keywords.result @@ -16,3 +16,19 @@ select events.binlog from events; binlog 1 drop table events; +create procedure p1() +begin +declare n int default 2; +authors: while n > 0 do +set n = n -1; +end while authors; +end| +create procedure p2() +begin +declare n int default 2; +contributors: while n > 0 do +set n = n -1; +end while contributors; +end| +drop procedure p1; +drop procedure p2; diff --git a/mysql-test/r/repair.result b/mysql-test/r/repair.result index d8fa4dbbb72..f08dc6a8a4a 100644 --- a/mysql-test/r/repair.result +++ b/mysql-test/r/repair.result @@ -41,3 +41,9 @@ Table Op Msg_type Msg_text test.t1 repair warning Number of rows changed from 0 to 1 test.t1 repair status OK drop table t1; +DROP TABLE IF EXISTS tt1; +CREATE TEMPORARY TABLE tt1 (c1 INT); +REPAIR TABLE tt1 USE_FRM; +Table Op Msg_type Msg_text +tt1 repair error Cannot repair temporary table from .frm file +DROP TABLE tt1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index efe58579785..168d011a2ac 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -482,3 +482,57 @@ SELECT * FROM t1; ALTER TABLE t1 MODIFY COLUMN v VARCHAR(4); SELECT * FROM t1; DROP TABLE t1; + +# End of 5.0 tests + +# +# Bug#18775 - Temporary table from alter table visible to other threads +# +# Check if special characters work and duplicates are detected. +--disable_warnings +DROP TABLE IF EXISTS `t+1`, `t+2`; +--enable_warnings +CREATE TABLE `t+1` (c1 INT); +ALTER TABLE `t+1` RENAME `t+2`; +CREATE TABLE `t+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `t+1` RENAME `t+2`; +DROP TABLE `t+1`, `t+2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +ALTER TABLE `tt+1` RENAME `tt+2`; +CREATE TEMPORARY TABLE `tt+1` (c1 INT); +--error ER_TABLE_EXISTS_ERROR +ALTER TABLE `tt+1` RENAME `tt+2`; +SHOW CREATE TABLE `tt+1`; +SHOW CREATE TABLE `tt+2`; +DROP TABLE `tt+1`, `tt+2`; +# +# Check if special characters as in tmp_file_prefix work. +CREATE TABLE `#sql1` (c1 INT); +CREATE TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +RENAME TABLE `#sql1` TO `@0023sql1`; +RENAME TABLE `@0023sql2` TO `#sql2`; +SHOW TABLES; +ALTER TABLE `@0023sql1` RENAME `#sql-1`; +ALTER TABLE `#sql2` RENAME `@0023sql-2`; +SHOW TABLES; +INSERT INTO `#sql-1` VALUES (1); +INSERT INTO `@0023sql-2` VALUES (2); +DROP TABLE `#sql-1`, `@0023sql-2`; +# +# Same for temporary tables though these names do not become file names. +CREATE TEMPORARY TABLE `#sql1` (c1 INT); +CREATE TEMPORARY TABLE `@0023sql2` (c1 INT); +SHOW TABLES; +ALTER TABLE `#sql1` RENAME `@0023sql1`; +ALTER TABLE `@0023sql2` RENAME `#sql2`; +SHOW TABLES; +INSERT INTO `#sql2` VALUES (1); +INSERT INTO `@0023sql1` VALUES (2); +SHOW CREATE TABLE `#sql2`; +SHOW CREATE TABLE `@0023sql1`; +DROP TABLE `#sql2`, `@0023sql1`; + diff --git a/mysql-test/t/backup.test b/mysql-test/t/backup.test index 917c3f98ebb..61bde0cecb0 100644 --- a/mysql-test/t/backup.test +++ b/mysql-test/t/backup.test @@ -58,3 +58,22 @@ drop table t5; --system rm $MYSQLTEST_VARDIR/tmp/t?.* # End of 4.1 tests +# End of 5.0 tests + +# +# Bug#18775 - Temporary table from alter table visible to other threads +# +# Backup did not encode table names. +--disable_warnings +DROP TABLE IF EXISTS `t+1`; +--enable_warnings +CREATE TABLE `t+1` (c1 INT); +INSERT INTO `t+1` VALUES (1), (2), (3); +BACKUP TABLE `t+1` TO '../tmp'; +DROP TABLE `t+1`; +# +# Same for restore. +RESTORE TABLE `t+1` FROM '../tmp'; +SELECT * FROM `t+1`; +DROP TABLE `t+1`; + diff --git a/mysql-test/t/federated_transactions-slave.opt b/mysql-test/t/federated_transactions-slave.opt new file mode 100644 index 00000000000..627becdbfb5 --- /dev/null +++ b/mysql-test/t/federated_transactions-slave.opt @@ -0,0 +1 @@ +--innodb diff --git a/mysql-test/t/federated_transactions.test b/mysql-test/t/federated_transactions.test index 5095c8ce9c3..9f3b030f462 100644 --- a/mysql-test/t/federated_transactions.test +++ b/mysql-test/t/federated_transactions.test @@ -1,6 +1,6 @@ # should work with embedded server after mysqltest is fixed -- source include/not_embedded.inc -source include/have_bdb.inc; +source include/have_innodb.inc; source include/federated.inc; connection slave; @@ -10,7 +10,7 @@ CREATE TABLE federated.t1 ( `id` int(20) NOT NULL, `name` varchar(32) NOT NULL default '' ) - DEFAULT CHARSET=latin1 ENGINE=BerkeleyDB; + DEFAULT CHARSET=latin1 ENGINE=InnoDB; connection master; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/t/keywords.test b/mysql-test/t/keywords.test index de0159a950e..1af4a1354be 100644 --- a/mysql-test/t/keywords.test +++ b/mysql-test/t/keywords.test @@ -19,3 +19,27 @@ select events.binlog from events; drop table events; # End of 4.1 tests + +# +# Bug#19939 "AUTHORS is not a keyword" +# +delimiter |; +create procedure p1() +begin + declare n int default 2; + authors: while n > 0 do + set n = n -1; + end while authors; +end| +create procedure p2() +begin + declare n int default 2; + contributors: while n > 0 do + set n = n -1; + end while contributors; +end| +delimiter ;| +drop procedure p1; +drop procedure p2; + +# End of 5.1 tests diff --git a/mysql-test/t/repair.test b/mysql-test/t/repair.test index 16e1d76d460..c79768dbb46 100644 --- a/mysql-test/t/repair.test +++ b/mysql-test/t/repair.test @@ -35,3 +35,16 @@ repair table t1 use_frm; drop table t1; # End of 4.1 tests +# End of 5.0 tests + +# +# Bug#18775 - Temporary table from alter table visible to other threads +# +# REPAIR TABLE ... USE_FRM on temporary table crashed the table or server. +--disable_warnings +DROP TABLE IF EXISTS tt1; +--enable_warnings +CREATE TEMPORARY TABLE tt1 (c1 INT); +REPAIR TABLE tt1 USE_FRM; +DROP TABLE tt1; + diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 565010a1889..cbb8a7a48c0 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -473,11 +473,14 @@ int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt) HA_CHECK_OPT tmp_check_opt; char *backup_dir= thd->lex->backup_dir; char src_path[FN_REFLEN], dst_path[FN_REFLEN]; - const char *table_name= table->s->table_name.str; + char table_name[FN_REFLEN]; int error; const char* errmsg; DBUG_ENTER("restore"); + VOID(tablename_to_filename(table->s->table_name.str, table_name, + sizeof(table_name))); + if (fn_format_relative_to_data_home(src_path, table_name, backup_dir, MI_NAME_DEXT)) DBUG_RETURN(HA_ADMIN_INVALID); @@ -513,11 +516,14 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt) { char *backup_dir= thd->lex->backup_dir; char src_path[FN_REFLEN], dst_path[FN_REFLEN]; - const char *table_name= table->s->table_name.str; + char table_name[FN_REFLEN]; int error; const char *errmsg; DBUG_ENTER("ha_myisam::backup"); + VOID(tablename_to_filename(table->s->table_name.str, table_name, + sizeof(table_name))); + if (fn_format_relative_to_data_home(dst_path, table_name, backup_dir, reg_ext)) { diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index a15787fdcf0..3ae5406824c 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -477,7 +477,7 @@ int ha_myisammrg::create(const char *name, register TABLE *form, an embedded server without changing the paths in the .MRG file. */ uint length= build_table_filename(buff, sizeof(buff), - tables->db, tables->table_name, ""); + tables->db, tables->table_name, "", 0); /* If a MyISAM table is in the same directory as the MERGE table, we use the table name without a path. This means that the diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 64f0cc0b76e..9b44573673d 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -5801,7 +5801,7 @@ int ndbcluster_discover(THD* thd, const char *db, const char *name, DBUG_RETURN(HA_ERR_NO_CONNECTION); ndb->setDatabaseName(db); NDBDICT* dict= ndb->getDictionary(); - build_table_filename(key, sizeof(key), db, name, ""); + build_table_filename(key, sizeof(key), db, name, "", 0); NDB_SHARE *share= get_share(key, 0, false); if (share && get_ndb_share_state(share) == NSS_ALTERED) { @@ -5944,7 +5944,7 @@ int ndbcluster_drop_database_impl(const char *path) // Drop any tables belonging to database char full_path[FN_REFLEN]; char *tmp= full_path + - build_table_filename(full_path, sizeof(full_path), dbname, "", ""); + build_table_filename(full_path, sizeof(full_path), dbname, "", "", 0); ndb->setDatabaseName(dbname); List_iterator_fast<char> it(drop_list); @@ -6067,7 +6067,7 @@ int ndbcluster_find_all_files(THD *thd) /* check if database exists */ char *end= key + - build_table_filename(key, sizeof(key), elmt.database, "", ""); + build_table_filename(key, sizeof(key), elmt.database, "", "", 0); if (my_access(key, F_OK)) { /* no such database defined, skip table */ @@ -6210,7 +6210,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, } // File is not in NDB, check for .ndb file with this name - build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext); + build_table_filename(name, sizeof(name), db, file_name, ha_ndb_ext, 0); DBUG_PRINT("info", ("Check access for %s", name)); if (my_access(name, F_OK)) { @@ -6235,7 +6235,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, /* setup logging to binlog for all discovered tables */ { char *end, *end1= name + - build_table_filename(name, sizeof(name), db, "", ""); + build_table_filename(name, sizeof(name), db, "", "", 0); for (i= 0; i < ok_tables.records; i++) { file_name= (char*)hash_element(&ok_tables, i); @@ -6257,7 +6257,7 @@ int ndbcluster_find_files(THD *thd,const char *db,const char *path, file_name= hash_element(&ndb_tables, i); if (!hash_search(&ok_tables, file_name, strlen(file_name))) { - build_table_filename(name, sizeof(name), db, file_name, reg_ext); + build_table_filename(name, sizeof(name), db, file_name, reg_ext, 0); if (my_access(name, F_OK)) { DBUG_PRINT("info", ("%s must be discovered", file_name)); @@ -6808,7 +6808,7 @@ uint ndb_get_commitcount(THD *thd, char *dbname, char *tabname, NDB_SHARE *share; DBUG_ENTER("ndb_get_commitcount"); - build_table_filename(name, sizeof(name), dbname, tabname, ""); + build_table_filename(name, sizeof(name), dbname, tabname, "", 0); DBUG_PRINT("enter", ("name: %s", name)); pthread_mutex_lock(&ndbcluster_mutex); if (!(share=(NDB_SHARE*) hash_search(&ndbcluster_open_tables, diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc index 8e9f0077dd0..ee9e639199c 100644 --- a/sql/ha_ndbcluster_binlog.cc +++ b/sql/ha_ndbcluster_binlog.cc @@ -737,7 +737,7 @@ static int ndbcluster_create_apply_status_table(THD *thd) */ { build_table_filename(buf, sizeof(buf), - NDB_REP_DB, NDB_APPLY_TABLE, reg_ext); + NDB_REP_DB, NDB_APPLY_TABLE, reg_ext, 0); my_delete(buf, MYF(0)); } @@ -786,7 +786,7 @@ static int ndbcluster_create_schema_table(THD *thd) */ { build_table_filename(buf, sizeof(buf), - NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext); + NDB_REP_DB, NDB_SCHEMA_TABLE, reg_ext, 0); my_delete(buf, MYF(0)); } @@ -1247,7 +1247,7 @@ int ndbcluster_log_schema_op(THD *thd, NDB_SHARE *share, NDB_SCHEMA_OBJECT *ndb_schema_object; { char key[FN_REFLEN]; - build_table_filename(key, sizeof(key), db, table_name, ""); + build_table_filename(key, sizeof(key), db, table_name, "", 0); ndb_schema_object= ndb_get_schema_object(key, TRUE, FALSE); } @@ -1577,7 +1577,7 @@ ndb_handle_schema_change(THD *thd, Ndb *ndb, NdbEventOperation *pOp, DBUG_PRINT("info", ("Detected frm change of table %s.%s", dbname, tabname)); - build_table_filename(key, FN_LEN-1, dbname, tabname, NullS); + build_table_filename(key, FN_LEN-1, dbname, tabname, NullS, 0); /* If the frm of the altered table is different than the one on disk then overwrite it with the new table definition @@ -1775,7 +1775,8 @@ ndb_binlog_thread_handle_schema_event(THD *thd, Ndb *ndb, case SOT_TRUNCATE_TABLE: { char key[FN_REFLEN]; - build_table_filename(key, sizeof(key), schema->db, schema->name, ""); + build_table_filename(key, sizeof(key), + schema->db, schema->name, "", 0); NDB_SHARE *share= get_share(key, 0, FALSE, FALSE); // invalidation already handled by binlog thread if (!share || !share->op) @@ -1979,7 +1980,7 @@ ndb_binlog_thread_handle_schema_event_post_epoch(THD *thd, { enum SCHEMA_OP_TYPE schema_type= (enum SCHEMA_OP_TYPE)schema->type; char key[FN_REFLEN]; - build_table_filename(key, sizeof(key), schema->db, schema->name, ""); + build_table_filename(key, sizeof(key), schema->db, schema->name, "", 0); if (schema_type == SOT_CLEAR_SLOCK) { pthread_mutex_lock(&ndbcluster_mutex); diff --git a/sql/ha_ndbcluster_binlog.h b/sql/ha_ndbcluster_binlog.h index 58bf7517df5..4c3cd105d1d 100644 --- a/sql/ha_ndbcluster_binlog.h +++ b/sql/ha_ndbcluster_binlog.h @@ -23,7 +23,7 @@ typedef NdbDictionary::Index NDBINDEX; typedef NdbDictionary::Dictionary NDBDICT; typedef NdbDictionary::Event NDBEVENT; -#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix) || is_prefix(A, "@0023sql")) +#define IS_TMP_PREFIX(A) (is_prefix(A, tmp_file_prefix)) extern ulong ndb_extra_logging; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index a9ecbb23a27..2fb02f0d9b8 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -754,7 +754,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables, bool if_exists, bool drop_temporary, bool log_query); bool quick_rm_table(handlerton *base,const char *db, - const char *table_name); + const char *table_name, uint flags); void close_cached_table(THD *thd, TABLE *table); bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent); bool mysql_change_db(THD *thd,const char *name,bool no_access_check); @@ -899,11 +899,9 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok); bool mysql_create_like_table(THD *thd, TABLE_LIST *table, HA_CREATE_INFO *create_info, Table_ident *src_table); -bool mysql_rename_table(handlerton *base, - const char *old_db, - const char * old_name, - const char *new_db, - const char * new_name); +bool mysql_rename_table(handlerton *base, const char *old_db, + const char * old_name, const char *new_db, + const char * new_name, uint flags); bool mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys); bool mysql_drop_index(THD *thd, TABLE_LIST *table_list, ALTER_INFO *alter_info); @@ -1850,7 +1848,12 @@ uint strconvert(CHARSET_INFO *from_cs, const char *from, uint filename_to_tablename(const char *from, char *to, uint to_length); uint tablename_to_filename(const char *from, char *to, uint to_length); uint build_table_filename(char *buff, size_t bufflen, const char *db, - const char *table, const char *ext); + const char *table, const char *ext, uint flags); +/* Flags for conversion functions. */ +#define FN_FROM_IS_TMP (1 << 0) +#define FN_TO_IS_TMP (1 << 1) +#define FN_IS_TMP (FN_FROM_IS_TMP | FN_TO_IS_TMP) + /* from hostname.cc */ struct in_addr; my_string ip_to_hostname(struct in_addr *in,uint *errors); diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 966d0f88ca3..5590dd0049d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -2962,7 +2962,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, { char buf[FN_REFLEN]; build_table_filename(buf, sizeof(buf), table_list->db, - table_list->table_name, reg_ext); + table_list->table_name, reg_ext, 0); fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS | MY_RETURN_REAL_PATH | MY_APPEND_EXT); if (access(buf,F_OK)) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8629cbda062..1c733e3c12d 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -254,7 +254,7 @@ uint cached_table_definitions(void) Get TABLE_SHARE for a table. get_table_share() - thd Table share + thd Thread handle table_list Table that should be opened key Table cache key key_length Length of key @@ -1500,15 +1500,18 @@ TABLE *find_temporary_table(THD *thd, TABLE_LIST *table_list) char key[MAX_DBKEY_LENGTH]; uint key_length; TABLE *table; + DBUG_ENTER("find_temporary_table"); + DBUG_PRINT("enter", ("table: '%s'.'%s'", + table_list->db, table_list->table_name)); key_length= create_table_def_key(thd, key, table_list, 1); for (table=thd->temporary_tables ; table ; table= table->next) { if (table->s->table_cache_key.length == key_length && !memcmp(table->s->table_cache_key.str, key, key_length)) - return table; + DBUG_RETURN(table); } - return 0; // Not a temporary table + DBUG_RETURN(0); // Not a temporary table } @@ -1949,7 +1952,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, char path[FN_REFLEN]; enum legacy_db_type not_used; build_table_filename(path, sizeof(path) - 1, - table_list->db, table_list->table_name, reg_ext); + table_list->db, table_list->table_name, reg_ext, 0); if (mysql_frm_type(thd, path, ¬_used) == FRMTYPE_VIEW) { /* @@ -3511,6 +3514,8 @@ TABLE *open_temporary_table(THD *thd, const char *path, const char *db, uint key_length; TABLE_LIST table_list; DBUG_ENTER("open_temporary_table"); + DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", + db, table_name, path)); table_list.db= (char*) db; table_list.table_name= (char*) table_name; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index 77d99862bf0..a5ad62ccad6 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -560,7 +560,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); /* Check directory */ - path_len= build_table_filename(path, sizeof(path), db, "", ""); + path_len= build_table_filename(path, sizeof(path), db, "", "", 0); path[path_len-1]= 0; // Remove last '/' from path if (my_stat(path,&stat_info,MYF(0))) @@ -704,7 +704,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) We pass MY_DB_OPT_FILE as "extension" to avoid "table name to file name" encoding. */ - build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE); + build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0); if ((error=write_db_opt(thd, path, create_info))) goto exit; @@ -797,7 +797,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); - length= build_table_filename(path, sizeof(path), db, "", ""); + length= build_table_filename(path, sizeof(path), db, "", "", 0); strmov(path+length, MY_DB_OPT_FILE); // Append db option file name del_dbopt(path); // Remove dboption hash entry path[length]= '\0'; // Remove file name @@ -1324,7 +1324,7 @@ bool mysql_change_db(THD *thd, const char *name, bool no_access_check) } } #endif - path_length= build_table_filename(path, sizeof(path), db_name, "", ""); + path_length= build_table_filename(path, sizeof(path), db_name, "", "", 0); if (path_length && path[path_length-1] == FN_LIBCHAR) path[path_length-1]= '\0'; // remove ending '\' if (my_access(path,F_OK)) @@ -1469,11 +1469,12 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) if (thd->db && !strcmp(thd->db, old_db->str)) change_to_newdb= 1; - build_table_filename(path, sizeof(path)-1, old_db->str, "", MY_DB_OPT_FILE); + build_table_filename(path, sizeof(path)-1, + old_db->str, "", MY_DB_OPT_FILE, 0); if ((load_db_opt(thd, path, &create_info))) create_info.default_table_charset= thd->variables.collation_server; - length= build_table_filename(path, sizeof(path)-1, old_db->str, "", ""); + length= build_table_filename(path, sizeof(path)-1, old_db->str, "", "", 0); if (length && path[length-1] == FN_LIBCHAR) path[length-1]=0; // remove ending '\' if ((error= my_access(path,F_OK))) @@ -1538,9 +1539,10 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) If some tables were left in the new directory, rmdir() will fail. It garantees we never loose any tables. */ - build_table_filename(path, sizeof(path)-1, new_db->str,"",MY_DB_OPT_FILE); + build_table_filename(path, sizeof(path)-1, + new_db->str,"",MY_DB_OPT_FILE, 0); my_delete(path, MYF(MY_WME)); - length= build_table_filename(path, sizeof(path)-1, new_db->str, "", ""); + length= build_table_filename(path, sizeof(path)-1, new_db->str, "", "", 0); if (length && path[length-1] == FN_LIBCHAR) path[length-1]=0; // remove ending '\' rmdir(path); @@ -1592,9 +1594,9 @@ bool mysql_rename_db(THD *thd, LEX_STRING *old_db, LEX_STRING *new_db) /* pass empty file name, and file->name as extension to avoid encoding */ build_table_filename(oldname, sizeof(oldname)-1, - old_db->str, "", file->name); + old_db->str, "", file->name, 0); build_table_filename(newname, sizeof(newname)-1, - new_db->str, "", file->name); + new_db->str, "", file->name, 0); my_rename(oldname, newname, MYF(MY_WME)); } my_dirend(dirp); diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 659695e8e73..d2517dc7613 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -888,7 +888,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) } path_length= build_table_filename(path, sizeof(path), table_list->db, - table_list->table_name, reg_ext); + table_list->table_name, reg_ext, 0); if (!dont_send_ok) { diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index e0164fa07be..5df6b1832f5 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -2823,7 +2823,8 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ((thd->prelocked_mode == PRELOCKED) ? MYSQL_OPEN_IGNORE_LOCKED_TABLES:0))))) quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); + table_case_name(create_info, create_table->table_name), + 0); } reenable_binlog(thd); if (!table) // open failed @@ -2845,7 +2846,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, hash_delete(&open_cache,(byte*) table); VOID(pthread_mutex_unlock(&LOCK_open)); quick_rm_table(create_info->db_type, create_table->db, - table_case_name(create_info, create_table->table_name)); + table_case_name(create_info, create_table->table_name), 0); DBUG_RETURN(0); } table->file->extra(HA_EXTRA_WRITE_CACHE); @@ -3026,7 +3027,8 @@ void select_create::abort() table->s->version= 0; hash_delete(&open_cache,(byte*) table); if (!create_info->table_existed) - quick_rm_table(table_type, create_table->db, create_table->table_name); + quick_rm_table(table_type, create_table->db, + create_table->table_name, 0); /* Tell threads waiting for refresh that something has happened */ if (version != refresh_version) broadcast_refresh(); diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 73091c0994e..f1c8e099441 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -3441,7 +3441,7 @@ bool mysql_unpack_partition(THD *thd, const uchar *part_buf, char *src_db= table_ident->db.str ? table_ident->db.str : thd->db; char *src_table= table_ident->table.str; char buf[FN_REFLEN]; - build_table_filename(buf, sizeof(buf), src_db, src_table, ""); + build_table_filename(buf, sizeof(buf), src_db, src_table, "", 0); if (partition_default_handling(table, part_info, FALSE, buf)) { @@ -4715,7 +4715,7 @@ static bool mysql_change_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) handler *file= lpt->table->file; DBUG_ENTER("mysql_change_partitions"); - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); if ((error= file->change_partitions(lpt->create_info, path, &lpt->copied, &lpt->deleted, lpt->pack_frm_data, lpt->pack_frm_len))) @@ -4755,7 +4755,7 @@ static bool mysql_rename_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) int error; DBUG_ENTER("mysql_rename_partitions"); - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); if ((error= lpt->table->file->rename_partitions(path))) { if (error != 1) @@ -4796,7 +4796,7 @@ static bool mysql_drop_partitions(ALTER_PARTITION_PARAM_TYPE *lpt) int error; DBUG_ENTER("mysql_drop_partitions"); - build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, ""); + build_table_filename(path, sizeof(path), lpt->db, lpt->table_name, "", 0); if ((error= lpt->table->file->drop_partitions(path))) { lpt->table->file->print_error(error, MYF(0)); @@ -5147,7 +5147,7 @@ static bool write_log_drop_shadow_frm(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("write_log_drop_shadow_frm"); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, NULL, (const char*)shadow_path, FALSE)) @@ -5195,9 +5195,9 @@ static bool write_log_rename_frm(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); + lpt->table_name, "", 0); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); pthread_mutex_lock(&LOCK_gdl); if (write_log_replace_delete_frm(lpt, 0UL, shadow_path, path, TRUE)) goto error; @@ -5249,9 +5249,9 @@ static bool write_log_drop_partition(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); + lpt->table_name, "", 0); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) @@ -5306,9 +5306,9 @@ static bool write_log_add_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) DBUG_ENTER("write_log_add_change_partition"); build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); + lpt->table_name, "", 0); build_table_filename(tmp_path, sizeof(tmp_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, FALSE)) @@ -5363,9 +5363,9 @@ static bool write_log_final_change_partition(ALTER_PARTITION_PARAM_TYPE *lpt) part_info->first_log_entry= NULL; build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); + lpt->table_name, "", 0); build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); pthread_mutex_lock(&LOCK_gdl); if (write_log_dropped_partitions(lpt, &next_entry, (const char*)path, lpt->alter_info->flags & ALTER_REORGANIZE_PARTITION)) diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index e3468b2b5cf..73473ddd24b 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -157,14 +157,14 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) new_alias= new_table->table_name; } build_table_filename(name, sizeof(name), - new_table->db, new_alias, reg_ext); + new_table->db, new_alias, reg_ext, 0); if (!access(name,F_OK)) { my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); DBUG_RETURN(ren_table); // This can't be skipped } build_table_filename(name, sizeof(name), - ren_table->db, old_alias, reg_ext); + ren_table->db, old_alias, reg_ext, 0); frm_type= mysql_frm_type(thd, name, &table_type); switch (frm_type) @@ -178,7 +178,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) if (!(rc= mysql_rename_table(ha_resolve_by_legacy_type(thd, table_type), ren_table->db, old_alias, - new_table->db, new_alias))) + new_table->db, new_alias, 0))) { if ((rc= Table_triggers_list::change_table_name(thd, ren_table->db, old_alias, @@ -194,7 +194,7 @@ rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error) (void) mysql_rename_table(ha_resolve_by_legacy_type(thd, table_type), new_table->db, new_alias, - ren_table->db, old_alias); + ren_table->db, old_alias, 0); } } } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index bf09f516499..13296f69e69 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -467,7 +467,6 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, uint col_access=thd->col_access; #endif TABLE_LIST table_list; - char tbbuff[FN_REFLEN]; DBUG_ENTER("mysql_find_files"); if (wild && !wild[0]) @@ -484,8 +483,6 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, DBUG_RETURN(-1); } - VOID(tablename_to_filename(tmp_file_prefix, tbbuff, sizeof(tbbuff))); - for (i=0 ; i < (uint) dirp->number_off_files ; i++) { char uname[NAME_LEN*3+1]; /* Unencoded name */ @@ -523,7 +520,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, { // Return only .frm files which aren't temp files. if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),reg_ext) || - is_prefix(file->name,tbbuff)) + is_prefix(file->name, tmp_file_prefix)) continue; *ext=0; VOID(filename_to_tablename(file->name, uname, sizeof(uname))); @@ -692,7 +689,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname, } else { - length= build_table_filename(path, sizeof(path), dbname, "", ""); + length= build_table_filename(path, sizeof(path), dbname, "", "", 0); found_libchar= 0; if (length && path[length-1] == FN_LIBCHAR) { @@ -2558,7 +2555,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) } else { - len= build_table_filename(path, sizeof(path), base_name, "", ""); + len= build_table_filename(path, sizeof(path), base_name, "", "", 0); end= path + len; len= FN_LEN - len; if (mysql_find_files(thd, &files, base_name, @@ -2712,7 +2709,7 @@ int fill_schema_shemata(THD *thd, TABLE_LIST *tables, COND *cond) (grant_option && !check_grant_db(thd, file_name))) #endif { - length= build_table_filename(path, sizeof(path), file_name, "", ""); + length= build_table_filename(path, sizeof(path), file_name, "", "", 0); found_libchar= 0; if (length && path[length-1] == FN_LIBCHAR) { diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 5325758fd12..ecbf16650b3 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -51,31 +51,77 @@ static int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info, #define MYSQL50_TABLE_NAME_PREFIX "#mysql50#" #define MYSQL50_TABLE_NAME_PREFIX_LENGTH 9 + +/* + Translate a file name to a table name (WL #1324). + + SYNOPSIS + filename_to_tablename() + from The file name in my_charset_filename. + to OUT The table name in system_charset_info. + to_length The size of the table name buffer. + + RETURN + Table name length. +*/ + uint filename_to_tablename(const char *from, char *to, uint to_length) { - uint errors, res= strconvert(&my_charset_filename, from, - system_charset_info, to, to_length, &errors); - if (errors) // Old 5.0 name + uint errors; + uint res; + DBUG_ENTER("filename_to_tablename"); + DBUG_PRINT("enter", ("from '%s'", from)); + + if (!memcmp(from, tmp_file_prefix, tmp_file_prefix_length)) { - res= strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) - to; - sql_print_error("Invalid (old?) table or database name '%s'", from); - /* - TODO: add a stored procedure for fix table and database names, - and mention its name in error log. - */ + /* Temporary table name. */ + res= (strnmov(to, from, to_length) - to); + } + else + { + res= strconvert(&my_charset_filename, from, + system_charset_info, to, to_length, &errors); + if (errors) // Old 5.0 name + { + res= (strxnmov(to, to_length, MYSQL50_TABLE_NAME_PREFIX, from, NullS) - + to); + sql_print_error("Invalid (old?) table or database name '%s'", from); + /* + TODO: add a stored procedure for fix table and database names, + and mention its name in error log. + */ + } } - return res; + + DBUG_PRINT("exit", ("to '%s'", to)); + DBUG_RETURN(res); } +/* + Translate a table name to a file name (WL #1324). + + SYNOPSIS + tablename_to_filename() + from The table name in system_charset_info. + to OUT The file name in my_charset_filename. + to_length The size of the file name buffer. + + RETURN + File name length. +*/ + uint tablename_to_filename(const char *from, char *to, uint to_length) { uint errors, length; + DBUG_ENTER("tablename_to_filename"); + DBUG_PRINT("enter", ("from '%s'", from)); + if (from[0] == '#' && !strncmp(from, MYSQL50_TABLE_NAME_PREFIX, MYSQL50_TABLE_NAME_PREFIX_LENGTH)) - return (uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH, - to_length-1) - - (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH)); + DBUG_RETURN((uint) (strmake(to, from+MYSQL50_TABLE_NAME_PREFIX_LENGTH, + to_length-1) - + (from + MYSQL50_TABLE_NAME_PREFIX_LENGTH))); length= strconvert(system_charset_info, from, &my_charset_filename, to, to_length, &errors); if (check_if_legal_tablename(to) && @@ -84,7 +130,8 @@ uint tablename_to_filename(const char *from, char *to, uint to_length) memcpy(to + length, "@@@", 4); length+= 3; } - return length; + DBUG_PRINT("exit", ("to '%s'", to)); + DBUG_RETURN(length); } @@ -93,52 +140,87 @@ uint tablename_to_filename(const char *from, char *to, uint to_length) SYNOPSIS build_table_filename() - buff where to write result - bufflen buff size - db database name, in system_charset_info - table table name, in system_charset_info - ext file extension + buff Where to write result in my_charset_filename. + bufflen buff size + db Database name in system_charset_info. + table_name Table name in system_charset_info. + ext File extension. + flags FN_FROM_IS_TMP or FN_TO_IS_TMP or FN_IS_TMP + table_name is temporary, do not change. NOTES Uses database and table name, and extension to create a file name in mysql_data_dir. Database and table names are converted from system_charset_info into "fscs". + Unless flags indicate a temporary table name. + 'db' is always converted. 'ext' is not converted. - RETURN + The conversion suppression is required for ALTER TABLE. This + statement creates intermediate tables. These are regular + (non-temporary) tables with a temporary name. Their path names must + be derivable from the table name. So we cannot use + build_tmptable_filename() for them. + RETURN + path length */ - uint build_table_filename(char *buff, size_t bufflen, const char *db, - const char *table, const char *ext) + const char *table_name, const char *ext, uint flags) { uint length; char dbbuff[FN_REFLEN]; char tbbuff[FN_REFLEN]; - VOID(tablename_to_filename(table, tbbuff, sizeof(tbbuff))); + DBUG_ENTER("build_table_filename"); + + if (flags & FN_IS_TMP) // FN_FROM_IS_TMP | FN_TO_IS_TMP + strnmov(tbbuff, table_name, sizeof(tbbuff)); + else + VOID(tablename_to_filename(table_name, tbbuff, sizeof(tbbuff))); + VOID(tablename_to_filename(db, dbbuff, sizeof(dbbuff))); - strxnmov(buff, bufflen, - mysql_data_home, "/", dbbuff, "/", tbbuff, ext, NullS); - length= unpack_filename(buff, buff); - return length; + length= strxnmov(buff, bufflen, mysql_data_home, "/", dbbuff, + "/", tbbuff, ext, NullS) - buff; + DBUG_PRINT("exit", ("buff: '%s'", buff)); + DBUG_RETURN(length); } +/* + Creates path to a file: mysql_tmpdir/#sql1234_12_1.ext + + SYNOPSIS + build_tmptable_filename() + thd The thread handle. + buff Where to write result in my_charset_filename. + bufflen buff size + + NOTES + + Uses current_pid, thread_id, and tmp_table counter to create + a file name in mysql_tmpdir. + + RETURN + path length +*/ + uint build_tmptable_filename(THD* thd, char *buff, size_t bufflen) { uint length; - char tbbuff[FN_REFLEN]; char tmp_table_name[tmp_file_prefix_length+22+22+22+3]; + DBUG_ENTER("build_tmptable_filename"); + my_snprintf(tmp_table_name, sizeof(tmp_table_name), "%s%lx_%lx_%x", tmp_file_prefix, current_pid, thd->thread_id, thd->tmp_table++); - VOID(tablename_to_filename(tmp_table_name, tbbuff, sizeof(tbbuff))); - strxnmov(buff, bufflen, mysql_tmpdir, "/", tbbuff, reg_ext, NullS); + + strxnmov(buff, bufflen, mysql_tmpdir, "/", tmp_table_name, reg_ext, NullS); length= unpack_filename(buff, buff); - return length; + DBUG_PRINT("exit", ("buff: '%s'", buff)); + DBUG_RETURN(length); } /* @@ -1201,7 +1283,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) Build shadow frm file name */ build_table_filename(shadow_path, sizeof(shadow_path), lpt->db, - lpt->table_name, "#"); + lpt->table_name, "#", 0); strxmov(shadow_frm_name, shadow_path, reg_ext, NullS); if (flags & WFRM_WRITE_SHADOW) { @@ -1285,7 +1367,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) Build frm file name */ build_table_filename(path, sizeof(path), lpt->db, - lpt->table_name, ""); + lpt->table_name, "", 0); strxmov(frm_name, path, reg_ext, NullS); /* When we are changing to use new frm file we need to ensure that we @@ -1618,7 +1700,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, alias= (lower_case_table_names == 2) ? table->alias : table->table_name; /* remove .frm file and engine files */ path_length= build_table_filename(path, sizeof(path), - db, alias, reg_ext); + db, alias, reg_ext, 0); } if (drop_temporary || (table_type == NULL && @@ -1742,15 +1824,30 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, } +/* + Quickly remove a table. + + SYNOPSIS + quick_rm_table() + base The handlerton handle. + db The database name. + table_name The table name. + flags flags for build_table_filename(). + + RETURN + 0 OK + != 0 Error +*/ + bool quick_rm_table(handlerton *base,const char *db, - const char *table_name) + const char *table_name, uint flags) { char path[FN_REFLEN]; bool error= 0; DBUG_ENTER("quick_rm_table"); uint path_length= build_table_filename(path, sizeof(path), - db, table_name, reg_ext); + db, table_name, reg_ext, flags); if (my_delete(path,MYF(0))) error= 1; /* purecov: inspected */ path[path_length - reg_ext_length]= '\0'; // Remove reg_ext @@ -2901,7 +2998,7 @@ static void set_table_default_charset(THD *thd, HA_CREATE_INFO db_info; char path[FN_REFLEN]; /* Abuse build_table_filename() to build the path to the db.opt file */ - build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE); + build_table_filename(path, sizeof(path), db, "", MY_DB_OPT_FILE, 0); load_db_opt(thd, path, &db_info); create_info->default_table_charset= db_info.default_table_charset; } @@ -3084,6 +3181,8 @@ bool mysql_create_table_internal(THD *thd, handler *file; bool error= TRUE; DBUG_ENTER("mysql_create_table_internal"); + DBUG_PRINT("enter", ("db: '%s' table: '%s' tmp: %d", + db, table_name, internal_tmp_table)); if (use_copy_create_info) { @@ -3303,7 +3402,8 @@ bool mysql_create_table_internal(THD *thd, start++; } #endif - path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext); + path_length= build_table_filename(path, sizeof(path), db, alias, reg_ext, + internal_tmp_table ? FN_IS_TMP : 0); } /* Check if table already exists */ @@ -3513,12 +3613,30 @@ make_unique_key_name(const char *field_name,KEY *start,KEY *end) ** Alter a table definition ****************************************************************************/ + +/* + Rename a table. + + SYNOPSIS + mysql_rename_table() + base The handlerton handle. + old_db The old database name. + old_name The old table name. + new_db The new database name. + new_name The new table name. + flags flags for build_table_filename(). + FN_FROM_IS_TMP old_name is temporary. + FN_TO_IS_TMP new_name is temporary. + + RETURN + 0 OK + != 0 Error +*/ + bool -mysql_rename_table(handlerton *base, - const char *old_db, - const char *old_name, - const char *new_db, - const char *new_name) +mysql_rename_table(handlerton *base, const char *old_db, + const char *old_name, const char *new_db, + const char *new_name, uint flags) { THD *thd= current_thd; char from[FN_REFLEN], to[FN_REFLEN], lc_from[FN_REFLEN], lc_to[FN_REFLEN]; @@ -3527,12 +3645,16 @@ mysql_rename_table(handlerton *base, handler *file; int error=0; DBUG_ENTER("mysql_rename_table"); + DBUG_PRINT("enter", ("old: '%s'.'%s' new: '%s'.'%s'", + old_db, old_name, new_db, new_name)); file= (base == NULL ? 0 : get_new_handler((TABLE_SHARE*) 0, thd->mem_root, base)); - build_table_filename(from, sizeof(from), old_db, old_name, ""); - build_table_filename(to, sizeof(to), new_db, new_name, ""); + build_table_filename(from, sizeof(from), old_db, old_name, "", + flags & FN_FROM_IS_TMP); + build_table_filename(to, sizeof(to), new_db, new_name, "", + flags & FN_TO_IS_TMP); /* If lower_case_table_names == 2 (case-preserving but case-insensitive @@ -3544,12 +3666,14 @@ mysql_rename_table(handlerton *base, { strmov(tmp_name, old_name); my_casedn_str(files_charset_info, tmp_name); - build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, ""); + build_table_filename(lc_from, sizeof(lc_from), old_db, tmp_name, "", + flags & FN_FROM_IS_TMP); from_base= lc_from; strmov(tmp_name, new_name); my_casedn_str(files_charset_info, tmp_name); - build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, ""); + build_table_filename(lc_to, sizeof(lc_to), new_db, tmp_name, "", + flags & FN_TO_IS_TMP); to_base= lc_to; } @@ -3685,7 +3809,8 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table, if (fn_format_relative_to_data_home(src_path, uname, backup_dir, reg_ext)) DBUG_RETURN(-1); // protect buffer overflow - build_table_filename(dst_path, sizeof(dst_path), db, table_name, reg_ext); + build_table_filename(dst_path, sizeof(dst_path), + db, table_name, reg_ext, 0); if (lock_and_wait_for_table_name(thd,table)) DBUG_RETURN(-1); @@ -3762,6 +3887,15 @@ static int prepare_for_repair(THD *thd, TABLE_LIST *table_list, table= &tmp_table; pthread_mutex_unlock(&LOCK_open); } + /* + REPAIR TABLE ... USE_FRM for temporary tables makes little sense. + */ + if (table->s->tmp_table) + { + error= send_check_errmsg(thd, table_list, "repair", + "Cannot repair temporary table from .frm file"); + goto end; + } /* User gave us USE_FRM which means that the header in the index file is @@ -4459,7 +4593,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, else { build_table_filename(src_path, sizeof(src_path), - src_db, src_table, reg_ext); + src_db, src_table, reg_ext, 0); /* Resolve symlinks (for windows) */ unpack_filename(src_path, src_path); if (lower_case_table_names) @@ -4498,7 +4632,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, else { dst_path_length= build_table_filename(dst_path, sizeof(dst_path), - db, table_name, reg_ext); + db, table_name, reg_ext, 0); if (!access(dst_path, F_OK)) goto table_exists; } @@ -4548,7 +4682,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, else if (err) { (void) quick_rm_table(create_info->db_type, db, - table_name); /* purecov: inspected */ + table_name, 0); /* purecov: inspected */ goto err; /* purecov: inspected */ } @@ -5062,8 +5196,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, db=table_list->db; if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db)) new_db= db; - build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext); - build_table_filename(path, sizeof(path), db, table_name, ""); + build_table_filename(reg_path, sizeof(reg_path), db, table_name, reg_ext, 0); + build_table_filename(path, sizeof(path), db, table_name, "", 0); used_fields=create_info->used_fields; @@ -5080,6 +5214,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* Check that we are not trying to rename to an existing table */ if (new_name) { + DBUG_PRINT("info", ("new_db.new_name: '%s'.'%s'", new_db, new_name)); strmov(new_name_buff,new_name); strmov(new_alias= new_alias_buff, new_name); if (lower_case_table_names) @@ -5112,11 +5247,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, } else { - char dir_buff[FN_REFLEN]; - strxnmov(dir_buff, sizeof(dir_buff)-1, - mysql_real_data_home, new_db, NullS); - if (!access(fn_format(new_name_buff,new_name_buff,dir_buff,reg_ext,0), - F_OK)) + build_table_filename(new_name_buff, sizeof(new_name_buff), + new_db, new_name_buff, reg_ext, 0); + if (!access(new_name_buff, F_OK)) { /* Table will be closed in do_command() */ my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); @@ -5197,13 +5330,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, *fn_ext(new_name)=0; table->s->version= 0; // Force removal of table def close_cached_table(thd, table); - if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias)) + if (mysql_rename_table(old_db_type,db,table_name,new_db,new_alias, 0)) error= -1; else if (Table_triggers_list::change_table_name(thd, db, table_name, new_db, new_alias)) { VOID(mysql_rename_table(old_db_type, new_db, new_alias, db, - table_name)); + table_name, 0)); error= -1; } } @@ -5834,7 +5967,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, { char path[FN_REFLEN]; /* table is a normal table: Create temporary table in same directory */ - build_table_filename(path, sizeof(path), new_db, tmp_name, ""); + build_table_filename(path, sizeof(path), new_db, tmp_name, "", + FN_IS_TMP); new_table=open_temporary_table(thd, path, new_db, tmp_name,0); } if (!new_table) @@ -6047,7 +6181,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_lock(&LOCK_open)); if (error) { - VOID(quick_rm_table(new_db_type,new_db,tmp_name)); + VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } @@ -6069,7 +6203,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, { error=1; my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_name_buff); - VOID(quick_rm_table(new_db_type,new_db,tmp_name)); + VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } @@ -6097,22 +6231,24 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, error=0; if (!need_copy_table) new_db_type=old_db_type= NULL; // this type cannot happen in regular ALTER - if (mysql_rename_table(old_db_type,db,table_name,db,old_name)) + if (mysql_rename_table(old_db_type, db, table_name, db, old_name, + FN_TO_IS_TMP)) { error=1; - VOID(quick_rm_table(new_db_type,new_db,tmp_name)); + VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); } else if (mysql_rename_table(new_db_type,new_db,tmp_name,new_db, - new_alias) || + new_alias, FN_FROM_IS_TMP) || (new_name != table_name || new_db != db) && // we also do rename Table_triggers_list::change_table_name(thd, db, table_name, new_db, new_alias)) - - { // Try to get everything back + { + /* Try to get everything back. */ error=1; - VOID(quick_rm_table(new_db_type,new_db,new_alias)); - VOID(quick_rm_table(new_db_type,new_db,tmp_name)); - VOID(mysql_rename_table(old_db_type,db,old_name,db,alias)); + VOID(quick_rm_table(new_db_type,new_db,new_alias, 0)); + VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); + VOID(mysql_rename_table(old_db_type, db, old_name, db, alias, + FN_FROM_IS_TMP)); } if (error) { @@ -6156,7 +6292,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, table->s->version= 0; // Force removal of table def close_cached_table(thd,table); } - VOID(quick_rm_table(old_db_type,db,old_name)); + VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP)); } else { @@ -6173,7 +6309,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, /* end threads waiting on lock */ mysql_lock_abort(thd,table, TRUE); } - VOID(quick_rm_table(old_db_type,db,old_name)); + VOID(quick_rm_table(old_db_type, db, old_name, FN_IS_TMP)); if (close_data_tables(thd,db,table_name) || reopen_tables(thd,1,0)) { // This shouldn't happen @@ -6223,7 +6359,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, shutdown. */ char path[FN_REFLEN]; - build_table_filename(path, sizeof(path), new_db, table_name, ""); + build_table_filename(path, sizeof(path), new_db, table_name, "", 0); table=open_temporary_table(thd, path, new_db, tmp_name,0); if (table) { @@ -6254,7 +6390,7 @@ end_temporary: close_temporary_table(thd, new_table, 1, 1); } else - VOID(quick_rm_table(new_db_type,new_db,tmp_name)); + VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); err: DBUG_RETURN(TRUE); diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 1837372c6c4..c2806b45121 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -468,12 +468,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables, */ file.length= build_table_filename(file_buff, FN_REFLEN-1, tables->db, tables->table_name, - triggers_file_ext); + triggers_file_ext, 0); file.str= file_buff; trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, tables->db, lex->spname->m_name.str, - trigname_file_ext); + trigname_file_ext, 0); trigname_file.str= trigname_buff; /* Use the filesystem to enforce trigger namespace constraints. */ @@ -579,7 +579,7 @@ err_with_cleanup: static bool rm_trigger_file(char *path, const char *db, const char *table_name) { - build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext); + build_table_filename(path, FN_REFLEN-1, db, table_name, triggers_file_ext, 0); return my_delete(path, MYF(MY_WME)); } @@ -602,7 +602,8 @@ static bool rm_trigger_file(char *path, const char *db, static bool rm_trigname_file(char *path, const char *db, const char *trigger_name) { - build_table_filename(path, FN_REFLEN-1, db, trigger_name, trigname_file_ext); + build_table_filename(path, FN_REFLEN-1, + db, trigger_name, trigname_file_ext, 0); return my_delete(path, MYF(MY_WME)); } @@ -628,7 +629,7 @@ static bool save_trigger_file(Table_triggers_list *triggers, const char *db, LEX_STRING file; file.length= build_table_filename(file_buff, FN_REFLEN-1, db, table_name, - triggers_file_ext); + triggers_file_ext, 0); file.str= file_buff; return sql_create_definition_file(NULL, &file, &triggers_file_type, (gptr)triggers, triggers_file_parameters, @@ -803,7 +804,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db, DBUG_ENTER("Table_triggers_list::check_n_load"); path.length= build_table_filename(path_buff, FN_REFLEN-1, - db, table_name, triggers_file_ext); + db, table_name, triggers_file_ext, 0); path.str= path_buff; // QQ: should we analyze errno somehow ? @@ -1159,7 +1160,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig) path.length= build_table_filename(path_buff, FN_REFLEN-1, trig->m_db.str, trig->m_name.str, - trigname_file_ext); + trigname_file_ext, 0); path.str= path_buff; if (access(path_buff, F_OK)) @@ -1366,7 +1367,7 @@ Table_triggers_list::change_table_name_in_trignames(const char *db_name, { trigname_file.length= build_table_filename(trigname_buff, FN_REFLEN-1, db_name, trigger->str, - trigname_file_ext); + trigname_file_ext, 0); trigname_file.str= trigname_buff; trigname.trigger_table= *new_table_name; diff --git a/sql/sql_view.cc b/sql/sql_view.cc index 201725301d6..9dd79458c66 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -662,11 +662,11 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view, /* print file name */ dir.length= build_table_filename(dir_buff, sizeof(dir_buff), - view->db, "", ""); + view->db, "", "", 0); dir.str= dir_buff; path.length= build_table_filename(path_buff, sizeof(path_buff), - view->db, view->table_name, reg_ext); + view->db, view->table_name, reg_ext, 0); path.str= path_buff; file.str= path.str + dir.length; @@ -1311,7 +1311,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode) TABLE_SHARE *share; frm_type_enum type= FRMTYPE_ERROR; build_table_filename(path, sizeof(path), - view->db, view->table_name, reg_ext); + view->db, view->table_name, reg_ext, 0); VOID(pthread_mutex_lock(&LOCK_open)); if (access(path, F_OK) || diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index b8d68a91afc..1d1bf85f665 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -9320,7 +9320,6 @@ user: keyword: keyword_sp {} | ASCII_SYM {} - | AUTHORS_SYM {} | BACKUP_SYM {} | BEGIN_SYM {} | BYTE_SYM {} @@ -9378,6 +9377,7 @@ keyword_sp: | ALGORITHM_SYM {} | ANY_SYM {} | AT_SYM {} + | AUTHORS_SYM {} | AUTO_INC {} | AUTOEXTEND_SIZE_SYM {} | AVG_ROW_LENGTH {} @@ -9403,6 +9403,7 @@ keyword_sp: | COMPRESSED_SYM {} | CONCURRENT {} | CONSISTENT_SYM {} + | CONTRIBUTORS_SYM {} | CUBE_SYM {} | DATA_SYM {} | DATAFILE_SYM {} diff --git a/sql/table.cc b/sql/table.cc index 21dbcccedd7..ce6dbadefc7 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -68,7 +68,7 @@ static byte *get_field_name(Field **buff, uint *length, char *fn_rext(char *name) { char *res= strrchr(name, '.'); - if (res && !strcmp(res, ".frm")) + if (res && !strcmp(res, reg_ext)) return res; return name + strlen(name); } @@ -95,10 +95,13 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, TABLE_SHARE *share; char path[FN_REFLEN]; uint path_length; + DBUG_ENTER("alloc_table_share"); + DBUG_PRINT("enter", ("table: '%s'.'%s'", + table_list->db, table_list->table_name)); path_length= build_table_filename(path, sizeof(path) - 1, table_list->db, - table_list->table_name, ""); + table_list->table_name, "", 0); init_sql_alloc(&mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); if ((share= (TABLE_SHARE*) alloc_root(&mem_root, sizeof(*share) + key_length + @@ -148,7 +151,7 @@ TABLE_SHARE *alloc_table_share(TABLE_LIST *table_list, char *key, pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); pthread_cond_init(&share->cond, NULL); } - return share; + DBUG_RETURN(share); } @@ -179,6 +182,7 @@ void init_tmp_table_share(TABLE_SHARE *share, const char *key, const char *path) { DBUG_ENTER("init_tmp_table_share"); + DBUG_PRINT("enter", ("table: '%s'.'%s'", key, table_name)); bzero((char*) share, sizeof(*share)); init_sql_alloc(&share->mem_root, TABLE_ALLOC_BLOCK_SIZE, 0); @@ -286,7 +290,8 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags) char path[FN_REFLEN]; MEM_ROOT **root_ptr, *old_root; DBUG_ENTER("open_table_def"); - DBUG_PRINT("enter", ("name: '%s.%s'",share->db.str, share->table_name.str)); + DBUG_PRINT("enter", ("table: '%s'.'%s' path: '%s'", share->db.str, + share->table_name.str, share->normalized_path.str)); error= 1; error_given= 0; diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c index 602e46f0998..5f4a882f4a8 100644 --- a/storage/innobase/row/row0mysql.c +++ b/storage/innobase/row/row0mysql.c @@ -3419,8 +3419,8 @@ row_is_mysql_tmp_table_name( const char* name) /* in: table name in the form 'database/tablename' */ { - /* return(strstr(name, "/#sql") != NULL); */ - return(strstr(name, "/@0023sql") != NULL); + return(strstr(name, "/#sql") != NULL); + /* return(strstr(name, "/@0023sql") != NULL); */ } /******************************************************************** diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c index 0487500ad33..8d45333137e 100644 --- a/storage/myisam/mi_dynrec.c +++ b/storage/myisam/mi_dynrec.c @@ -1304,12 +1304,41 @@ void _my_store_blob_length(byte *pos,uint pack_length,uint length) } - /* Read record from datafile */ - /* Returns 0 if ok, -1 if error */ +/* + Read record from datafile. + + SYNOPSIS + _mi_read_dynamic_record() + info MI_INFO pointer to table. + filepos From where to read the record. + buf Destination for record. + + NOTE + + If a write buffer is active, it needs to be flushed if its contents + intersects with the record to read. We always check if the position + of the first byte of the write buffer is lower than the position + past the last byte to read. In theory this is also true if the write + buffer is completely below the read segment. That is, if there is no + intersection. But this case is unusual. We flush anyway. Only if the + first byte in the write buffer is above the last byte to read, we do + not flush. + + A dynamic record may need several reads. So this check must be done + before every read. Reading a dynamic record starts with reading the + block header. If the record does not fit into the free space of the + header, the block may be longer than the header. In this case a + second read is necessary. These one or two reads repeat for every + part of the record. + + RETURN + 0 OK + -1 Error +*/ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) { - int flag; + int block_of_record; uint b_type,left_length; byte *to; MI_BLOCK_INFO block_info; @@ -1321,20 +1350,19 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) LINT_INIT(to); LINT_INIT(left_length); file=info->dfile; - block_info.next_filepos=filepos; /* for easyer loop */ - flag=block_info.second_read=0; + block_of_record= 0; /* First block of record is numbered as zero. */ + block_info.second_read= 0; do { + /* A corrupted table can have wrong pointers. (Bug# 19835) */ + if (filepos == HA_OFFSET_ERROR) + goto panic; if (info->opt_flag & WRITE_CACHE_USED && - info->rec_cache.pos_in_file <= block_info.next_filepos && + info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) goto err; - /* A corrupted table can have wrong pointers. (Bug# 19835) */ - if (block_info.next_filepos == HA_OFFSET_ERROR) - goto panic; info->rec_cache.seek_not_done=1; - if ((b_type=_mi_get_block_info(&block_info,file, - block_info.next_filepos)) + if ((b_type= _mi_get_block_info(&block_info, file, filepos)) & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR)) { @@ -1342,9 +1370,8 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) my_errno=HA_ERR_RECORD_DELETED; goto err; } - if (flag == 0) /* First block */ + if (block_of_record++ == 0) /* First block */ { - flag=1; if (block_info.rec_len > (uint) info->s->base.max_pack_length) goto panic; if (info->s->base.blobs) @@ -1359,11 +1386,41 @@ int _mi_read_dynamic_record(MI_INFO *info, my_off_t filepos, byte *buf) } if (left_length < block_info.data_len || ! block_info.data_len) goto panic; /* Wrong linked record */ - if (info->s->file_read(info,(byte*) to,block_info.data_len,block_info.filepos, - MYF(MY_NABP))) - goto panic; - left_length-=block_info.data_len; - to+=block_info.data_len; + /* copy information that is already read */ + { + uint offset= (uint) (block_info.filepos - filepos); + uint prefetch_len= (sizeof(block_info.header) - offset); + filepos+= sizeof(block_info.header); + + if (prefetch_len > block_info.data_len) + prefetch_len= block_info.data_len; + if (prefetch_len) + { + memcpy((byte*) to, block_info.header + offset, prefetch_len); + block_info.data_len-= prefetch_len; + left_length-= prefetch_len; + to+= prefetch_len; + } + } + /* read rest of record from file */ + if (block_info.data_len) + { + if (info->opt_flag & WRITE_CACHE_USED && + info->rec_cache.pos_in_file < filepos + block_info.data_len && + flush_io_cache(&info->rec_cache)) + goto err; + /* + What a pity that this method is not called 'file_pread' and that + there is no equivalent without seeking. We are at the right + position already. :( + */ + if (info->s->file_read(info, (byte*) to, block_info.data_len, + filepos, MYF(MY_NABP))) + goto panic; + left_length-=block_info.data_len; + to+=block_info.data_len; + } + filepos= block_info.next_filepos; } while (left_length); info->update|= HA_STATE_AKTIV; /* We have a aktive record */ @@ -1520,11 +1577,45 @@ err: } +/* + Read record from datafile. + + SYNOPSIS + _mi_read_rnd_dynamic_record() + info MI_INFO pointer to table. + buf Destination for record. + filepos From where to read the record. + skip_deleted_blocks If to repeat reading until a non-deleted + record is found. + + NOTE + + If a write buffer is active, it needs to be flushed if its contents + intersects with the record to read. We always check if the position + of the first byte of the write buffer is lower than the position + past the last byte to read. In theory this is also true if the write + buffer is completely below the read segment. That is, if there is no + intersection. But this case is unusual. We flush anyway. Only if the + first byte in the write buffer is above the last byte to read, we do + not flush. + + A dynamic record may need several reads. So this check must be done + before every read. Reading a dynamic record starts with reading the + block header. If the record does not fit into the free space of the + header, the block may be longer than the header. In this case a + second read is necessary. These one or two reads repeat for every + part of the record. + + RETURN + 0 OK + != 0 Error +*/ + int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, register my_off_t filepos, my_bool skip_deleted_blocks) { - int flag,info_read,save_errno; + int block_of_record, info_read, save_errno; uint left_len,b_type; byte *to; MI_BLOCK_INFO block_info; @@ -1550,7 +1641,8 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, else info_read=1; /* memory-keyinfoblock is ok */ - flag=block_info.second_read=0; + block_of_record= 0; /* First block of record is numbered as zero. */ + block_info.second_read= 0; left_len=1; do { @@ -1573,15 +1665,15 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, { if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos, sizeof(block_info.header), - (!flag && skip_deleted_blocks ? READING_NEXT : 0) | - READING_HEADER)) + (!block_of_record && skip_deleted_blocks ? + READING_NEXT : 0) | READING_HEADER)) goto panic; b_type=_mi_get_block_info(&block_info,-1,filepos); } else { if (info->opt_flag & WRITE_CACHE_USED && - info->rec_cache.pos_in_file <= filepos && + info->rec_cache.pos_in_file < filepos + MI_BLOCK_INFO_HEADER_LENGTH && flush_io_cache(&info->rec_cache)) DBUG_RETURN(my_errno); info->rec_cache.seek_not_done=1; @@ -1606,7 +1698,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, } goto err; } - if (flag == 0) /* First block */ + if (block_of_record == 0) /* First block */ { if (block_info.rec_len > (uint) share->base.max_pack_length) goto panic; @@ -1639,7 +1731,7 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, left_len-=tmp_length; to+=tmp_length; filepos+=tmp_length; - } + } } /* read rest of record from file */ if (block_info.data_len) @@ -1648,11 +1740,17 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, { if (_mi_read_cache(&info->rec_cache,(byte*) to,filepos, block_info.data_len, - (!flag && skip_deleted_blocks) ? READING_NEXT :0)) + (!block_of_record && skip_deleted_blocks) ? + READING_NEXT : 0)) goto panic; } else { + if (info->opt_flag & WRITE_CACHE_USED && + info->rec_cache.pos_in_file < + block_info.filepos + block_info.data_len && + flush_io_cache(&info->rec_cache)) + goto err; /* VOID(my_seek(info->dfile,filepos,MY_SEEK_SET,MYF(0))); */ if (my_read(info->dfile,(byte*) to,block_info.data_len,MYF(MY_NABP))) { @@ -1662,10 +1760,14 @@ int _mi_read_rnd_dynamic_record(MI_INFO *info, byte *buf, } } } - if (flag++ == 0) + /* + Increment block-of-record counter. If it was the first block, + remember the position behind the block for the next call. + */ + if (block_of_record++ == 0) { - info->nextpos=block_info.filepos+block_info.block_len; - skip_deleted_blocks=0; + info->nextpos= block_info.filepos + block_info.block_len; + skip_deleted_blocks= 0; } left_len-=block_info.data_len; to+=block_info.data_len; @@ -1697,6 +1799,11 @@ uint _mi_get_block_info(MI_BLOCK_INFO *info, File file, my_off_t filepos) if (file >= 0) { + /* + We do not use my_pread() here because we want to have the file + pointer set to the end of the header after this function. + my_pread() may leave the file pointer untouched. + */ VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0))); if (my_read(file,(char*) header,sizeof(info->header),MYF(0)) != sizeof(info->header)) |