diff --git a/storage/innodb_plugin/dict/dict0boot.c b/storage/innodb_plugin/dict/dict0boot.c index 8f948c06c51..c1df2bac0bf 100644 --- a/storage/innodb_plugin/dict/dict0boot.c +++ b/storage/innodb_plugin/dict/dict0boot.c @@ -358,7 +358,7 @@ dict_boot(void) dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4); - /* The '+ 2' below comes from the 2 system fields */ + /* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */ #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2 #error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2" #endif @@ -367,6 +367,9 @@ dict_boot(void) #endif #if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2 #error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2" +#endif +#if DICT_SYS_INDEXES_NAME_FIELD != 1 + 2 +#error "DICT_SYS_INDEXES_NAME_FIELD != 1 + 2" #endif table->id = DICT_INDEXES_ID; diff --git a/storage/innodb_plugin/include/dict0boot.h b/storage/innodb_plugin/include/dict0boot.h index 51d37ee98d1..404fc23bfa3 100644 --- a/storage/innodb_plugin/include/dict0boot.h +++ b/storage/innodb_plugin/include/dict0boot.h @@ -137,6 +137,7 @@ clustered index */ #define DICT_SYS_INDEXES_PAGE_NO_FIELD 8 #define DICT_SYS_INDEXES_SPACE_NO_FIELD 7 #define DICT_SYS_INDEXES_TYPE_FIELD 6 +#define DICT_SYS_INDEXES_NAME_FIELD 3 /* When a row id which is zero modulo this number (which must be a power of two) is assigned, the field DICT_HDR_ROW_ID on the dictionary header page is diff --git a/storage/innodb_plugin/row/row0merge.c b/storage/innodb_plugin/row/row0merge.c index 7be9bd412a3..1608751dc89 100644 --- a/storage/innodb_plugin/row/row0merge.c +++ b/storage/innodb_plugin/row/row0merge.c @@ -2031,38 +2031,79 @@ row_merge_drop_temp_indexes(void) /*=============================*/ { trx_t* trx; - ulint err; - - /* We use the private SQL parser of Innobase to generate the - query graphs needed in deleting the dictionary data from system - tables in Innobase. Deleting a row from SYS_INDEXES table also - frees the file segments of the B-tree associated with the index. */ - static const char drop_temp_indexes[] = - "PROCEDURE DROP_TEMP_INDEXES_PROC () IS\n" - "indexid CHAR;\n" - "DECLARE CURSOR c IS SELECT ID FROM SYS_INDEXES\n" - "WHERE SUBSTR(NAME,0,1)='" TEMP_INDEX_PREFIX_STR "';\n" - "BEGIN\n" - "\tOPEN c;\n" - "\tWHILE 1=1 LOOP\n" - "\t\tFETCH c INTO indexid;\n" - "\t\tIF (SQL % NOTFOUND) THEN\n" - "\t\t\tEXIT;\n" - "\t\tEND IF;\n" - "\t\tDELETE FROM SYS_FIELDS WHERE INDEX_ID = indexid;\n" - "\t\tDELETE FROM SYS_INDEXES WHERE ID = indexid;\n" - "\tEND LOOP;\n" - "\tCLOSE c;\n" - "\tCOMMIT WORK;\n" - "END;\n"; + btr_pcur_t pcur; + mtr_t mtr; + /* Load the table definitions that contain partially defined + indexes, so that the data dictionary information can be checked + when accessing the tablename.ibd files. */ trx = trx_allocate_for_background(); trx->op_info = "dropping partially created indexes"; row_mysql_lock_data_dictionary(trx); - err = que_eval_sql(NULL, drop_temp_indexes, FALSE, trx); - ut_a(err == DB_SUCCESS); + mtr_start(&mtr); + btr_pcur_open_at_index_side( + TRUE, + dict_table_get_first_index(dict_sys->sys_indexes), + BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); + + for (;;) { + const rec_t* rec; + const byte* field; + ulint len; + dulint table_id; + dict_table_t* table; + + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) { + break; + } + + rec = btr_pcur_get_rec(&pcur); + field = rec_get_nth_field_old(rec, DICT_SYS_INDEXES_NAME_FIELD, + &len); + if (len == UNIV_SQL_NULL || len == 0 + || mach_read_from_1(field) != (ulint) TEMP_INDEX_PREFIX) { + continue; + } + + /* This is a temporary index. */ + + field = rec_get_nth_field_old(rec, 0/*TABLE_ID*/, &len); + if (len != 8) { + /* Corrupted TABLE_ID */ + continue; + } + + table_id = mach_read_from_8(field); + + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + table = dict_load_table_on_id(table_id); + + if (table) { + dict_index_t* index; + + for (index = dict_table_get_first_index(table); + index; index = dict_table_get_next_index(index)) { + + if (*index->name == TEMP_INDEX_PREFIX) { + row_merge_drop_index(index, table, trx); + trx_commit_for_mysql(trx); + } + } + } + + mtr_start(&mtr); + btr_pcur_restore_position(BTR_SEARCH_LEAF, + &pcur, &mtr); + } + + btr_pcur_close(&pcur); + mtr_commit(&mtr); row_mysql_unlock_data_dictionary(trx); trx_free_for_background(trx); } diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index ad78c559141..0223a389b5d 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3370,88 +3370,79 @@ void row_mysql_drop_temp_tables(void) /*============================*/ { - trx_t* trx; - ulint err; + trx_t* trx; + btr_pcur_t pcur; + mtr_t mtr; + mem_heap_t* heap; trx = trx_allocate_for_background(); trx->op_info = "dropping temporary tables"; row_mysql_lock_data_dictionary(trx); - err = que_eval_sql( - NULL, - "PROCEDURE DROP_TEMP_TABLES_PROC () IS\n" - "table_name CHAR;\n" - "table_id CHAR;\n" - "foreign_id CHAR;\n" - "index_id CHAR;\n" - "DECLARE CURSOR c IS SELECT NAME,ID FROM SYS_TABLES\n" - "WHERE N_COLS > 2147483647\n" - /* N_COLS>>31 is set unless ROW_FORMAT=REDUNDANT, - and MIX_LEN may be garbage for those tables */ - "AND MIX_LEN=(MIX_LEN/2*2+1);\n" - /* MIX_LEN & 1 is set for temporary tables */ -#if DICT_TF2_TEMPORARY != 1 -# error "DICT_TF2_TEMPORARY != 1" -#endif - "BEGIN\n" - "OPEN c;\n" - "WHILE 1=1 LOOP\n" - " FETCH c INTO table_name, table_id;\n" - " IF (SQL % NOTFOUND) THEN\n" - " EXIT;\n" - " END IF;\n" - " WHILE 1=1 LOOP\n" - " SELECT ID INTO index_id\n" - " FROM SYS_INDEXES\n" - " WHERE TABLE_ID = table_id\n" - " LOCK IN SHARE MODE;\n" - " IF (SQL % NOTFOUND) THEN\n" - " EXIT;\n" - " END IF;\n" + heap = mem_heap_create(200); - /* Do not drop tables for which there exist - foreign key constraints. */ - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE FOR_NAME = table_name\n" - " AND TO_BINARY(FOR_NAME)\n" - " = TO_BINARY(table_name)\n;" - " IF NOT (SQL % NOTFOUND) THEN\n" - " EXIT;\n" - " END IF;\n" + mtr_start(&mtr); - " SELECT ID INTO foreign_id\n" - " FROM SYS_FOREIGN\n" - " WHERE REF_NAME = table_name\n" - " AND TO_BINARY(REF_NAME)\n" - " = TO_BINARY(table_name)\n;" - " IF NOT (SQL % NOTFOUND) THEN\n" - " EXIT;\n" - " END IF;\n" + btr_pcur_open_at_index_side( + TRUE, + dict_table_get_first_index(dict_sys->sys_tables), + BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); - " DELETE FROM SYS_FIELDS\n" - " WHERE INDEX_ID = index_id;\n" - " DELETE FROM SYS_INDEXES\n" - " WHERE ID = index_id\n" - " AND TABLE_ID = table_id;\n" - " END LOOP;\n" - " DELETE FROM SYS_COLUMNS\n" - " WHERE TABLE_ID = table_id;\n" - " DELETE FROM SYS_TABLES\n" - " WHERE ID = table_id;\n" - "END LOOP;\n" - "COMMIT WORK;\n" - "END;\n" - , FALSE, trx); + for (;;) { + const rec_t* rec; + const byte* field; + ulint len; + const char* table_name; + dict_table_t* table; - if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: Failed to drop temporary tables:" - " error %lu occurred\n", - (ulong) err); + btr_pcur_move_to_next_user_rec(&pcur, &mtr); + + if (!btr_pcur_is_on_user_rec(&pcur)) { + break; + } + + rec = btr_pcur_get_rec(&pcur); + field = rec_get_nth_field_old(rec, 4/*N_COLS*/, &len); + if (len != 4 || !(mach_read_from_4(field) & 0x80000000UL)) { + continue; + } + + /* Because this is not a ROW_FORMAT=REDUNDANT table, + the is_temp flag is valid. Examine it. */ + + field = rec_get_nth_field_old(rec, 7/*MIX_LEN*/, &len); + if (len != 4 + || !(mach_read_from_4(field) & DICT_TF2_TEMPORARY)) { + continue; + } + + /* This is a temporary table. */ + field = rec_get_nth_field_old(rec, 0/*NAME*/, &len); + if (len == UNIV_SQL_NULL || len == 0) { + /* Corrupted SYS_TABLES.NAME */ + continue; + } + + table_name = mem_heap_strdupl(heap, (const char*) field, len); + + btr_pcur_store_position(&pcur, &mtr); + btr_pcur_commit_specify_mtr(&pcur, &mtr); + + table = dict_load_table(table_name); + + if (table) { + row_drop_table_for_mysql(table_name, trx, FALSE); + trx_commit_for_mysql(trx); + } + + mtr_start(&mtr); + btr_pcur_restore_position(BTR_SEARCH_LEAF, + &pcur, &mtr); } + btr_pcur_close(&pcur); + mtr_commit(&mtr); + mem_heap_free(heap); row_mysql_unlock_data_dictionary(trx); trx_free_for_background(trx); }