Commit bab2231f authored by unknown's avatar unknown

InnoDB cleanup: Fix potential buffer overflows,

allow deletion of tablespaces whose names contain "'"


innobase/dict/dict0load.c:
  dict_check_tablespaces_or_store_max_id():
  Dynamically allocate memory for file name
innobase/fil/fil0fil.c:
  Dynamically allocate memory for file names
innobase/os/os0file.c:
  os_file_dirname(): allocate slightly less memory
  os_file_create_subdirs_if_needed(): compare more efficiently
innobase/row/row0mysql.c:
  Allow tablespaces with "'" in their names to be deleted
  Display identifiers with ut_print_name() or dict_index_name_print()
parent c0b6c9f7
...@@ -207,7 +207,6 @@ dict_check_tablespaces_or_store_max_id( ...@@ -207,7 +207,6 @@ dict_check_tablespaces_or_store_max_id(
ulint space_id; ulint space_id;
ulint max_space_id = 0; ulint max_space_id = 0;
mtr_t mtr; mtr_t mtr;
char name[OS_FILE_MAX_PATH];
mutex_enter(&(dict_sys->mutex)); mutex_enter(&(dict_sys->mutex));
...@@ -247,9 +246,7 @@ dict_check_tablespaces_or_store_max_id( ...@@ -247,9 +246,7 @@ dict_check_tablespaces_or_store_max_id(
/* We found one */ /* We found one */
ut_a(len < OS_FILE_MAX_PATH - 10); char* name = mem_strdupl(field, len);
ut_memcpy(name, field, len);
name[len] = '\0';
field = rec_get_nth_field(rec, 9, &len); field = rec_get_nth_field(rec, 9, &len);
ut_a(len == 4); ut_a(len == 4);
...@@ -267,7 +264,9 @@ dict_check_tablespaces_or_store_max_id( ...@@ -267,7 +264,9 @@ dict_check_tablespaces_or_store_max_id(
fil_space_for_table_exists_in_mem(space_id, name, fil_space_for_table_exists_in_mem(space_id, name,
TRUE, TRUE); TRUE, TRUE);
} }
mem_free(name);
if (space_id > max_space_id) { if (space_id > max_space_id) {
max_space_id = space_id; max_space_id = space_id;
} }
......
...@@ -1749,7 +1749,7 @@ fil_delete_tablespace( ...@@ -1749,7 +1749,7 @@ fil_delete_tablespace(
fil_space_t* space; fil_space_t* space;
fil_node_t* node; fil_node_t* node;
ulint count = 0; ulint count = 0;
char path[OS_FILE_MAX_PATH]; char* path;
ut_a(id != 0); ut_a(id != 0);
stop_ibuf_merges: stop_ibuf_merges:
...@@ -1806,11 +1806,8 @@ fil_delete_tablespace( ...@@ -1806,11 +1806,8 @@ fil_delete_tablespace(
} }
ut_a(space); ut_a(space);
ut_a(strlen(space->name) < OS_FILE_MAX_PATH);
ut_a(space->n_pending_ibuf_merges == 0); ut_a(space->n_pending_ibuf_merges == 0);
strcpy(path, space->name);
space->is_being_deleted = TRUE; space->is_being_deleted = TRUE;
ut_a(UT_LIST_GET_LEN(space->chain) == 1); ut_a(UT_LIST_GET_LEN(space->chain) == 1);
...@@ -1834,6 +1831,8 @@ fil_delete_tablespace( ...@@ -1834,6 +1831,8 @@ fil_delete_tablespace(
goto try_again; goto try_again;
} }
path = mem_strdup(space->name);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
/* Invalidate in the buffer pool all pages belonging to the /* Invalidate in the buffer pool all pages belonging to the
...@@ -1851,27 +1850,26 @@ fil_delete_tablespace( ...@@ -1851,27 +1850,26 @@ fil_delete_tablespace(
if (success) { if (success) {
success = os_file_delete(path); success = os_file_delete(path);
}
if (success) { mem_free(path);
/* Write a log record about the deletion of the .ibd
file, so that ibbackup can replay it in the if (success) {
--apply-log phase. We use a dummy mtr and the familiar
log write mechanism. */
#ifndef UNIV_HOTBACKUP #ifndef UNIV_HOTBACKUP
{ /* Write a log record about the deletion of the .ibd
mtr_t mtr; file, so that ibbackup can replay it in the
--apply-log phase. We use a dummy mtr and the familiar
log write mechanism. */
mtr_t mtr;
/* When replaying the operation in ibbackup, do not try /* When replaying the operation in ibbackup, do not try
to write any log record */ to write any log record */
mtr_start(&mtr); mtr_start(&mtr);
fil_op_write_log(MLOG_FILE_DELETE, id, path, fil_op_write_log(MLOG_FILE_DELETE, id, path, NULL, &mtr);
NULL, &mtr); mtr_commit(&mtr);
mtr_commit(&mtr);
}
#endif #endif
return(TRUE); return(TRUE);
}
} }
return(FALSE); return(FALSE);
...@@ -1956,6 +1954,29 @@ fil_rename_tablespace_in_mem( ...@@ -1956,6 +1954,29 @@ fil_rename_tablespace_in_mem(
return(TRUE); return(TRUE);
} }
/***********************************************************************
Allocates a file name for a single-table tablespace.
The string must be freed by caller with mem_free(). */
static
char*
fil_make_ibd_name(
/*==============*/
/* out, own: file name */
const char* name) /* in: table name */
{
ulint namelen = strlen(name);
ulint dirlen = strlen(fil_path_to_mysql_datadir);
char* filename = mem_alloc(namelen + dirlen + sizeof "/.ibd");
memcpy(filename, fil_path_to_mysql_datadir, dirlen);
filename[dirlen] = '/';
memcpy(filename + dirlen + 1, name, namelen);
memcpy(filename + dirlen + namelen + 1, ".ibd", sizeof ".ibd");
srv_normalize_path_for_win(filename);
return(filename);
}
/*********************************************************************** /***********************************************************************
Renames a single-table tablespace. The tablespace must be cached in the Renames a single-table tablespace. The tablespace must be cached in the
tablespace memory cache. */ tablespace memory cache. */
...@@ -1978,9 +1999,9 @@ fil_rename_tablespace( ...@@ -1978,9 +1999,9 @@ fil_rename_tablespace(
fil_space_t* space; fil_space_t* space;
fil_node_t* node; fil_node_t* node;
ulint count = 0; ulint count = 0;
char* path = NULL; char* path;
ibool old_name_was_specified = TRUE; ibool old_name_was_specified = TRUE;
char old_path[OS_FILE_MAX_PATH]; char* old_path;
ut_a(id != 0); ut_a(id != 0);
...@@ -2059,48 +2080,33 @@ fil_rename_tablespace( ...@@ -2059,48 +2080,33 @@ fil_rename_tablespace(
/* Check that the old name in the space is right */ /* Check that the old name in the space is right */
if (old_name_was_specified) { if (old_name_was_specified) {
ut_a(strlen(old_name) + strlen(fil_path_to_mysql_datadir) old_path = fil_make_ibd_name(old_name);
< OS_FILE_MAX_PATH - 10);
sprintf(old_path, "%s/%s.ibd", fil_path_to_mysql_datadir,
old_name);
srv_normalize_path_for_win(old_path);
ut_a(strcmp(space->name, old_path) == 0); ut_a(strcmp(space->name, old_path) == 0);
ut_a(strcmp(node->name, old_path) == 0); ut_a(strcmp(node->name, old_path) == 0);
} else { } else {
sprintf(old_path, "%s", space->name); old_path = mem_strdup(space->name);
} }
/* Rename the tablespace and the node in the memory cache */ /* Rename the tablespace and the node in the memory cache */
path = fil_make_ibd_name(new_name);
ut_a(strlen(new_name) + strlen(fil_path_to_mysql_datadir)
< OS_FILE_MAX_PATH - 10);
path = mem_alloc(OS_FILE_MAX_PATH);
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, new_name);
srv_normalize_path_for_win(path);
success = fil_rename_tablespace_in_mem(space, node, path); success = fil_rename_tablespace_in_mem(space, node, path);
if (!success) { if (success) {
success = os_file_rename(old_path, path);
goto func_exit;
}
success = os_file_rename(old_path, path);
if (!success) { if (!success) {
/* We have to revert the changes we made to the tablespace /* We have to revert the changes we made
memory cache */ to the tablespace memory cache */
ut_a(fil_rename_tablespace_in_mem(space, node, old_path)); ut_a(fil_rename_tablespace_in_mem(space, node,
old_path));
}
} }
func_exit: mem_free(path);
if (path) { mem_free(old_path);
mem_free(path);
}
space->stop_ios = FALSE; space->stop_ios = FALSE;
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
...@@ -2144,15 +2150,11 @@ fil_create_new_single_table_tablespace( ...@@ -2144,15 +2150,11 @@ fil_create_new_single_table_tablespace(
ulint err; ulint err;
byte* page; byte* page;
ibool success; ibool success;
char path[OS_FILE_MAX_PATH]; char* path;
ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE); ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
ut_a(strlen(tablename) + strlen(fil_path_to_mysql_datadir) path = fil_make_ibd_name(tablename);
< OS_FILE_MAX_PATH - 10);
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, tablename);
srv_normalize_path_for_win(path);
file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL, file = os_file_create(path, OS_FILE_CREATE, OS_FILE_NORMAL,
OS_DATA_FILE, &ret); OS_DATA_FILE, &ret);
...@@ -2175,14 +2177,17 @@ fil_create_new_single_table_tablespace( ...@@ -2175,14 +2177,17 @@ fil_create_new_single_table_tablespace(
"InnoDB: resolve the problem by removing the file %s\n" "InnoDB: resolve the problem by removing the file %s\n"
"InnoDB: under the 'datadir' of MySQL.\n", path); "InnoDB: under the 'datadir' of MySQL.\n", path);
mem_free(path);
return(DB_TABLESPACE_ALREADY_EXISTS); return(DB_TABLESPACE_ALREADY_EXISTS);
} }
if (err == OS_FILE_DISK_FULL) { if (err == OS_FILE_DISK_FULL) {
mem_free(path);
return(DB_OUT_OF_FILE_SPACE); return(DB_OUT_OF_FILE_SPACE);
} }
mem_free(path);
return(DB_ERROR); return(DB_ERROR);
} }
...@@ -2195,6 +2200,7 @@ fil_create_new_single_table_tablespace( ...@@ -2195,6 +2200,7 @@ fil_create_new_single_table_tablespace(
os_file_close(file); os_file_close(file);
os_file_delete(path); os_file_delete(path);
mem_free(path);
return(DB_OUT_OF_FILE_SPACE); return(DB_OUT_OF_FILE_SPACE);
} }
...@@ -2206,9 +2212,11 @@ fil_create_new_single_table_tablespace( ...@@ -2206,9 +2212,11 @@ fil_create_new_single_table_tablespace(
if (*space_id == ULINT_UNDEFINED) { if (*space_id == ULINT_UNDEFINED) {
ut_free(page); ut_free(page);
error_exit:
os_file_close(file); os_file_close(file);
os_file_delete(path); os_file_delete(path);
mem_free(path);
return(DB_ERROR); return(DB_ERROR);
} }
...@@ -2234,11 +2242,7 @@ fil_create_new_single_table_tablespace( ...@@ -2234,11 +2242,7 @@ fil_create_new_single_table_tablespace(
if (!ret) { if (!ret) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: could not write the first page to tablespace %s\n", path); "InnoDB: Error: could not write the first page to tablespace %s\n", path);
goto error_exit;
os_file_close(file);
os_file_delete(path);
return(DB_ERROR);
} }
ret = os_file_flush(file); ret = os_file_flush(file);
...@@ -2246,27 +2250,22 @@ fil_create_new_single_table_tablespace( ...@@ -2246,27 +2250,22 @@ fil_create_new_single_table_tablespace(
if (!ret) { if (!ret) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: file flush of tablespace %s failed\n", path); "InnoDB: Error: file flush of tablespace %s failed\n", path);
goto error_exit;
os_file_close(file);
os_file_delete(path);
return(DB_ERROR);
} }
os_file_close(file); os_file_close(file);
if (*space_id == ULINT_UNDEFINED) { if (*space_id == ULINT_UNDEFINED) {
os_file_delete(path); os_file_delete(path);
error_exit2:
mem_free(path);
return(DB_ERROR); return(DB_ERROR);
} }
success = fil_space_create(path, *space_id, FIL_TABLESPACE); success = fil_space_create(path, *space_id, FIL_TABLESPACE);
if (!success) { if (!success) {
os_file_delete(path); goto error_exit2;
return(DB_ERROR);
} }
fil_node_create(path, size, *space_id, FALSE); fil_node_create(path, size, *space_id, FALSE);
...@@ -2282,6 +2281,7 @@ fil_create_new_single_table_tablespace( ...@@ -2282,6 +2281,7 @@ fil_create_new_single_table_tablespace(
mtr_commit(&mtr); mtr_commit(&mtr);
} }
#endif #endif
mem_free(path);
return(DB_SUCCESS); return(DB_SUCCESS);
} }
...@@ -2315,13 +2315,7 @@ fil_reset_too_high_lsns( ...@@ -2315,13 +2315,7 @@ fil_reset_too_high_lsns(
ulint page_no; ulint page_no;
ibool success; ibool success;
filepath = ut_malloc(OS_FILE_MAX_PATH); filepath = fil_make_ibd_name(name);
ut_a(strlen(name) < OS_FILE_MAX_PATH - 10);
sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(filepath);
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN, file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
OS_FILE_READ_WRITE, &success); OS_FILE_READ_WRITE, &success);
...@@ -2450,13 +2444,7 @@ fil_open_single_table_tablespace( ...@@ -2450,13 +2444,7 @@ fil_open_single_table_tablespace(
ulint space_id; ulint space_id;
ibool ret = TRUE; ibool ret = TRUE;
filepath = ut_malloc(OS_FILE_MAX_PATH); filepath = fil_make_ibd_name(name);
ut_a(strlen(name) < OS_FILE_MAX_PATH - 10);
sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(filepath);
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN, file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
OS_FILE_READ_ONLY, &success); OS_FILE_READ_ONLY, &success);
...@@ -2525,6 +2513,28 @@ fil_open_single_table_tablespace( ...@@ -2525,6 +2513,28 @@ fil_open_single_table_tablespace(
return(ret); return(ret);
} }
#ifdef UNIV_HOTBACKUP
/***********************************************************************
Allocates a file name for an old version of a single-table tablespace.
The string must be freed by caller with mem_free(). */
static
char*
fil_make_ibbackup_old_name(
/*=======================*/
/* out, own: file name */
const char* name) /* in: original file name */
{
static const char suffix[] = "_ibbackup_old_vers_";
ulint len = strlen(name);
char* path = ut_malloc(len + (15 + sizeof suffix));
memcpy(path, name, len);
memcpy(path + len, suffix, (sizeof suffix) - 1);
ut_sprintf_timestamp_without_extra_chars(path + len + sizeof suffix);
return(path);
}
#endif /* UNIV_HOTBACKUP */
/************************************************************************ /************************************************************************
Opens an .ibd file and adds the associated single-table tablespace to the Opens an .ibd file and adds the associated single-table tablespace to the
InnoDB fil0fil.c data structures. */ InnoDB fil0fil.c data structures. */
...@@ -2547,10 +2557,8 @@ fil_load_single_table_tablespace( ...@@ -2547,10 +2557,8 @@ fil_load_single_table_tablespace(
#ifdef UNIV_HOTBACKUP #ifdef UNIV_HOTBACKUP
fil_space_t* space; fil_space_t* space;
#endif #endif
filepath = ut_malloc(OS_FILE_MAX_PATH); filepath = ut_malloc(strlen(dbname) + strlen(filename)
+ strlen(fil_path_to_mysql_datadir) + 3);
ut_a(strlen(dbname) + strlen(filename)
+ strlen(fil_path_to_mysql_datadir) < OS_FILE_MAX_PATH - 100);
sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname, sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname,
filename); filename);
...@@ -2639,11 +2647,7 @@ fil_load_single_table_tablespace( ...@@ -2639,11 +2647,7 @@ fil_load_single_table_tablespace(
filepath, space_id, filepath, size); filepath, space_id, filepath, size);
os_file_close(file); os_file_close(file);
new_path = ut_malloc(OS_FILE_MAX_PATH); new_path = fil_make_ibbackup_old_name(filepath);
sprintf(new_path, "%s_ibbackup_old_vers_", filepath);
ut_sprintf_timestamp_without_extra_chars(
new_path + ut_strlen(new_path));
ut_a(os_file_rename(filepath, new_path)); ut_a(os_file_rename(filepath, new_path));
ut_free(page); ut_free(page);
...@@ -2676,11 +2680,8 @@ fil_load_single_table_tablespace( ...@@ -2676,11 +2680,8 @@ fil_load_single_table_tablespace(
space->name); space->name);
os_file_close(file); os_file_close(file);
new_path = ut_malloc(OS_FILE_MAX_PATH); new_path = fil_make_ibbackup_old_name(filepath);
sprintf(new_path, "%s_ibbackup_old_vers_", filepath);
ut_sprintf_timestamp_without_extra_chars(
new_path + ut_strlen(new_path));
mutex_exit(&(fil_system->mutex)); mutex_exit(&(fil_system->mutex));
ut_a(os_file_rename(filepath, new_path)); ut_a(os_file_rename(filepath, new_path));
...@@ -2724,7 +2725,8 @@ fil_load_single_table_tablespaces(void) ...@@ -2724,7 +2725,8 @@ fil_load_single_table_tablespaces(void)
/* out: DB_SUCCESS or error number */ /* out: DB_SUCCESS or error number */
{ {
int ret; int ret;
char* dbpath; char* dbpath = NULL;
ulint dbpath_len = 0;
os_file_dir_t dir; os_file_dir_t dir;
os_file_dir_t dbdir; os_file_dir_t dbdir;
os_file_stat_t dbinfo; os_file_stat_t dbinfo;
...@@ -2739,7 +2741,7 @@ fil_load_single_table_tablespaces(void) ...@@ -2739,7 +2741,7 @@ fil_load_single_table_tablespaces(void)
return(DB_ERROR); return(DB_ERROR);
} }
dbpath = ut_malloc(OS_FILE_MAX_PATH); dbpath = ut_malloc(dbpath_len);
/* Scan all directories under the datadir. They are the database /* Scan all directories under the datadir. They are the database
directories of MySQL. */ directories of MySQL. */
...@@ -2747,6 +2749,7 @@ fil_load_single_table_tablespaces(void) ...@@ -2747,6 +2749,7 @@ fil_load_single_table_tablespaces(void)
ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir, ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir,
&dbinfo); &dbinfo);
while (ret == 0) { while (ret == 0) {
ulint len;
/* printf("Looking at %s in datadir\n", dbinfo.name); */ /* printf("Looking at %s in datadir\n", dbinfo.name); */
if (dbinfo.type == OS_FILE_TYPE_FILE if (dbinfo.type == OS_FILE_TYPE_FILE
...@@ -2757,9 +2760,19 @@ fil_load_single_table_tablespaces(void) ...@@ -2757,9 +2760,19 @@ fil_load_single_table_tablespaces(void)
/* We found a symlink or a directory; try opening it to see /* We found a symlink or a directory; try opening it to see
if a symlink is a directory */ if a symlink is a directory */
ut_a(strlen(dbinfo.name) < OS_FILE_MAX_PATH - 10);
len = strlen(fil_path_to_mysql_datadir)
+ strlen (dbinfo.name) + 2;
if (len > dbpath_len) {
dbpath_len = len;
if (!dbpath) {
dbpath = mem_alloc(dbpath_len);
}
else {
dbpath = mem_realloc(dbpath, dbpath_len,
__FILE__, __LINE__);
}
}
sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir, sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir,
dbinfo.name); dbinfo.name);
srv_normalize_path_for_win(dbpath); srv_normalize_path_for_win(dbpath);
...@@ -2809,7 +2822,9 @@ fil_load_single_table_tablespaces(void) ...@@ -2809,7 +2822,9 @@ fil_load_single_table_tablespaces(void)
dir, &dbinfo); dir, &dbinfo);
} }
ut_free(dbpath); if (dbpath) {
ut_free(dbpath);
}
/* At the end of directory we should get 1 as the return value, -1 /* At the end of directory we should get 1 as the return value, -1
if there was an error */ if there was an error */
...@@ -2962,14 +2977,13 @@ fil_space_for_table_exists_in_mem( ...@@ -2962,14 +2977,13 @@ fil_space_for_table_exists_in_mem(
fil_system_t* system = fil_system; fil_system_t* system = fil_system;
fil_space_t* namespace; fil_space_t* namespace;
fil_space_t* space; fil_space_t* space;
char path[OS_FILE_MAX_PATH]; char* path;
ut_ad(system); ut_ad(system);
mutex_enter(&(system->mutex)); mutex_enter(&(system->mutex));
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name); path = fil_make_ibd_name(name);
srv_normalize_path_for_win(path);
/* Look if there is a space with the same id */ /* Look if there is a space with the same id */
...@@ -2988,6 +3002,7 @@ fil_space_for_table_exists_in_mem( ...@@ -2988,6 +3002,7 @@ fil_space_for_table_exists_in_mem(
space->mark = TRUE; space->mark = TRUE;
} }
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(TRUE); return(TRUE);
...@@ -2995,6 +3010,7 @@ fil_space_for_table_exists_in_mem( ...@@ -2995,6 +3010,7 @@ fil_space_for_table_exists_in_mem(
if (!print_error_if_does_not_exist) { if (!print_error_if_does_not_exist) {
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(FALSE); return(FALSE);
...@@ -3024,6 +3040,7 @@ fil_space_for_table_exists_in_mem( ...@@ -3024,6 +3040,7 @@ fil_space_for_table_exists_in_mem(
"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n" "InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
"InnoDB: how to resolve the issue.\n"); "InnoDB: how to resolve the issue.\n");
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(FALSE); return(FALSE);
...@@ -3047,11 +3064,13 @@ fil_space_for_table_exists_in_mem( ...@@ -3047,11 +3064,13 @@ fil_space_for_table_exists_in_mem(
"InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n" "InnoDB: You can look from section 15.1 of http://www.innodb.com/ibman.html\n"
"InnoDB: how to resolve the issue.\n"); "InnoDB: how to resolve the issue.\n");
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(FALSE); return(FALSE);
} }
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(FALSE); return(FALSE);
...@@ -3072,14 +3091,13 @@ fil_get_space_id_for_table( ...@@ -3072,14 +3091,13 @@ fil_get_space_id_for_table(
fil_system_t* system = fil_system; fil_system_t* system = fil_system;
fil_space_t* namespace; fil_space_t* namespace;
ulint id = ULINT_UNDEFINED; ulint id = ULINT_UNDEFINED;
char path[OS_FILE_MAX_PATH]; char* path;
ut_ad(system); ut_ad(system);
mutex_enter(&(system->mutex)); mutex_enter(&(system->mutex));
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name); path = fil_make_ibd_name(name);
srv_normalize_path_for_win(path);
/* Look if there is a space with the same name; the name is the /* Look if there is a space with the same name; the name is the
directory path to the file */ directory path to the file */
...@@ -3091,6 +3109,8 @@ fil_get_space_id_for_table( ...@@ -3091,6 +3109,8 @@ fil_get_space_id_for_table(
id = namespace->id; id = namespace->id;
} }
mem_free(path);
mutex_exit(&(system->mutex)); mutex_exit(&(system->mutex));
return(id); return(id);
......
...@@ -2331,31 +2331,22 @@ os_file_dirname( ...@@ -2331,31 +2331,22 @@ os_file_dirname(
pathname */ pathname */
const char* path) /* in: pathname */ const char* path) /* in: pathname */
{ {
char* dir;
int i, length, last_slash;
/* find the offset of the last slash */ /* find the offset of the last slash */
length = ut_strlen(path); const char* last_slash = strrchr(path, OS_FILE_PATH_SEPARATOR);
for (i = length - 1; i >= 0 && path[i] != OS_FILE_PATH_SEPARATOR; i++); if (!last_slash) {
last_slash = i;
if (last_slash < 0) {
/* no slash in the path, return "." */ /* no slash in the path, return "." */
return(mem_strdup(".")); return(mem_strdup("."));
} }
/* ok, there is a slash */ /* ok, there is a slash */
if (last_slash == 0) { if (last_slash == path) {
/* last slash is the first char of the path */ /* last slash is the first char of the path */
return(mem_strdup("/")); return(mem_strdup("/"));
} }
/* non-trivial directory component */ /* non-trivial directory component */
dir = mem_strdup(path); return(mem_strdupl(path, last_slash - path));
dir[last_slash] = 0;
return(dir);
} }
/******************************************************************** /********************************************************************
...@@ -2369,12 +2360,12 @@ os_file_create_subdirs_if_needed( ...@@ -2369,12 +2360,12 @@ os_file_create_subdirs_if_needed(
const char* path) /* in: path name */ const char* path) /* in: path name */
{ {
char* subdir; char* subdir;
static char rootdir[2] = { OS_FILE_PATH_SEPARATOR, 0 };
ibool success, subdir_exists; ibool success, subdir_exists;
os_file_type_t type; os_file_type_t type;
subdir = os_file_dirname(path); subdir = os_file_dirname(path);
if (0 == strcmp(subdir, rootdir) || 0 == strcmp(subdir, ".")) { if (strlen(subdir) == 1
&& (*subdir == OS_FILE_PATH_SEPARATOR || *subdir == '.')) {
/* subdir is root or cwd, nothing to do */ /* subdir is root or cwd, nothing to do */
ut_free(subdir); ut_free(subdir);
return(TRUE); return(TRUE);
......
...@@ -1951,7 +1951,37 @@ row_discard_tablespace_for_mysql( ...@@ -1951,7 +1951,37 @@ row_discard_tablespace_for_mysql(
que_t* graph = NULL; que_t* graph = NULL;
ibool success; ibool success;
ulint err; ulint err;
char buf[2 * OS_FILE_MAX_PATH]; char* buf;
static const char discard_tablespace_proc1[] =
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n"
"old_id CHAR;\n"
"new_id CHAR;\n"
"new_id_low INT;\n"
"new_id_high INT;\n"
"table_name CHAR;\n"
"BEGIN\n"
"table_name := ";
static const char discard_tablespace_proc2[] =
";\n"
"new_id_high := %lu;\n"
"new_id_low := %lu;\n"
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
"SELECT ID INTO old_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = table_name;\n"
"IF (SQL %% NOTFOUND) THEN\n"
" COMMIT WORK;\n"
" RETURN;\n"
"END IF;\n"
"UPDATE SYS_TABLES SET ID = new_id\n"
"WHERE ID = old_id;\n"
"UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"COMMIT WORK;\n"
"END;\n";
ut_ad(trx->mysql_thread_id == os_thread_get_curr_id()); ut_ad(trx->mysql_thread_id == os_thread_get_curr_id());
...@@ -1973,9 +2003,10 @@ row_discard_tablespace_for_mysql( ...@@ -1973,9 +2003,10 @@ row_discard_tablespace_for_mysql(
if (table->space == 0) { if (table->space == 0) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: table ", stderr);
" InnoDB: Error: table %s\n" ut_print_name(stderr, name);
"InnoDB: is in the system tablespace 0 which cannot be discarded\n", name); fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be discarded\n", stderr);
err = DB_ERROR; err = DB_ERROR;
goto funct_exit; goto funct_exit;
...@@ -1983,36 +2014,16 @@ row_discard_tablespace_for_mysql( ...@@ -1983,36 +2014,16 @@ row_discard_tablespace_for_mysql(
new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID); new_id = dict_hdr_get_new_id(DICT_HDR_TABLE_ID);
sprintf(buf, buf = mem_alloc((sizeof discard_tablespace_proc1) +
"PROCEDURE DISCARD_TABLESPACE_PROC () IS\n" (sizeof discard_tablespace_proc2) +
"old_id CHAR;\n" 20 + ut_strlenq(name, '\''));
"new_id CHAR;\n"
"new_id_low INT;\n"
"new_id_high INT;\n"
"table_name CHAR;\n"
"BEGIN\n"
"table_name :='%s';\n"
"new_id_high := %lu;\n"
"new_id_low := %lu;\n"
"new_id := CONCAT(TO_BINARY(new_id_high, 4), TO_BINARY(new_id_low, 4));\n"
"SELECT ID INTO old_id\n"
"FROM SYS_TABLES\n"
"WHERE NAME = table_name;\n"
"IF (SQL %% NOTFOUND) THEN\n"
" COMMIT WORK;\n"
" RETURN;\n"
"END IF;\n"
"UPDATE SYS_TABLES SET ID = new_id\n"
"WHERE ID = old_id;\n"
"UPDATE SYS_COLUMNS SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"UPDATE SYS_INDEXES SET TABLE_ID = new_id\n"
"WHERE TABLE_ID = old_id;\n"
"COMMIT WORK;\n"
"END;\n", name, (ulong) ut_dulint_get_high(new_id),
(ulong) ut_dulint_get_low(new_id));
ut_a(strlen(buf) < 2 * OS_FILE_MAX_PATH); memcpy(buf, discard_tablespace_proc1, sizeof discard_tablespace_proc1);
sprintf(ut_strcpyq(buf + (sizeof discard_tablespace_proc1 - 1),
'\'', name),
discard_tablespace_proc2,
(ulong) ut_dulint_get_high(new_id),
(ulong) ut_dulint_get_low(new_id));
graph = pars_sql(buf); graph = pars_sql(buf);
...@@ -2126,9 +2137,10 @@ row_import_tablespace_for_mysql( ...@@ -2126,9 +2137,10 @@ row_import_tablespace_for_mysql(
if (table->space == 0) { if (table->space == 0) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: table ", stderr);
" InnoDB: Error: table %s\n" ut_print_name(stderr, name);
"InnoDB: is in the system tablespace 0 which cannot be imported\n", name); fputs("\n"
"InnoDB: is in the system tablespace 0 which cannot be imported\n", stderr);
err = DB_ERROR; err = DB_ERROR;
goto funct_exit; goto funct_exit;
...@@ -2136,10 +2148,12 @@ row_import_tablespace_for_mysql( ...@@ -2136,10 +2148,12 @@ row_import_tablespace_for_mysql(
if (!table->tablespace_discarded) { if (!table->tablespace_discarded) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(
" InnoDB: Error: you are trying to IMPORT a tablespace\n" " InnoDB: Error: you are trying to IMPORT a tablespace\n"
"InnoDB: %s, though you have not called DISCARD on it yet\n" "InnoDB: ", stderr);
"InnoDB: during the lifetime of the mysqld process!\n", name); ut_print_name(stderr, name);
fputs(", though you have not called DISCARD on it yet\n"
"InnoDB: during the lifetime of the mysqld process!\n", stderr);
err = DB_ERROR; err = DB_ERROR;
...@@ -2469,7 +2483,7 @@ row_drop_table_for_mysql( ...@@ -2469,7 +2483,7 @@ row_drop_table_for_mysql(
if (dict_load_table(name) != NULL) { if (dict_load_table(name) != NULL) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fputs(" InnoDB: Error: not able to remove table ", fputs(" InnoDB: Error: not able to remove table ",
stderr); stderr);
ut_print_name(stderr, name); ut_print_name(stderr, name);
fputs(" from the dictionary cache!\n", stderr); fputs(" from the dictionary cache!\n", stderr);
err = DB_ERROR; err = DB_ERROR;
...@@ -2491,8 +2505,10 @@ row_drop_table_for_mysql( ...@@ -2491,8 +2505,10 @@ row_drop_table_for_mysql(
if (!success) { if (!success) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fprintf(stderr,
" InnoDB: Error: not able to delete tablespace %lu of table %s!\n", " InnoDB: Error: not able to delete tablespace %lu of table ",
(ulong) space_id, name); (ulong) space_id);
ut_print_name(stderr, name);
fputs("!\n", stderr);
err = DB_ERROR; err = DB_ERROR;
} }
} }
...@@ -2757,15 +2773,14 @@ row_rename_table_for_mysql( ...@@ -2757,15 +2773,14 @@ row_rename_table_for_mysql(
err = DB_TABLE_NOT_FOUND; err = DB_TABLE_NOT_FOUND;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: table ", stderr);
" InnoDB: Error: table %s\n" ut_print_name(stderr, old_name);
"InnoDB: does not exist in the InnoDB internal\n" fputs(" does not exist in the InnoDB internal\n"
"InnoDB: data dictionary though MySQL is trying to rename the table.\n" "InnoDB: data dictionary though MySQL is trying to rename the table.\n"
"InnoDB: Have you copied the .frm file of the table to the\n" "InnoDB: Have you copied the .frm file of the table to the\n"
"InnoDB: MySQL database directory from another database?\n" "InnoDB: MySQL database directory from another database?\n"
"InnoDB: You can look for further help from section 15.1 of\n" "InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n", "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
old_name);
goto funct_exit; goto funct_exit;
} }
...@@ -2773,12 +2788,12 @@ row_rename_table_for_mysql( ...@@ -2773,12 +2788,12 @@ row_rename_table_for_mysql(
err = DB_TABLE_NOT_FOUND; err = DB_TABLE_NOT_FOUND;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: table ", stderr);
" InnoDB: Error: table %s\n" ut_print_name(stderr, old_name);
"InnoDB: does not have an .ibd file in the database directory.\n" fputs(
" does not have an .ibd file in the database directory.\n"
"InnoDB: You can look for further help from section 15.1 of\n" "InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n", "InnoDB: http://www.innodb.com/ibman.php\n", stderr);
old_name);
goto funct_exit; goto funct_exit;
} }
...@@ -2905,23 +2920,25 @@ row_rename_table_for_mysql( ...@@ -2905,23 +2920,25 @@ row_rename_table_for_mysql(
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
if (err == DB_DUPLICATE_KEY) { if (err == DB_DUPLICATE_KEY) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: table ", stderr);
" InnoDB: Error: table %s exists in the InnoDB internal data\n" ut_print_name(stderr, new_name);
"InnoDB: dictionary though MySQL is trying rename table %s to it.\n" fputs(" exists in the InnoDB internal data\n"
"InnoDB: dictionary though MySQL is trying rename table ", stderr);
ut_print_name(stderr, old_name);
fputs(" to it.\n"
"InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n" "InnoDB: Have you deleted the .frm file and not used DROP TABLE?\n"
"InnoDB: You can look for further help from section 15.1 of\n" "InnoDB: You can look for further help from section 15.1 of\n"
"InnoDB: http://www.innodb.com/ibman.html\n", "InnoDB: http://www.innodb.com/ibman.php\n"
new_name, old_name); "InnoDB: If table ", stderr);
fprintf(stderr, ut_print_name(stderr, new_name);
"InnoDB: If table %s is a temporary table #sql..., then it can be that\n" fputs(" is a temporary table #sql..., then it can be that\n"
"InnoDB: there are still queries running on the table, and it will be\n" "InnoDB: there are still queries running on the table, and it will be\n"
"InnoDB: dropped automatically when the queries end.\n", new_name); "InnoDB: dropped automatically when the queries end.\n"
fprintf(stderr,
"InnoDB: You can drop the orphaned table inside InnoDB by\n" "InnoDB: You can drop the orphaned table inside InnoDB by\n"
"InnoDB: creating an InnoDB table with the same name in another\n" "InnoDB: creating an InnoDB table with the same name in another\n"
"InnoDB: database and moving the .frm file to the current database.\n" "InnoDB: database and moving the .frm file to the current database.\n"
"InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n" "InnoDB: Then MySQL thinks the table exists, and DROP TABLE will\n"
"InnoDB: succeed.\n"); "InnoDB: succeed.\n", stderr);
} }
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
trx_general_rollback_for_mysql(trx, FALSE, NULL); trx_general_rollback_for_mysql(trx, FALSE, NULL);
...@@ -2937,9 +2954,12 @@ row_rename_table_for_mysql( ...@@ -2937,9 +2954,12 @@ row_rename_table_for_mysql(
trx_general_rollback_for_mysql(trx, FALSE, NULL); trx_general_rollback_for_mysql(trx, FALSE, NULL);
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error in table rename, cannot rename ",
" InnoDB: Error in table rename, cannot rename %s to %s\n", old_name, stderr);
new_name); ut_print_name(stderr, old_name);
fputs(" to ", stderr);
ut_print_name(stderr, new_name);
putc('\n', stderr);
err = DB_ERROR; err = DB_ERROR;
goto funct_exit; goto funct_exit;
...@@ -2958,11 +2978,14 @@ row_rename_table_for_mysql( ...@@ -2958,11 +2978,14 @@ row_rename_table_for_mysql(
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
fprintf(stderr, fputs(" InnoDB: Error: in ALTER TABLE ",
" InnoDB: Error: in ALTER TABLE table %s\n" stderr);
"InnoDB: has or is referenced in foreign key constraints\n" ut_print_name(stderr, new_name);
"InnoDB: which are not compatible with the new table definition.\n", fputs("\n"
new_name); "InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n",
stderr);
ut_a(dict_table_rename_in_cache(table, ut_a(dict_table_rename_in_cache(table,
old_name, FALSE)); old_name, FALSE));
trx->error_state = DB_SUCCESS; trx->error_state = DB_SUCCESS;
...@@ -3160,9 +3183,11 @@ row_check_table_for_mysql( ...@@ -3160,9 +3183,11 @@ row_check_table_for_mysql(
ret = DB_ERROR; ret = DB_ERROR;
fputs("Error: ", stderr);
dict_index_name_print(stderr, index);
fprintf(stderr, fprintf(stderr,
"Error: index %s contains %lu entries, should be %lu\n", " contains %lu entries, should be %lu\n",
index->name, (ulong) n_rows, (ulong) n_rows,
(ulong) n_rows_in_table); (ulong) n_rows_in_table);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment