diff options
author | Jan Lindström <jplindst@mariadb.org> | 2013-09-03 17:50:36 +0300 |
---|---|---|
committer | Jan Lindström <jplindst@mariadb.org> | 2013-09-03 17:50:36 +0300 |
commit | ba3ff50ab2bfabab6a4307282f92854f6efe6382 (patch) | |
tree | 904c9b94cc5f1dfa8727f17af56f50fba4155205 /sql/handler.cc | |
parent | 81739d308fee0317e56bd70d97e3429ece83dd4b (diff) | |
parent | c8b87ca16f05826c6801c70fb20a88a61959264e (diff) | |
download | mariadb-git-ba3ff50ab2bfabab6a4307282f92854f6efe6382.tar.gz |
Merge 10.0 to galera-10.0
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 509 |
1 files changed, 404 insertions, 105 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index ec30057758c..e20afb5798f 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -65,7 +65,7 @@ static handlerton *installed_htons[128]; #define BITMAP_STACKBUF_SIZE (128/8) KEY_CREATE_INFO default_key_create_info= - { HA_KEY_ALG_UNDEF, 0, {NullS, 0}, {NullS, 0} }; +{ HA_KEY_ALG_UNDEF, 0, {NullS, 0}, {NullS, 0}, true }; /* number of entries in handlertons[] */ ulong total_ha= 0; @@ -102,6 +102,7 @@ uint known_extensions_id= 0; static int commit_one_phase_2(THD *thd, bool all, THD_TRANS *trans, bool is_real_trans); + static plugin_ref ha_default_plugin(THD *thd) { if (thd->variables.table_plugin) @@ -124,7 +125,7 @@ handlerton *ha_default_handlerton(THD *thd) { plugin_ref plugin= ha_default_plugin(thd); DBUG_ASSERT(plugin); - handlerton *hton= plugin_data(plugin, handlerton*); + handlerton *hton= plugin_hton(plugin); DBUG_ASSERT(hton); return hton; } @@ -155,7 +156,7 @@ redo: if ((plugin= my_plugin_lock_by_name(thd, name, MYSQL_STORAGE_ENGINE_PLUGIN))) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton && !(hton->flags & HTON_NOT_USER_SELECTABLE)) return plugin; @@ -203,7 +204,7 @@ handlerton *ha_resolve_by_legacy_type(THD *thd, enum legacy_db_type db_type) default: if (db_type > DB_TYPE_UNKNOWN && db_type < DB_TYPE_DEFAULT && (plugin= ha_lock_engine(thd, installed_htons[db_type]))) - return plugin_data(plugin, handlerton*); + return plugin_hton(plugin); /* fall through */ case DB_TYPE_UNKNOWN: return NULL; @@ -663,7 +664,7 @@ int ha_end() static my_bool dropdb_handlerton(THD *unused1, plugin_ref plugin, void *path) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->drop_database) hton->drop_database(hton, (char *)path); return FALSE; @@ -679,7 +680,7 @@ void ha_drop_database(char* path) static my_bool checkpoint_state_handlerton(THD *unused1, plugin_ref plugin, void *disable) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->checkpoint_state) hton->checkpoint_state(hton, (int) *(bool*) disable); return FALSE; @@ -701,7 +702,7 @@ static my_bool commit_checkpoint_request_handlerton(THD *unused1, plugin_ref plu void *data) { st_commit_checkpoint_request *st= (st_commit_checkpoint_request *)data; - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->commit_checkpoint_request) { void *cookie= st->cookie; @@ -733,7 +734,7 @@ ha_commit_checkpoint_request(void *cookie, void (*pre_hook)(void *)) static my_bool closecon_handlerton(THD *thd, plugin_ref plugin, void *unused) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); /* there's no need to rollback here as all transactions must be rolled back already @@ -760,7 +761,7 @@ void ha_close_connection(THD* thd) static my_bool kill_handlerton(THD *thd, plugin_ref plugin, void *level) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->kill_query && thd_get_ha_data(thd, hton)) @@ -1145,10 +1146,11 @@ int ha_prepare(THD *thd) } else { - push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, ER_GET_ERRNO, ER(ER_GET_ERRNO), HA_ERR_WRONG_COMMAND, ha_resolve_storage_engine_name(ht)); + } } } @@ -1254,7 +1256,7 @@ int ha_commit_trans(THD *thd, bool all) /* Just a random warning to test warnings pushed during autocommit. */ DBUG_EXECUTE_IF("warn_during_ha_commit_trans", - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));); @@ -1385,6 +1387,7 @@ int ha_commit_trans(THD *thd, bool all) err= ht->prepare(ht, thd, all); status_var_increment(thd->status_var.ha_prepare_count); if (err) + { #ifdef WITH_WSREP if (WSREP(thd) && ht->db_type== DB_TYPE_WSREP) { @@ -1399,6 +1402,7 @@ int ha_commit_trans(THD *thd, bool all) /* not wsrep hton, bail to native mysql behavior */ #endif my_error(ER_ERROR_DURING_COMMIT, MYF(0), err); + } if (err) goto err; @@ -1622,7 +1626,7 @@ int ha_rollback_trans(THD *thd, bool all) trans->no_2pc=0; if (is_real_trans && thd->transaction_rollback_request && thd->transaction.xid_state.xa_state != XA_NOTR) - thd->transaction.xid_state.rm_error= thd->stmt_da->sql_errno(); + thd->transaction.xid_state.rm_error= thd->get_stmt_da()->sql_errno(); } /* Always cleanup. Even if nht==0. There may be savepoints. */ if (is_real_trans) @@ -1649,7 +1653,7 @@ int ha_rollback_trans(THD *thd, bool all) */ if (is_real_trans && thd->transaction.all.modified_non_trans_table && !thd->slave_thread && thd->killed < KILL_CONNECTION) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_WARNING_NOT_COMPLETE_ROLLBACK, ER(ER_WARNING_NOT_COMPLETE_ROLLBACK)); (void) RUN_HOOK(transaction, after_rollback, (thd, FALSE)); @@ -1665,7 +1669,7 @@ struct xahton_st { static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin, void *arg) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->recover) { hton->commit_by_xid(hton, ((struct xahton_st *)arg)->xid); @@ -1677,7 +1681,7 @@ static my_bool xacommit_handlerton(THD *unused1, plugin_ref plugin, static my_bool xarollback_handlerton(THD *unused1, plugin_ref plugin, void *arg) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->recover) { hton->rollback_by_xid(hton, ((struct xahton_st *)arg)->xid); @@ -1783,7 +1787,7 @@ struct xarecover_st static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin, void *arg) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); struct xarecover_st *info= (struct xarecover_st *) arg; int got; @@ -2118,7 +2122,7 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv) static my_bool snapshot_handlerton(THD *thd, plugin_ref plugin, void *arg) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->start_consistent_snapshot) { @@ -2148,7 +2152,7 @@ int ha_start_consistent_snapshot(THD *thd) exist: */ if (warn) - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR, "This MySQL server does not support any " "consistent-read capable storage engine"); return 0; @@ -2158,7 +2162,7 @@ int ha_start_consistent_snapshot(THD *thd) static my_bool flush_handlerton(THD *thd, plugin_ref plugin, void *arg) { - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->flush_logs && hton->flush_logs(hton)) return TRUE; @@ -2244,9 +2248,9 @@ public: virtual bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, + Sql_condition::enum_warning_level level, const char* msg, - MYSQL_ERROR ** cond_hdl); + Sql_condition ** cond_hdl); char buff[MYSQL_ERRMSG_SIZE]; }; @@ -2256,9 +2260,9 @@ Ha_delete_table_error_handler:: handle_condition(THD *, uint, const char*, - MYSQL_ERROR::enum_warning_level, + Sql_condition::enum_warning_level, const char* msg, - MYSQL_ERROR ** cond_hdl) + Sql_condition ** cond_hdl) { *cond_hdl= NULL; /* Grab the error message */ @@ -2323,7 +2327,7 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, XXX: should we convert *all* errors to warnings here? What if the error is fatal? */ - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, error, + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, error, ha_delete_table_error_handler.buff); } delete file; @@ -2337,8 +2341,11 @@ int ha_delete_table(THD *thd, handlerton *table_type, const char *path, handler *handler::clone(const char *name, MEM_ROOT *mem_root) { handler *new_handler= get_new_handler(table->s, mem_root, ht); - if (! new_handler) + + if (!new_handler) return NULL; + if (new_handler->set_ha_share_ref(ha_share)) + goto err; /* Allocate handler->ref here because otherwise ha_open will allocate it @@ -2348,7 +2355,7 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root) if (!(new_handler->ref= (uchar*) alloc_root(mem_root, ALIGN_SIZE(ref_length)*2))) - return NULL; + goto err; /* TODO: Implement a more efficient way to have more than one index open for @@ -2359,9 +2366,13 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root) */ if (new_handler->ha_open(table, name, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED)) - return NULL; + goto err; return new_handler; + +err: + delete new_handler; + return NULL; } @@ -2438,6 +2449,8 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, table= table_arg; DBUG_ASSERT(table->s == table_share); + DBUG_ASSERT(m_lock_type == F_UNLCK); + DBUG_PRINT("info", ("old m_lock_type: %d F_UNLCK %d", m_lock_type, F_UNLCK)); DBUG_ASSERT(alloc_root_inited(&table->mem_root)); if ((error=open(name,mode,test_if_locked))) @@ -2458,7 +2471,15 @@ int handler::ha_open(TABLE *table_arg, const char *name, int mode, { DBUG_ASSERT(m_psi == NULL); DBUG_ASSERT(table_share != NULL); - m_psi= PSI_CALL_open_table(ha_table_share_psi(), this); + /* + Do not call this for partitions handlers, since it may take too much + resources. + So only use the m_psi on table level, not for individual partitions. + */ + if (!(test_if_locked & HA_OPEN_NO_PSI_CALL)) + { + m_psi= PSI_CALL_open_table(ha_table_share_psi(), this); + } if (table->s->db_options_in_use & HA_OPTION_READ_ONLY_DATA) table->db_stat|=HA_READ_ONLY; @@ -2492,12 +2513,18 @@ int handler::ha_close(void) PSI_CALL_close_table(m_psi); m_psi= NULL; /* instrumentation handle, invalid after close_table() */ + DBUG_ASSERT(m_lock_type == F_UNLCK); + DBUG_ASSERT(inited == NONE); DBUG_RETURN(close()); } int handler::ha_rnd_next(uchar *buf) { int result; + DBUG_ENTER("handler::ha_rnd_next"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); + DBUG_ASSERT(inited == RND); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, { result= rnd_next(buf); }) @@ -2512,12 +2539,17 @@ int handler::ha_rnd_next(uchar *buf) increment_statistics(&SSV::ha_read_rnd_next_count); table->status=result ? STATUS_NOT_FOUND: 0; - return result; + DBUG_RETURN(result); } int handler::ha_rnd_pos(uchar *buf, uchar *pos) { int result; + DBUG_ENTER("handler::ha_rnd_pos"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); + /* TODO: Find out how to solve ha_rnd_pos when finding duplicate update. */ + /* DBUG_ASSERT(inited == RND); */ MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, MAX_KEY, 0, { result= rnd_pos(buf, pos); }) @@ -2525,7 +2557,7 @@ int handler::ha_rnd_pos(uchar *buf, uchar *pos) if (!result) update_rows_read(); table->status=result ? STATUS_NOT_FOUND: 0; - return result; + DBUG_RETURN(result); } int handler::ha_index_read_map(uchar *buf, const uchar *key, @@ -2533,6 +2565,9 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key, enum ha_rkey_function find_flag) { int result; + DBUG_ENTER("handler::ha_index_read_map"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -2541,7 +2576,7 @@ int handler::ha_index_read_map(uchar *buf, const uchar *key, if (!result) update_index_statistics(); table->status=result ? STATUS_NOT_FOUND: 0; - return result; + DBUG_RETURN(result); } /* @@ -2556,6 +2591,8 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key, { int result; DBUG_ASSERT(inited==NONE); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(end_range == NULL); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, index, 0, { result= index_read_idx_map(buf, index, key, keypart_map, find_flag); }) @@ -2572,6 +2609,9 @@ int handler::ha_index_read_idx_map(uchar *buf, uint index, const uchar *key, int handler::ha_index_next(uchar * buf) { int result; + DBUG_ENTER("handler::ha_index_next"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -2580,12 +2620,15 @@ int handler::ha_index_next(uchar * buf) if (!result) update_index_statistics(); table->status=result ? STATUS_NOT_FOUND: 0; - return result; + DBUG_RETURN(result); } int handler::ha_index_prev(uchar * buf) { int result; + DBUG_ENTER("handler::ha_index_prev"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -2594,12 +2637,14 @@ int handler::ha_index_prev(uchar * buf) if (!result) update_index_statistics(); table->status=result ? STATUS_NOT_FOUND: 0; - return result; + DBUG_RETURN(result); } int handler::ha_index_first(uchar * buf) { int result; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -2614,6 +2659,8 @@ int handler::ha_index_first(uchar * buf) int handler::ha_index_last(uchar * buf) { int result; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -2628,6 +2675,8 @@ int handler::ha_index_last(uchar * buf) int handler::ha_index_next_same(uchar *buf, const uchar *key, uint keylen) { int result; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ASSERT(inited==INDEX); MYSQL_TABLE_IO_WAIT(m_psi, PSI_TABLE_FETCH_ROW, active_index, 0, @@ -3096,6 +3145,7 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment, { /* This should never happen, assert in debug, and fail in release build */ DBUG_ASSERT(0); + (void) extra(HA_EXTRA_NO_KEYREAD); *first_value= ULONGLONG_MAX; return; } @@ -3155,6 +3205,9 @@ void handler::get_auto_increment(ulonglong offset, ulonglong increment, void handler::ha_release_auto_increment() { DBUG_ENTER("ha_release_auto_increment"); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK || + (!next_insert_id && !insert_id_for_cur_row)); release_auto_increment(); insert_id_for_cur_row= 0; auto_inc_interval_for_cur_row.replace(0, 0, 0); @@ -3172,13 +3225,25 @@ void handler::ha_release_auto_increment() } -void handler::print_keydup_error(uint key_nr, const char *msg, myf errflag) +/** + Construct and emit duplicate key error message using information + from table's record buffer. + + @param table TABLE object which record buffer should be used as + source for column values. + @param key Key description. + @param msg Error message template to which key value should be + added. + @param errflag Flags for my_error() call. +*/ + +void print_keydup_error(TABLE *table, KEY *key, const char *msg, myf errflag) { /* Write the duplicated key in the error message */ - char key[MAX_KEY_LENGTH]; - String str(key,sizeof(key),system_charset_info); + char key_buff[MAX_KEY_LENGTH]; + String str(key_buff,sizeof(key_buff),system_charset_info); - if (key_nr == MAX_KEY) + if (key == NULL) { /* Key is unknown */ str.copy("", 0, system_charset_info); @@ -3187,18 +3252,29 @@ void handler::print_keydup_error(uint key_nr, const char *msg, myf errflag) else { /* Table is opened and defined at this point */ - key_unpack(&str,table,(uint) key_nr); + key_unpack(&str,table, key); uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(msg); if (str.length() >= max_length) { str.length(max_length-4); str.append(STRING_WITH_LEN("...")); } - my_printf_error(ER_DUP_ENTRY, msg, - errflag, str.c_ptr_safe(), table->key_info[key_nr].name); + my_printf_error(ER_DUP_ENTRY, msg, errflag, str.c_ptr_safe(), key->name); } } +/** + Construct and emit duplicate key error message using information + from table's record buffer. + + @sa print_keydup_error(table, key, msg, errflag). +*/ + +void print_keydup_error(TABLE *table, KEY *key, myf errflag) +{ + print_keydup_error(table, key, ER(ER_DUP_ENTRY_WITH_KEY_NAME), errflag); +} + /** Print error that we got from handler function. @@ -3263,7 +3339,9 @@ void handler::print_error(int error, myf errflag) uint key_nr=get_dup_key(error); if ((int) key_nr >= 0) { - print_keydup_error(key_nr, ER(ER_DUP_ENTRY_WITH_KEY_NAME), errflag); + print_keydup_error(table, + key_nr == MAX_KEY ? NULL : &table->key_info[key_nr], + errflag); DBUG_VOID_RETURN; } } @@ -3275,9 +3353,12 @@ void handler::print_error(int error, myf errflag) char rec_buf[MAX_KEY_LENGTH]; String rec(rec_buf, sizeof(rec_buf), system_charset_info); /* Table is opened and defined at this point */ - key_unpack(&rec, table, 0 /* just print the subset of fields that are - part of the first index, printing the whole - row from there is not easy */); + + /* + Just print the subset of fields that are part of the first index, + printing the whole row from there is not easy. + */ + key_unpack(&rec, table, &table->key_info[0]); char child_table_name[NAME_LEN + 1]; char child_key_name[NAME_LEN + 1]; @@ -3414,7 +3495,7 @@ void handler::print_error(int error, myf errflag) case HA_ERR_AUTOINC_ERANGE: textno= error; my_error(textno, errflag, table->next_number_field->field_name, - table->in_use->warning_info->current_row_for_warning()); + table->in_use->get_stmt_da()->current_row_for_warning()); DBUG_VOID_RETURN; break; case HA_ERR_TOO_MANY_CONCURRENT_TRXS: @@ -3423,6 +3504,9 @@ void handler::print_error(int error, myf errflag) case HA_ERR_INDEX_COL_TOO_LONG: textno= ER_INDEX_COLUMN_TOO_LONG; break; + case HA_ERR_NOT_IN_LOCK_PARTITIONS: + textno=ER_ROW_DOES_NOT_MATCH_GIVEN_PARTITION_SET; + break; case HA_ERR_INDEX_CORRUPT: textno= ER_INDEX_CORRUPT; break; @@ -3520,7 +3604,7 @@ int handler::check_collation_compatibility() for (; key < key_end; key++) { KEY_PART_INFO *key_part= key->key_part; - KEY_PART_INFO *key_part_end= key_part + key->key_parts; + KEY_PART_INFO *key_part_end= key_part + key->user_defined_key_parts; for (; key_part < key_part_end; key_part++) { if (!key_part->fieldnr) @@ -3561,7 +3645,7 @@ int handler::ha_check_for_upgrade(HA_CHECK_OPT *check_opt) for (; keyinfo < keyend; keyinfo++) { keypart= keyinfo->key_part; - keypartend= keypart + keyinfo->key_parts; + keypartend= keypart + keyinfo->user_defined_key_parts; for (; keypart < keypartend; keypart++) { if (!keypart->fieldnr) @@ -3653,6 +3737,8 @@ err: */ uint handler::get_dup_key(int error) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); DBUG_ENTER("handler::get_dup_key"); table->file->errkey = (uint) -1; if (error == HA_ERR_FOUND_DUPP_KEY || error == HA_ERR_FOREIGN_DUPLICATE_KEY || @@ -3763,6 +3849,8 @@ void handler::drop_table(const char *name) int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt) { int error; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); if ((table->s->mysql_version >= MYSQL_VERSION_ID) && (check_opt->sql_flags & TT_FOR_UPGRADE)) @@ -3852,6 +3940,8 @@ int handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, uint *dup_key_found) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return bulk_update_row(old_data, new_data, dup_key_found); @@ -3867,6 +3957,8 @@ handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data, int handler::ha_delete_all_rows() { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return delete_all_rows(); @@ -3882,6 +3974,8 @@ handler::ha_delete_all_rows() int handler::ha_truncate() { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return truncate(); @@ -3897,6 +3991,8 @@ handler::ha_truncate() int handler::ha_reset_auto_increment(ulonglong value) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return reset_auto_increment(value); @@ -3912,6 +4008,8 @@ handler::ha_reset_auto_increment(ulonglong value) int handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return optimize(thd, check_opt); @@ -3927,6 +4025,8 @@ handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt) int handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); mark_trx_read_write(); return analyze(thd, check_opt); @@ -3942,6 +4042,8 @@ handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt) bool handler::ha_check_and_repair(THD *thd) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_UNLCK); mark_trx_read_write(); return check_and_repair(thd); @@ -3957,6 +4059,8 @@ handler::ha_check_and_repair(THD *thd) int handler::ha_disable_indexes(uint mode) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); mark_trx_read_write(); return disable_indexes(mode); @@ -3972,6 +4076,8 @@ handler::ha_disable_indexes(uint mode) int handler::ha_enable_indexes(uint mode) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); mark_trx_read_write(); return enable_indexes(mode); @@ -3987,26 +4093,116 @@ handler::ha_enable_indexes(uint mode) int handler::ha_discard_or_import_tablespace(my_bool discard) { + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); mark_trx_read_write(); return discard_or_import_tablespace(discard); } -/** - Prepare for alter: public interface. +bool handler::ha_prepare_inplace_alter_table(TABLE *altered_table, + Alter_inplace_info *ha_alter_info) +{ + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); + mark_trx_read_write(); - Called to prepare an *online* ALTER. + return prepare_inplace_alter_table(altered_table, ha_alter_info); +} - @sa handler::prepare_for_alter() + +bool handler::ha_commit_inplace_alter_table(TABLE *altered_table, + Alter_inplace_info *ha_alter_info, + bool commit) +{ + /* + At this point we should have an exclusive metadata lock on the table. + The exception is if we're about to roll back changes (commit= false). + In this case, we might be rolling back after a failed lock upgrade, + so we could be holding the same lock level as for inplace_alter_table(). + */ + DBUG_ASSERT(ha_thd()->mdl_context.is_lock_owner(MDL_key::TABLE, + table->s->db.str, + table->s->table_name.str, + MDL_EXCLUSIVE) || + !commit); + + return commit_inplace_alter_table(altered_table, ha_alter_info, commit); +} + + +/* + Default implementation to support in-place alter table + and old online add/drop index API */ -void -handler::ha_prepare_for_alter() +enum_alter_inplace_result +handler::check_if_supported_inplace_alter(TABLE *altered_table, + Alter_inplace_info *ha_alter_info) { - mark_trx_read_write(); + DBUG_ENTER("check_if_supported_alter"); + + HA_CREATE_INFO *create_info= ha_alter_info->create_info; - prepare_for_alter(); + Alter_inplace_info::HA_ALTER_FLAGS inplace_offline_operations= + Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH | + Alter_inplace_info::ALTER_COLUMN_NAME | + Alter_inplace_info::ALTER_COLUMN_DEFAULT | + Alter_inplace_info::CHANGE_CREATE_OPTION | + Alter_inplace_info::ALTER_RENAME; + + /* Is there at least one operation that requires copy algorithm? */ + if (ha_alter_info->handler_flags & ~inplace_offline_operations) + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + + /* + ALTER TABLE tbl_name CONVERT TO CHARACTER SET .. and + ALTER TABLE table_name DEFAULT CHARSET = .. most likely + change column charsets and so not supported in-place through + old API. + + Changing of PACK_KEYS, MAX_ROWS and ROW_FORMAT options were + not supported as in-place operations in old API either. + */ + if (create_info->used_fields & (HA_CREATE_USED_CHARSET | + HA_CREATE_USED_DEFAULT_CHARSET | + HA_CREATE_USED_PACK_KEYS | + HA_CREATE_USED_MAX_ROWS) || + (table->s->row_type != create_info->row_type)) + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); + + uint table_changes= (ha_alter_info->handler_flags & + Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH) ? + IS_EQUAL_PACK_LENGTH : IS_EQUAL_YES; + if (table->file->check_if_incompatible_data(create_info, table_changes) + == COMPATIBLE_DATA_YES) + DBUG_RETURN(HA_ALTER_INPLACE_EXCLUSIVE_LOCK); + + DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); +} + + +/* + Default implementation to support in-place alter table + and old online add/drop index API +*/ + +void handler::notify_table_changed() +{ + ha_create_partitioning_metadata(table->s->path.str, NULL, CHF_INDEX_FLAG); +} + + +void Alter_inplace_info::report_unsupported_error(const char *not_supported, + const char *try_instead) +{ + if (unsupported_reason == NULL) + my_error(ER_ALTER_OPERATION_NOT_SUPPORTED, MYF(0), + not_supported, try_instead); + else + my_error(ER_ALTER_OPERATION_NOT_SUPPORTED_REASON, MYF(0), + not_supported, unsupported_reason, try_instead); } @@ -4019,6 +4215,7 @@ handler::ha_prepare_for_alter() int handler::ha_rename_table(const char *from, const char *to) { + DBUG_ASSERT(m_lock_type == F_UNLCK); mark_trx_read_write(); return rename_table(from, to); @@ -4051,6 +4248,7 @@ handler::ha_delete_table(const char *name) void handler::ha_drop_table(const char *name) { + DBUG_ASSERT(m_lock_type == F_UNLCK); mark_trx_read_write(); return drop_table(name); @@ -4066,6 +4264,7 @@ handler::ha_drop_table(const char *name) int handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info) { + DBUG_ASSERT(m_lock_type == F_UNLCK); mark_trx_read_write(); int error= create(name, form, info); if (!error && @@ -4085,6 +4284,13 @@ int handler::ha_create_partitioning_metadata(const char *name, const char *old_name, int action_flag) { + /* + Normally this is done when unlocked, but in fast_alter_partition_table, + it is done on an already locked handler when preparing to alter/rename + partitions. + */ + DBUG_ASSERT(m_lock_type == F_UNLCK || + (!old_name && strcmp(name, table_share->path.str))); mark_trx_read_write(); return create_partitioning_metadata(name, old_name, action_flag); @@ -4104,7 +4310,13 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info, ulonglong * const deleted, const uchar *pack_frm_data, size_t pack_frm_len) -{ +{ /* + Must have at least RDLCK or be a TMP table. Read lock is needed to read + from current partitions and write lock will be taken on new partitions. + */ + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type != F_UNLCK); + mark_trx_read_write(); return change_partitions(create_info, path, copied, deleted, @@ -4121,6 +4333,8 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info, int handler::ha_drop_partitions(const char *path) { + DBUG_ASSERT(!table->db_stat); + mark_trx_read_write(); return drop_partitions(path); @@ -4136,6 +4350,8 @@ handler::ha_drop_partitions(const char *path) int handler::ha_rename_partitions(const char *path) { + DBUG_ASSERT(!table->db_stat); + mark_trx_read_write(); return rename_partitions(path); @@ -4196,7 +4412,7 @@ int handler::index_next_same(uchar *buf, const uchar *key, uint keylen) table->record[0]= buf; key_info= table->key_info + active_index; key_part= key_info->key_part; - key_part_end= key_part + key_info->key_parts; + key_part_end= key_part + key_info->user_defined_key_parts; for (; key_part < key_part_end; key_part++) { DBUG_ASSERT(key_part->field); @@ -4561,7 +4777,7 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin, void *arg) { TABLE_SHARE *share= (TABLE_SHARE *)arg; - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->discover_table) { share->db_plugin= plugin; @@ -4570,8 +4786,13 @@ static my_bool discover_handlerton(THD *thd, plugin_ref plugin, { if (error) { - DBUG_ASSERT(share->error); // MUST be always set for get_cached_table_share to work - my_error(ER_GET_ERRNO, MYF(0), error, plugin_name(plugin)->str); + DBUG_ASSERT(share->error); // tdc_lock_share needs that + /* + report an error, unless it is "generic" and a more + specific one was already reported + */ + if (error != HA_ERR_GENERIC || !thd->is_error()) + my_error(ER_GET_ERRNO, MYF(0), error, plugin_name(plugin)->str); share->db_plugin= 0; } else @@ -4624,7 +4845,7 @@ static my_bool discover_existence(THD *thd, plugin_ref plugin, void *arg) { st_discover_existence_args *args= (st_discover_existence_args*)arg; - handlerton *ht= plugin_data(plugin, handlerton *); + handlerton *ht= plugin_hton(plugin); if (ht->state != SHOW_OPTION_YES || !ht->discover_table_existence) return FALSE; @@ -4647,9 +4868,9 @@ public: bool handle_condition(THD *thd, uint sql_errno, const char* sqlstate, - MYSQL_ERROR::enum_warning_level level, + Sql_condition::enum_warning_level level, const char* msg, - MYSQL_ERROR ** cond_hdl) + Sql_condition ** cond_hdl) { *cond_hdl= NULL; if (sql_errno == ER_NO_SUCH_TABLE || @@ -4660,7 +4881,7 @@ public: return TRUE; } - if (level == MYSQL_ERROR::WARN_LEVEL_ERROR) + if (level == Sql_condition::WARN_LEVEL_ERROR) m_unhandled_errors++; return FALSE; } @@ -4703,29 +4924,27 @@ bool ha_table_exists(THD *thd, const char *db, const char *table_name, Table_exists_error_handler no_such_table_handler; thd->push_internal_handler(&no_such_table_handler); - TABLE_SHARE *share= get_table_share(thd, db, table_name, flags); + TABLE_SHARE *share= tdc_acquire_share(thd, db, table_name, flags); thd->pop_internal_handler(); if (hton && share) { *hton= share->db_type(); - mysql_mutex_lock(&LOCK_open); - release_table_share(share); - mysql_mutex_unlock(&LOCK_open); + tdc_release_share(share); } // the table doesn't exist if we've caught ER_NO_SUCH_TABLE and nothing else DBUG_RETURN(!no_such_table_handler.safely_trapped_errors()); } - mysql_mutex_lock(&LOCK_open); - TABLE_SHARE *share= get_cached_table_share(db, table_name); - if (hton && share) - *hton= share->db_type(); - mysql_mutex_unlock(&LOCK_open); - + TABLE_SHARE *share= tdc_lock_share(db, table_name); if (share) + { + if (hton) + *hton= share->db_type(); + tdc_unlock_share(share); DBUG_RETURN(TRUE); + } char path[FN_REFLEN + 1]; size_t path_len = build_table_filename(path, sizeof(path) - 1, @@ -4822,10 +5041,10 @@ void Discovered_table_list::remove_duplicates() { LEX_STRING **src= tables->front(); LEX_STRING **dst= src; - while (++dst < tables->back()) + while (++dst <= tables->back()) { LEX_STRING *s= *src, *d= *dst; - DBUG_ASSERT(strncmp(s->str, d->str, min(s->length, d->length)) <= 0); + DBUG_ASSERT(strncmp(s->str, d->str, MY_MIN(s->length, d->length)) <= 0); if ((s->length != d->length || strncmp(s->str, d->str, d->length))) { src++; @@ -4833,7 +5052,7 @@ void Discovered_table_list::remove_duplicates() *src= *dst; } } - tables->set_elements(src - tables->front() + 1); + tables->elements(src - tables->front() + 1); } struct st_discover_names_args @@ -4848,7 +5067,7 @@ static my_bool discover_names(THD *thd, plugin_ref plugin, void *arg) { st_discover_names_args *args= (st_discover_names_args *)arg; - handlerton *ht= plugin_data(plugin, handlerton *); + handlerton *ht= plugin_hton(plugin); if (ht->state == SHOW_OPTION_YES && ht->discover_table_names) { @@ -4868,12 +5087,12 @@ static my_bool discover_names(THD *thd, plugin_ref plugin, } int ha_discover_table_names(THD *thd, LEX_STRING *db, MY_DIR *dirp, - Discovered_table_list *result) + Discovered_table_list *result, bool reusable) { int error; DBUG_ENTER("ha_discover_table_names"); - if (engines_with_discover_table_names == 0) + if (engines_with_discover_table_names == 0 && !reusable) { error= ext_table_discovery_simple(dirp, result); result->sort(); @@ -4925,7 +5144,7 @@ struct binlog_func_st static my_bool binlog_func_list(THD *thd, plugin_ref plugin, void *arg) { hton_list_st *hton_list= (hton_list_st *)arg; - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->binlog_func) { uint sz= hton_list->sz; @@ -5015,7 +5234,7 @@ static my_bool binlog_log_query_handlerton(THD *thd, plugin_ref plugin, void *args) { - return binlog_log_query_handlerton2(thd, plugin_data(plugin, handlerton *), args); + return binlog_log_query_handlerton2(thd, plugin_hton(plugin), args); } void ha_binlog_log_query(THD *thd, handlerton *hton, @@ -5065,14 +5284,7 @@ int handler::read_range_first(const key_range *start_key, DBUG_ENTER("handler::read_range_first"); eq_range= eq_range_arg; - end_range= 0; - if (end_key) - { - end_range= &save_end_range; - save_end_range= *end_key; - key_compare_result_on_equal= ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 : - (end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0); - } + set_end_range(end_key); range_key_part= table->key_info[active_index].key_part; if (!start_key) // Read first record @@ -5148,12 +5360,26 @@ int handler::read_range_next() } +void handler::set_end_range(const key_range *end_key) +{ + end_range= 0; + if (end_key) + { + end_range= &save_end_range; + save_end_range= *end_key; + key_compare_result_on_equal= + ((end_key->flag == HA_READ_BEFORE_KEY) ? 1 : + (end_key->flag == HA_READ_AFTER_KEY) ? -1 : 0); + } +} + + /** Compare if found key (in row) is over max-value. @param range range to compare to row. May be 0 for no range - @seealso + @see also key.cc::key_cmp() @return @@ -5246,7 +5472,7 @@ static my_bool exts_handlerton(THD *unused, plugin_ref plugin, void *arg) { List<char> *found_exts= (List<char> *) arg; - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); List_iterator_fast<char> it(*found_exts); const char **ext, *old_ext; @@ -5315,7 +5541,7 @@ static my_bool showstat_handlerton(THD *thd, plugin_ref plugin, void *arg) { enum ha_stat_type stat= *(enum ha_stat_type *) arg; - handlerton *hton= plugin_data(plugin, handlerton *); + handlerton *hton= plugin_hton(plugin); if (hton->state == SHOW_OPTION_YES && hton->show_status && hton->show_status(hton, thd, stat_print, stat)) return TRUE; @@ -5383,6 +5609,7 @@ static bool check_table_binlog_row_based(THD *thd, TABLE *table) if (table->s->cached_row_logging_check == -1) { int const check(table->s->tmp_table == NO_TMP_TABLE && + ! table->no_replicate && binlog_filter->db_ok(table->s->db.str)); table->s->cached_row_logging_check= check; } @@ -5494,8 +5721,6 @@ static int binlog_log_row(TABLE* table, const uchar *after_record, Log_func *log_func) { - if (table->no_replicate) - return 0; bool error= 0; THD *const thd= table->in_use; @@ -5550,6 +5775,12 @@ int handler::ha_external_lock(THD *thd, int lock_type) taken a table lock), ha_release_auto_increment() was too. */ DBUG_ASSERT(next_insert_id == 0); + /* Consecutive calls for lock without unlocking in between is not allowed */ + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + ((lock_type != F_UNLCK && m_lock_type == F_UNLCK) || + lock_type == F_UNLCK)); + /* SQL HANDLER call locks/unlock while scanning (RND/INDEX). */ + DBUG_ASSERT(inited == NONE || table->open_by_handler); if (MYSQL_HANDLER_RDLOCK_START_ENABLED() || MYSQL_HANDLER_WRLOCK_START_ENABLED() || @@ -5583,6 +5814,7 @@ int handler::ha_external_lock(THD *thd, int lock_type) if (error == 0) { + m_lock_type= lock_type; cached_table_flags= table_flags(); if (table_share->tmp_table == NO_TMP_TABLE) mysql_audit_external_lock(thd, table_share, lock_type); @@ -5639,10 +5871,10 @@ int handler::ha_write_row(uchar *buf) { int error; Log_func *log_func= Write_rows_log_event::binlog_row_logging_function; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); DBUG_ENTER("handler::ha_write_row"); DEBUG_SYNC_C("ha_write_row_start"); - DBUG_EXECUTE_IF("inject_error_ha_write_row", - DBUG_RETURN(HA_ERR_INTERNAL_ERROR); ); MYSQL_INSERT_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); @@ -5667,13 +5899,14 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data) { int error; Log_func *log_func= Update_rows_log_event::binlog_row_logging_function; + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); /* Some storage engines require that the new record is in record[0] (and the old record is in record[1]). */ DBUG_ASSERT(new_data == table->record[0]); - DBUG_ASSERT(old_data == table->record[1]); MYSQL_UPDATE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); @@ -5695,13 +5928,8 @@ int handler::ha_delete_row(const uchar *buf) { int error; Log_func *log_func= Delete_rows_log_event::binlog_row_logging_function; - /* - Normally table->record[0] is used, but sometimes table->record[1] is used. - */ - DBUG_ASSERT(buf == table->record[0] || - buf == table->record[1]); - DBUG_EXECUTE_IF("inject_error_ha_delete_row", - return HA_ERR_INTERNAL_ERROR; ); + DBUG_ASSERT(table_share->tmp_table != NO_TMP_TABLE || + m_lock_type == F_WRLCK); MYSQL_DELETE_ROW_START(table_share->db.str, table_share->table_name.str); mark_trx_read_write(); @@ -5732,6 +5960,77 @@ void handler::use_hidden_primary_key() } +/** + Get an initialized ha_share. + + @return Initialized ha_share + @retval NULL ha_share is not yet initialized. + @retval != NULL previous initialized ha_share. + + @note + If not a temp table, then LOCK_ha_data must be held. +*/ + +Handler_share *handler::get_ha_share_ptr() +{ + DBUG_ENTER("handler::get_ha_share_ptr"); + DBUG_ASSERT(ha_share && table_share); + +#ifndef DBUG_OFF + if (table_share->tmp_table == NO_TMP_TABLE) + mysql_mutex_assert_owner(&table_share->LOCK_ha_data); +#endif + + DBUG_RETURN(*ha_share); +} + + +/** + Set ha_share to be used by all instances of the same table/partition. + + @param ha_share Handler_share to be shared. + + @note + If not a temp table, then LOCK_ha_data must be held. +*/ + +void handler::set_ha_share_ptr(Handler_share *arg_ha_share) +{ + DBUG_ENTER("handler::set_ha_share_ptr"); + DBUG_ASSERT(ha_share); +#ifndef DBUG_OFF + if (table_share->tmp_table == NO_TMP_TABLE) + mysql_mutex_assert_owner(&table_share->LOCK_ha_data); +#endif + + *ha_share= arg_ha_share; + DBUG_VOID_RETURN; +} + + +/** + Take a lock for protecting shared handler data. +*/ + +void handler::lock_shared_ha_data() +{ + DBUG_ASSERT(table_share); + if (table_share->tmp_table == NO_TMP_TABLE) + mysql_mutex_lock(&table_share->LOCK_ha_data); +} + + +/** + Release lock for protecting ha_share. +*/ + +void handler::unlock_shared_ha_data() +{ + DBUG_ASSERT(table_share); + if (table_share->tmp_table == NO_TMP_TABLE) + mysql_mutex_unlock(&table_share->LOCK_ha_data); +} + /** @brief Dummy function which accept information about log files which is not need by handlers |