Commit 2b2e7e45 authored by marko@hundin.mysql.fi's avatar marko@hundin.mysql.fi

InnoDB cleanup: Fix potential buffer overflows,

allow deletion of tablespaces whose names contain "'"
parent d01c7b18
...@@ -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 @@ loop: ...@@ -247,9 +246,7 @@ loop:
/* 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);
...@@ -268,6 +265,8 @@ loop: ...@@ -268,6 +265,8 @@ loop:
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;
} }
......
This diff is collapsed.
...@@ -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;
...@@ -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);
ut_print_name(stderr, new_name);
fputs("\n"
"InnoDB: has or is referenced in foreign key constraints\n" "InnoDB: has or is referenced in foreign key constraints\n"
"InnoDB: which are not compatible with the new table definition.\n", "InnoDB: which are not compatible with the new table definition.\n",
new_name); 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