diff options
Diffstat (limited to 'sql/sql_table.cc')
-rw-r--r-- | sql/sql_table.cc | 614 |
1 files changed, 438 insertions, 176 deletions
diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f11a4e683f1..d9d36c260fd 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -19,10 +19,12 @@ #include <hash.h> #include <myisam.h> #include <my_dir.h> +#include "create_options.h" #include "sp_head.h" #include "sql_trigger.h" #include "sql_show.h" #include "debug_sync.h" +#include "sql_handler.h" #ifdef __WIN__ #include <io.h> @@ -41,9 +43,11 @@ static int copy_data_between_tables(TABLE *,TABLE *, List<Create_field> &, bool, static bool prepare_blob_field(THD *thd, Create_field *sql_field); static bool check_engine(THD *, const char *, HA_CREATE_INFO *); static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *, - bool, uint *, handler *, KEY **, uint *, int); + bool, uint *, handler *, KEY **, uint *, + int); static bool mysql_prepare_alter_table(THD *, TABLE *, HA_CREATE_INFO *, Alter_info *); +static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list); #ifndef DBUG_OFF @@ -2002,9 +2006,10 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { TABLE *locked_table; abort_locked_tables(thd, db, table->table_name); + table->deleting= TRUE; remove_table_from_cache(thd, db, table->table_name, RTFC_WAIT_OTHER_THREAD_FLAG | - RTFC_CHECK_KILLED_FLAG); + RTFC_CHECK_KILLED_FLAG, FALSE); /* If the table was used in lock tables, remember it so that unlock_table_names can free it @@ -2031,7 +2036,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, (!drop_view && mysql_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE))) { - // Table was not found on disk and table can't be created from engine + /* Table was not found on disk and table can't be created from engine */ if (if_exists) push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), @@ -2107,7 +2112,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (!foreign_key_error) my_printf_error(ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR), MYF(0), - wrong_tables.c_ptr()); + wrong_tables.c_ptr_safe()); else my_message(ER_ROW_IS_REFERENCED, ER(ER_ROW_IS_REFERENCED), MYF(0)); error= 1; @@ -2244,10 +2249,10 @@ static int sort_keys(KEY *a, KEY *b) { if (!(b_flags & HA_NOSAME)) return -1; - if ((a_flags ^ b_flags) & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) + if ((a_flags ^ b_flags) & HA_NULL_PART_KEY) { /* Sort NOT NULL keys before other keys */ - return (a_flags & (HA_NULL_PART_KEY | HA_END_SPACE_KEY)) ? 1 : -1; + return (a_flags & HA_NULL_PART_KEY) ? 1 : -1; } if (a->name == primary_key_name) return -1; @@ -2528,7 +2533,12 @@ int prepare_create_field(Create_field *sql_field, (sql_field->decimals << FIELDFLAG_DEC_SHIFT)); break; } - if (!(sql_field->flags & NOT_NULL_FLAG)) + if (sql_field->flags & NOT_NULL_FLAG) + DBUG_PRINT("info", ("1")); + if (sql_field->vcol_info) + DBUG_PRINT("info", ("2")); + if (!(sql_field->flags & NOT_NULL_FLAG) || + (sql_field->vcol_info)) /* Make virtual columns allow NULL values */ sql_field->pack_flag|= FIELDFLAG_MAYBE_NULL; if (sql_field->flags & NO_DEFAULT_VALUE_FLAG) sql_field->pack_flag|= FIELDFLAG_NO_DEFAULT; @@ -2842,6 +2852,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, null_fields--; sql_field->flags= dup_field->flags; sql_field->interval= dup_field->interval; + sql_field->vcol_info= dup_field->vcol_info; + sql_field->stored_in_db= dup_field->stored_in_db; it2.remove(); // Remove first (create) definition select_field_pos--; break; @@ -2851,7 +2863,7 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, /* Don't pack rows in old tables if the user has requested this */ if ((sql_field->flags & BLOB_FLAG) || (sql_field->sql_type == MYSQL_TYPE_VARCHAR && - create_info->row_type != ROW_TYPE_FIXED)) + create_info->row_type != ROW_TYPE_FIXED)) (*db_options)|= HA_OPTION_PACK_RECORD; it2.rewind(); } @@ -2874,7 +2886,28 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, sql_field->offset= record_offset; if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER) auto_increment++; - record_offset+= sql_field->pack_length; + if (parse_option_list(thd, &sql_field->option_struct, + sql_field->option_list, + create_info->db_type->field_options, FALSE, + thd->mem_root)) + DBUG_RETURN(TRUE); + /* + For now skip fields that are not physically stored in the database + (virtual fields) and update their offset later + (see the next loop). + */ + if (sql_field->stored_in_db) + record_offset+= sql_field->pack_length; + } + /* Update virtual fields' offset*/ + it.rewind(); + while ((sql_field=it++)) + { + if (!sql_field->stored_in_db) + { + sql_field->offset= record_offset; + record_offset+= sql_field->pack_length; + } } if (timestamps_with_niladic > 1) { @@ -2924,6 +2957,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, if (key->type == Key::FOREIGN_KEY) { fk_key_count++; + if (((Foreign_key *)key)->validate(alter_info->create_list)) + DBUG_RETURN(TRUE); Foreign_key *fk_key= (Foreign_key*) key; if (fk_key->ref_columns.elements && fk_key->ref_columns.elements != fk_key->columns.elements) @@ -3054,6 +3089,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, key_info->key_part=key_part_info; key_info->usable_key_parts= key_number; key_info->algorithm= key->key_create_info.algorithm; + key_info->option_list= key->option_list; + if (parse_option_list(thd, &key_info->option_struct, + key_info->option_list, + create_info->db_type->index_options, FALSE, + thd->mem_root)) + DBUG_RETURN(TRUE); if (key->type == Key::FULLTEXT) { @@ -3210,6 +3251,17 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } } #endif + if (!sql_field->stored_in_db) + { + /* Key fields must always be physically stored. */ + my_error(ER_KEY_BASED_ON_GENERATED_VIRTUAL_COLUMN, MYF(0)); + DBUG_RETURN(TRUE); + } + if (key->type == Key::PRIMARY && sql_field->vcol_info) + { + my_error(ER_PRIMARY_KEY_BASED_ON_VIRTUAL_COLUMN, MYF(0)); + DBUG_RETURN(TRUE); + } if (!(sql_field->flags & NOT_NULL_FLAG)) { if (key->type == Key::PRIMARY) @@ -3287,10 +3339,10 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, else if (!(file->ha_table_flags() & HA_NO_PREFIX_CHAR_KEYS)) length=column->length; } - else if (length == 0) + else if (length == 0 && (sql_field->flags & NOT_NULL_FLAG)) { my_error(ER_WRONG_KEY_COLUMN, MYF(0), column->field_name); - DBUG_RETURN(TRUE); + DBUG_RETURN(TRUE); } if (length > file->max_key_part_length() && key->type != Key::FULLTEXT) { @@ -3421,6 +3473,12 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info, } } + if (parse_option_list(thd, &create_info->option_struct, + create_info->option_list, + file->partition_ht()->table_options, FALSE, + thd->mem_root)) + DBUG_RETURN(TRUE); + DBUG_RETURN(FALSE); } @@ -3599,6 +3657,68 @@ static inline int write_create_table_bin_log(THD *thd, } +/** + Check that there is no frm file for given table + + @param old_path path to the old frm file + @param path path to the frm file in new encoding + @param db database name + @param table_name table name + @param alias table name for error message (for new encoding) + @param issue_error should we issue error messages + + @retval FALSE there is no frm file + @retval TRUE there is frm file +*/ + +bool check_table_file_presence(char *old_path, + char *path, + const char *db, + const char *table_name, + const char *alias, + bool issue_error) +{ + if (!access(path,F_OK)) + { + if (issue_error) + my_error(ER_TABLE_EXISTS_ERROR,MYF(0),alias); + return TRUE; + } + { + /* + Check if file of the table in 5.0 file name encoding exists. + + Except case when it is the same table. + */ + char tbl50[FN_REFLEN]; +#ifdef _WIN32 + if (check_if_legal_tablename(table_name) != 0) + { + /* + Check for reserved device names for which access() returns 0 + (CON, AUX etc). + */ + return FALSE; + } +#endif + strxmov(tbl50, mysql_data_home, "/", db, "/", table_name, NullS); + fn_format(tbl50, tbl50, "", reg_ext, MY_UNPACK_FILENAME); + if (!access(tbl50, F_OK) && + (old_path == NULL || + strcmp(old_path, tbl50) != 0)) + { + if (issue_error) + { + strxmov(tbl50, MYSQL50_TABLE_NAME_PREFIX, table_name, NullS); + my_error(ER_TABLE_EXISTS_ERROR, MYF(0), tbl50); + } + return TRUE; + } + } + return FALSE; +} + + /* Create a table @@ -3661,8 +3781,9 @@ bool mysql_create_table_no_lock(THD *thd, if (check_engine(thd, table_name, create_info)) DBUG_RETURN(TRUE); db_options= create_info->table_options; - if (create_info->row_type == ROW_TYPE_DYNAMIC) - db_options|=HA_OPTION_PACK_RECORD; + if (create_info->row_type != ROW_TYPE_FIXED && + create_info->row_type != ROW_TYPE_DEFAULT) + db_options|= HA_OPTION_PACK_RECORD; alias= table_case_name(create_info, table_name); if (!(file= get_new_handler((TABLE_SHARE*) 0, thd->mem_root, create_info->db_type))) @@ -3868,14 +3989,27 @@ bool mysql_create_table_no_lock(THD *thd, goto err; } + /* Give warnings for not supported table options */ +#if defined(WITH_ARIA_STORAGE_ENGINE) + extern handlerton *maria_hton; + if (file->ht != maria_hton) +#endif + if (create_info->transactional) + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR, + ER_ILLEGAL_HA_CREATE_OPTION, + ER(ER_ILLEGAL_HA_CREATE_OPTION), + file->engine_name()->str, + "TRANSACTIONAL=1"); + VOID(pthread_mutex_lock(&LOCK_open)); if (!internal_tmp_table && !(create_info->options & HA_LEX_CREATE_TMP_TABLE)) { - if (!access(path,F_OK)) + if (check_table_file_presence(NULL, path, db, table_name, table_name, + !(create_info->options & + HA_LEX_CREATE_IF_NOT_EXISTS))) { if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) goto warn; - my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto unlock_and_end; } /* @@ -3920,7 +4054,6 @@ bool mysql_create_table_no_lock(THD *thd, goto warn; my_error(ER_TABLE_EXISTS_ERROR,MYF(0),table_name); goto unlock_and_end; - break; default: DBUG_PRINT("info", ("error: %u from storage engine", retcode)); my_error(retcode, MYF(0),table_name); @@ -4154,7 +4287,7 @@ mysql_rename_table(handlerton *base, const char *old_db, char from[FN_REFLEN + 1], to[FN_REFLEN + 1], lc_from[FN_REFLEN + 1], lc_to[FN_REFLEN + 1]; char *from_base= from, *to_base= to; - char tmp_name[NAME_LEN+1]; + char tmp_name[SAFE_NAME_LEN+1]; handler *file; int error=0; DBUG_ENTER("mysql_rename_table"); @@ -4228,7 +4361,7 @@ mysql_rename_table(handlerton *base, const char *old_db, Win32 clients must also have a WRITE LOCK on the table ! */ -void wait_while_table_is_used(THD *thd, TABLE *table, +void wait_while_table_is_used(THD *thd,TABLE *table, enum ha_extra_function function) { DBUG_ENTER("wait_while_table_is_used"); @@ -4237,15 +4370,17 @@ void wait_while_table_is_used(THD *thd, TABLE *table, table->db_stat, table->s->version)); safe_mutex_assert_owner(&LOCK_open); - - VOID(table->file->extra(function)); + /* Mark all tables that are in use as 'old' */ mysql_lock_abort(thd, table, TRUE); /* end threads waiting on lock */ /* Wait until all there are no other threads that has this table open */ remove_table_from_cache(thd, table->s->db.str, table->s->table_name.str, - RTFC_WAIT_OTHER_THREAD_FLAG); + RTFC_WAIT_OTHER_THREAD_FLAG, FALSE); + /* extra() call must come only after all instances above are closed */ + if (function != HA_EXTRA_NOT_USED) + VOID(table->file->extra(function)); DBUG_VOID_RETURN; } @@ -4544,6 +4679,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol *protocol= thd->protocol; LEX *lex= thd->lex; int result_code; + bool need_repair_or_alter= 0; DBUG_ENTER("mysql_admin_table"); if (end_active_trans(thd)) @@ -4564,7 +4700,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, for (table= tables; table; table= table->next_local) { - char table_name[NAME_LEN*2+2]; + char table_name[SAFE_NAME_LEN*2+2]; char* db = table->db; bool fatal_error=0; @@ -4744,7 +4880,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, remove_table_from_cache(thd, table->table->s->db.str, table->table->s->table_name.str, RTFC_WAIT_OTHER_THREAD_FLAG | - RTFC_CHECK_KILLED_FLAG); + RTFC_CHECK_KILLED_FLAG, FALSE); thd->exit_cond(old_message); DBUG_EXECUTE_IF("wait_in_mysql_admin_table", wait_for_kill_signal(thd);); if (thd->killed) @@ -4772,32 +4908,38 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, if (operator_func == &handler::ha_repair && !(check_opt->sql_flags & TT_USEFRM)) { - if ((table->table->file->check_old_types() == HA_ADMIN_NEEDS_ALTER) || - (table->table->file->ha_check_for_upgrade(check_opt) == - HA_ADMIN_NEEDS_ALTER)) + handler *file= table->table->file; + int check_old_types= file->check_old_types(); + int check_for_upgrade= file->ha_check_for_upgrade(check_opt); + + if (check_old_types == HA_ADMIN_NEEDS_ALTER || + check_for_upgrade == HA_ADMIN_NEEDS_ALTER) { - DBUG_PRINT("admin", ("recreating table")); - ha_autocommit_or_rollback(thd, 1); - close_thread_tables(thd); - tmp_disable_binlog(thd); // binlogging is done by caller if wanted - result_code= mysql_recreate_table(thd, table); - reenable_binlog(thd); - /* - mysql_recreate_table() can push OK or ERROR. - Clear 'OK' status. If there is an error, keep it: - we will store the error message in a result set row - and then clear. - */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + /* We use extra_open_options to be able to open crashed tables */ + thd->open_options|= extra_open_options; + result_code= admin_recreate_table(thd, table); + thd->open_options= ~extra_open_options; goto send_result; } + if (check_old_types || check_for_upgrade) + { + /* If repair is not implemented for the engine, run ALTER TABLE */ + need_repair_or_alter= 1; + } } DBUG_PRINT("admin", ("calling operator_func '%s'", operator_name)); result_code = (table->table->file->*operator_func)(thd, check_opt); DBUG_PRINT("admin", ("operator_func returned: %d", result_code)); + if (result_code == HA_ADMIN_NOT_IMPLEMENTED && need_repair_or_alter) + { + /* + repair was not implemented and we need to upgrade the table + to a new version so we recreate the table with ALTER TABLE + */ + result_code= admin_recreate_table(thd, table); + } send_result: lex->cleanup_after_one_table_open(); @@ -4897,23 +5039,13 @@ send_result_message: system_charset_info); if (protocol->write()) goto err; - ha_autocommit_or_rollback(thd, 0); - close_thread_tables(thd); DBUG_PRINT("info", ("HA_ADMIN_TRY_ALTER, trying analyze...")); TABLE_LIST *save_next_local= table->next_local, *save_next_global= table->next_global; table->next_local= table->next_global= 0; - tmp_disable_binlog(thd); // binlogging is done by caller if wanted - result_code= mysql_recreate_table(thd, table); - reenable_binlog(thd); - /* - mysql_recreate_table() can push OK or ERROR. - Clear 'OK' status. If there is an error, keep it: - we will store the error message in a result set row - and then clear. - */ - if (thd->main_da.is_ok()) - thd->main_da.reset_diagnostics_area(); + + result_code= admin_recreate_table(thd, table); + ha_autocommit_or_rollback(thd, 0); close_thread_tables(thd); if (!result_code) // recreation went ok @@ -5002,7 +5134,8 @@ send_result_message: { pthread_mutex_lock(&LOCK_open); remove_table_from_cache(thd, table->table->s->db.str, - table->table->s->table_name.str, RTFC_NO_FLAG); + table->table->s->table_name.str, + RTFC_NO_FLAG, FALSE); pthread_mutex_unlock(&LOCK_open); } /* May be something modified consequently we have to invalidate cache */ @@ -5669,8 +5802,8 @@ is_index_maintenance_unique (TABLE *table, Alter_info *alter_info) that need to be dropped and/or (re-)created. RETURN VALUES - TRUE error - FALSE success + TRUE The tables are not compatible; We have to do a full alter table + FALSE The tables are compatible; We only have to modify the .frm */ static @@ -5693,6 +5826,7 @@ compare_tables(TABLE *table, KEY_PART_INFO *key_part; KEY_PART_INFO *end; THD *thd= table->in_use; + uint i; /* Remember if the new definition has new VARCHAR column; create_info->varchar will be reset in mysql_prepare_create_table. @@ -5719,6 +5853,9 @@ compare_tables(TABLE *table, Alter_info tmp_alter_info(*alter_info, thd->mem_root); uint db_options= 0; /* not used */ + /* Set default value for return value (to ensure it's always set) */ + *need_copy_table= ALTER_TABLE_DATA_CHANGED; + /* Create the prepared information. */ if (mysql_prepare_create_table(thd, create_info, &tmp_alter_info, @@ -5767,6 +5904,8 @@ compare_tables(TABLE *table, create_info->used_fields & HA_CREATE_USED_CHARSET || create_info->used_fields & HA_CREATE_USED_DEFAULT_CHARSET || (table->s->row_type != create_info->row_type) || + create_info->used_fields & HA_CREATE_USED_PAGE_CHECKSUM || + create_info->used_fields & HA_CREATE_USED_TRANSACTIONAL || create_info->used_fields & HA_CREATE_USED_PACK_KEYS || create_info->used_fields & HA_CREATE_USED_MAX_ROWS || (alter_info->flags & (ALTER_RECREATE | ALTER_FOREIGN_KEY)) || @@ -5774,10 +5913,16 @@ compare_tables(TABLE *table, !table->s->mysql_version || (table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar)) { - *need_copy_table= ALTER_TABLE_DATA_CHANGED; + DBUG_PRINT("info", ("Basic checks -> ALTER_TABLE_DATA_CHANGED")); DBUG_RETURN(0); } + if ((create_info->fields_option_struct= (ha_field_option_struct**) + thd->calloc(sizeof(void*) * table->s->fields)) == NULL || + (create_info->indexes_option_struct= (ha_index_option_struct**) + thd->calloc(sizeof(void*) * table->s->keys)) == NULL) + DBUG_RETURN(1); + /* Use transformed info to evaluate possibility of fast ALTER TABLE but use the preserved field to persist modifications. @@ -5789,12 +5934,18 @@ compare_tables(TABLE *table, Go through fields and check if the original ones are compatible with new table. */ - for (f_ptr= table->field, new_field= new_field_it++, + for (i= 0, f_ptr= table->field, new_field= new_field_it++, tmp_new_field= tmp_new_field_it++; (field= *f_ptr); - f_ptr++, new_field= new_field_it++, + i++, f_ptr++, new_field= new_field_it++, tmp_new_field= tmp_new_field_it++) { + DBUG_ASSERT(i < table->s->fields); + create_info->fields_option_struct[i]= tmp_new_field->option_struct; + + /* reset common markers of how field changed */ + field->flags&= ~(FIELD_IS_RENAMED | FIELD_IN_ADD_INDEX); + /* Make sure we have at least the default charset in use. */ if (!new_field->charset) new_field->charset= create_info->default_table_charset; @@ -5803,19 +5954,32 @@ compare_tables(TABLE *table, if ((tmp_new_field->flags & NOT_NULL_FLAG) != (uint) (field->flags & NOT_NULL_FLAG)) { + DBUG_PRINT("info", ("NULL behaviour difference in field '%s' -> " + "ALTER_TABLE_DATA_CHANGED", new_field->field_name)); + DBUG_RETURN(0); + } + + /* + Check if the altered column is computed and either + is stored or is used in the partitioning expression. + TODO: Mark such a column with an alter flag only if + the defining expression has changed. + */ + if (field->vcol_info && + (field->stored_in_db || field->vcol_info->is_in_partitioning_expr())) + { *need_copy_table= ALTER_TABLE_DATA_CHANGED; DBUG_RETURN(0); } /* Don't pack rows in old tables if the user has requested this. */ - if (create_info->row_type == ROW_TYPE_DYNAMIC || - (tmp_new_field->flags & BLOB_FLAG) || - (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR && - create_info->row_type != ROW_TYPE_FIXED)) - create_info->table_options|= HA_OPTION_PACK_RECORD; + if (create_info->row_type == ROW_TYPE_DYNAMIC || + (tmp_new_field->flags & BLOB_FLAG) || + (tmp_new_field->sql_type == MYSQL_TYPE_VARCHAR && + create_info->row_type != ROW_TYPE_FIXED)) + create_info->table_options|= HA_OPTION_PACK_RECORD; /* Check if field was renamed */ - field->flags&= ~FIELD_IS_RENAMED; if (my_strcasecmp(system_charset_info, field->field_name, tmp_new_field->field_name)) @@ -5824,11 +5988,10 @@ compare_tables(TABLE *table, /* Evaluate changes bitmap and send to check_if_incompatible_data() */ if (!(tmp= field->is_equal(tmp_new_field))) { - *need_copy_table= ALTER_TABLE_DATA_CHANGED; + DBUG_PRINT("info", ("!field_is_equal('%s') -> ALTER_TABLE_DATA_CHANGED", + new_field->field_name)); DBUG_RETURN(0); } - // Clear indexed marker - field->flags&= ~FIELD_IN_ADD_INDEX; changes|= tmp; } @@ -5933,7 +6096,9 @@ compare_tables(TABLE *table, for (new_key= *key_info_buffer; new_key < new_key_end; new_key++) { /* Search an old key with the same name. */ - for (table_key= table->key_info; table_key < table_key_end; table_key++) + for (i= 0, table_key= table->key_info; + table_key < table_key_end; + i++, table_key++) { if (! strcmp(table_key->name, new_key->name)) break; @@ -5952,21 +6117,31 @@ compare_tables(TABLE *table, } DBUG_PRINT("info", ("index added: '%s'", new_key->name)); } + else + { + DBUG_ASSERT(i < table->s->keys); + create_info->indexes_option_struct[i]= new_key->option_struct; + } } /* Check if changes are compatible with current handler without a copy */ if (table->file->check_if_incompatible_data(create_info, changes)) { - *need_copy_table= ALTER_TABLE_DATA_CHANGED; + DBUG_PRINT("info", ("check_if_incompatible_data() -> " + "ALTER_TABLE_DATA_CHANGED")); DBUG_RETURN(0); } if (*index_drop_count || *index_add_count) { + DBUG_PRINT("info", ("Index dropped=%u added=%u -> " + "ALTER_TABLE_INDEX_CHANGED", + *index_drop_count, *index_add_count)); *need_copy_table= ALTER_TABLE_INDEX_CHANGED; DBUG_RETURN(0); } + DBUG_PRINT("info", (" -> ALTER_TABLE_METADATA_ONLY")); *need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible DBUG_RETURN(0); } @@ -6057,6 +6232,7 @@ bool alter_table_manage_keys(TABLE *table, int indexes_were_disabled, Sets create_info->varchar if the table has a VARCHAR column. Prepares alter_info->create_list and alter_info->key_list with columns and keys of the new table. + @retval TRUE error, out of memory or a semantical error in ALTER TABLE instructions @retval FALSE success @@ -6083,7 +6259,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, uint used_fields= create_info->used_fields; KEY *key_info=table->key_info; bool rc= TRUE; - + Create_field *def; + Field **f_ptr,*field; DBUG_ENTER("mysql_prepare_alter_table"); create_info->varchar= FALSE; @@ -6104,6 +6281,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!(used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE)) create_info->key_block_size= table->s->key_block_size; + if (!(used_fields & HA_CREATE_USED_TRANSACTIONAL)) + create_info->transactional= table->s->transactional; if (!create_info->tablespace && create_info->storage_media != HA_SM_MEMORY) { @@ -6117,18 +6296,18 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, create_info->tablespace= tablespace; } restore_record(table, s->default_values); // Empty record for DEFAULT - Create_field *def; + create_info->option_list= merge_engine_table_options(table->s->option_list, + create_info->option_list, thd->mem_root); /* First collect all fields from table which isn't in drop_list */ - Field **f_ptr,*field; for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++) { - if (field->type() == MYSQL_TYPE_STRING) + Alter_drop *drop; + if (field->type() == MYSQL_TYPE_VARCHAR) create_info->varchar= TRUE; /* Check if field should be dropped */ - Alter_drop *drop; drop_it.rewind(); while ((drop=drop_it++)) { @@ -6161,6 +6340,11 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, if (def) { // Field is changed def->field=field; + if (field->stored_in_db != def->stored_in_db) + { + my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN, MYF(0)); + goto err; + } if (!def->after) { new_create_list.push_back(def); @@ -6202,7 +6386,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, { if (def->change && ! def->field) { - my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, table->s->table_name.str); + my_error(ER_BAD_FIELD_ERROR, MYF(0), def->change, + table->s->table_name.str); goto err; } /* @@ -6237,7 +6422,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!find) { - my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, table->s->table_name.str); + my_error(ER_BAD_FIELD_ERROR, MYF(0), def->after, + table->s->table_name.str); goto err; } find_it.after(def); // Put element after this @@ -6287,6 +6473,8 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, continue; // Wrong field (from UNIREG) const char *key_part_name=key_part->field->field_name; Create_field *cfield; + uint key_part_length; + field_it.rewind(); while ((cfield=field_it++)) { @@ -6302,7 +6490,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, } if (!cfield) continue; // Field is removed - uint key_part_length=key_part->length; + key_part_length= key_part->length; if (cfield->field) // Not new field { /* @@ -6361,7 +6549,7 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, key= new Key(key_type, key_name, &key_create_info, test(key_info->flags & HA_GENERATED_KEY), - key_parts); + key_parts, key_info->option_list); new_key_list.push_back(key); } } @@ -6369,6 +6557,9 @@ mysql_prepare_alter_table(THD *thd, TABLE *table, Key *key; while ((key=key_it++)) // Add new keys { + if (key->type == Key::FOREIGN_KEY && + ((Foreign_key *)key)->validate(new_create_list)) + goto err; if (key->type != Key::FOREIGN_KEY) new_key_list.push_back(key); if (key->name && @@ -6440,6 +6631,7 @@ err: order_num How many ORDER BY fields has been specified. order List of fields to ORDER BY. ignore Whether we have ALTER IGNORE TABLE + require_online Give an error if we can't do operation online DESCRIPTION This is a veery long function and is everything but the kitchen sink :) @@ -6470,11 +6662,13 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, HA_CREATE_INFO *create_info, TABLE_LIST *table_list, Alter_info *alter_info, - uint order_num, ORDER *order, bool ignore) + uint order_num, ORDER *order, bool ignore, + bool require_online) { TABLE *table, *new_table= 0, *name_lock= 0; int error= 0; char tmp_name[80],old_name[32],new_name_buff[FN_REFLEN + 1]; + char old_name_buff[FN_REFLEN + 1]; char new_alias_buff[FN_REFLEN], *table_name, *db, *new_alias, *alias; char index_file[FN_REFLEN], data_file[FN_REFLEN]; char path[FN_REFLEN + 1]; @@ -6496,6 +6690,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint *index_add_buffer= NULL; uint candidate_key_count= 0; bool no_pk; + ulong explicit_used_fields= 0; DBUG_ENTER("mysql_alter_table"); /* @@ -6703,10 +6898,12 @@ view_err: build_table_filename(new_name_buff, sizeof(new_name_buff) - 1, new_db, new_name_buff, reg_ext, 0); - if (!access(new_name_buff, F_OK)) + build_table_filename(old_name_buff, sizeof(old_name_buff) - 1, + db, table_name, reg_ext, 0); + if (check_table_file_presence(old_name_buff, new_name_buff, new_db, + new_name, new_alias, TRUE)) { /* Table will be closed in do_command() */ - my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias); goto err; } } @@ -6752,19 +6949,21 @@ view_err: } /* - If this is an ALTER TABLE and no explicit row type specified reuse - the table's row type. - Note : this is the same as if the row type was specified explicitly. + If this is an ALTER TABLE and no explicit row type specified reuse + the table's row type. + Note: this is the same as if the row type was specified explicitly and + we must thus set HA_CREATE_USED_ROW_FORMAT! */ if (create_info->row_type == ROW_TYPE_NOT_USED) { /* ALTER TABLE without explicit row type */ create_info->row_type= table->s->row_type; - } - else - { - /* ALTER TABLE with specific row type */ - create_info->used_fields |= HA_CREATE_USED_ROW_FORMAT; + /* + We have to mark the row type as used, as otherwise the engine may + change the row format in update_create_info(). + */ + create_info->used_fields|= HA_CREATE_USED_ROW_FORMAT; + explicit_used_fields|= HA_CREATE_USED_ROW_FORMAT; } DBUG_PRINT("info", ("old type: %s new type: %s", @@ -6796,7 +6995,9 @@ view_err: from concurrent DDL statements. */ VOID(pthread_mutex_lock(&LOCK_open)); - wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + wait_while_table_is_used(thd, table, + thd->locked_tables ? HA_EXTRA_NOT_USED : + HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_EXECUTE_IF("sleep_alter_enable_indexes", my_sleep(6000000);); error= table->file->ha_enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); @@ -6804,7 +7005,9 @@ view_err: break; case DISABLE: VOID(pthread_mutex_lock(&LOCK_open)); - wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + wait_while_table_is_used(thd, table, + thd->locked_tables ? HA_EXTRA_NOT_USED : + HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); error=table->file->ha_disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ @@ -6819,7 +7022,7 @@ view_err: error= 0; push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), - table->alias); + table->alias.c_ptr()); } /* @@ -6883,7 +7086,7 @@ view_err: error= 0; push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA), - table->alias); + table->alias.c_ptr()); } if (!error) @@ -6931,6 +7134,9 @@ view_err: if (mysql_prepare_alter_table(thd, table, create_info, alter_info)) goto err; + /* Remove markers set for update_create_info */ + create_info->used_fields&= ~explicit_used_fields; + if (need_copy_table == ALTER_TABLE_METADATA_ONLY) need_copy_table= alter_info->change_level; @@ -7085,6 +7291,16 @@ view_err: /* Non-primary unique key. */ needed_online_flags|= HA_ONLINE_ADD_UNIQUE_INDEX; needed_fast_flags|= HA_ONLINE_ADD_UNIQUE_INDEX_NO_WRITES; + if (ignore) + { + /* + If ignore is used, we have to remove all duplicate rows, + which require a full table copy. + */ + need_copy_table= ALTER_TABLE_DATA_CHANGED; + pk_changed= 2; // Don't change need_copy_table + break; + } } } else @@ -7250,10 +7466,23 @@ view_err: */ } + /* Check if we can do the ALTER TABLE as online */ + if (require_online) + { + if (index_add_count || index_drop_count || + (new_table && + !(new_table->file->ha_table_flags() & HA_NO_COPY_ON_ALTER))) + { + my_error(ER_CANT_DO_ONLINE, MYF(0), "ALTER"); + goto close_table_and_return_error; + } + } + /* Copy the data if necessary. */ thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields thd->cuted_fields=0L; copied=deleted=0; + /* We do not copy data for MERGE tables. Only the children have data. MERGE tables have HA_NO_COPY_ON_ALTER set. @@ -7273,7 +7502,9 @@ view_err: else { VOID(pthread_mutex_lock(&LOCK_open)); - wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + wait_while_table_is_used(thd, table, + thd->locked_tables ? HA_EXTRA_NOT_USED : + HA_EXTRA_FORCE_REOPEN); VOID(pthread_mutex_unlock(&LOCK_open)); thd_proc_info(thd, "manage keys"); alter_table_manage_keys(table, table->file->indexes_are_disabled(), @@ -7283,6 +7514,8 @@ view_err: error= 1; } thd->count_cuted_fields= CHECK_FIELD_IGNORE; + if (error) + goto close_table_and_return_error; /* If we did not need to copy, we might still need to add/drop indexes. */ if (! new_table) @@ -7317,14 +7550,18 @@ view_err: /* Add the indexes. */ if ((error= table->file->add_index(table, key_info, index_add_count))) { - /* - Exchange the key_info for the error message. If we exchange - key number by key name in the message later, we need correct info. - */ - KEY *save_key_info= table->key_info; - table->key_info= key_info; - table->file->print_error(error, MYF(0)); - table->key_info= save_key_info; + /* Only report error if handler has not already reported an error */ + if (!thd->main_da.is_error()) + { + /* + Exchange the key_info for the error message. If we exchange + key number by key name in the message later, we need correct info. + */ + KEY *save_key_info= table->key_info; + table->key_info= key_info; + table->file->print_error(error, MYF(0)); + table->key_info= save_key_info; + } goto err1; } } @@ -7372,11 +7609,11 @@ view_err: } /*end of if (! new_table) for add/drop index*/ + DBUG_ASSERT(error == 0); + if (table->s->tmp_table != NO_TMP_TABLE) { /* We changed a temporary table */ - if (error) - goto err1; /* Close lock if this is a transactional table */ if (thd->lock) { @@ -7411,12 +7648,6 @@ view_err: } DEBUG_SYNC(thd, "alter_table_before_rename_result_table"); VOID(pthread_mutex_lock(&LOCK_open)); - if (error) - { - VOID(quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP)); - VOID(pthread_mutex_unlock(&LOCK_open)); - goto err; - } /* Data is copied. Now we: @@ -7474,11 +7705,11 @@ view_err: else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db, new_alias, FN_FROM_IS_TMP) || ((new_name != table_name || new_db != db) && // we also do rename - (need_copy_table != ALTER_TABLE_METADATA_ONLY || - mysql_rename_table(save_old_db_type, db, table_name, new_db, - new_alias, NO_FRM_RENAME)) && - Table_triggers_list::change_table_name(thd, db, table_name, - new_db, new_alias))) + (need_copy_table != ALTER_TABLE_METADATA_ONLY || + mysql_rename_table(save_old_db_type, db, table_name, new_db, + new_alias, NO_FRM_RENAME)) && + Table_triggers_list::change_table_name(thd, db, table_name, + new_db, new_alias))) { /* Try to get everything back. */ error=1; @@ -7564,27 +7795,6 @@ view_err: if (write_bin_log(thd, TRUE, thd->query(), thd->query_length())) DBUG_RETURN(TRUE); - if (ha_check_storage_engine_flag(old_db_type, HTON_FLUSH_AFTER_RENAME)) - { - /* - For the alter table to be properly flushed to the logs, we - have to open the new table. If not, we get a problem on server - shutdown. But we do not need to attach MERGE children. - */ - char path[FN_REFLEN]; - TABLE *t_table; - build_table_filename(path + 1, sizeof(path) - 1, new_db, table_name, "", 0); - t_table= open_temporary_table(thd, path, new_db, tmp_name, 0); - if (t_table) - { - intern_close_table(t_table); - my_free(t_table, MYF(0)); - } - else - sql_print_warning("Could not open table %s.%s after rename\n", - new_db,table_name); - ha_flush_logs(old_db_type); - } table_list->table=0; // For query cache query_cache_invalidate3(thd, table_list, 0); @@ -7610,6 +7820,16 @@ end_temporary: thd->some_tables_deleted=0; DBUG_RETURN(FALSE); +close_table_and_return_error: + if (new_table && table->s->tmp_table == NO_TMP_TABLE) + { + /* This is not a temporary table, so close it the normal way */ + new_table->s->deleting= TRUE; + intern_close_table(new_table); + my_free(new_table,MYF(0)); + new_table= 0; // This forces call to quick_rm_table() below + } + err1: if (new_table) { @@ -7675,7 +7895,9 @@ err_with_placeholders: VOID(pthread_mutex_unlock(&LOCK_open)); DBUG_RETURN(TRUE); } -/* mysql_alter_table */ + + +/* Copy all rows from one table to another */ static int copy_data_between_tables(TABLE *from,TABLE *to, @@ -7687,9 +7909,9 @@ copy_data_between_tables(TABLE *from,TABLE *to, enum enum_enable_or_disable keys_onoff, bool error_if_not_empty) { - int error; - Copy_field *copy,*copy_end; - ulong found_count,delete_count; + int error= 1, errpos= 0; + Copy_field *copy= NULL, *copy_end; + ha_rows found_count= 0, delete_count= 0; THD *thd= current_thd; uint length= 0; SORT_FIELD *sortorder; @@ -7699,8 +7921,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, List<Item> all_fields; ha_rows examined_rows; bool auto_increment_field_copied= 0; - ulong save_sql_mode; + ulong save_sql_mode= thd->variables.sql_mode; ulonglong prev_insert_id; + List_iterator<Create_field> it(create); + Create_field *def; DBUG_ENTER("copy_data_between_tables"); /* @@ -7709,15 +7933,16 @@ copy_data_between_tables(TABLE *from,TABLE *to, This needs to be done before external_lock */ - error= ha_enable_transaction(thd, FALSE); - if (error) - DBUG_RETURN(-1); - + if (ha_enable_transaction(thd, FALSE)) + goto err; + errpos=1; + if (!(copy= new Copy_field[to->s->fields])) - DBUG_RETURN(-1); /* purecov: inspected */ + goto err; /* purecov: inspected */ if (to->file->ha_external_lock(thd, F_WRLCK)) - DBUG_RETURN(-1); + goto err; + errpos= 2; /* We need external lock before we can disable/enable keys */ alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff); @@ -7729,11 +7954,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, from->file->info(HA_STATUS_VARIABLE); to->file->ha_start_bulk_insert(from->file->stats.records); + errpos= 3; - save_sql_mode= thd->variables.sql_mode; - - List_iterator<Create_field> it(create); - Create_field *def; copy_end=copy; for (Field **ptr=to->field ; *ptr ; ptr++) { @@ -7757,11 +7979,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, } - found_count=delete_count=0; - if (order) { - if (to->s->primary_key != MAX_KEY && to->file->primary_key_is_clustered()) + if (to->s->primary_key != MAX_KEY && + to->file->ha_table_flags() & HA_TABLE_SCAN_ON_INDEX) { char warn_buff[MYSQL_ERRMSG_SIZE]; my_snprintf(warn_buff, sizeof(warn_buff), @@ -7778,7 +7999,6 @@ copy_data_between_tables(TABLE *from,TABLE *to, tables.table= from; tables.alias= tables.table_name= from->s->table_name.str; tables.db= from->s->db.str; - error= 1; if (thd->lex->select_lex.setup_ref_array(thd, order_num) || setup_order(thd, thd->lex->select_lex.ref_pointer_array, @@ -7794,7 +8014,10 @@ copy_data_between_tables(TABLE *from,TABLE *to, /* Tell handler that we have values for all columns in the to table */ to->use_all_columns(); - init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE); + to->mark_virtual_columns_for_write(TRUE); + if (init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1, 1, FALSE)) + goto err; + errpos= 4; if (ignore) to->file->extra(HA_EXTRA_IGNORE_DUP_KEY); thd->row_count= 0; @@ -7807,6 +8030,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, error= 1; break; } + update_virtual_fields(thd, from); thd->row_count++; /* Return error if source table isn't empty. */ if (error_if_not_empty) @@ -7827,6 +8051,12 @@ copy_data_between_tables(TABLE *from,TABLE *to, copy_ptr->do_copy(copy_ptr); } prev_insert_id= to->file->next_insert_id; + update_virtual_fields(thd, to, TRUE); + if (thd->is_error()) + { + error= 1; + break; + } error=to->file->ha_write_row(to->record[0]); to->auto_increment_field_not_null= FALSE; if (error) @@ -7858,22 +8088,24 @@ copy_data_between_tables(TABLE *from,TABLE *to, else found_count++; } - end_read_record(&info); + +err: + if (errpos >= 4) + end_read_record(&info); free_io_cache(from); - delete [] copy; // This is never 0 + delete [] copy; - if (to->file->ha_end_bulk_insert() && error <= 0) + if (error > 0) + to->file->extra(HA_EXTRA_PREPARE_FOR_DROP); + if (errpos >= 3 && to->file->ha_end_bulk_insert() && error <= 0) { to->file->print_error(my_errno,MYF(0)); - error=1; + error= 1; } to->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY); - if (ha_enable_transaction(thd, TRUE)) - { + if (errpos >= 1 && ha_enable_transaction(thd, TRUE)) error= 1; - goto err; - } /* Ensure that the new table is saved properly to disk so that we @@ -7884,19 +8116,43 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (end_active_trans(thd)) error=1; - err: thd->variables.sql_mode= save_sql_mode; thd->abort_on_warning= 0; - free_io_cache(from); *copied= found_count; *deleted=delete_count; to->file->ha_release_auto_increment(); - if (to->file->ha_external_lock(thd,F_UNLCK)) + if (errpos >= 2 && to->file->ha_external_lock(thd,F_UNLCK)) error=1; + if (error < 0 && to->file->extra(HA_EXTRA_PREPARE_FOR_RENAME)) + error= 1; DBUG_RETURN(error > 0 ? -1 : 0); } +/* Prepare, run and cleanup for mysql_recreate_table() */ + +static bool admin_recreate_table(THD *thd, TABLE_LIST *table_list) +{ + bool result_code; + DBUG_ENTER("admin_recreate_table"); + + ha_autocommit_or_rollback(thd, 1); + close_thread_tables(thd); + tmp_disable_binlog(thd); // binlogging is done by caller if wanted + result_code= mysql_recreate_table(thd, table_list); + reenable_binlog(thd); + /* + mysql_recreate_table() can push OK or ERROR. + Clear 'OK' status. If there is an error, keep it: + we will store the error message in a result set row + and then clear. + */ + if (thd->main_da.is_ok()) + thd->main_da.reset_diagnostics_area(); + DBUG_RETURN(result_code); +} + + /* Recreates tables by calling mysql_alter_table(). @@ -7928,7 +8184,7 @@ bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list) alter_info.flags= (ALTER_CHANGE_COLUMN | ALTER_RECREATE); DBUG_RETURN(mysql_alter_table(thd, NullS, NullS, &create_info, table_list, &alter_info, 0, - (ORDER *) 0, 0)); + (ORDER *) 0, 0, 0)); } @@ -7953,7 +8209,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, /* Open one table after the other to keep lock time as short as possible. */ for (table= tables; table; table= table->next_local) { - char table_name[NAME_LEN*2+2]; + char table_name[SAFE_NAME_LEN*2+2]; TABLE *t; strxmov(table_name, table->db ,".", table->table_name, NullS); @@ -7972,11 +8228,14 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, } else { - if (t->file->ha_table_flags() & HA_HAS_CHECKSUM && - !(check_opt->flags & T_EXTEND)) + /* Call ->checksum() if the table checksum matches 'old_mode' settings */ + if (!(check_opt->flags & T_EXTEND) && + (((t->file->ha_table_flags() & HA_HAS_OLD_CHECKSUM) && + thd->variables.old_mode) || + ((t->file->ha_table_flags() & HA_HAS_NEW_CHECKSUM) && + !thd->variables.old_mode))) protocol->store((ulonglong)t->file->checksum()); - else if (!(t->file->ha_table_flags() & HA_HAS_CHECKSUM) && - (check_opt->flags & T_QUICK)) + else if (check_opt->flags & T_QUICK) protocol->store_null(); else { @@ -8003,7 +8262,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, goto err; } ha_checksum row_crc= 0; - int error= t->file->rnd_next(t->record[0]); + int error= t->file->ha_rnd_next(t->record[0]); if (unlikely(error)) { if (error == HA_ERR_RECORD_DELETED) @@ -8024,6 +8283,9 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, { Field *f= t->field[i]; + if (! thd->variables.old_mode && + f->is_real_null(0)) + continue; /* BLOB and VARCHAR have pointers in their field, we must convert to string; GEOMETRY is implemented on top of BLOB. @@ -8096,7 +8358,7 @@ static bool check_engine(THD *thd, const char *table_name, if (create_info->used_fields & HA_CREATE_USED_ENGINE) { my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0), - ha_resolve_storage_engine_name(*new_engine), "TEMPORARY"); + hton_name(*new_engine)->str, "TEMPORARY"); *new_engine= 0; return TRUE; } |