From 7ae2d469037f85892aab534bb908fa57682d8ed9 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Mon, 12 Dec 2005 21:06:59 +0300 Subject: [PATCH 1/2] Fix BUG#12071: "Windows hang: 'Opening tables' or 'Waiting for table' lockup". Changes from the innodb-4.1-ss11 snapshot. Do not call os_file-create_tmpfile() at runtime. Instead, create a tempfile at startup and guard access to it with a mutex. Also, fix bugs: 10511: "Wrong padding of UCS2 CHAR columns in ON UPDATE CASCADE"; 13778: "If FOREIGN_KEY_CHECKS=0, one can create inconsistent FOREIGN KEYs". When FOREIGN_KEY_CHECKS=0 we still need to check that datatypes between foreign key references are compatible. Also, added test cases (also for bug 9802). --- innobase/dict/dict0dict.c | 34 ++++------ innobase/dict/dict0load.c | 9 +-- innobase/include/dict0dict.h | 3 +- innobase/include/dict0load.h | 3 +- innobase/include/os0file.h | 2 +- innobase/include/rem0cmp.h | 3 +- innobase/include/srv0srv.h | 6 ++ innobase/rem/rem0cmp.c | 11 ++-- innobase/row/row0ins.c | 68 +++++++++---------- innobase/row/row0mysql.c | 64 ++++++++---------- innobase/srv/srv0srv.c | 6 ++ innobase/srv/srv0start.c | 14 +++- mysql-test/r/innodb.result | 32 +++++++++ mysql-test/t/innodb.test | 49 ++++++++++++++ sql/ha_innodb.cc | 123 +++++++++++++++++------------------ 15 files changed, 257 insertions(+), 170 deletions(-) diff --git a/innobase/dict/dict0dict.c b/innobase/dict/dict0dict.c index b0327f77fd3..0cdd593b678 100644 --- a/innobase/dict/dict0dict.c +++ b/innobase/dict/dict0dict.c @@ -2077,8 +2077,11 @@ dict_foreign_find_index( dict_table_t* table, /* in: table */ const char** columns,/* in: array of column names */ ulint n_cols, /* in: number of columns */ - dict_index_t* types_idx)/* in: NULL or an index to whose types the - column types must match */ + dict_index_t* types_idx, /* in: NULL or an index to whose types the + column types must match */ + ibool check_charsets) /* in: whether to check charsets. + only has an effect if types_idx != + NULL. */ { dict_index_t* index; const char* col_name; @@ -2107,7 +2110,8 @@ dict_foreign_find_index( if (types_idx && !cmp_types_are_equal( dict_index_get_nth_type(index, i), - dict_index_get_nth_type(types_idx, i))) { + dict_index_get_nth_type(types_idx, i), + check_charsets)) { break; } @@ -2178,7 +2182,8 @@ dict_foreign_add_to_cache( /*======================*/ /* out: DB_SUCCESS or error code */ dict_foreign_t* foreign, /* in, own: foreign key constraint */ - ibool check_types) /* in: TRUE=check type compatibility */ + ibool check_charsets) /* in: TRUE=check charset + compatibility */ { dict_table_t* for_table; dict_table_t* ref_table; @@ -2214,16 +2219,10 @@ dict_foreign_add_to_cache( } if (for_in_cache->referenced_table == NULL && ref_table) { - dict_index_t* types_idx; - if (check_types) { - types_idx = for_in_cache->foreign_index; - } else { - types_idx = NULL; - } index = dict_foreign_find_index(ref_table, (const char**) for_in_cache->referenced_col_names, for_in_cache->n_fields, - types_idx); + for_in_cache->foreign_index, check_charsets); if (index == NULL) { dict_foreign_error_report(ef, for_in_cache, @@ -2247,16 +2246,10 @@ dict_foreign_add_to_cache( } if (for_in_cache->foreign_table == NULL && for_table) { - dict_index_t* types_idx; - if (check_types) { - types_idx = for_in_cache->referenced_index; - } else { - types_idx = NULL; - } index = dict_foreign_find_index(for_table, (const char**) for_in_cache->foreign_col_names, for_in_cache->n_fields, - types_idx); + for_in_cache->referenced_index, check_charsets); if (index == NULL) { dict_foreign_error_report(ef, for_in_cache, @@ -3033,7 +3026,7 @@ col_loop1: /* Try to find an index which contains the columns as the first fields and in the right order */ - index = dict_foreign_find_index(table, column_names, i, NULL); + index = dict_foreign_find_index(table, column_names, i, NULL, TRUE); if (!index) { mutex_enter(&dict_foreign_err_mutex); @@ -3298,8 +3291,7 @@ try_find_index: if (referenced_table) { index = dict_foreign_find_index(referenced_table, - column_names, i, - foreign->foreign_index); + column_names, i, foreign->foreign_index, TRUE); if (!index) { dict_foreign_free(foreign); mutex_enter(&dict_foreign_err_mutex); diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 0d58823a2ea..5127e258f56 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -1094,7 +1094,7 @@ dict_load_foreign( /* out: DB_SUCCESS or error code */ const char* id, /* in: foreign constraint id as a null-terminated string */ - ibool check_types)/* in: TRUE=check type compatibility */ + ibool check_charsets)/* in: TRUE=check charset compatibility */ { dict_foreign_t* foreign; dict_table_t* sys_foreign; @@ -1205,7 +1205,7 @@ dict_load_foreign( a new foreign key constraint but loading one from the data dictionary. */ - return(dict_foreign_add_to_cache(foreign, check_types)); + return(dict_foreign_add_to_cache(foreign, check_charsets)); } /*************************************************************************** @@ -1220,7 +1220,8 @@ dict_load_foreigns( /*===============*/ /* out: DB_SUCCESS or error code */ const char* table_name, /* in: table name */ - ibool check_types) /* in: TRUE=check type compatibility */ + ibool check_charsets) /* in: TRUE=check charset + compatibility */ { btr_pcur_t pcur; mem_heap_t* heap; @@ -1319,7 +1320,7 @@ loop: /* Load the foreign constraint definition to the dictionary cache */ - err = dict_load_foreign(id, check_types); + err = dict_load_foreign(id, check_charsets); if (err != DB_SUCCESS) { btr_pcur_close(&pcur); diff --git a/innobase/include/dict0dict.h b/innobase/include/dict0dict.h index 3333385ec56..bf1382e8bb2 100644 --- a/innobase/include/dict0dict.h +++ b/innobase/include/dict0dict.h @@ -197,7 +197,8 @@ dict_foreign_add_to_cache( /*======================*/ /* out: DB_SUCCESS or error code */ dict_foreign_t* foreign, /* in, own: foreign key constraint */ - ibool check_types); /* in: TRUE=check type compatibility */ + ibool check_charsets);/* in: TRUE=check charset + compatibility */ /************************************************************************* Checks if a table is referenced by foreign keys. */ diff --git a/innobase/include/dict0load.h b/innobase/include/dict0load.h index f13620bc6e8..741123614ab 100644 --- a/innobase/include/dict0load.h +++ b/innobase/include/dict0load.h @@ -82,7 +82,8 @@ dict_load_foreigns( /*===============*/ /* out: DB_SUCCESS or error code */ const char* table_name, /* in: table name */ - ibool check_types); /* in: TRUE=check type compatibility */ + ibool check_charsets);/* in: TRUE=check charsets + compatibility */ /************************************************************************ Prints to the standard output information on all tables found in the data dictionary system table. */ diff --git a/innobase/include/os0file.h b/innobase/include/os0file.h index 280a949c1c5..cd07eb49cd6 100644 --- a/innobase/include/os0file.h +++ b/innobase/include/os0file.h @@ -182,7 +182,7 @@ Creates a temporary file. */ FILE* os_file_create_tmpfile(void); /*========================*/ - /* out: temporary file handle (never NULL) */ + /* out: temporary file handle, or NULL on error */ /*************************************************************************** The os_file_opendir() function opens a directory stream corresponding to the directory named by the dirname argument. The directory stream is positioned diff --git a/innobase/include/rem0cmp.h b/innobase/include/rem0cmp.h index 712e263350e..6288d47bd63 100644 --- a/innobase/include/rem0cmp.h +++ b/innobase/include/rem0cmp.h @@ -24,7 +24,8 @@ cmp_types_are_equal( /* out: TRUE if the types are considered equal in comparisons */ dtype_t* type1, /* in: type 1 */ - dtype_t* type2); /* in: type 2 */ + dtype_t* type2, /* in: type 2 */ + ibool check_charsets); /* in: whether to check charsets */ /***************************************************************** This function is used to compare two data fields for which we know the data type. */ diff --git a/innobase/include/srv0srv.h b/innobase/include/srv0srv.h index 4352083b21f..992271e32ee 100644 --- a/innobase/include/srv0srv.h +++ b/innobase/include/srv0srv.h @@ -34,6 +34,12 @@ extern ibool srv_lower_case_table_names; extern mutex_t srv_monitor_file_mutex; /* Temporary file for innodb monitor output */ extern FILE* srv_monitor_file; +/* Mutex for locking srv_dict_tmpfile. +This mutex has a very high rank; threads reserving it should not +be holding any InnoDB latches. */ +extern mutex_t srv_dict_tmpfile_mutex; +/* Temporary file for output from the data dictionary */ +extern FILE* srv_dict_tmpfile; /* Server parameters which are read from the initfile */ diff --git a/innobase/rem/rem0cmp.c b/innobase/rem/rem0cmp.c index f2dc8a7021a..ce3ed6e6355 100644 --- a/innobase/rem/rem0cmp.c +++ b/innobase/rem/rem0cmp.c @@ -98,7 +98,8 @@ cmp_types_are_equal( /* out: TRUE if the types are considered equal in comparisons */ dtype_t* type1, /* in: type 1 */ - dtype_t* type2) /* in: type 2 */ + dtype_t* type2, /* in: type 2 */ + ibool check_charsets) /* in: whether to check charsets */ { if (dtype_is_non_binary_string_type(type1->mtype, type1->prtype) && dtype_is_non_binary_string_type(type2->mtype, type2->prtype)) { @@ -106,12 +107,12 @@ cmp_types_are_equal( /* Both are non-binary string types: they can be compared if and only if the charset-collation is the same */ - if (dtype_get_charset_coll(type1->prtype) - == dtype_get_charset_coll(type2->prtype)) { + if (check_charsets) { + return(dtype_get_charset_coll(type1->prtype) + == dtype_get_charset_coll(type2->prtype)); + } else { return(TRUE); } - - return(FALSE); } if (dtype_is_binary_string_type(type1->mtype, type1->prtype) diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 456bb51d424..26ae0e6cc76 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -522,7 +522,7 @@ row_ins_cascade_calc_update_vec( && ufield->new_val.len < dtype_get_fixed_size(type)) { - ulint cset; + ulint cset; ufield->new_val.data = mem_heap_alloc(heap, @@ -530,42 +530,42 @@ row_ins_cascade_calc_update_vec( ufield->new_val.len = dtype_get_fixed_size(type); - /* Handle UCS2 strings differently. - As no new collations will be - introduced in 4.1, we hardcode the - charset-collation codes here. - In 5.0, the logic is based on - mbminlen. */ - cset = dtype_get_charset_coll( - dtype_get_prtype(type)); + /* Handle UCS2 strings differently. + As no new collations will be + introduced in 4.1, we hardcode the + charset-collation codes here. + In 5.0, the logic is based on + mbminlen. */ + cset = dtype_get_charset_coll( + dtype_get_prtype(type)); - if (cset == 35/*ucs2_general_ci*/ - || cset == 90/*ucs2_bin*/ - || (cset >= 128/*ucs2_unicode_ci*/ - && cset <= 144 - /*ucs2_persian_ci*/)) { - /* space=0x0020 */ - ulint i; - for (i = 0; - i < ufield->new_val.len; - i += 2) { - mach_write_to_2(((byte*) - ufield->new_val.data) - + i, 0x0020); - } - } else { - ut_a(dtype_get_pad_char(type) - != ULINT_UNDEFINED); + if (cset == 35/*ucs2_general_ci*/ + || cset == 90/*ucs2_bin*/ + || (cset >= 128/*ucs2_unicode_ci*/ + && cset <= 144 + /*ucs2_persian_ci*/)) { + /* space=0x0020 */ + ulint i; + for (i = 0; + i < ufield->new_val.len; + i += 2) { + mach_write_to_2(((byte*) + ufield->new_val.data) + + i, 0x0020); + } + } else { + ut_a(dtype_get_pad_char(type) + != ULINT_UNDEFINED); - memset(ufield->new_val.data, - (byte)dtype_get_pad_char( - type), - ufield->new_val.len); - } + memset(ufield->new_val.data, + (byte)dtype_get_pad_char( + type), + ufield->new_val.len); + } - memcpy(ufield->new_val.data, - parent_ufield->new_val.data, - parent_ufield->new_val.len); + memcpy(ufield->new_val.data, + parent_ufield->new_val.data, + parent_ufield->new_val.len); } ufield->extern_storage = FALSE; diff --git a/innobase/row/row0mysql.c b/innobase/row/row0mysql.c index 7ce5c766e06..ba50e6a3511 100644 --- a/innobase/row/row0mysql.c +++ b/innobase/row/row0mysql.c @@ -1804,7 +1804,7 @@ row_table_add_foreign_constraints( if (err == DB_SUCCESS) { /* Check that also referencing constraints are ok */ - err = dict_load_foreigns(name, trx->check_foreigns); + err = dict_load_foreigns(name, TRUE); } if (err != DB_SUCCESS) { @@ -2963,7 +2963,8 @@ row_rename_table_for_mysql( mem_heap_t* heap = NULL; const char** constraints_to_drop = NULL; ulint n_constraints_to_drop = 0; - ibool recovering_temp_table = FALSE; + ibool recovering_temp_table = FALSE; + ibool old_is_tmp, new_is_tmp; ulint len; ulint i; ibool success; @@ -3003,6 +3004,9 @@ row_rename_table_for_mysql( trx->op_info = "renaming table"; trx_start_if_not_started(trx); + old_is_tmp = row_is_mysql_tmp_table_name(old_name); + new_is_tmp = row_is_mysql_tmp_table_name(new_name); + if (row_mysql_is_recovered_tmp_table(new_name)) { recovering_temp_table = TRUE; @@ -3047,7 +3051,7 @@ row_rename_table_for_mysql( len = (sizeof str1) + (sizeof str2) + (sizeof str3) + (sizeof str5) - 4 + ut_strlenq(new_name, '\'') + ut_strlenq(old_name, '\''); - if (row_is_mysql_tmp_table_name(new_name)) { + if (new_is_tmp) { db_name_len = dict_get_db_name_len(old_name) + 1; /* MySQL is doing an ALTER TABLE command and it renames the @@ -3200,7 +3204,7 @@ row_rename_table_for_mysql( the table is stored in a single-table tablespace */ success = dict_table_rename_in_cache(table, new_name, - !row_is_mysql_tmp_table_name(new_name)); + !new_is_tmp); if (!success) { trx->error_state = DB_SUCCESS; trx_general_rollback_for_mysql(trx, FALSE, NULL); @@ -3217,19 +3221,16 @@ row_rename_table_for_mysql( goto funct_exit; } - err = dict_load_foreigns(new_name, trx->check_foreigns); + /* We only want to switch off some of the type checking in + an ALTER, not in a RENAME. */ + + err = dict_load_foreigns(new_name, + old_is_tmp ? trx->check_foreigns : TRUE); - if (row_is_mysql_tmp_table_name(old_name)) { + if (err != DB_SUCCESS) { + ut_print_timestamp(stderr); - /* MySQL is doing an ALTER TABLE command and it - renames the created temporary table to the name - of the original table. In the ALTER TABLE we maybe - created some FOREIGN KEY constraints for the temporary - table. But we want to load also the foreign key - constraint definitions for the original table name. */ - - if (err != DB_SUCCESS) { - ut_print_timestamp(stderr); + if (old_is_tmp) { fputs(" InnoDB: Error: in ALTER TABLE ", stderr); ut_print_name(stderr, trx, new_name); @@ -3237,36 +3238,23 @@ row_rename_table_for_mysql( "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, - old_name, FALSE)); - trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, - NULL); - trx->error_state = DB_SUCCESS; - } - } else { - if (err != DB_SUCCESS) { - - ut_print_timestamp(stderr); - + } else { fputs( " InnoDB: Error: in RENAME TABLE table ", stderr); ut_print_name(stderr, trx, new_name); fputs("\n" - "InnoDB: is referenced in foreign key constraints\n" - "InnoDB: which are not compatible with the new table definition.\n", + "InnoDB: 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, - old_name, FALSE)); - - trx->error_state = DB_SUCCESS; - trx_general_rollback_for_mysql(trx, FALSE, - NULL); - trx->error_state = DB_SUCCESS; } + + ut_a(dict_table_rename_in_cache(table, + old_name, FALSE)); + trx->error_state = DB_SUCCESS; + trx_general_rollback_for_mysql(trx, FALSE, + NULL); + trx->error_state = DB_SUCCESS; } } funct_exit: diff --git a/innobase/srv/srv0srv.c b/innobase/srv/srv0srv.c index e56389a8541..d7bd698fe0e 100644 --- a/innobase/srv/srv0srv.c +++ b/innobase/srv/srv0srv.c @@ -334,6 +334,12 @@ mutex_t srv_innodb_monitor_mutex; mutex_t srv_monitor_file_mutex; /* Temporary file for innodb monitor output */ FILE* srv_monitor_file; +/* Mutex for locking srv_dict_tmpfile. +This mutex has a very high rank; threads reserving it should not +be holding any InnoDB latches. */ +mutex_t srv_dict_tmpfile_mutex; +/* Temporary file for output from the data dictionary */ +FILE* srv_dict_tmpfile; ulint srv_main_thread_process_no = 0; ulint srv_main_thread_id = 0; diff --git a/innobase/srv/srv0start.c b/innobase/srv/srv0start.c index 87f4c31257a..4d208ea2d15 100644 --- a/innobase/srv/srv0start.c +++ b/innobase/srv/srv0start.c @@ -1178,6 +1178,13 @@ NetWare. */ } } + mutex_create(&srv_dict_tmpfile_mutex); + mutex_set_level(&srv_dict_tmpfile_mutex, SYNC_DICT_OPERATION); + srv_dict_tmpfile = os_file_create_tmpfile(); + if (!srv_dict_tmpfile) { + return(DB_ERROR); + } + /* Restrict the maximum number of file i/o threads */ if (srv_n_file_io_threads > SRV_MAX_N_IO_THREADS) { @@ -1804,8 +1811,13 @@ innobase_shutdown_for_mysql(void) mem_free(srv_monitor_file_name); } } - + if (srv_dict_tmpfile) { + fclose(srv_dict_tmpfile); + srv_dict_tmpfile = 0; + } + mutex_free(&srv_monitor_file_mutex); + mutex_free(&srv_dict_tmpfile_mutex); /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside them */ diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result index ca78d23e6dc..b43d00bda1c 100644 --- a/mysql-test/r/innodb.result +++ b/mysql-test/r/innodb.result @@ -1722,3 +1722,35 @@ checksum table test_checksum; Table Checksum test.test_checksum 2050879373 drop table test_checksum; +set foreign_key_checks=0; +create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +ERROR HY000: Can't create table './test/t1.frm' (errno: 150) +set foreign_key_checks=1; +drop table t2; +set foreign_key_checks=0; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; +ERROR HY000: Can't create table './test/t2.frm' (errno: 150) +set foreign_key_checks=1; +drop table t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; +create table t1(a varchar(10) primary key) engine = innodb; +alter table t1 modify column a int; +Got one of the listed errors +set foreign_key_checks=1; +drop table t2,t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +alter table t1 convert to character set utf8; +set foreign_key_checks=1; +drop table t2,t1; +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; +rename table t3 to t1; +ERROR HY000: Error on rename of './test/t3' to './test/t1' (errno: 150) +set foreign_key_checks=1; +drop table t2,t3; diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test index 3a693968769..03aa113c662 100644 --- a/mysql-test/t/innodb.test +++ b/mysql-test/t/innodb.test @@ -1280,4 +1280,53 @@ connection a; checksum table test_checksum; drop table test_checksum; +# tests for bugs #9802 and #13778 + +# test that FKs between invalid types are not accepted + +set foreign_key_checks=0; +create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; +-- error 1005 +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +set foreign_key_checks=1; +drop table t2; + +# test that FKs between different charsets are not accepted in CREATE even +# when f_k_c is 0 + +set foreign_key_checks=0; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +-- error 1005 +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; +set foreign_key_checks=1; +drop table t1; + +# test that invalid datatype conversions with ALTER are not allowed + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb; +create table t1(a varchar(10) primary key) engine = innodb; +-- error 1025,1025 +alter table t1 modify column a int; +set foreign_key_checks=1; +drop table t2,t1; + +# test that charset conversions with ALTER are allowed when f_k_c is 0 + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; +alter table t1 convert to character set utf8; +set foreign_key_checks=1; +drop table t2,t1; + +# test that RENAME does not allow invalid charsets when f_k_c is 0 + +set foreign_key_checks=0; +create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=latin1; +create table t3(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=utf8; +-- error 1025 +rename table t3 to t1; +set foreign_key_checks=1; +drop table t2,t3; # End of 4.1 tests diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 5c81dd2163c..b188cfcba21 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -4729,6 +4729,7 @@ ha_innobase::update_table_comment( uint length = strlen(comment); char* str; row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; + long flen; /* We do not know if MySQL can call this function before calling external_lock(). To be safe, update the thd of the current table @@ -4748,43 +4749,43 @@ ha_innobase::update_table_comment( trx_search_latch_release_if_reserved(prebuilt->trx); str = NULL; - if (FILE* file = os_file_create_tmpfile()) { - long flen; + /* output the data to a temporary file */ - /* output the data to a temporary file */ - fprintf(file, "InnoDB free: %lu kB", + mutex_enter_noninline(&srv_dict_tmpfile_mutex); + rewind(srv_dict_tmpfile); + + fprintf(srv_dict_tmpfile, "InnoDB free: %lu kB", (ulong) fsp_get_available_space_in_free_extents( prebuilt->table->space)); - dict_print_info_on_foreign_keys(FALSE, file, + dict_print_info_on_foreign_keys(FALSE, srv_dict_tmpfile, prebuilt->trx, prebuilt->table); - flen = ftell(file); - if (flen < 0) { - flen = 0; - } else if (length + flen + 3 > 64000) { - flen = 64000 - 3 - length; - } - - /* allocate buffer for the full string, and - read the contents of the temporary file */ - - str = my_malloc(length + flen + 3, MYF(0)); - - if (str) { - char* pos = str + length; - if(length) { - memcpy(str, comment, length); - *pos++ = ';'; - *pos++ = ' '; - } - rewind(file); - flen = fread(pos, 1, flen, file); - pos[flen] = 0; - } - - fclose(file); + flen = ftell(srv_dict_tmpfile); + if (flen < 0) { + flen = 0; + } else if (length + flen + 3 > 64000) { + flen = 64000 - 3 - length; } + /* allocate buffer for the full string, and + read the contents of the temporary file */ + + str = my_malloc(length + flen + 3, MYF(0)); + + if (str) { + char* pos = str + length; + if (length) { + memcpy(str, comment, length); + *pos++ = ';'; + *pos++ = ' '; + } + rewind(srv_dict_tmpfile); + flen = (uint) fread(pos, 1, flen, srv_dict_tmpfile); + pos[flen] = 0; + } + + mutex_exit_noninline(&srv_dict_tmpfile_mutex); + prebuilt->trx->op_info = (char*)""; return(str ? str : (char*) comment); @@ -4802,6 +4803,7 @@ ha_innobase::get_foreign_key_create_info(void) { row_prebuilt_t* prebuilt = (row_prebuilt_t*)innobase_prebuilt; char* str = 0; + long flen; ut_a(prebuilt != NULL); @@ -4811,47 +4813,42 @@ ha_innobase::get_foreign_key_create_info(void) update_thd(current_thd); - if (FILE* file = os_file_create_tmpfile()) { - long flen; + prebuilt->trx->op_info = (char*)"getting info on foreign keys"; - prebuilt->trx->op_info = (char*)"getting info on foreign keys"; + /* In case MySQL calls this in the middle of a SELECT query, + release possible adaptive hash latch to avoid + deadlocks of threads */ - /* In case MySQL calls this in the middle of a SELECT query, - release possible adaptive hash latch to avoid - deadlocks of threads */ + trx_search_latch_release_if_reserved(prebuilt->trx); - trx_search_latch_release_if_reserved(prebuilt->trx); + mutex_enter_noninline(&srv_dict_tmpfile_mutex); + rewind(srv_dict_tmpfile); - /* output the data to a temporary file */ - dict_print_info_on_foreign_keys(TRUE, file, + /* output the data to a temporary file */ + dict_print_info_on_foreign_keys(TRUE, srv_dict_tmpfile, prebuilt->trx, prebuilt->table); - prebuilt->trx->op_info = (char*)""; + prebuilt->trx->op_info = (char*)""; - flen = ftell(file); - if (flen < 0) { - flen = 0; - } else if(flen > 64000 - 1) { - flen = 64000 - 1; - } - - /* allocate buffer for the string, and - read the contents of the temporary file */ - - str = my_malloc(flen + 1, MYF(0)); - - if (str) { - rewind(file); - flen = fread(str, 1, flen, file); - str[flen] = 0; - } - - fclose(file); - } else { - /* unable to create temporary file */ - str = my_strdup( -"/* Error: cannot display foreign key constraints */", MYF(0)); + flen = ftell(srv_dict_tmpfile); + if (flen < 0) { + flen = 0; + } else if (flen > 64000 - 1) { + flen = 64000 - 1; } + /* allocate buffer for the string, and + read the contents of the temporary file */ + + str = my_malloc(flen + 1, MYF(0)); + + if (str) { + rewind(srv_dict_tmpfile); + flen = (uint) fread(str, 1, flen, srv_dict_tmpfile); + str[flen] = 0; + } + + mutex_exit_noninline(&srv_dict_tmpfile_mutex); + return(str); } From ba09e4c004bc7d95e4e54bcb5999707ecdb64d83 Mon Sep 17 00:00:00 2001 From: "aivanov@mysql.com" <> Date: Tue, 13 Dec 2005 16:29:31 +0300 Subject: [PATCH 2/2] Null-merge from 4.1 --- innobase/dict/dict0load.c | 172 +++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 86 deletions(-) diff --git a/innobase/dict/dict0load.c b/innobase/dict/dict0load.c index 5127e258f56..3281f9926f9 100644 --- a/innobase/dict/dict0load.c +++ b/innobase/dict/dict0load.c @@ -8,6 +8,9 @@ Created 4/24/1996 Heikki Tuuri *******************************************************/ #include "dict0load.h" +#ifndef UNIV_HOTBACKUP +#include "mysql_version.h" +#endif /* !UNIV_HOTBACKUP */ #ifdef UNIV_NONINL #include "dict0load.ic" @@ -55,6 +58,7 @@ dict_get_first_table_name_in_db( sys_tables = dict_table_get_low("SYS_TABLES"); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + ut_a(!sys_tables->comp); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -77,7 +81,7 @@ loop: return(NULL); } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); if (len < strlen(name) || ut_memcmp(name, field, strlen(name)) != 0) { @@ -90,7 +94,7 @@ loop: return(NULL); } - if (!rec_get_deleted_flag(rec)) { + if (!rec_get_deleted_flag(rec, sys_tables->comp)) { /* We found one */ @@ -163,9 +167,9 @@ loop: return; } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); - if (!rec_get_deleted_flag(rec)) { + if (!rec_get_deleted_flag(rec, sys_tables->comp)) { /* We found one */ @@ -180,7 +184,7 @@ loop: if (table == NULL) { fputs("InnoDB: Failed to load table ", stderr); - ut_print_namel(stderr, NULL, field, len); + ut_print_namel(stderr, NULL, (char*) field, len); putc('\n', stderr); } else { /* The table definition was corrupt if there @@ -231,6 +235,7 @@ dict_check_tablespaces_and_store_max_id( sys_tables = dict_table_get_low("SYS_TABLES"); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + ut_a(!sys_tables->comp); btr_pcur_open_at_index_side(TRUE, sys_index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr); @@ -257,15 +262,15 @@ loop: return; } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); - if (!rec_get_deleted_flag(rec)) { + if (!rec_get_deleted_flag(rec, sys_tables->comp)) { /* We found one */ char* name = mem_strdupl((char*) field, len); - field = rec_get_nth_field(rec, 9, &len); + field = rec_get_nth_field_old(rec, 9, &len); ut_a(len == 4); space_id = mach_read_from_4(field); @@ -338,6 +343,7 @@ dict_load_columns( sys_columns = dict_table_get_low("SYS_COLUMNS"); sys_index = UT_LIST_GET_FIRST(sys_columns->indexes); + ut_a(!sys_columns->comp); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -356,28 +362,27 @@ dict_load_columns( ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - ut_a(!rec_get_deleted_flag(rec)); - - field = rec_get_nth_field(rec, 0, &len); + ut_a(!rec_get_deleted_flag(rec, sys_columns->comp)); + + field = rec_get_nth_field_old(rec, 0, &len); ut_ad(len == 8); ut_a(ut_dulint_cmp(table->id, mach_read_from_8(field)) == 0); - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); ut_ad(len == 4); ut_a(i == mach_read_from_4(field)); ut_a(0 == ut_strcmp("NAME", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_columns), 4))->name)); + dict_index_get_nth_field(sys_index, 4))->name)); - field = rec_get_nth_field(rec, 4, &len); + field = rec_get_nth_field_old(rec, 4, &len); name = mem_heap_strdupl(heap, (char*) field, len); - field = rec_get_nth_field(rec, 5, &len); + field = rec_get_nth_field_old(rec, 5, &len); mtype = mach_read_from_4(field); - field = rec_get_nth_field(rec, 6, &len); + field = rec_get_nth_field_old(rec, 6, &len); prtype = mach_read_from_4(field); if (dtype_is_non_binary_string_type(mtype, prtype) @@ -389,15 +394,14 @@ dict_load_columns( data_mysql_default_charset_coll); } - field = rec_get_nth_field(rec, 7, &len); + field = rec_get_nth_field_old(rec, 7, &len); col_len = mach_read_from_4(field); ut_a(0 == ut_strcmp("PREC", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_columns), 8))->name)); + dict_index_get_nth_field(sys_index, 8))->name)); - field = rec_get_nth_field(rec, 8, &len); + field = rec_get_nth_field_old(rec, 8, &len); prec = mach_read_from_4(field); dict_mem_table_add_col(table, name, mtype, prtype, col_len, @@ -462,6 +466,7 @@ dict_load_fields( sys_fields = dict_table_get_low("SYS_FIELDS"); sys_index = UT_LIST_GET_FIRST(sys_fields->indexes); + ut_a(!sys_fields->comp); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -479,15 +484,15 @@ dict_load_fields( rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - if (rec_get_deleted_flag(rec)) { + if (rec_get_deleted_flag(rec, sys_fields->comp)) { dict_load_report_deleted_index(table->name, i); } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); ut_ad(len == 8); ut_a(ut_memcmp(buf, field, len) == 0); - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); ut_a(len == 4); /* The next field stores the field position in the index @@ -513,10 +518,9 @@ dict_load_fields( ut_a(0 == ut_strcmp("COL_NAME", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_fields), 4))->name)); + dict_index_get_nth_field(sys_index, 4))->name)); - field = rec_get_nth_field(rec, 4, &len); + field = rec_get_nth_field_old(rec, 4, &len); dict_mem_index_add_field(index, mem_heap_strdupl(heap, (char*) field, len), 0, prefix_len); @@ -575,6 +579,7 @@ dict_load_indexes( sys_indexes = dict_table_get_low("SYS_INDEXES"); sys_index = UT_LIST_GET_FIRST(sys_indexes->indexes); + ut_a(!sys_indexes->comp); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -595,14 +600,14 @@ dict_load_indexes( rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); ut_ad(len == 8); if (ut_memcmp(buf, field, len) != 0) { break; } - if (rec_get_deleted_flag(rec)) { + if (rec_get_deleted_flag(rec, table->comp)) { dict_load_report_deleted_index(table->name, ULINT_UNDEFINED); @@ -612,33 +617,31 @@ dict_load_indexes( return(FALSE); } - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); ut_ad(len == 8); id = mach_read_from_8(field); ut_a(0 == ut_strcmp("NAME", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_indexes), 4))->name)); - - field = rec_get_nth_field(rec, 4, &name_len); + dict_index_get_nth_field(sys_index, 4))->name)); + + field = rec_get_nth_field_old(rec, 4, &name_len); name_buf = mem_heap_strdupl(heap, (char*) field, name_len); - field = rec_get_nth_field(rec, 5, &len); + field = rec_get_nth_field_old(rec, 5, &len); n_fields = mach_read_from_4(field); - field = rec_get_nth_field(rec, 6, &len); + field = rec_get_nth_field_old(rec, 6, &len); type = mach_read_from_4(field); - field = rec_get_nth_field(rec, 7, &len); + field = rec_get_nth_field_old(rec, 7, &len); space = mach_read_from_4(field); ut_a(0 == ut_strcmp("PAGE_NO", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_indexes), 8))->name)); + dict_index_get_nth_field(sys_index, 8))->name)); - field = rec_get_nth_field(rec, 8, &len); + field = rec_get_nth_field_old(rec, 8, &len); page_no = mach_read_from_4(field); if (page_no == FIL_NULL) { @@ -680,12 +683,10 @@ dict_load_indexes( } else { index = dict_mem_index_create(table->name, name_buf, space, type, n_fields); - index->page_no = page_no; index->id = id; dict_load_fields(table, index, heap); - - dict_index_add_to_cache(table, index); + dict_index_add_to_cache(table, index, page_no); } btr_pcur_move_to_next_user_rec(&pcur, &mtr); @@ -741,6 +742,7 @@ dict_load_table( sys_tables = dict_table_get_low("SYS_TABLES"); sys_index = UT_LIST_GET_FIRST(sys_tables->indexes); + ut_a(!sys_tables->comp); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -753,7 +755,7 @@ dict_load_table( rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec)) { + || rec_get_deleted_flag(rec, sys_tables->comp)) { /* Not found */ btr_pcur_close(&pcur); @@ -763,11 +765,10 @@ dict_load_table( return(NULL); } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); /* Check if the table name in record is the searched one */ if (len != ut_strlen(name) || ut_memcmp(name, field, len) != 0) { - err_exit: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); @@ -777,10 +778,9 @@ dict_load_table( ut_a(0 == ut_strcmp("SPACE", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_tables), 9))->name)); + dict_index_get_nth_field(sys_index, 9))->name)); - field = rec_get_nth_field(rec, 9, &len); + field = rec_get_nth_field_old(rec, 9, &len); space = mach_read_from_4(field); /* Check if the tablespace exists and has the right name */ @@ -812,49 +812,44 @@ dict_load_table( ut_a(0 == ut_strcmp("N_COLS", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_tables), 4))->name)); + dict_index_get_nth_field(sys_index, 4))->name)); - field = rec_get_nth_field(rec, 4, &len); + field = rec_get_nth_field_old(rec, 4, &len); n_cols = mach_read_from_4(field); - if (n_cols & 0x80000000UL) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: table %s is in the new compact format\n" - "InnoDB: of MySQL 5.0.3 or later\n", name); - goto err_exit; - } - table = dict_mem_table_create(name, space, n_cols); + /* The high-order bit of N_COLS is the "compact format" flag. */ + table = dict_mem_table_create(name, space, + n_cols & ~0x80000000UL, + !!(n_cols & 0x80000000UL)); table->ibd_file_missing = ibd_file_missing; ut_a(0 == ut_strcmp("ID", dict_field_get_col( - dict_index_get_nth_field( - dict_table_get_first_index(sys_tables), 3))->name)); + dict_index_get_nth_field(sys_index, 3))->name)); - field = rec_get_nth_field(rec, 3, &len); + field = rec_get_nth_field_old(rec, 3, &len); table->id = mach_read_from_8(field); - field = rec_get_nth_field(rec, 5, &len); + field = rec_get_nth_field_old(rec, 5, &len); table->type = mach_read_from_4(field); if (table->type == DICT_TABLE_CLUSTER_MEMBER) { ut_error; #if 0 /* clustered tables have not been implemented yet */ - field = rec_get_nth_field(rec, 6, &len); + field = rec_get_nth_field_old(rec, 6, &len); table->mix_id = mach_read_from_8(field); - field = rec_get_nth_field(rec, 8, &len); + field = rec_get_nth_field_old(rec, 8, &len); table->cluster_name = mem_heap_strdupl(heap, (char*) field, len); #endif } if ((table->type == DICT_TABLE_CLUSTER) || (table->type == DICT_TABLE_CLUSTER_MEMBER)) { - - field = rec_get_nth_field(rec, 7, &len); + + field = rec_get_nth_field_old(rec, 7, &len); + ut_a(len == 4); table->mix_len = mach_read_from_4(field); } @@ -933,6 +928,7 @@ dict_load_table_on_id( sys_tables = dict_sys->sys_tables; sys_table_ids = dict_table_get_next_index( dict_table_get_first_index(sys_tables)); + ut_a(!sys_tables->comp); heap = mem_heap_create(256); tuple = dtuple_create(heap, 1); @@ -949,7 +945,7 @@ dict_load_table_on_id( rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec)) { + || rec_get_deleted_flag(rec, sys_tables->comp)) { /* Not found */ btr_pcur_close(&pcur); @@ -964,7 +960,7 @@ dict_load_table_on_id( table ID and NAME */ rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); ut_ad(len == 8); /* Check if the table id in record is the one searched for */ @@ -978,7 +974,7 @@ dict_load_table_on_id( } /* Now we get the table name from the record */ - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); /* Load the table definition to memory */ table = dict_load_table(mem_heap_strdupl(heap, (char*) field, len)); @@ -1046,6 +1042,7 @@ dict_load_foreign_cols( sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes); + ut_a(!sys_foreign_cols->comp); tuple = dtuple_create(foreign->heap, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -1060,21 +1057,21 @@ dict_load_foreign_cols( rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); - ut_a(!rec_get_deleted_flag(rec)); - - field = rec_get_nth_field(rec, 0, &len); + ut_a(!rec_get_deleted_flag(rec, sys_foreign_cols->comp)); + + field = rec_get_nth_field_old(rec, 0, &len); ut_a(len == ut_strlen(id)); ut_a(ut_memcmp(id, field, len) == 0); - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); ut_a(len == 4); ut_a(i == mach_read_from_4(field)); - field = rec_get_nth_field(rec, 4, &len); + field = rec_get_nth_field_old(rec, 4, &len); foreign->foreign_col_names[i] = mem_heap_strdupl(foreign->heap, (char*) field, len); - field = rec_get_nth_field(rec, 5, &len); + field = rec_get_nth_field_old(rec, 5, &len); foreign->referenced_col_names[i] = mem_heap_strdupl(foreign->heap, (char*) field, len); @@ -1118,6 +1115,7 @@ dict_load_foreign( sys_foreign = dict_table_get_low("SYS_FOREIGN"); sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes); + ut_a(!sys_foreign->comp); tuple = dtuple_create(heap2, 1); dfield = dtuple_get_nth_field(tuple, 0); @@ -1130,7 +1128,7 @@ dict_load_foreign( rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr) - || rec_get_deleted_flag(rec)) { + || rec_get_deleted_flag(rec, sys_foreign->comp)) { /* Not found */ fprintf(stderr, @@ -1144,7 +1142,7 @@ dict_load_foreign( return(DB_ERROR); } - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); /* Check if the id in record is the searched one */ if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { @@ -1167,7 +1165,8 @@ dict_load_foreign( foreign = dict_mem_foreign_create(); - foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len)); + foreign->n_fields = + mach_read_from_4(rec_get_nth_field_old(rec, 5, &len)); ut_a(len == 4); @@ -1178,11 +1177,11 @@ dict_load_foreign( foreign->id = mem_heap_strdup(foreign->heap, id); - field = rec_get_nth_field(rec, 3, &len); + field = rec_get_nth_field_old(rec, 3, &len); foreign->foreign_table_name = mem_heap_strdupl(foreign->heap, (char*) field, len); - - field = rec_get_nth_field(rec, 4, &len); + + field = rec_get_nth_field_old(rec, 4, &len); foreign->referenced_table_name = mem_heap_strdupl(foreign->heap, (char*) field, len); @@ -1251,6 +1250,7 @@ dict_load_foreigns( return(DB_ERROR); } + ut_a(!sys_foreign->comp); mtr_start(&mtr); /* Get the secondary index based on FOR_NAME from table @@ -1282,7 +1282,7 @@ loop: name and a foreign constraint ID */ rec = btr_pcur_get_rec(&pcur); - field = rec_get_nth_field(rec, 0, &len); + field = rec_get_nth_field_old(rec, 0, &len); /* Check if the table name in the record is the one searched for; the following call does the comparison in the latin1_swedish_ci @@ -1305,13 +1305,13 @@ loop: goto next_rec; } - if (rec_get_deleted_flag(rec)) { + if (rec_get_deleted_flag(rec, sys_foreign->comp)) { goto next_rec; } /* Now we get a foreign key constraint id */ - field = rec_get_nth_field(rec, 1, &len); + field = rec_get_nth_field_old(rec, 1, &len); id = mem_heap_strdupl(heap, (char*) field, len); btr_pcur_store_position(&pcur, &mtr);