diff --git a/mysql-test/r/ndb_alter_table_row.result b/mysql-test/r/ndb_alter_table_row.result index 450b2c9a5af..552df63b030 100644 --- a/mysql-test/r/ndb_alter_table_row.result +++ b/mysql-test/r/ndb_alter_table_row.result @@ -8,6 +8,8 @@ a b c 2 two two alter table t1 drop index c; select * from t1 where c = 'two'; +ERROR HY000: Table definition has changed, please retry transaction +select * from t1 where c = 'two'; a b c 2 two two drop table t1; diff --git a/mysql-test/t/ndb_alter_table_row.test b/mysql-test/t/ndb_alter_table_row.test index 5dbfa26289b..a48d17ec02a 100644 --- a/mysql-test/t/ndb_alter_table_row.test +++ b/mysql-test/t/ndb_alter_table_row.test @@ -17,6 +17,8 @@ select * from t1 where c = 'two'; connection server1; alter table t1 drop index c; connection server2; +--error 1412 +select * from t1 where c = 'two'; select * from t1 where c = 'two'; connection server1; drop table t1; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 45593a171f8..5668116e387 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -989,22 +989,25 @@ int ha_ndbcluster::get_metadata(const char *path) if (cmp_frm(tab, pack_data, pack_length)) { - if (!invalidating_ndb_table) + if (m_share->state != NSS_ALTERED) { - DBUG_PRINT("info", ("Invalidating table")); - invalidate_dictionary_cache(TRUE); - invalidating_ndb_table= TRUE; - } - else - { - DBUG_PRINT("error", - ("metadata, pack_length: %d getFrmLength: %d memcmp: %d", - pack_length, tab->getFrmLength(), - memcmp(pack_data, tab->getFrmData(), pack_length))); - DBUG_DUMP("pack_data", (char*)pack_data, pack_length); - DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); - error= HA_ERR_TABLE_DEF_CHANGED; - invalidating_ndb_table= FALSE; + if (!invalidating_ndb_table) + { + DBUG_PRINT("info", ("Invalidating table")); + invalidate_dictionary_cache(TRUE); + invalidating_ndb_table= TRUE; + } + else + { + DBUG_PRINT("error", + ("metadata, pack_length: %d getFrmLength: %d memcmp: %d", + pack_length, tab->getFrmLength(), + memcmp(pack_data, tab->getFrmData(), pack_length))); + DBUG_DUMP("pack_data", (char*)pack_data, pack_length); + DBUG_DUMP("frm", (char*)tab->getFrmData(), tab->getFrmLength()); + error= HA_ERR_TABLE_DEF_CHANGED; + invalidating_ndb_table= FALSE; + } } } else @@ -1059,6 +1062,36 @@ static int fix_unique_index_attr_order(NDB_INDEX_DATA &data, DBUG_RETURN(0); } +int ha_ndbcluster::table_changed(const void *pack_frm_data, uint pack_frm_len) +{ + Ndb *ndb; + NDBDICT *dict; + const NDBTAB *orig_tab; + NdbDictionary::Table new_tab; + int result; + DBUG_ENTER("ha_ndbcluster::table_changed"); + DBUG_PRINT("info", ("Modifying frm for table %s", m_tabname)); + if (check_ndb_connection()) + DBUG_RETURN(my_errno= HA_ERR_NO_CONNECTION); + + ndb= get_ndb(); + dict= ndb->getDictionary(); + if (!(orig_tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + // Check if thread has stale local cache + if (orig_tab->getObjectStatus() == NdbDictionary::Object::Invalid) + { + dict->removeCachedTable(m_tabname); + if (!(orig_tab= dict->getTable(m_tabname))) + ERR_RETURN(dict->getNdbError()); + } + new_tab= *orig_tab; + new_tab.setFrm(pack_frm_data, pack_frm_len); + if (dict->alterTable(new_tab) != 0) + ERR_RETURN(dict->getNdbError()); + DBUG_RETURN(0); +} + /* Create all the indexes for a table. If any index should fail to be created, @@ -4316,6 +4349,47 @@ int ha_ndbcluster::create(const char *name, DBUG_RETURN(my_errno); } +int ha_ndbcluster::create_handler_files(const char *file) +{ + const char *name; + Ndb* ndb; + const NDBTAB *tab; + const void *data, *pack_data; + uint length, pack_length; + int error= 0; + + DBUG_ENTER("create_handler_files"); + + if (!(ndb= get_ndb())) + DBUG_RETURN(HA_ERR_NO_CONNECTION); + + NDBDICT *dict= ndb->getDictionary(); + if (!(tab= dict->getTable(m_tabname))) + DBUG_RETURN(0); // Must be a create, ignore since frm is saved in create + + name= table->s->normalized_path.str; + DBUG_PRINT("enter", ("m_tabname: %s, path: %s", m_tabname, name)); + if (readfrm(name, &data, &length) || + packfrm(data, length, &pack_data, &pack_length)) + { + DBUG_PRINT("info", ("Missing frm for %s", m_tabname)); + my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR)); + DBUG_RETURN(1); + } + if (cmp_frm(tab, pack_data, pack_length)) + { + DBUG_PRINT("info", ("Table %s has changed, altering frm in ndb", + m_tabname)); + error= table_changed(pack_data, pack_length); + m_share->state= NSS_INITIAL; + } + my_free((char*)data, MYF(MY_ALLOW_ZERO_PTR)); + my_free((char*)pack_data, MYF(MY_ALLOW_ZERO_PTR)); + + DBUG_RETURN(error); +} + int ha_ndbcluster::create_index(const char *name, KEY *key_info, NDB_INDEX_TYPE idx_type, uint idx_no) { @@ -4443,7 +4517,7 @@ int ha_ndbcluster::add_index(TABLE *table_arg, if((error= create_index(key_info[idx].name, key, idx_type, idx))) break; } - + m_share->state= NSS_ALTERED; DBUG_RETURN(error); } @@ -4478,6 +4552,7 @@ int ha_ndbcluster::prepare_drop_index(TABLE *table_arg, THD *thd= current_thd; Thd_ndb *thd_ndb= get_thd_ndb(thd); Ndb *ndb= thd_ndb->ndb; + m_share->state= NSS_ALTERED; DBUG_RETURN(renumber_indexes(ndb, table_arg)); } @@ -4488,14 +4563,11 @@ int ha_ndbcluster::final_drop_index(TABLE *table_arg) { DBUG_ENTER("ha_ndbcluster::final_drop_index"); DBUG_PRINT("info", ("ha_ndbcluster::final_drop_index")); - int error= 0; // Really drop indexes THD *thd= current_thd; Thd_ndb *thd_ndb= get_thd_ndb(thd); Ndb *ndb= thd_ndb->ndb; - error= drop_indexes(ndb, table_arg); - - DBUG_RETURN(error); + DBUG_RETURN(drop_indexes(ndb, table_arg)); } /* @@ -5331,9 +5403,13 @@ int ndbcluster_find_all_files(THD *thd) } else if (cmp_frm(ndbtab, pack_data, pack_length)) { - discover= 1; - sql_print_information("NDB: mismatch in frm for %s.%s, discovering...", - elmt.database, elmt.name); + NDB_SHARE *share= get_share(key, 0, false); + if (!share || share->state != NSS_ALTERED) + { + discover= 1; + sql_print_information("NDB: mismatch in frm for %s.%s, discovering...", + elmt.database, elmt.name); + } } my_free((char*) data, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*) pack_data, MYF(MY_ALLOW_ZERO_PTR)); @@ -6529,7 +6605,7 @@ NDB_SHARE *ndbcluster_get_share(const char *key, TABLE *table, MEM_ROOT *old_root= *root_ptr; init_sql_alloc(&share->mem_root, 1024, 0); *root_ptr= &share->mem_root; // remember to reset before return - + share->state= NSS_INITIAL; /* enough space for key, db, and table_name */ share->key= alloc_root(*root_ptr, 2 * (length + 1)); share->key_length= length; @@ -9086,13 +9162,6 @@ uint ha_ndbcluster::set_up_partition_info(partition_info *part_info, bool ha_ndbcluster::check_if_incompatible_data(HA_CREATE_INFO *info, uint table_changes) { - /* - TODO: Remove the dummy return below, when cluster gets - signal from alter table when only .frm is changed. Cluster - needs it to manage the copies. - */ - return COMPATIBLE_DATA_NO; - if (table_changes != IS_EQUAL_YES) return COMPATIBLE_DATA_NO; diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index c36cefcf5b5..73b1b27ede2 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -80,10 +80,12 @@ typedef union { const NdbRecAttr *rec; NdbBlob *blob; void *ptr; } NdbValue; typedef enum { NSS_INITIAL= 0, - NSS_DROPPED + NSS_DROPPED, + NSS_ALTERED } NDB_SHARE_STATE; typedef struct st_ndbcluster_share { + NDB_SHARE_STATE state; MEM_ROOT mem_root; THR_LOCK lock; pthread_mutex_t mutex; @@ -97,7 +99,6 @@ typedef struct st_ndbcluster_share { char *table_name; #ifdef HAVE_NDB_BINLOG uint32 flags; - NDB_SHARE_STATE state; NdbEventOperation *op; NdbEventOperation *op_old; // for rename table char *old_names; // for rename table @@ -579,6 +580,7 @@ class ha_ndbcluster: public handler int rename_table(const char *from, const char *to); int delete_table(const char *name); int create(const char *name, TABLE *form, HA_CREATE_INFO *info); + int create_handler_files(const char *file); int get_default_no_partitions(ulonglong max_rows); bool get_no_parts(const char *name, uint *no_parts); void set_auto_partitions(partition_info *part_info); @@ -669,6 +671,7 @@ private: int create_index(const char *name, KEY *key_info, NDB_INDEX_TYPE idx_type, uint idx_no); int drop_ndb_index(const char *name); + int table_changed(const void *pack_frm_data, uint pack_frm_len); // Index list management int create_indexes(Ndb *ndb, TABLE *tab); void clear_index(int i); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 96a4ae22f2e..d1ecef06fe0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3842,6 +3842,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, uint *index_drop_buffer; uint index_add_count; uint *index_add_buffer; + bool committed= 0; DBUG_ENTER("mysql_alter_table"); thd->proc_info="init"; @@ -4759,6 +4760,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, DBUG_PRINT("info", ("Committing after add/drop index")); if (ha_commit_stmt(thd) || ha_commit(thd)) goto err; + committed= 1; } } /*end of if (! new_table) for add/drop index*/ @@ -4890,7 +4892,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, VOID(pthread_mutex_unlock(&LOCK_open)); goto err; } -#ifdef XXX_TO_BE_DONE_LATER_BY_WL1892 if (! need_copy_table) { if (! table) @@ -4907,7 +4908,6 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; } } -#endif if (thd->lock || new_name != table_name) // True if WIN32 { /* @@ -4957,11 +4957,14 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, wait_if_global_read_lock(), which could create a deadlock if called with LOCK_open. */ - error = ha_commit_stmt(thd); - if (ha_commit(thd)) - error=1; - if (error) - goto err; + if (!committed) + { + error = ha_commit_stmt(thd); + if (ha_commit(thd)) + error=1; + if (error) + goto err; + } thd->proc_info="end"; DBUG_ASSERT(!(mysql_bin_log.is_open() && binlog_row_based &&