diff options
author | Sergei Golubchik <serg@mariadb.org> | 2016-11-07 22:35:02 +0100 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2016-12-12 20:27:42 +0100 |
commit | 1cae1af6f9286ca6695206ce20c63bb639c60310 (patch) | |
tree | 3877547f579596add5d757059d1e2f10dd8ef429 /storage | |
parent | 7fca91f2b454db6e33d964a7484237793699f77d (diff) | |
download | mariadb-git-1cae1af6f9286ca6695206ce20c63bb639c60310.tar.gz |
MDEV-5800 InnoDB support for indexed vcols
* remove old 5.2+ InnoDB support for virtual columns
* enable corresponding parts of the innodb-5.7 sources
* copy corresponding test cases from 5.7
* copy detailed Alter_inplace_info::HA_ALTER_FLAGS flags from 5.7
- and more detailed detection of changes in fill_alter_inplace_info()
* more "innodb compatibility hooks" in sql_class.cc to
- create/destroy/reset a THD (used by background purge threads)
- find a prelocked table by name
- open a table (from a background purge thread)
* different from 5.7:
- new service thread "thd_destructor_proxy" to make sure all THDs are
destroyed at the correct point in time during the server shutdown
- proper opening/closing of tables for vcol evaluations in
+ FK checks (use already opened prelocked tables)
+ purge threads (open the table, MDLock it, add it to tdc, close
when not needed)
- cache open tables in vc_templ
- avoid unnecessary allocations, reuse table->record[0] and table->s->default_values
- not needed in 5.7, because it overcalculates:
+ tell the server to calculate vcols for an on-going inline ADD INDEX
+ calculate vcols for correct error messages
* update other engines (mroonga/tokudb) accordingly
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 567 | ||||
-rw-r--r-- | storage/innobase/handler/ha_innodb.h | 18 | ||||
-rw-r--r-- | storage/innobase/handler/handler0alter.cc | 422 | ||||
-rw-r--r-- | storage/innobase/include/dict0dict.ic | 1 | ||||
-rw-r--r-- | storage/innobase/include/dict0mem.h | 11 | ||||
-rw-r--r-- | storage/innobase/include/ha_prototypes.h | 16 | ||||
-rw-r--r-- | storage/innobase/log/log0log.cc | 7 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.cc | 6 | ||||
-rw-r--r-- | storage/innobase/row/row0merge.cc | 5 | ||||
-rw-r--r-- | storage/innobase/row/row0mysql.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0purge.cc | 4 | ||||
-rw-r--r-- | storage/innobase/row/row0sel.cc | 2 | ||||
-rw-r--r-- | storage/innobase/row/row0upd.cc | 6 | ||||
-rw-r--r-- | storage/innobase/row/row0vers.cc | 6 | ||||
-rw-r--r-- | storage/innobase/srv/srv0srv.cc | 44 | ||||
-rw-r--r-- | storage/mroonga/ha_mroonga.cpp | 4 | ||||
-rw-r--r-- | storage/tokudb/ha_tokudb_alter_56.cc | 20 |
17 files changed, 548 insertions, 593 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 598047e31d6..a235195ae91 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -126,6 +126,14 @@ this program; if not, write to the Free Software Foundation, Inc., #define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X)) extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all); +unsigned long long thd_get_query_id(const MYSQL_THD thd); +TABLE *find_fk_open_table(THD *thd, const char *db, size_t db_len, + const char *table, size_t table_len); +MYSQL_THD create_thd(); +void destroy_thd(MYSQL_THD thd); +void reset_thd(MYSQL_THD thd); +TABLE *open_purge_table(THD *thd, const char *db, size_t dblen, + const char *tb, size_t tblen); #ifdef MYSQL_DYNAMIC_PLUGIN #define tc_size 400 @@ -300,6 +308,45 @@ is_partition( #endif /* _WIN32 */ } +/** Service thread that waits for the server shutdown and stops purge threads. +Purge workers have THDs that are needed to calculate virtual columns. +This THDs must be destroyed rather early in the server shutdown sequence. +This service thread creates a THD and idly waits for it to get a signal to +die. Then it notifies all purge workers to shutdown. +*/ +st_my_thread_var *thd_destructor_myvar= NULL; +mysql_cond_t thd_destructor_cond; +pthread_t thd_destructor_thread; + +pthread_handler_t +thd_destructor_proxy(void *) +{ + mysql_mutex_t thd_destructor_mutex; + + my_thread_init(); + mysql_mutex_init(PSI_NOT_INSTRUMENTED, &thd_destructor_mutex, 0); + mysql_cond_init(PSI_NOT_INSTRUMENTED, &thd_destructor_cond, 0); + + thd_destructor_myvar = _my_thread_var(); + THD *thd= create_thd(); + + mysql_mutex_lock(&thd_destructor_mutex); + thd_destructor_myvar->current_mutex = &thd_destructor_mutex; + thd_destructor_myvar->current_cond = &thd_destructor_cond; + /* wait until the server wakes the THD to abort and die */ + while (!thd_destructor_myvar->abort) + mysql_cond_wait(&thd_destructor_cond, &thd_destructor_mutex); + mysql_mutex_unlock(&thd_destructor_mutex); + thd_destructor_myvar = NULL; + + srv_purge_wakeup(); + + destroy_thd(thd); + mysql_cond_destroy(&thd_destructor_cond); + mysql_mutex_destroy(&thd_destructor_mutex); + my_thread_end(); + return 0; +} /** Return the InnoDB ROW_FORMAT enum value @param[in] row_format row_format from "innodb_default_row_format" @@ -473,6 +520,7 @@ static mysql_pfs_key_t innobase_share_mutex_key; static mysql_pfs_key_t commit_cond_mutex_key; static mysql_pfs_key_t commit_cond_key; static mysql_pfs_key_t pending_checkpoint_mutex_key; +static mysql_pfs_key_t thd_destructor_thread_key; static PSI_mutex_info all_pthread_mutexes[] = { PSI_KEY(commit_cond_mutex), @@ -601,6 +649,7 @@ static PSI_thread_info all_innodb_threads[] = { PSI_KEY(srv_purge_thread), PSI_KEY(srv_worker_thread), PSI_KEY(trx_rollback_clean_thread), + PSI_KEY(thd_destructor_thread), }; # endif /* UNIV_PFS_THREAD */ @@ -1718,6 +1767,55 @@ thd_trx_is_read_only( return(thd != 0 && thd_tx_is_read_only(thd)); } +static MYSQL_THDVAR_BOOL(background_thread, + PLUGIN_VAR_NOCMDOPT | PLUGIN_VAR_NOSYSVAR, + "Internal (not user visible) flag to mark " + "background purge threads", NULL, NULL, 0); + +/** Create a MYSQL_THD for background purge threads and mark it as such. +@returns new MYSQL_THD */ +MYSQL_THD +innobase_create_background_thd() +/*============================*/ +{ + MYSQL_THD thd= create_thd(); + THDVAR(thd, background_thread) = true; + return thd; +} + + +/** Destroy a background purge thread THD. +@param[in] thd MYSQL_THD to destroy */ +void +innobase_destroy_background_thd( +/*============================*/ + MYSQL_THD thd) +{ + /* need to close the connection explicitly, the server won't do it + if innodb is in the PLUGIN_IS_DYING state */ + innobase_close_connection(innodb_hton_ptr, thd); + thd_set_ha_data(thd, innodb_hton_ptr, NULL); + destroy_thd(thd); +} + +/** Close opened tables, free memory, delete items for a MYSQL_THD. +@param[in] thd MYSQL_THD to reset */ +void +innobase_reset_background_thd(MYSQL_THD thd) +{ + if (!thd) { + thd = current_thd; + } + + ut_ad(thd); + ut_ad(THDVAR(thd, background_thread)); + + /* background purge thread */ + reset_thd(thd); + thd_proc_info(thd, ""); +} + + #if 0 /** Check if the transaction can be rolled back @@ -3252,6 +3350,7 @@ ha_innobase::ha_innobase( | HA_CAN_VIRTUAL_COLUMNS | HA_CAN_INDEX_BLOBS | HA_CAN_SQL_HANDLER + | HA_REQUIRES_KEY_COLUMNS_FOR_DELETE | HA_PRIMARY_KEY_REQUIRED_FOR_POSITION | HA_PRIMARY_KEY_IN_READ_INDEX | HA_BINLOG_ROW_CAPABLE @@ -4582,6 +4681,12 @@ innobase_change_buffering_inited_ok: } */ + if (!srv_read_only_mode) { + mysql_thread_create(thd_destructor_thread_key, + &thd_destructor_thread, + NULL, thd_destructor_proxy, NULL); + } + /* Since we in this module access directly the fields of a trx struct, and due to different headers and flags it might happen that ib_mutex_t has a different size in this module and in InnoDB @@ -4716,6 +4821,13 @@ innobase_end( #ifdef MYSQL_ENCRYPTION mutex_free(&master_key_id_mutex); #endif + + if (!abort_loop && thd_destructor_myvar) { + // may be UNINSTALL PLUGIN statement + thd_destructor_myvar->abort = 1; + mysql_cond_broadcast(thd_destructor_myvar->current_cond); + } + if (innobase_shutdown_for_mysql() != DB_SUCCESS) { err = 1; } @@ -5839,6 +5951,36 @@ ha_innobase::keys_to_use_for_scanning() } /****************************************************************//** +Ensures that if there's a concurrent inplace ADD INDEX, being-indexed virtual +columns are computed. They are not marked as indexed in the old table, so the +server won't add them to the vcol_set automatically */ +void +ha_innobase::column_bitmaps_signal() +/*================================*/ +{ + if (!table->vfield || table->current_lock != F_WRLCK) { + return; + } + + dict_index_t* clust_index = dict_table_get_first_index(m_prebuilt->table); + uint num_v = 0; + for (uint j = 0; j < table->s->virtual_fields; j++) { + if (table->vfield[j]->stored_in_db()) { + continue; + } + + dict_col_t* col = &m_prebuilt->table->v_cols[num_v].m_col; + if (col->ord_part || + (dict_index_is_online_ddl(clust_index) && + row_log_col_is_indexed(clust_index, num_v))) { + table->mark_virtual_col(table->vfield[j]); + } + num_v++; + } +} + + +/****************************************************************//** Determines if table caching is supported. @return HA_CACHE_TBL_ASKTRANSACT */ @@ -6168,7 +6310,6 @@ innobase_match_index_columns( DBUG_RETURN(TRUE); } -#ifdef MYSQL_VIRTUAL_COLUMNS /** Build a template for a base column for a virtual column @param[in] table MySQL TABLE @param[in] clust_index InnoDB clustered index @@ -6228,21 +6369,6 @@ innobase_vcol_build_templ( templ->is_unsigned = col->prtype & DATA_UNSIGNED; } -/** callback used by MySQL server layer to initialize -the table virtual columns' template -@param[in] table MySQL TABLE -@param[in,out] ib_table InnoDB table */ -void -innobase_build_v_templ_callback( - const TABLE* table, - void* ib_table) -{ - const dict_table_t* t_table = static_cast<dict_table_t*>(ib_table); - - innobase_build_v_templ(table, t_table, t_table->vc_templ, NULL, - true, NULL); -} - /** Build template for the virtual columns and their base columns. This is done when the table first opened. @param[in] table MySQL TABLE @@ -6250,16 +6376,14 @@ is done when the table first opened. @param[in,out] s_templ InnoDB template structure @param[in] add_v new virtual columns added along with add index call -@param[in] locked true if dict_sys mutex is held -@param[in] share_tbl_name original MySQL table name */ +@param[in] locked true if dict_sys mutex is held */ void innobase_build_v_templ( const TABLE* table, const dict_table_t* ib_table, dict_vcol_templ_t* s_templ, const dict_add_v_col_t* add_v, - bool locked, - const char* share_tbl_name) + bool locked) { ulint ncol = ib_table->n_cols - DATA_N_SYS_COLS; ulint n_v_col = ib_table->n_v_cols; @@ -6291,15 +6415,8 @@ innobase_build_v_templ( * sizeof *s_templ->vtempl)); s_templ->n_col = ncol; s_templ->n_v_col = n_v_col; - s_templ->rec_len = table->s->stored_rec_length; - // JAN: MySQL 5.6 - // s_templ->default_rec = table->s->default_values; - - s_templ->default_rec = static_cast<byte*>( - ut_malloc_nokey(table->s->stored_rec_length)); - memcpy(s_templ->default_rec, table->s->default_values, - table->s->stored_rec_length); - + s_templ->rec_len = table->s->reclength; + s_templ->default_rec = table->s->default_values; /* Mark those columns could be base columns */ for (ulint i = 0; i < ib_table->n_v_cols; i++) { @@ -6399,12 +6516,7 @@ innobase_build_v_templ( s_templ->db_name = table->s->db.str; s_templ->tb_name = table->s->table_name.str; - - if (share_tbl_name) { - s_templ->share_name = share_tbl_name; - } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /*******************************************************************//** This function builds a translation table in INNOBASE_SHARE @@ -6774,14 +6886,14 @@ ha_innobase::open( if (ib_table != NULL && ((!DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID) - && table->s->stored_fields != dict_table_get_n_tot_u_cols(ib_table)) + && table->s->fields != dict_table_get_n_tot_u_cols(ib_table)) || (DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID) - && (table->s->stored_fields + && (table->s->fields != dict_table_get_n_tot_u_cols(ib_table) - 1)))) { ib::warn() << "Table " << norm_name << " contains " << dict_table_get_n_user_cols(ib_table) << " user" - " defined columns in InnoDB, but " << table->s->stored_fields + " defined columns in InnoDB, but " << table->s->fields << " columns in MariaDB. Please check" " INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and " REFMAN "innodb-troubleshooting.html for how to resolve the" @@ -6927,7 +7039,7 @@ ha_innobase::open( DBUG_RETURN(ret_err); } - m_prebuilt = row_create_prebuilt(ib_table, table->s->stored_rec_length); + m_prebuilt = row_create_prebuilt(ib_table, table->s->reclength); m_prebuilt->default_rec = table->s->default_values; ut_ad(m_prebuilt->default_rec); @@ -6939,12 +7051,10 @@ ha_innobase::open( key_used_on_scan = m_primary_key; -#ifdef MYSQL_VIRTUAL_COLUMNS if (ib_table->n_v_cols) { mutex_enter(&dict_sys->mutex); if (ib_table->vc_templ == NULL) { ib_table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t()); - ib_table->vc_templ->vtempl = NULL; } else if (ib_table->get_ref_count() == 1) { /* Clean and refresh the template if no one else get hold on it */ @@ -6955,12 +7065,11 @@ ha_innobase::open( if (ib_table->vc_templ->vtempl == NULL) { innobase_build_v_templ( table, ib_table, ib_table->vc_templ, NULL, - true, m_share->table_name); + true); } mutex_exit(&dict_sys->mutex); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ if (!innobase_build_index_translation(table, ib_table, m_share)) { sql_print_error("Build InnoDB index translation table for" @@ -8058,10 +8167,9 @@ build_template_needs_field( dict_index_t* index, /*!< in: InnoDB index to use */ const TABLE* table, /*!< in: MySQL table object */ ulint i, /*!< in: field index in InnoDB table */ - ulint sql_idx, /*!< in: field index in SQL table */ ulint num_v) /*!< in: num virtual column so far */ { - const Field* field = table->field[sql_idx]; + const Field* field = table->field[i]; if (!index_contains) { if (read_just_key) { @@ -8076,8 +8184,8 @@ build_template_needs_field( return(field); } - if (bitmap_is_set(table->read_set, static_cast<uint>(sql_idx)) - || bitmap_is_set(table->write_set, static_cast<uint>(sql_idx))) { + if (bitmap_is_set(table->read_set, static_cast<uint>(i)) + || bitmap_is_set(table->write_set, static_cast<uint>(i))) { /* This field is needed in the query */ return(field); @@ -8259,10 +8367,10 @@ ha_innobase::build_template( { dict_index_t* index; dict_index_t* clust_index; - ulint n_stored_fields; + ulint n_fields; ibool fetch_all_in_key = FALSE; ibool fetch_primary_key_cols = FALSE; - ulint i, sql_idx; + ulint i; if (m_prebuilt->select_lock_type == LOCK_X) { /* We always retrieve the whole clustered index record if we @@ -8315,12 +8423,11 @@ ha_innobase::build_template( /* Below we check column by column if we need to access the clustered index. */ - /* number of stored columns */ - n_stored_fields= (ulint)table->s->stored_fields; + n_fields = (ulint) table->s->fields; /* number of columns */ if (!m_prebuilt->mysql_template) { m_prebuilt->mysql_template = (mysql_row_templ_t*) - ut_malloc_nokey(n_stored_fields * sizeof(mysql_row_templ_t)); + ut_malloc_nokey(n_fields * sizeof(mysql_row_templ_t)); } m_prebuilt->template_type = whole_row @@ -8342,14 +8449,10 @@ ha_innobase::build_template( ulint num_v = 0; /* Push down an index condition or an end_range check. */ - for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) { + for (i = 0; i < n_fields; i++) { ibool index_contains; - while (!table->field[sql_idx]->stored_in_db()) { - sql_idx++; - } - - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { index_contains = dict_index_contains_col_or_prefix( index, num_v, true); } else { @@ -8372,8 +8475,7 @@ ha_innobase::build_template( the subset field->part_of_key.is_set(active_index) which would be acceptable if end_range==NULL. */ - bool is_v = innobase_is_v_fld(table->field[sql_idx]); - + bool is_v = innobase_is_v_fld(table->field[i]); if (build_template_needs_field_in_icp( index, m_prebuilt, index_contains, is_v ? num_v : i - num_v, is_v)) { @@ -8382,17 +8484,17 @@ ha_innobase::build_template( mysql_row_templ_t* templ; if (whole_row) { - field = table->field[sql_idx]; + field = table->field[i]; } else { field = build_template_needs_field( index_contains, m_prebuilt->read_just_key, fetch_all_in_key, fetch_primary_key_cols, - index, table, i, sql_idx, num_v); + index, table, i, num_v); if (!field) { if (innobase_is_v_fld( - table->field[sql_idx])) { + table->field[i])) { num_v++; } continue; @@ -8474,7 +8576,7 @@ ha_innobase::build_template( < m_prebuilt->index->n_uniq); */ } - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { num_v++; } } @@ -8486,15 +8588,11 @@ ha_innobase::build_template( /* Include the fields that are not needed in index condition pushdown. */ - for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) { + for (i = 0; i < n_fields; i++) { mysql_row_templ_t* templ; ibool index_contains; - while (!table->field[sql_idx]->stored_in_db()) { - sql_idx++; - } - - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { index_contains = dict_index_contains_col_or_prefix( index, num_v, true); } else { @@ -8502,7 +8600,7 @@ ha_innobase::build_template( index, i - num_v, false); } - bool is_v = innobase_is_v_fld(table->field[sql_idx]); + bool is_v = innobase_is_v_fld(table->field[i]); if (!build_template_needs_field_in_icp( index, m_prebuilt, index_contains, @@ -8511,16 +8609,16 @@ ha_innobase::build_template( const Field* field; if (whole_row) { - field = table->field[sql_idx]; + field = table->field[i]; } else { field = build_template_needs_field( index_contains, m_prebuilt->read_just_key, fetch_all_in_key, fetch_primary_key_cols, - index, table, i, sql_idx, num_v); + index, table, i, num_v); if (!field) { - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { num_v++; } continue; @@ -8544,13 +8642,9 @@ ha_innobase::build_template( /* No index condition pushdown */ m_prebuilt->idx_cond = NULL; - for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) { + for (i = 0; i < n_fields; i++) { const Field* field; - while (!table->field[sql_idx]->stored_in_db()) { - sql_idx++; - } - if (whole_row) { /* Even this is whole_row, if the seach is on a virtual column, and read_just_key is @@ -8558,7 +8652,7 @@ ha_innobase::build_template( will not try to fill the value since they are not stored in such index nor in the cluster index. */ - if (innobase_is_v_fld(table->field[sql_idx]) + if (innobase_is_v_fld(table->field[i]) && m_prebuilt->read_just_key && !dict_index_contains_col_or_prefix( m_prebuilt->index, num_v, true)) @@ -8570,11 +8664,11 @@ ha_innobase::build_template( continue; } - field = table->field[sql_idx]; + field = table->field[i]; } else { ibool contain; - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { contain = dict_index_contains_col_or_prefix( index, num_v, true); } else { @@ -8583,16 +8677,14 @@ ha_innobase::build_template( false); } - field = build_template_needs_field( contain, m_prebuilt->read_just_key, fetch_all_in_key, fetch_primary_key_cols, - index, table, i, sql_idx, num_v); - + index, table, i, num_v); if (!field) { - if (innobase_is_v_fld(table->field[sql_idx])) { + if (innobase_is_v_fld(table->field[i])) { num_v++; } continue; @@ -9177,7 +9269,7 @@ calc_row_difference( ulint n_changed = 0; dfield_t dfield; dict_index_t* clust_index; - uint sql_idx,i, innodb_idx= 0; + uint i; ibool changes_fts_column = FALSE; ibool changes_fts_doc_col = FALSE; trx_t* trx = thd_to_trx(thd); @@ -9192,19 +9284,15 @@ calc_row_difference( /* We use upd_buff to convert changed fields */ buf = (byte*) upd_buff; - for (sql_idx = 0,i=0; i < n_fields; i++, sql_idx++) { - field = table->field[sql_idx]; + for (i = 0; i < n_fields; i++) { + field = table->field[i]; bool is_virtual = innobase_is_v_fld(field); dict_col_t* col; - if (!field->stored_in_db()) { - continue; - } - if (is_virtual) { col = &prebuilt->table->v_cols[num_v].m_col; } else { - col = &prebuilt->table->cols[innodb_idx - num_v]; + col = &prebuilt->table->cols[i - num_v]; } o_ptr = (const byte*) old_row + get_field_offset(table, field); @@ -9419,7 +9507,7 @@ calc_row_difference( num_v++; } else { ufield->field_no = dict_col_get_clust_pos( - &prebuilt->table->cols[innodb_idx - num_v], + &prebuilt->table->cols[i - num_v], clust_index); ufield->old_v_val = NULL; } @@ -9465,10 +9553,6 @@ calc_row_difference( ut_ad(col->ord_part || online_ord_part); num_v++; } - - if (field->stored_in_db()) { - innodb_idx++; - } } /* If the update changes a column with an FTS index on it, we @@ -9669,12 +9753,11 @@ ha_innobase::update_row( ut_ad(m_upd_buf_size == 0); /* Create a buffer for packing the fields of a record. Why - table->stored_rec_length did not work here? Obviously, - because char fields when packed actually became 1 byte - longer, when we also stored the string length as the first - byte. */ + table->reclength did not work here? Obviously, because char + fields when packed actually became 1 byte longer, when we also + stored the string length as the first byte. */ - m_upd_buf_size = table->s->stored_rec_length + table->s->max_key_length + m_upd_buf_size = table->s->reclength + table->s->max_key_length + MAX_REF_PARTS * 3; m_upd_buf = reinterpret_cast<uchar*>( @@ -11704,7 +11787,43 @@ create_table_check_doc_id_col( return(false); } -#ifdef MYSQL_VIRTUAL_COLUMNS + +/** Finds all base columns needed to compute a given generated column. +This is returned as a bitmap, in field->table->tmp_set. +Works for both dict_v_col_t and dict_s_col_t columns. +@param[in] table InnoDB table +@param[in] field MySQL field +@param[in,out] col virtual or stored column */ +template <typename T> +void +prepare_vcol_for_base_setup( +/*========================*/ + const dict_table_t* table, + const Field* field, + T* col) +{ + ut_ad(col->num_base == 0); + ut_ad(col->base_col == NULL); + + MY_BITMAP *old_read_set = field->table->read_set; + MY_BITMAP *old_vcol_set = field->table->vcol_set; + + field->table->read_set = field->table->vcol_set = &field->table->tmp_set; + + bitmap_clear_all(&field->table->tmp_set); + field->vcol_info->expr_item->walk( + &Item::register_field_in_read_map, 1, field->table); + col->num_base= bitmap_bits_set(&field->table->tmp_set); + if (col->num_base != 0) { + col->base_col = static_cast<dict_col_t**>(mem_heap_zalloc( + table->heap, col->num_base * sizeof( + * col->base_col))); + } + field->table->read_set= old_read_set; + field->table->vcol_set= old_vcol_set; +} + + /** Set up base columns for virtual column @param[in] table InnoDB table @param[in] field MySQL field @@ -11717,10 +11836,12 @@ innodb_base_col_setup( { int n = 0; + prepare_vcol_for_base_setup(table, field, v_col); + for (uint i= 0; i < field->table->s->fields; ++i) { const Field* base_field = field->table->field[i]; - if (!base_field->is_virtual_gcol() - && bitmap_is_set(&field->gcol_info->base_columns_map, i)) { + if (base_field->stored_in_db() + && bitmap_is_set(&field->table->tmp_set, i)) { ulint z; for (z = 0; z < table->n_cols; z++) { @@ -11738,10 +11859,9 @@ innodb_base_col_setup( n++; } } + v_col->num_base= n; } -#endif /* MYSQL_VIRTUAL_COLUMNS */ -#ifdef MYSQL_VIRTUAL_COLUMNS /** Set up base columns for stored column @param[in] table InnoDB table @param[in] field MySQL field @@ -11754,12 +11874,14 @@ innodb_base_col_setup_for_stored( { ulint n = 0; + prepare_vcol_for_base_setup(table, field, s_col); + for (uint i= 0; i < field->table->s->fields; ++i) { const Field* base_field = field->table->field[i]; if (!innobase_is_s_fld(base_field) && !innobase_is_v_fld(base_field) - && bitmap_is_set(&field->gcol_info->base_columns_map, + && bitmap_is_set(&field->table->tmp_set, i)) { ulint z; for (z = 0; z < table->n_cols; z++) { @@ -11781,8 +11903,8 @@ innodb_base_col_setup_for_stored( } } } + s_col->num_base= n; } -#endif /** Create a table definition to an InnoDB database. @return ER_* level error */ @@ -11792,7 +11914,6 @@ create_table_info_t::create_table_def() { dict_table_t* table; ulint n_cols; - ulint s_cols; ulint col_type; ulint col_len; ulint nulls_allowed; @@ -11801,6 +11922,7 @@ create_table_info_t::create_table_def() ulint long_true_varchar; ulint charset_no; ulint i; + ulint j = 0; ulint doc_id_col = 0; ibool has_doc_id_col = FALSE; mem_heap_t* heap; @@ -11837,9 +11959,7 @@ create_table_info_t::create_table_def() } n_cols = m_form->s->fields; - s_cols = m_form->s->stored_fields; -#ifdef MYSQL_VIRTUAL_COLUMNS /* Find out any virtual column */ for (i = 0; i < n_cols; i++) { Field* field = m_form->field[i]; @@ -11848,7 +11968,6 @@ create_table_info_t::create_table_def() num_v++; } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED)); @@ -11874,8 +11993,7 @@ create_table_info_t::create_table_def() } /* Adjust the number of columns for the FTS hidden field */ - actual_n_cols = m_form->s->stored_fields; - + actual_n_cols = n_cols; if (m_flags2 & DICT_TF2_FTS && !has_doc_id_col) { actual_n_cols += 1; } @@ -11886,7 +12004,7 @@ create_table_info_t::create_table_def() /* Set the hidden doc_id column. */ if (m_flags2 & DICT_TF2_FTS) { table->fts->doc_col = has_doc_id_col - ? doc_id_col : s_cols; + ? doc_id_col : n_cols - num_v; } if (strlen(m_temp_path) != 0) { @@ -11915,12 +12033,9 @@ create_table_info_t::create_table_def() for (i = 0; i < n_cols; i++) { ulint is_virtual; - bool is_stored MY_ATTRIBUTE((unused)); - Field* field = m_form->field[i]; + bool is_stored = false; - if (!field->stored_in_db()) { - continue; - } + Field* field = m_form->field[i]; col_type = get_innobase_type_from_mysql_type( &unsigned_type, field); @@ -12019,7 +12134,6 @@ err_col: charset_no), col_len); } else { -#ifdef MYSQL_VIRTUAL_COLUMNS dict_mem_table_add_v_col(table, heap, field->field_name, col_type, dtype_form_prtype( @@ -12028,26 +12142,18 @@ err_col: | binary_type | long_true_varchar | is_virtual, charset_no), - col_len, i, - 0); - - field->gcol_info->non_virtual_base_columns()); -#endif - } + col_len, i, 0); + } -#ifdef MYSQL_VIRTUAL_COLUMNS if (is_stored) { ut_ad(!is_virtual); /* Added stored column in m_s_cols list. */ dict_mem_table_add_s_col( - table, - field->gcol_info->non_virtual_base_columns()); + table, 0); } -#endif } -#ifdef MYSQL_VIRTUAL_COLUMNS + if (num_v) { - ulint j = 0; for (i = 0; i < n_cols; i++) { dict_v_col_t* v_col; @@ -12088,7 +12194,6 @@ err_col: } } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /* Add the FTS doc_id hidden column. */ if (m_flags2 & DICT_TF2_FTS && !has_doc_id_col) { @@ -12121,7 +12226,6 @@ err_col: my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0)); err = DB_UNSUPPORTED; dict_mem_table_free(table); - */ } else { #endif /* MYSQL_COMPRESSION */ /* Get a new table ID */ @@ -13833,6 +13937,30 @@ create_table_info_t::initialize() } +/** Check if a virtual column is part of a fulltext or spatial index. */ +bool +create_table_info_t::gcols_in_fulltext_or_spatial() +{ + for (ulint i = 0; i < m_form->s->keys; i++) { + const KEY* key = m_form->key_info + i; + if (key->flags & (HA_SPATIAL | HA_FULLTEXT)) { + for (ulint j = 0; j < key->user_defined_key_parts; j++) { + const KEY_PART_INFO* key_part = key->key_part + j; + + /* We do not support special (Fulltext or + Spatial) index on virtual columns */ + if (innobase_is_v_fld(key_part->field)) { + my_error(ER_UNSUPPORTED_ACTION_ON_VIRTUAL_COLUMN, MYF(0)); + return true; + } + } + } + + } + return false; +} + + /** Prepare to create a new table to an InnoDB database. @param[in] name Table name @return error number */ @@ -13874,6 +14002,10 @@ create_table_info_t::prepare_create_table( DBUG_RETURN(HA_ERR_TABLE_READONLY); } + if (gcols_in_fulltext_or_spatial()) { + DBUG_RETURN(HA_ERR_UNSUPPORTED); + } + DBUG_RETURN(parse_table_name(name)); } @@ -14040,19 +14172,15 @@ create_table_info_t::create_table() " table where referencing columns appear" " as the first columns.\n", m_table_name); break; -#ifdef MYSQL_VIRTUAL_COLUMNS - case DB_NO_FK_ON_V_BASE_COL: + case DB_NO_FK_ON_S_BASE_COL: push_warning_printf( m_thd, Sql_condition::WARN_LEVEL_WARN, HA_ERR_CANNOT_ADD_FOREIGN, "Create table '%s' with foreign key constraint" " failed. Cannot add foreign key constraint" - " placed on the base column of indexed" - " virtual column, or constraint placed" - " on columns being part of virtual index.\n", + " placed on the base column of stored" + " column. \n", m_table_name); - break; -#endif default: break; } @@ -14647,8 +14775,7 @@ validate_create_tablespace_info( THD* thd, st_alter_tablespace* alter_info) { - - int error = 0; + ulint space_id; /* The parser ensures that these fields are provided. */ ut_a(alter_info->tablespace_name); @@ -15427,6 +15554,7 @@ ha_innobase::records( DBUG_RETURN(HA_ERR_QUERY_INTERRUPTED); } + *num_rows= n_rows; DBUG_RETURN(0); } #endif /* MYSQL_57_SELECT_COUNT_OPTIMIZATION */ @@ -23203,6 +23331,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= { #endif MYSQL_SYSVAR(instrument_semaphores), MYSQL_SYSVAR(buf_dump_status_frequency), + MYSQL_SYSVAR(background_thread), NULL }; @@ -23377,29 +23506,29 @@ innobase_index_cond( return handler_index_cond_check(file); } -#ifdef MYSQL_VIRTUAL_COLUMNS -/** Get the computed value by supplying the base column values. -@param[in,out] table the table whose virtual column template to be built */ -void -innobase_init_vc_templ( + +/** Find or open a mysql table for the virtual column template +@param[in] thd mysql thread handle +@param[in,out] table InnoDB table whose virtual column template is to be updated +@return TABLE if successful or NULL */ +static TABLE * +innobase_find_mysql_table_for_vc( +/*=============================*/ + THD* thd, dict_table_t* table) { - char dbname[MAX_DATABASE_NAME_LEN + 1]; - char tbname[MAX_TABLE_NAME_LEN + 1]; - char* name = table->name.m_name; - ulint dbnamelen = dict_get_db_name_len(name); - ulint tbnamelen = strlen(name) - dbnamelen - 1; - char t_dbname[MAX_DATABASE_NAME_LEN + 1]; - char t_tbname[MAX_TABLE_NAME_LEN + 1]; - - mutex_enter(&dict_sys->mutex); - - if (table->vc_templ != NULL) { - mutex_exit(&dict_sys->mutex); - - return; + if (table->vc_templ->mysql_table_query_id == thd_get_query_id(thd)) { + return table->vc_templ->mysql_table; } + char dbname[MAX_DATABASE_NAME_LEN + 1]; + char tbname[MAX_TABLE_NAME_LEN + 1]; + char* name = table->name.m_name; + uint dbnamelen = dict_get_db_name_len(name); + uint tbnamelen = strlen(name) - dbnamelen - 1; + char t_dbname[MAX_DATABASE_NAME_LEN + 1]; + char t_tbname[MAX_TABLE_NAME_LEN + 1]; + strncpy(dbname, name, dbnamelen); dbname[dbnamelen] = 0; strncpy(tbname, name + dbnamelen + 1, tbnamelen); @@ -23407,32 +23536,53 @@ innobase_init_vc_templ( /* For partition table, remove the partition name and use the "main" table name to build the template */ - char* is_part = is_partition(tbname); + char* is_part = is_partition(tbname); if (is_part != NULL) { *is_part = '\0'; tbnamelen = is_part - tbname; } - table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t()); - table->vc_templ->vtempl = NULL; - dbnamelen = filename_to_tablename(dbname, t_dbname, MAX_DATABASE_NAME_LEN + 1); tbnamelen = filename_to_tablename(tbname, t_tbname, MAX_TABLE_NAME_LEN + 1); -#ifdef UNIV_DEBUG - // bool ret = -#endif /* UNIV_DEBUG */ + TABLE *mysql_table = find_fk_open_table(thd, t_dbname, dbnamelen, + t_tbname, tbnamelen); - /* JAN: TODO: MySQL: 5.7 virtual columsn - handler::my_prepare_gcolumn_template( - thd, t_dbname, t_tbname, - &innobase_build_v_templ_callback, - static_cast<void*>(table)); - ut_ad(!ret); - */ + if (!mysql_table && THDVAR(thd, background_thread)) { + /* only open the table in background purge threads */ + mysql_table = open_purge_table(thd, t_dbname, dbnamelen, + t_tbname, tbnamelen); + } + + table->vc_templ->mysql_table = mysql_table; + table->vc_templ->mysql_table_query_id = thd_get_query_id(thd); + return mysql_table; +} + +/** Get the computed value by supplying the base column values. +@param[in,out] table table whose virtual column template to be built */ +void +innobase_init_vc_templ( + dict_table_t* table) +{ + if (table->vc_templ != NULL) { + return; + } + + table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t()); + + TABLE *mysql_table= innobase_find_mysql_table_for_vc(current_thd, table); + + ut_ad(mysql_table); + if (!mysql_table) { + return; + } + + mutex_enter(&dict_sys->mutex); + innobase_build_v_templ(mysql_table, table, table->vc_templ, NULL, true); mutex_exit(&dict_sys->mutex); } @@ -23542,7 +23692,6 @@ innobase_get_computed_value( upd_t* parent_update, dict_foreign_t* foreign) { - byte rec_buf1[REC_VERSION_56_MAX_INDEX_COL_LEN]; byte rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN]; byte* mysql_rec; byte* buf; @@ -23568,15 +23717,20 @@ innobase_get_computed_value( *local_heap = mem_heap_create(UNIV_PAGE_SIZE); } - mysql_rec = static_cast<byte*>(mem_heap_alloc( - *local_heap, index->table->vc_templ->rec_len)); buf = static_cast<byte*>(mem_heap_alloc( *local_heap, index->table->vc_templ->rec_len)); } else { - mysql_rec = rec_buf1; buf = rec_buf2; } + if (!mysql_table) { + mysql_table = innobase_find_mysql_table_for_vc(thd, index->table); + } + + ut_ad(mysql_table); + + mysql_rec = mysql_table->record[0]; + for (ulint i = 0; i < col->num_base; i++) { dict_col_t* base_col = col->base_col[i]; const dfield_t* row_field = NULL; @@ -23635,46 +23789,11 @@ innobase_get_computed_value( field = dtuple_get_nth_v_field(row, col->v_pos); - /* Bitmap for specifying which virtual columns the server - should evaluate */ - MY_BITMAP column_map; - my_bitmap_map col_map_storage[bitmap_buffer_size(REC_MAX_N_FIELDS)]; - - bitmap_init(&column_map, col_map_storage, REC_MAX_N_FIELDS, false); - - /* Specify the column the server should evaluate */ - bitmap_set_bit(&column_map, col->m_col.ind); - - if (mysql_table == NULL) { - if (vctempl->type == DATA_BLOB) { - ulint max_len; - - if (vctempl->mysql_col_len - 8 == 1) { - /* This is for TINYBLOB only, which needs - only 1 byte, other BLOBs won't be affected */ - max_len = 255; - } else { - max_len = DICT_MAX_FIELD_LEN_BY_FORMAT( - index->table) + 1; - } - - byte* blob_mem = static_cast<byte*>( - mem_heap_alloc(heap, max_len)); - - row_mysql_store_blob_ref( - mysql_rec + vctempl->mysql_col_offset, - vctempl->mysql_col_len, blob_mem, max_len); - } - - ret = handler::my_eval_gcolumn_expr_with_open( - thd, index->table->vc_templ->db_name.c_str(), - index->table->vc_templ->tb_name.c_str(), &column_map, - (uchar *)mysql_rec); - } else { - ret = handler::my_eval_gcolumn_expr( - thd, mysql_table, &column_map, - (uchar *)mysql_rec); - } + my_bitmap_map* old_write_set = dbug_tmp_use_all_columns(mysql_table, mysql_table->write_set); + my_bitmap_map* old_read_set = dbug_tmp_use_all_columns(mysql_table, mysql_table->read_set); + ret = mysql_table->update_virtual_field(mysql_table->field[col->m_col.ind]); + dbug_tmp_restore_column_map(mysql_table->read_set, old_read_set); + dbug_tmp_restore_column_map(mysql_table->write_set, old_write_set); if (ret != 0) { #ifdef INNODB_VIRTUAL_DEBUG @@ -23725,7 +23844,7 @@ innobase_get_computed_value( return(field); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ + /** Attempt to push down an index condition. @param[in] keyno MySQL key number diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index a78925d94e1..99d50d82fd1 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -119,6 +119,8 @@ public: const key_map* keys_to_use_for_scanning(); + void column_bitmaps_signal(); + /** Opens dictionary table object using table name. For partition, we need to try alternative lower/upper case names to support moving data files across platforms. @@ -781,6 +783,8 @@ public: @return NULL if valid, string name of bad option if not. */ const char* create_options_are_invalid(); + bool gcols_in_fulltext_or_spatial(); + /** Validates engine specific table options not handled by SQL-parser. @return NULL if valid, string name of bad option if not. */ @@ -1037,13 +1041,9 @@ innodb_base_col_setup_for_stored( dict_s_col_t* s_col); /** whether this is a stored column */ -// JAN: TODO: MySQL 5.7 virtual fields -//#define innobase_is_s_fld(field) ((field)->gcol_info && (field)->stored_in_db) -#define innobase_is_s_fld(field) (field == NULL) -// JAN: TODO: MySQL 5.7 virtual fields +#define innobase_is_s_fld(field) ((field)->vcol_info && (field)->stored_in_db()) /** whether this is a computed virtual column */ -//#define innobase_is_v_fld(field) ((field)->gcol_info && !(field)->stored_in_db) -#define innobase_is_v_fld(field) (field == NULL) +#define innobase_is_v_fld(field) ((field)->vcol_info && !(field)->stored_in_db()) /** Release temporary latches. Call this function when mysqld passes control to the client. That is to @@ -1120,16 +1120,14 @@ innodb_rec_per_key( @param[in,out] s_templ InnoDB template structure @param[in] add_v new virtual columns added along with add index call -@param[in] locked true if innobase_share_mutex is held -@param[in] share_tbl_name original MySQL table name */ +@param[in] locked true if innobase_share_mutex is held */ void innobase_build_v_templ( const TABLE* table, const dict_table_t* ib_table, dict_vcol_templ_t* s_templ, const dict_add_v_col_t* add_v, - bool locked, - const char* share_tbl_name); + bool locked); /** callback used by MySQL server layer to initialized the table virtual columns' template diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 3da543d246e..51aef715ee2 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -59,6 +59,10 @@ Smart ALTER TABLE #include <sql_acl.h> // PROCESS_ACL #endif +static const char *MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN= + "INPLACE ADD or DROP of virtual columns cannot be " + "combined with other ALTER TABLE actions"; + /* For supporting Native InnoDB Partitioning. */ /* JAN: TODO: MySQL 5.7 #include "partition_info.h" @@ -67,7 +71,8 @@ Smart ALTER TABLE /** Operations for creating secondary indexes (no rebuild needed) */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ONLINE_CREATE = Alter_inplace_info::ADD_INDEX - | Alter_inplace_info::ADD_UNIQUE_INDEX; + | Alter_inplace_info::ADD_UNIQUE_INDEX + | Alter_inplace_info::ADD_SPATIAL_INDEX; /** Operations for rebuilding a table in place */ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD @@ -77,17 +82,12 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD /* CHANGE_CREATE_OPTION needs to check innobase_need_rebuild() */ | Alter_inplace_info::ALTER_COLUMN_NULLABLE | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE - | Alter_inplace_info::ALTER_COLUMN_ORDER - | Alter_inplace_info::DROP_COLUMN - | Alter_inplace_info::ADD_COLUMN -#ifdef MYSQL_VIRTUAL_COLUMNS | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | Alter_inplace_info::DROP_STORED_COLUMN | Alter_inplace_info::ADD_STORED_BASE_COLUMN - | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE -#endif | Alter_inplace_info::RECREATE_TABLE /* + | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE */ ; @@ -101,9 +101,7 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INPLACE_IGNORE | Alter_inplace_info::ALTER_PARTITIONED | Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT | Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE -#ifdef MYSQL_VIRTUAL_COLUMNS | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR -#endif | Alter_inplace_info::ALTER_RENAME; /** Operations on foreign key definitions (changing the schema only) */ @@ -121,15 +119,12 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_NOREBUILD | Alter_inplace_info::RENAME_INDEX #endif | Alter_inplace_info::ALTER_COLUMN_NAME - | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH; -#ifdef MYSQL_VIRTUAL_COLUMNS - | Alter_inplace_info::ALTER_INDEX_COMMENT + | Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH + //| Alter_inplace_info::ALTER_INDEX_COMMENT | Alter_inplace_info::ADD_VIRTUAL_COLUMN | Alter_inplace_info::DROP_VIRTUAL_COLUMN - | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER - | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE -#endif - ; + | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER; + struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx { /** Dummy query graph */ @@ -453,7 +448,6 @@ innobase_need_rebuild( return(!!(ha_alter_info->handler_flags & INNOBASE_ALTER_REBUILD)); } -#ifdef MYSQL_VIRTUAL_COLUMNS /** Check if virtual column in old and new table are in order, excluding those dropped column. This is needed because when we drop a virtual column, ALTER_VIRTUAL_COLUMN_ORDER is also turned on, so we can't decide if this @@ -484,7 +478,7 @@ check_v_col_in_order( cf_it.rewind(); while (const Create_field* new_field = cf_it++) { - if (!new_field->is_virtual_gcol()) { + if (!innobase_is_v_fld(new_field)) { continue; } @@ -510,11 +504,9 @@ check_v_col_in_order( } for (ulint i = 0; i < table->s->fields; i++) { - Field* field = table->s->field[i]; - bool dropped = false; - Alter_drop* drop; + Field* field = table->field[i]; - if (field->stored_in_db) { + if (field->stored_in_db()) { continue; } @@ -529,7 +521,7 @@ check_v_col_in_order( while (j < altered_table->s->fields) { Field* new_field = altered_table->s->field[j]; - if (new_field->stored_in_db) { + if (new_field->stored_in_db()) { j++; continue; } @@ -555,7 +547,6 @@ check_v_col_in_order( return(true); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /** Check if InnoDB supports a particular alter table in-place @param altered_table TABLE object for new version of table. @@ -590,7 +581,7 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } - if (altered_table->s->stored_fields > REC_MAX_N_USER_FIELDS) { + if (altered_table->s->fields > REC_MAX_N_USER_FIELDS) { /* Deny the inplace ALTER TABLE. MySQL will try to re-create the table and ha_innobase::create() will return an error too. This is how we effectively @@ -646,14 +637,11 @@ ha_innobase::check_if_supported_inplace_alter( | INNOBASE_ALTER_NOREBUILD | INNOBASE_ALTER_REBUILD)) { -#ifdef MYSQL_VIRTUAL_COLUMNS if (ha_alter_info->handler_flags & Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) { ha_alter_info->unsupported_reason = innobase_get_err_msg( ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE); } -#endif - DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } @@ -794,8 +782,8 @@ ha_innobase::check_if_supported_inplace_alter( DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } -#ifdef MYSQL_VIRTUAL_COLUMNS - // JAN: TODO: MySQL 5.7 Virtual columns + bool add_drop_v_cols = false; + /* If there is add or drop virtual columns, we will support operations with these 2 options alone with inplace interface for now */ @@ -812,8 +800,8 @@ ha_innobase::check_if_supported_inplace_alter( | Alter_inplace_info::DROP_VIRTUAL_COLUMN | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR + | Alter_inplace_info::ALTER_COLUMN_VCOL /* - | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | Alter_inplace_info::ADD_STORED_BASE_COLUMN | Alter_inplace_info::DROP_STORED_COLUMN | Alter_inplace_info::ALTER_STORED_COLUMN_ORDER @@ -828,14 +816,12 @@ ha_innobase::check_if_supported_inplace_alter( || (!check_v_col_in_order( this->table, altered_table, ha_alter_info))) { ha_alter_info->unsupported_reason = - innobase_get_err_msg( - ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); + MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN; DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } add_drop_v_cols = true; } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /* We should be able to do the operation in-place. See if we can do it online (LOCK=NONE). */ @@ -850,18 +836,15 @@ ha_innobase::check_if_supported_inplace_alter( + ha_alter_info->key_count; new_key++) { -#ifdef MYSQL_VIRTUAL_COLUMNS /* Do not support adding/droping a virtual column, while there is a table rebuild caused by adding a new FTS_DOC_ID */ if ((new_key->flags & HA_FULLTEXT) && add_drop_v_cols && !DICT_TF2_FLAG_IS_SET(m_prebuilt->table, DICT_TF2_FTS_HAS_DOC_ID)) { ha_alter_info->unsupported_reason = - innobase_get_err_msg( - ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); + MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN; DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ for (KEY_PART_INFO* key_part = new_key->key_part; key_part < new_key->key_part + new_key->user_defined_key_parts; @@ -928,31 +911,27 @@ ha_innobase::check_if_supported_inplace_alter( online = false; } -#ifdef MYSQL_VIRTUAL_COLUMNS - if (key_part->field->is_virtual_gcol()) { + if (innobase_is_v_fld(key_part->field)) { /* Do not support adding index on newly added virtual column, while there is also a drop virtual column in the same clause */ if (ha_alter_info->handler_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN) { ha_alter_info->unsupported_reason = - innobase_get_err_msg( - ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN); + MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN; DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED); } ha_alter_info->unsupported_reason = - innobase_get_err_msg( - ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN); + MSG_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN; online = false; } -#endif /* MYSQL_VIRTUAL_COLUMNS */ } } DBUG_ASSERT(!m_prebuilt->table->fts || m_prebuilt->table->fts->doc_col - <= table->s->stored_fields); + <= table->s->fields); DBUG_ASSERT(!m_prebuilt->table->fts || m_prebuilt->table->fts->doc_col < dict_table_get_n_user_cols(m_prebuilt->table)); @@ -1356,8 +1335,6 @@ next_rec: return(NULL); } -#ifdef MYSQL_VIRTUAL_COLUMNS - /** Check whether given column is a base of stored column. @param[in] col_name column name @param[in] table table @@ -1419,7 +1396,6 @@ innobase_check_fk_stored( return(false); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /** Create InnoDB foreign key structure from MySQL alter_info @param[in] ha_alter_info alter table info @@ -1667,13 +1643,14 @@ innobase_get_foreign_key_info( goto err_exit; } -#ifdef MYSQL_VIRTUAL_COLUMNS if (innobase_check_fk_stored( add_fk[num_fk], table, s_cols)) { - my_error(ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED, MYF(0)); + my_printf_error( + HA_ERR_UNSUPPORTED, + "Cannot add foreign key on the base column " + "of stored column", MYF(0)); goto err_exit; } -#endif num_fk++; } @@ -1794,24 +1771,19 @@ innobase_rec_to_mysql( const ulint* offsets)/*!< in: rec_get_offsets( rec, index, ...) */ { - uint n_fields = table->s->stored_fields; - uint sql_idx = 0; + uint n_fields = table->s->fields; ut_ad(n_fields == dict_table_get_n_user_cols(index->table) - !!(DICT_TF2_FLAG_IS_SET(index->table, DICT_TF2_FTS_HAS_DOC_ID))); - for (uint i = 0; i < n_fields; i++, sql_idx++) { - Field* field; + for (uint i = 0; i < n_fields; i++) { + Field* field = table->field[i]; ulint ipos; ulint ilen; const uchar* ifield; ulint prefix_col; - while (!((field= table->field[sql_idx])->stored_in_db())) { - sql_idx++; - } - field->reset(); ipos = dict_index_get_nth_col_or_prefix_pos( @@ -1852,8 +1824,7 @@ innobase_fields_to_mysql( const dict_index_t* index, /*!< in: InnoDB index */ const dfield_t* fields) /*!< in: InnoDB index fields */ { - uint n_fields = table->s->stored_fields; - uint sql_idx = 0; + uint n_fields = table->s->fields; ulint num_v = 0; ut_ad(n_fields == dict_table_get_n_user_cols(index->table) @@ -1861,16 +1832,12 @@ innobase_fields_to_mysql( - !!(DICT_TF2_FLAG_IS_SET(index->table, DICT_TF2_FTS_HAS_DOC_ID))); - for (uint i = 0; i < n_fields; i++, sql_idx++) { - Field* field; + for (uint i = 0; i < n_fields; i++) { + Field* field = table->field[i]; ulint ipos; ulint col_n; ulint prefix_col; - while (!((field= table->field[sql_idx])->stored_in_db())) { - sql_idx++; - } - field->reset(); if (innobase_is_v_fld(field)) { @@ -1914,9 +1881,8 @@ innobase_row_to_mysql( const dict_table_t* itab, /*!< in: InnoDB table */ const dtuple_t* row) /*!< in: InnoDB row */ { - uint n_fields = table->s->stored_fields; - uint sql_idx = 0; - uint num_v = 0; + uint n_fields = table->s->fields; + ulint num_v = 0; /* The InnoDB row may contain an extra FTS_DOC_ID column at the end. */ ut_ad(row->n_fields == dict_table_get_n_cols(itab)); @@ -1924,12 +1890,8 @@ innobase_row_to_mysql( + dict_table_get_n_v_cols(itab) - !!(DICT_TF2_FLAG_IS_SET(itab, DICT_TF2_FTS_HAS_DOC_ID))); - for (uint i = 0; i < n_fields; i++, sql_idx++) { - Field* field; - - while (!((field= table->field[sql_idx])->stored_in_db())) { - sql_idx++; - } + for (uint i = 0; i < n_fields; i++) { + Field* field = table->field[i]; field->reset(); @@ -1953,6 +1915,11 @@ innobase_row_to_mysql( dfield_get_len(df), field); } } + if (table->vfield) { + my_bitmap_map* old_vcol_set = tmp_use_all_columns(table, table->vcol_set); + table->update_virtual_fields(VCOL_UPDATE_FOR_READ_WRITE); + tmp_restore_column_map(table->vcol_set, old_vcol_set); + } } /*************************************************************//** @@ -2129,22 +2096,19 @@ name_ok: is not being created @param[in] key_part MySQL key definition @param[in,out] index_field index field -@param[in] new_clustered new cluster -@param[in] fields MySQL table fields*/ +@param[in] new_clustered new cluster */ static void innobase_create_index_field_def( const TABLE* altered_table, const KEY_PART_INFO* key_part, index_field_t* index_field, - bool new_clustered, - const Field** fields) + bool new_clustered) { const Field* field; ibool is_unsigned; ulint col_type; ulint num_v = 0; - ulint num_m_v = 0; DBUG_ENTER("innobase_create_index_field_def"); @@ -2157,33 +2121,21 @@ innobase_create_index_field_def( ut_a(field); for (ulint i = 0; i < key_part->fieldnr; i++) { - const Field* ifield = altered_table->field[i]; - if (innobase_is_v_fld(ifield)) { + if (innobase_is_v_fld(altered_table->field[i])) { num_v++; } - - if (!ifield->stored_in_db()) { - num_m_v++; - } } col_type = get_innobase_type_from_mysql_type( &is_unsigned, field); -#ifdef MYSQL_VIRTUAL_COLUMNS - if (!field->stored_in_db && field->gcol_info) { - if (!field->stored_in_db && false) { - index_field->is_v_col = true; - index_field->col_no = num_v; - } else { - index_field->is_v_col = false; - index_field->col_no = key_part->fieldnr - num_v; - } + if (innobase_is_v_fld(field)) { + index_field->is_v_col = true; + index_field->col_no = num_v; + } else { + index_field->is_v_col = false; + index_field->col_no = key_part->fieldnr - num_v; } -#else - index_field->is_v_col = false; - index_field->col_no = key_part->fieldnr - num_m_v; -#endif /* MYSQL_VIRTUAL_COLUMNS */ if (DATA_LARGE_MTYPE(col_type) || (key_part->length < field->pack_length() @@ -2218,8 +2170,7 @@ innobase_create_index_def( bool new_clustered, bool key_clustered, index_def_t* index, - mem_heap_t* heap, - const Field** fields) + mem_heap_t* heap) { const KEY* key = &keys[key_number]; ulint i; @@ -2298,21 +2249,16 @@ innobase_create_index_def( index->fields[0].prefix_len = 0; index->fields[0].is_v_col = false; - #ifdef MYSQL_VIRTUAL_COLUMNS - if (!key->key_part[0].field->stored_in_db - && key->key_part[0].field->gcol_info) { + if (innobase_is_v_fld(key->key_part[0].field)) { /* Currently, the spatial index cannot be created on virtual columns. It is blocked in server layer */ - ut_ad(0); index->fields[0].is_v_col = true; } else { - index->fields[0].is_v_col = false; } -#endif /* MYSQL_VIRTUAL_COLUMNS */ } else { index->ind_type = (key->flags & HA_NOSAME) ? DICT_UNIQUE : 0; } @@ -2321,7 +2267,7 @@ innobase_create_index_def( for (i = 0; i < n_fields; i++) { innobase_create_index_field_def( altered_table, &key->key_part[i], - &index->fields[i], new_clustered, fields); + &index->fields[i], new_clustered); if (index->fields[i].is_v_col) { index->ind_type |= DICT_VIRTUAL; @@ -2352,18 +2298,13 @@ innobase_fts_check_doc_id_col( { *fts_doc_col_no = ULINT_UNDEFINED; - const uint n_cols = altered_table->s->stored_fields; - uint sql_idx = 0; + const uint n_cols = altered_table->s->fields; ulint i; *num_v = 0; - for (i = 0; i < n_cols; i++, sql_idx++) { - const Field* field; - - while (!((field= altered_table->field[sql_idx])->stored_in_db())) { - sql_idx++; - } + for (i = 0; i < n_cols; i++) { + const Field* field = altered_table->field[i]; if (innobase_is_v_fld(field)) { (*num_v)++; @@ -2676,7 +2617,7 @@ innobase_create_key_defs( /* Create the PRIMARY key index definition */ innobase_create_index_def( altered_table, key_info, primary_key_number, - TRUE, TRUE, indexdef++, heap, (const Field **)altered_table->field); + true, true, indexdef++, heap); created_clustered: n_add = 1; @@ -2688,7 +2629,7 @@ created_clustered: /* Copy the index definitions. */ innobase_create_index_def( altered_table, key_info, i, true, - false, indexdef, heap, (const Field **)altered_table->field); + false, indexdef, heap); if (indexdef->ind_type & DICT_FTS) { n_fts_add++; @@ -2705,8 +2646,7 @@ created_clustered: && !innobase_fts_check_doc_id_col( NULL, altered_table, &fts_doc_id_col, &num_v)) { - fts_doc_id_col = - altered_table->s->stored_fields; + fts_doc_id_col = altered_table->s->fields - num_v; add_fts_doc_id = true; } @@ -2735,7 +2675,7 @@ created_clustered: for (ulint i = 0; i < n_add; i++) { innobase_create_index_def( altered_table, key_info, add[i], - false, false, indexdef, heap, (const Field **)altered_table->field); + false, false, indexdef, heap); if (indexdef->ind_type & DICT_FTS) { n_fts_add++; @@ -3136,16 +3076,15 @@ innobase_build_col_map( dtuple_t* add_cols, mem_heap_t* heap) { - uint old_i, old_innobase_i; DBUG_ENTER("innobase_build_col_map"); DBUG_ASSERT(altered_table != table); DBUG_ASSERT(new_table != old_table); DBUG_ASSERT(dict_table_get_n_cols(new_table) + dict_table_get_n_v_cols(new_table) - >= altered_table->s->stored_fields + DATA_N_SYS_COLS); + >= altered_table->s->fields + DATA_N_SYS_COLS); DBUG_ASSERT(dict_table_get_n_cols(old_table) + dict_table_get_n_v_cols(old_table) - >= table->s->stored_fields + DATA_N_SYS_COLS); + >= table->s->fields + DATA_N_SYS_COLS); DBUG_ASSERT(!!add_cols == !!(ha_alter_info->handler_flags & Alter_inplace_info::ADD_COLUMN)); DBUG_ASSERT(!add_cols || dtuple_get_n_fields(add_cols) @@ -3158,14 +3097,13 @@ innobase_build_col_map( List_iterator_fast<Create_field> cf_it( ha_alter_info->alter_info->create_list); - uint i = 0, sql_idx = 0; + uint i = 0; uint num_v = 0; /* Any dropped columns will map to ULINT_UNDEFINED. */ - for (old_innobase_i = 0; - old_innobase_i + DATA_N_SYS_COLS < old_table->n_cols; - old_innobase_i++) { - col_map[old_innobase_i] = ULINT_UNDEFINED; + for (uint old_i = 0; old_i + DATA_N_SYS_COLS < old_table->n_cols; + old_i++) { + col_map[old_i] = ULINT_UNDEFINED; } for (uint old_i = 0; old_i < old_table->n_v_cols; old_i++) { @@ -3181,21 +3119,8 @@ innobase_build_col_map( ulint num_old_v = 0; - if (!new_field->stored_in_db()) - { - sql_idx++; - continue; - } - - for (old_i = 0, old_innobase_i= 0; - table->field[old_i]; - old_i++) { + for (uint old_i = 0; table->field[old_i]; old_i++) { const Field* field = table->field[old_i]; - - if (!table->field[old_i]->stored_in_db()) { - continue; - } - if (innobase_is_v_fld(field)) { if (is_v && new_field->field == field) { col_map[old_table->n_cols + num_v] @@ -3208,30 +3133,27 @@ innobase_build_col_map( } if (new_field->field == field) { - col_map[old_innobase_i] = i; + col_map[old_i - num_old_v] = i; goto found_col; } - old_innobase_i++; } ut_ad(!is_v); innobase_build_col_map_add( heap, dtuple_get_nth_field(add_cols, i), - altered_table->field[sql_idx], + altered_table->field[i + num_v], dict_table_is_comp(new_table)); found_col: if (is_v) { num_v++; } else { i++; - sql_idx++; } } - DBUG_ASSERT(i == altered_table->s->stored_fields - num_v); + DBUG_ASSERT(i == altered_table->s->fields - num_v); - i = table->s->stored_fields; - //i = table->s->fields - old_table->n_v_cols; + i = table->s->fields - old_table->n_v_cols; /* Add the InnoDB hidden FTS_DOC_ID column, if any. */ if (i + DATA_N_SYS_COLS < old_table->n_cols) { @@ -3241,21 +3163,21 @@ found_col: DICT_TF2_FTS_HAS_DOC_ID)); DBUG_ASSERT(i + DATA_N_SYS_COLS + 1 == old_table->n_cols); DBUG_ASSERT(!strcmp(dict_table_get_col_name( - old_table, table->s->stored_fields), + old_table, i), FTS_DOC_ID_COL_NAME)); - if (altered_table->s->stored_fields + DATA_N_SYS_COLS + if (altered_table->s->fields + DATA_N_SYS_COLS - new_table->n_v_cols < new_table->n_cols) { DBUG_ASSERT(DICT_TF2_FLAG_IS_SET( new_table, DICT_TF2_FTS_HAS_DOC_ID)); - DBUG_ASSERT(altered_table->s->stored_fields + DBUG_ASSERT(altered_table->s->fields + DATA_N_SYS_COLS + 1 - == new_table->n_cols); - col_map[i] = altered_table->s->stored_fields; - /* col_map[i] = altered_table->s->fields + == static_cast<ulint>( + new_table->n_cols + + new_table->n_v_cols)); + col_map[i] = altered_table->s->fields - new_table->n_v_cols; - */ } else { DBUG_ASSERT(!DICT_TF2_FLAG_IS_SET( new_table, @@ -3671,8 +3593,6 @@ innobase_check_gis_columns( DBUG_RETURN(DB_SUCCESS); } -#ifdef MYSQL_VIRTUAL_COLUMNS - /** Collect virtual column info for its addition @param[in] ha_alter_info Data used during in-place alter @param[in] altered_table MySQL table that is being altered to @@ -3738,10 +3658,8 @@ prepare_inplace_add_virtual( &is_unsigned, field); - if (!field->gcol_info || field->stored_in_db) { - my_error(ER_WRONG_KEY_COLUMN, MYF(0), - field->field_name); - return(true); + if (!innobase_is_v_fld(field)) { + continue; } col_len = field->pack_length(); @@ -3798,13 +3716,9 @@ prepare_inplace_add_virtual( ctx->add_vcol[j].m_col.len = col_len; ctx->add_vcol[j].m_col.ind = i - 1; - /* ctx->add_vcol[j].num_base = - field->gcol_info->non_virtual_base_columns(); - */ + ctx->add_vcol[j].num_base = 0; ctx->add_vcol_name[j] = field->field_name; - ctx->add_vcol[j].base_col = static_cast<dict_col_t**>( - mem_heap_alloc(ctx->heap, ctx->add_vcol[j].num_base - * sizeof *(ctx->add_vcol[j].base_col))); + ctx->add_vcol[j].base_col = NULL; ctx->add_vcol[j].v_pos = ctx->old_table->n_v_cols - ctx->num_to_drop_vcol + j; @@ -3833,12 +3747,17 @@ prepare_inplace_drop_virtual( ha_innobase_inplace_ctx* ctx; ulint i = 0; ulint j = 0; - Alter_drop *drop; ctx = static_cast<ha_innobase_inplace_ctx*> (ha_alter_info->handler_ctx); - ctx->num_to_drop_vcol = ha_alter_info->alter_info->drop_list.elements; + ctx->num_to_drop_vcol = 0; + for (i = 0; table->field[i]; i++) { + const Field* field = table->field[i]; + if (field->flags & FIELD_IS_DROPPED && !field->stored_in_db()) { + ctx->num_to_drop_vcol++; + } + } ctx->drop_vcol = static_cast<dict_v_col_t*>( mem_heap_alloc(ctx->heap, ctx->num_to_drop_vcol @@ -3847,26 +3766,9 @@ prepare_inplace_drop_virtual( mem_heap_alloc(ctx->heap, ctx->num_to_drop_vcol * sizeof *ctx->drop_vcol_name)); - List_iterator_fast<Alter_drop> cf_it( - ha_alter_info->alter_info->drop_list); - - while ((drop = (cf_it++)) != NULL) { - const Field* field; - ulint old_i; - - ut_ad(drop->type == Alter_drop::COLUMN); - - for (old_i = 0; table->field[old_i]; old_i++) { - const Field* n_field = table->field[old_i]; - if (!my_strcasecmp(system_charset_info, - n_field->field_name, drop->name)) { - break; - } - } - - i++; - - if (!table->field[old_i]) { + for (i = 0; table->field[i]; i++) { + Field *field = table->field[i]; + if (!(field->flags & FIELD_IS_DROPPED) || field->stored_in_db()) { continue; } @@ -3875,19 +3777,10 @@ prepare_inplace_drop_virtual( ulint field_type; ulint charset_no; - field = table->field[old_i]; - ulint col_type = get_innobase_type_from_mysql_type( &is_unsigned, field); - - if (!field->gcol_info || field->stored_in_db) { - my_error(ER_WRONG_KEY_COLUMN, MYF(0), - field->field_name); - return(true); - } - col_len = field->pack_length(); field_type = (ulint) field->type(); @@ -3941,12 +3834,12 @@ prepare_inplace_drop_virtual( ctx->drop_vcol[j].m_col.len = col_len; - ctx->drop_vcol[j].m_col.ind = old_i; + ctx->drop_vcol[j].m_col.ind = i; ctx->drop_vcol_name[j] = field->field_name; dict_v_col_t* v_col = dict_table_get_nth_v_col_mysql( - ctx->old_table, old_i); + ctx->old_table, i); ctx->drop_vcol[j].v_pos = v_col->v_pos; j++; } @@ -4404,7 +4297,7 @@ innodb_v_adjust_idx_col( /* Found the field in the new table */ while (const Create_field* new_field = cf_it++) { - if (!new_field->is_virtual_gcol()) { + if (!innobase_is_v_fld(new_field)) { continue; } @@ -4424,7 +4317,7 @@ innodb_v_adjust_idx_col( ut_a(0); } - ut_ad(field->is_virtual_gcol()); + ut_ad(innobase_is_v_fld(field)); num_v = 0; @@ -4438,7 +4331,7 @@ innodb_v_adjust_idx_col( break; } - if (old_table->field[old_i]->is_virtual_gcol()) { + if (innobase_is_v_fld(old_table->field[old_i])) { num_v++; } } @@ -4446,7 +4339,6 @@ innodb_v_adjust_idx_col( ut_ad(col_found); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /** Update internal structures with concurrent writes blocked, while preparing ALTER TABLE. @@ -4511,7 +4403,6 @@ prepare_inplace_alter_table_dict( trx_start_if_not_started_xa(ctx->prebuilt->trx, true); -#ifdef MYSQL_VIRTUAL_COLUMNS if (ha_alter_info->handler_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN) { if (prepare_inplace_drop_virtual( @@ -4543,7 +4434,6 @@ prepare_inplace_alter_table_dict( /* There should be no order change for virtual columns coming in here */ ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info)); -#endif /* MYSQL_VIRTUAL_COLUMNS */ /* Create a background transaction for the operations on the data dictionary tables. */ @@ -4658,9 +4548,9 @@ prepare_inplace_alter_table_dict( ctx->new_table->id); ulint n_cols = 0; ulint n_v_cols = 0; - ulint n_mv_cols = 0; dtuple_t* add_cols; ulint space_id = 0; + ulint z = 0; ulint key_id = FIL_DEFAULT_ENCRYPTION_KEY; fil_encryption_t mode = FIL_SPACE_ENCRYPTION_DEFAULT; const char* compression=NULL; @@ -4684,15 +4574,11 @@ prepare_inplace_alter_table_dict( if (innobase_is_v_fld(field)) { n_v_cols++; } else { - if (field->stored_in_db()) { n_cols++; - } else { - n_mv_cols++; - } } } - ut_ad(n_cols + n_v_cols + n_mv_cols == altered_table->s->fields); + ut_ad(n_cols + n_v_cols == altered_table->s->fields); if (add_fts_doc_id) { n_cols++; @@ -4744,21 +4630,17 @@ prepare_inplace_alter_table_dict( user_table->data_dir_path); } - for (uint i = 0, sql_idx=0; i < altered_table->s->stored_fields; i++, sql_idx++) { - Field* field; + for (uint i = 0; i < altered_table->s->fields; i++) { + const Field* field = altered_table->field[i]; ulint is_unsigned; - ulint charset_no; - ulint col_len; - - while (!((field= altered_table->field[sql_idx])->stored_in_db())) { - sql_idx++; - } - - ulint field_type = (ulint) field->type(); - bool is_virtual = innobase_is_v_fld(field); + ulint field_type + = (ulint) field->type(); ulint col_type = get_innobase_type_from_mysql_type( &is_unsigned, field); + ulint charset_no; + ulint col_len; + bool is_virtual = innobase_is_v_fld(field); /* we assume in dtype_form_prtype() that this fits in two bytes */ @@ -4825,7 +4707,6 @@ prepare_inplace_alter_table_dict( } if (is_virtual) { -#ifdef MYSQL_VIRTUAL_COLUMNS dict_mem_table_add_v_col( ctx->new_table, ctx->heap, field->field_name, @@ -4833,9 +4714,7 @@ prepare_inplace_alter_table_dict( dtype_form_prtype( field_type, charset_no) | DATA_VIRTUAL, - col_len, i, - field->gcol_info->non_virtual_base_columns()); -#endif /* MYSQL_VIRTUAL_COLUMNS */ + col_len, i, 0); } else { dict_mem_table_add_col( ctx->new_table, ctx->heap, @@ -4847,9 +4726,6 @@ prepare_inplace_alter_table_dict( } } -#ifdef MYSQL_VIRTUAL_COLUMNS - ulint z = 0; - if (n_v_cols) { for (uint i = 0; i < altered_table->s->fields; i++) { dict_v_col_t* v_col; @@ -4865,15 +4741,12 @@ prepare_inplace_alter_table_dict( ctx->new_table, field, v_col); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ if (add_fts_doc_id) { fts_add_doc_id_column(ctx->new_table, ctx->heap); ctx->new_table->fts->doc_col = fts_doc_id_col; ut_ad(fts_doc_id_col - == altered_table->s->stored_fields - n_v_cols); - ut_ad(fts_doc_id_col == altered_table->s->stored_fields); - + == altered_table->s->fields - n_v_cols); } else if (ctx->new_table->fts) { ctx->new_table->fts->doc_col = fts_doc_id_col; } @@ -5023,14 +4896,12 @@ new_clustered_failed: for (ulint a = 0; a < ctx->num_to_add_index; a++) { -#ifdef MYSQL_VIRTUAL_COLUMNS if (index_defs[a].ind_type & DICT_VIRTUAL && ctx->num_to_drop_vcol > 0 && !new_clustered) { innodb_v_adjust_idx_col(ha_alter_info, old_table, ctx->num_to_drop_vcol, &index_defs[a]); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ ctx->add_index[a] = row_merge_create_index( ctx->trx, ctx->new_table, @@ -5601,7 +5472,6 @@ rename_indexes_in_cache( } #endif /* MYSQL_RENAME_INDEX */ -#ifdef MYSQL_VIRTUAL_COLUMNS /** Fill the stored column information in s_cols list. @param[in] altered_table mysql table object @param[in] table innodb table object @@ -5626,7 +5496,7 @@ alter_fill_stored_column( continue; } - ulint num_base = field->gcol_info->non_virtual_base_columns(); + ulint num_base = 0; dict_col_t* col = dict_table_get_nth_col(table, i); s_col.m_col = col; @@ -5649,7 +5519,7 @@ alter_fill_stored_column( (*s_cols)->push_back(s_col); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ + /** Allows InnoDB to update internal structures with concurrent writes blocked (provided that check_if_supported_inplace_alter() @@ -5790,6 +5660,12 @@ ha_innobase::prepare_inplace_alter_table( info.set_tablespace_type(is_file_per_table); + if (ha_alter_info->handler_flags & Alter_inplace_info::ADD_INDEX) { + if (info.gcols_in_fulltext_or_spatial()) { + goto err_exit_no_heap; + } + } + if (ha_alter_info->handler_flags & Alter_inplace_info::CHANGE_CREATE_OPTION) { const char* invalid_opt = info.create_options_are_invalid(); @@ -6228,10 +6104,9 @@ check_if_can_drop_indexes: & Alter_inplace_info::ADD_FOREIGN_KEY) { ut_ad(!m_prebuilt->trx->check_foreigns); -#ifdef MYSQL_VIRTUAL_COLUMNS alter_fill_stored_column(altered_table, m_prebuilt->table, &s_cols, &s_heap); -#endif + add_fk = static_cast<dict_foreign_t**>( mem_heap_zalloc( heap, @@ -6302,7 +6177,6 @@ err_exit: } -#ifdef MYSQL_VIRTUAL_COLUMNS if ((ha_alter_info->handler_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN) && prepare_inplace_drop_virtual( @@ -6316,7 +6190,6 @@ err_exit: ha_alter_info, altered_table, table)) { DBUG_RETURN(true); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ DBUG_RETURN(false); } @@ -6332,7 +6205,7 @@ err_exit: m_prebuilt->table, altered_table, &fts_doc_col_no, &num_v)) { - fts_doc_col_no = altered_table->s->stored_fields; + fts_doc_col_no = altered_table->s->fields - num_v; add_fts_doc_id = true; add_fts_doc_id_idx = true; @@ -6360,36 +6233,24 @@ err_exit: DBUG_ASSERT( doc_col_no == fts_doc_col_no || doc_col_no == ULINT_UNDEFINED - || (ha_alter_info->handler_flags)); - /* JAN: TODO: MySQL 5.7 Virtual columns + || (ha_alter_info->handler_flags & (Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | Alter_inplace_info::DROP_STORED_COLUMN - | - Alter_inplace_info::ADD_STORED_COLUMN))); - */ + | Alter_inplace_info::ADD_STORED_BASE_COLUMN))); } } /* See if an AUTO_INCREMENT column was added. */ - uint i = 0, innodb_idx= 0; + uint i = 0; ulint num_v = 0; List_iterator_fast<Create_field> cf_it( ha_alter_info->alter_info->create_list); while (const Create_field* new_field = cf_it++) { const Field* field; - if (!new_field->stored_in_db()) { - i++; - continue; - } DBUG_ASSERT(i < altered_table->s->fields); - DBUG_ASSERT(innodb_idx < altered_table->s->stored_fields); for (uint old_i = 0; table->field[old_i]; old_i++) { - if (!table->field[old_i]->stored_in_db()) { - continue; - } - if (new_field->field == table->field[old_i]) { goto found_col; } @@ -6413,12 +6274,10 @@ err_exit: my_error(ER_WRONG_AUTO_KEY, MYF(0)); goto err_exit; } - add_autoinc_col_no = innodb_idx; - /* JAN: TODO: MySQL 5.7 - autoinc_col_max_value = - field->get_max_int_value(); - */ + /* Get the col no of the old table non-virtual column array */ + add_autoinc_col_no = i - num_v; + autoinc_col_max_value = innobase_get_int_col_max_value(field); } found_col: @@ -6427,7 +6286,6 @@ found_col: } i++; - innodb_idx++; } DBUG_ASSERT(heap); @@ -6601,7 +6459,6 @@ ok_exit: && alter_templ_needs_rebuild( altered_table, ha_alter_info, ctx->new_table)); -#ifdef MYSQL_VIRTUAL_COLUMNS if ((ctx->new_table->n_v_cols > 0) && rebuild_templ) { /* Save the templ if isn't NULL so as to restore the original state in case of alter operation failures. */ @@ -6609,11 +6466,9 @@ ok_exit: old_templ = ctx->new_table->vc_templ; } s_templ = UT_NEW_NOKEY(dict_vcol_templ_t()); - s_templ->vtempl = NULL; innobase_build_v_templ( - altered_table, ctx->new_table, s_templ, - NULL, false, NULL); + altered_table, ctx->new_table, s_templ, NULL, false); ctx->new_table->vc_templ = s_templ; } else if (ctx->num_to_add_vcol > 0 && ctx->num_to_drop_vcol == 0) { @@ -6630,11 +6485,8 @@ ok_exit: add_v->v_col = ctx->add_vcol; add_v->v_col_name = ctx->add_vcol_name; - s_templ->vtempl = NULL; - innobase_build_v_templ( - altered_table, ctx->new_table, s_templ, - add_v, false, NULL); + altered_table, ctx->new_table, s_templ, add_v, false); old_templ = ctx->new_table->vc_templ; ctx->new_table->vc_templ = s_templ; } @@ -6645,7 +6497,6 @@ ok_exit: if (!ctx->need_rebuild() && ctx->num_to_drop_vcol > 0) { eval_table = table; } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /* Read the clustered index of the table and build indexes based on this information using temporary @@ -7452,14 +7303,13 @@ innobase_enlarge_columns_try( List_iterator_fast<Create_field> cf_it( ha_alter_info->alter_info->create_list); ulint i = 0; - bool is_v=false; + ulint num_v = 0; + bool is_v; for (Field** fp = table->field; *fp; fp++, i++) { ulint idx; -#ifdef MYSQL_VIRTUAL_COLUMNS - ulint num_v = 0; - if ((*fp)->is_virtual_gcol()) { + if (innobase_is_v_fld(*fp)) { is_v = true; idx = num_v; num_v++; @@ -7467,10 +7317,6 @@ innobase_enlarge_columns_try( idx = i - num_v; is_v = false; } -#else - idx = i; - is_v = false; -#endif cf_it.rewind(); while (Create_field* cf = cf_it++) { @@ -7614,8 +7460,6 @@ commit_get_autoinc( ulonglong offset; col_max_value = innobase_get_int_col_max_value(autoinc_field); - // JAN: TODO: MySQL 5.7 - //col_max_value = autoinc_field->get_max_int_value(); offset = ctx->prebuilt->autoinc_offset; max_autoinc = innobase_next_autoinc( @@ -8213,7 +8057,6 @@ commit_try_norebuild( } #endif /* MYSQL_RENAME_INDEX */ -#ifdef MYSQL_VIRTUAL_COLUMNS if ((ha_alter_info->handler_flags & Alter_inplace_info::DROP_VIRTUAL_COLUMN) && innobase_drop_virtual_try( @@ -8229,7 +8072,6 @@ commit_try_norebuild( ctx->old_table, trx)) { DBUG_RETURN(true); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ DBUG_RETURN(false); } diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic index 5e5fbae9081..c44dc156aaa 100644 --- a/storage/innobase/include/dict0dict.ic +++ b/storage/innobase/include/dict0dict.ic @@ -1984,7 +1984,6 @@ dict_free_vc_templ( ut_free(vc_templ->vtempl[i]); } } - ut_free(vc_templ->default_rec); ut_free(vc_templ->vtempl); vc_templ->vtempl = NULL; } diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h index 019e20680e5..c81d893ed5a 100644 --- a/storage/innobase/include/dict0mem.h +++ b/storage/innobase/include/dict0mem.h @@ -1328,14 +1328,19 @@ struct dict_vcol_templ_t { /** table name */ std::string tb_name; - /** share->table_name */ - std::string share_name; - /** MySQL record length */ ulint rec_len; /** default column value if any */ byte* default_rec; + + /** cached MySQL TABLE object */ + TABLE* mysql_table; + + /** when mysql_table was cached */ + uint64_t mysql_table_query_id; + + dict_vcol_templ_t() : vtempl(0), mysql_table_query_id(-1) {} }; /* This flag is for sync SQL DDL and memcached DML. diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index f3641f93681..116ca781726 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -52,7 +52,6 @@ struct fts_string_t; #undef MYSQL_SPATIAL_INDEX #undef MYSQL_STORE_FTS_DOC_ID #undef MYSQL_TABLESPACES -#undef MYSQL_VIRTUAL_COLUMNS /*********************************************************************//** Wrapper around MySQL's copy_and_convert function. @@ -654,5 +653,20 @@ buffer pool size. void innodb_set_buf_pool_size(ulonglong buf_pool_size); +/** Create a MYSQL_THD for background purge threads and mark it as such. +@returns new MYSQL_THD */ +MYSQL_THD +innobase_create_background_thd(); + +/** Destroy a background purge thread THD. +@param[in] thd MYSQL_THD to destroy */ +void +innobase_destroy_background_thd(MYSQL_THD); + +/** Close opened tables, free memory, delete items for a MYSQL_THD. +@param[in] thd MYSQL_THD to reset */ +void +innobase_reset_background_thd(MYSQL_THD); + #endif /* !UNIV_HOTBACKUP && !UNIV_INNOCHECKSUM */ #endif /* HA_INNODB_PROTOTYPES_H */ diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index bc421774320..0a5e3b27bc0 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -2195,6 +2195,13 @@ loop: count = 0; } + /* Wake up purge threads to die - they have MYSQL_THD's and + thus might keep open transactions. In particular, this is + needed in embedded server and when one uses UNINSTALL PLUGIN. + In the normal server shutdown purge threads should've been + already notified by the thd_destructor_proxy thread. */ + srv_purge_wakeup(); + goto loop; } diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 20c64a4288c..271d70d4da9 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -931,7 +931,6 @@ row_ins_invalidate_query_cache( innobase_invalidate_query_cache(thr_get_trx(thr), name, len); } -#ifdef MYSQL_VIRTUAL_COLUMNS /** Fill virtual column information in cascade node for the child table. @param[out] cascade child update node @@ -1042,7 +1041,6 @@ func_exit: mem_heap_free(v_heap); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ #ifdef WITH_WSREP dberr_t wsrep_append_foreign_key(trx_t *trx, @@ -1338,7 +1336,6 @@ row_ins_foreign_check_on_constraint( cascade->fts_doc_id = doc_id; } -#ifdef MYSQL_VIRTUAL_COLUMNS if (foreign->v_cols != NULL && foreign->v_cols->size() > 0) { row_ins_foreign_fill_virtual( @@ -1349,7 +1346,6 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ } else if (table->fts && cascade->is_delete) { /* DICT_FOREIGN_ON_DELETE_CASCADE case */ for (i = 0; i < foreign->n_fields; i++) { @@ -1379,7 +1375,6 @@ row_ins_foreign_check_on_constraint( trx, &fts_col_affacted, cascade); -#ifdef MYSQL_VIRTUAL_COLUMNS if (foreign->v_cols != NULL && foreign->v_cols->size() > 0) { row_ins_foreign_fill_virtual( @@ -1390,7 +1385,6 @@ row_ins_foreign_check_on_constraint( goto nonstandard_exit_func; } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ if (n_to_update == ULINT_UNDEFINED) { err = DB_ROW_IS_REFERENCED; diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index d302b493f21..7a8b74279f5 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -655,13 +655,10 @@ row_merge_buf_add( const dfield_t* row_field; col = ifield->col; - -#ifdef MYSQL_VIRTUAL_COLUMNS const dict_v_col_t* v_col = NULL; if (dict_col_is_virtual(col)) { v_col = reinterpret_cast<const dict_v_col_t*>(col); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ col_no = dict_col_get_no(col); @@ -687,7 +684,6 @@ row_merge_buf_add( } else { /* Use callback to get the virtual column value */ if (dict_col_is_virtual(col)) { - #ifdef MYSQL_VIRTUAL_COLUMN dict_index_t* clust_index = dict_table_get_first_index(new_table); @@ -701,7 +697,6 @@ row_merge_buf_add( DBUG_RETURN(0); } dfield_copy(field, row_field); -#endif /* MYSQL_VIRTUAL_COLUMN */ } else { row_field = dtuple_get_nth_field(row, col_no); dfield_copy(field, row_field); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 5b38b7c6c01..100e1bcb708 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -5034,14 +5034,12 @@ end: goto funct_exit; } -#ifdef MYSQL_VIRTUAL_COLUMNS /* In case of copy alter, template db_name and table_name should be renamed only for newly created table. */ if (table->vc_templ != NULL && !new_is_tmp) { innobase_rename_vc_templ(table); } -#endif /* We only want to switch off some of the type checking in an ALTER TABLE...ALGORITHM=COPY, not in a RENAME. */ diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc index bac55694056..23e08c38cdd 100644 --- a/storage/innobase/row/row0purge.cc +++ b/storage/innobase/row/row0purge.cc @@ -868,7 +868,6 @@ try_again: goto err_exit; } -#ifdef MYSQL_VIRTUAL_COLUMNS if (node->table->n_v_cols && !node->table->vc_templ && dict_table_has_indexed_v_cols(node->table)) { /* Need server fully up for virtual column computation */ @@ -886,7 +885,6 @@ try_again: /* Initialize the template for the table */ innobase_init_vc_templ(node->table); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /* Disable purging for temp-tables as they are short-lived and no point in re-organzing such short lived tables */ @@ -1120,6 +1118,8 @@ row_purge_step( row_purge_end(thr); } + innobase_reset_background_thd(thr_get_trx(thr)->mysql_thd); + return(thr); } diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 62fd18d027b..5daa26319a5 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -221,7 +221,6 @@ row_sel_sec_rec_is_for_clust_rec( /* For virtual column, its value will need to be reconstructed from base column in cluster index */ if (is_virtual) { -#ifdef MYSQL_VIRTUAL_COLUMNS const dict_v_col_t* v_col; const dtuple_t* row; dfield_t* vfield; @@ -243,7 +242,6 @@ row_sel_sec_rec_is_for_clust_rec( clust_len = vfield->len; clust_field = static_cast<byte*>(vfield->data); -#endif /* MYSQL_VIRTUAL_COLUMNS */ } else { clust_pos = dict_col_get_clust_pos(col, clust_index); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 759bfb57428..2a990904242 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1076,7 +1076,6 @@ row_upd_build_difference_binary( } } -#ifdef MYSQL_VIRTUAL_COLUMNS /* Check the virtual columns updates. Even if there is no non-virtual column (base columns) change, we will still need to build the indexed virtual column value so that undo log would log them ( @@ -1141,7 +1140,6 @@ row_upd_build_difference_binary( mem_heap_free(v_heap); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ update->n_fields = n_diff; ut_ad(update->validate()); @@ -2061,7 +2059,6 @@ row_upd_eval_new_vals( } } -#ifdef MYSQL_VIRTUAL_COLUMNS /** Stores to the heap the virtual columns that need for any indexes @param[in,out] node row update node @param[in] update an update vector if it is update @@ -2140,7 +2137,6 @@ row_upd_store_v_row( mem_heap_free(heap); } } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /** Stores to the heap the row on which the node->pcur is positioned. @param[in] node row update node @@ -2190,12 +2186,10 @@ row_upd_store_row( node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets, NULL, NULL, NULL, ext, node->heap); -#ifdef MYSQL_VIRTUAL_COLUMNS if (node->table->n_v_cols) { row_upd_store_v_row(node, node->is_delete ? NULL : node->update, thd, mysql_table); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ if (node->is_delete) { node->upd_row = NULL; diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index fd17683fb48..f21b1ebbb85 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -467,7 +467,6 @@ row_vers_non_vc_match( return(ret); } -#ifdef MYSQL_VIRTUAL_COLUMNS /** build virtual column value from current cluster index record data @param[in,out] row the cluster index row in dtuple form @param[in] clust_index clustered index @@ -841,7 +840,6 @@ row_vers_build_cur_vrow( ULINT_UNDEFINED, &heap); return(cur_vrow); } -#endif /* MYSQL_VIRTUAL_COLUMNS */ /*****************************************************************//** Finds out if a version of the record, where the version >= the current @@ -913,7 +911,6 @@ row_vers_old_has_index_entry( if (dict_index_has_virtual(index)) { -#ifdef MYSQL_VIRTUAL_COLUMNS #ifdef DBUG_OFF # define dbug_v_purge false @@ -963,7 +960,6 @@ row_vers_old_has_index_entry( } clust_offsets = rec_get_offsets(rec, clust_index, NULL, ULINT_UNDEFINED, &heap); -#endif /* MYSQL_VIRTUAL_COLUMNS */ } else { entry = row_build_index_entry( @@ -1001,7 +997,6 @@ row_vers_old_has_index_entry( } } } else if (dict_index_has_virtual(index)) { -#ifdef MYSQL_VIRTUAL_COLUMNS /* The current cluster index record could be deleted, but the previous version of it might not. We will need to get the virtual column data from undo record @@ -1009,7 +1004,6 @@ row_vers_old_has_index_entry( cur_vrow = row_vers_build_cur_vrow( also_curr, rec, clust_index, &clust_offsets, index, ientry, roll_ptr, trx_id, heap, v_heap, mtr); -#endif /* MYSQL_VIRTUAL_COLUMNS */ } version = rec; diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index d2f13ad9b37..2e9e3b7ea8a 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -2664,8 +2664,13 @@ Check if purge should stop. static bool srv_purge_should_exit( + MYSQL_THD thd, ulint n_purged) /*!< in: pages purged in last batch */ { + if (thd_kill_level(thd)) { + return(true); + } + switch (srv_shutdown_state) { case SRV_SHUTDOWN_NONE: /* Normal operation. */ @@ -2736,8 +2741,7 @@ DECLARE_THREAD(srv_worker_thread)( ut_ad(!srv_read_only_mode); ut_a(srv_force_recovery < SRV_FORCE_NO_BACKGROUND); my_thread_init(); - // JAN: TODO: MySQL 5.7 - // THD *thd= create_thd(false, true, true); + THD* thd = innobase_create_background_thd(); #ifdef UNIV_DEBUG_THREAD_CREATION ib::info() << "Worker thread starting, id " @@ -2781,7 +2785,7 @@ DECLARE_THREAD(srv_worker_thread)( ut_a(!purge_sys->running); ut_a(purge_sys->state == PURGE_STATE_EXIT); - ut_a(srv_shutdown_state > SRV_SHUTDOWN_NONE); + ut_a(srv_shutdown_state > SRV_SHUTDOWN_NONE || thd_kill_level(thd)); rw_lock_x_unlock(&purge_sys->latch); @@ -2790,9 +2794,8 @@ DECLARE_THREAD(srv_worker_thread)( << os_thread_pf(os_thread_get_curr_id()); #endif /* UNIV_DEBUG_THREAD_CREATION */ - // JAN: TODO: MySQL 5.7 - // destroy_thd(thd); - my_thread_end(); + innobase_destroy_background_thd(thd); + my_thread_end(); /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ os_thread_exit(); @@ -2807,6 +2810,7 @@ static ulint srv_do_purge( /*=========*/ + MYSQL_THD thd, ulint n_threads, /*!< in: number of threads to use */ ulint* n_total_purged) /*!< in/out: total pages purged */ { @@ -2877,7 +2881,7 @@ srv_do_purge( *n_total_purged += n_pages_purged; - } while (!srv_purge_should_exit(n_pages_purged) + } while (!srv_purge_should_exit(thd, n_pages_purged) && n_pages_purged > 0 && purge_sys->state == PURGE_STATE_RUN); @@ -2890,6 +2894,7 @@ static void srv_purge_coordinator_suspend( /*==========================*/ + MYSQL_THD thd, srv_slot_t* slot, /*!< in/out: Purge coordinator thread slot */ ulint rseg_history_len) /*!< in: history list length @@ -2977,7 +2982,7 @@ srv_purge_coordinator_suspend( } } - } while (stop); + } while (stop && !thd_kill_level(thd)); srv_sys_mutex_enter(); @@ -3001,8 +3006,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)( required by os_thread_create */ { my_thread_init(); - // JAN: TODO: MySQL 5.7 - // THD *thd= create_thd(false, true, true); + THD* thd = innobase_create_background_thd(); srv_slot_t* slot; ulint n_total_purged = ULINT_UNDEFINED; @@ -3036,13 +3040,14 @@ DECLARE_THREAD(srv_purge_coordinator_thread)( purge didn't purge any records then wait for activity. */ if (srv_shutdown_state == SRV_SHUTDOWN_NONE + && !thd_kill_level(thd) && (purge_sys->state == PURGE_STATE_STOP || n_total_purged == 0)) { - srv_purge_coordinator_suspend(slot, rseg_history_len); + srv_purge_coordinator_suspend(thd, slot, rseg_history_len); } - if (srv_purge_should_exit(n_total_purged)) { + if (srv_purge_should_exit(thd, n_total_purged)) { ut_a(!slot->suspended); break; } @@ -3050,14 +3055,14 @@ DECLARE_THREAD(srv_purge_coordinator_thread)( n_total_purged = 0; rseg_history_len = srv_do_purge( - srv_n_purge_threads, &n_total_purged); + thd, srv_n_purge_threads, &n_total_purged); - } while (!srv_purge_should_exit(n_total_purged)); + } while (!srv_purge_should_exit(thd, n_total_purged)); /* Ensure that we don't jump out of the loop unless the exit condition is satisfied. */ - ut_a(srv_purge_should_exit(n_total_purged)); + ut_a(srv_purge_should_exit(thd, n_total_purged)); ulint n_pages_purged = ULINT_MAX; @@ -3068,12 +3073,6 @@ DECLARE_THREAD(srv_purge_coordinator_thread)( n_pages_purged = trx_purge(1, srv_purge_batch_size, false); } -#ifdef UNIV_DEBUG - if (srv_fast_shutdown == 0) { - trx_commit_disallowed = true; - } -#endif /* UNIV_DEBUG */ - /* This trx_purge is called to remove any undo records (added by background threads) after completion of the above loop. When srv_fast_shutdown != 0, a large batch size can cause significant @@ -3116,8 +3115,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)( srv_release_threads(SRV_WORKER, srv_n_purge_threads - 1); } - // JAN: TODO: MYSQL 5.7 - // destroy_thd(thd); + innobase_destroy_background_thd(thd); my_thread_end(); /* We count the number of threads in os_thread_exit(). A created thread should always use that to exit and not use return() to exit. */ diff --git a/storage/mroonga/ha_mroonga.cpp b/storage/mroonga/ha_mroonga.cpp index cb902f976fa..27a3e7b3294 100644 --- a/storage/mroonga/ha_mroonga.cpp +++ b/storage/mroonga/ha_mroonga.cpp @@ -13969,8 +13969,8 @@ enum_alter_inplace_result ha_mroonga::wrapper_check_if_supported_inplace_alter( ( Alter_inplace_info::ADD_COLUMN | Alter_inplace_info::DROP_COLUMN | - Alter_inplace_info::ALTER_COLUMN_TYPE | - Alter_inplace_info::ALTER_COLUMN_ORDER | + Alter_inplace_info::ALTER_STORED_COLUMN_TYPE | + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER | Alter_inplace_info::ALTER_COLUMN_NULLABLE | Alter_inplace_info::ALTER_COLUMN_NOT_NULLABLE | Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE | diff --git a/storage/tokudb/ha_tokudb_alter_56.cc b/storage/tokudb/ha_tokudb_alter_56.cc index 00a4602b554..ba1afbf091a 100644 --- a/storage/tokudb/ha_tokudb_alter_56.cc +++ b/storage/tokudb/ha_tokudb_alter_56.cc @@ -216,11 +216,11 @@ static ulong fix_handler_flags( handler_flags &= ~Alter_inplace_info::TOKU_ALTER_RENAME; } - // ALTER_COLUMN_TYPE may be set when no columns have been changed, + // ALTER_STORED_COLUMN_TYPE may be set when no columns have been changed, // so turn off the flag - if (handler_flags & Alter_inplace_info::ALTER_COLUMN_TYPE) { + if (handler_flags & Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) { if (all_fields_are_same_type(table, altered_table)) { - handler_flags &= ~Alter_inplace_info::ALTER_COLUMN_TYPE; + handler_flags &= ~Alter_inplace_info::ALTER_STORED_COLUMN_TYPE; } } @@ -358,7 +358,7 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter( // but let's do some more checks // we will only allow an hcr if there are no changes - // in column positions (ALTER_COLUMN_ORDER is not set) + // in column positions (ALTER_STORED_COLUMN_ORDER is not set) // now need to verify that one and only one column // has changed only its name. If we find anything to @@ -369,7 +369,7 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter( table, altered_table, (ctx->handler_flags & - Alter_inplace_info::ALTER_COLUMN_ORDER) != 0); + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER) != 0); if (cr_supported) result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK; } @@ -377,7 +377,7 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter( only_flags( ctx->handler_flags, Alter_inplace_info::ADD_COLUMN + - Alter_inplace_info::ALTER_COLUMN_ORDER) && + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER) && setup_kc_info(altered_table, ctx->altered_table_kc_info) == 0) { // add column @@ -407,7 +407,7 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter( only_flags( ctx->handler_flags, Alter_inplace_info::DROP_COLUMN + - Alter_inplace_info::ALTER_COLUMN_ORDER) && + Alter_inplace_info::ALTER_STORED_COLUMN_ORDER) && setup_kc_info(altered_table, ctx->altered_table_kc_info) == 0) { // drop column @@ -452,10 +452,10 @@ enum_alter_inplace_result ha_tokudb::check_if_supported_inplace_alter( ha_alter_info, ctx)) { result = HA_ALTER_INPLACE_EXCLUSIVE_LOCK; } - } else if ((ctx->handler_flags & Alter_inplace_info::ALTER_COLUMN_TYPE) && + } else if ((ctx->handler_flags & Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) && only_flags( ctx->handler_flags, - Alter_inplace_info::ALTER_COLUMN_TYPE + + Alter_inplace_info::ALTER_STORED_COLUMN_TYPE + Alter_inplace_info::ALTER_COLUMN_DEFAULT) && table->s->fields == altered_table->s->fields && find_changed_fields( @@ -1578,7 +1578,7 @@ static bool change_field_type_is_supported( return false; } else if (old_type == MYSQL_TYPE_VARCHAR) { // varchar(X) -> varchar(Y) and varbinary(X) -> varbinary(Y) expansion - // where X < 256 <= Y the ALTER_COLUMN_TYPE handler flag is set for + // where X < 256 <= Y the ALTER_STORED_COLUMN_TYPE handler flag is set for // these cases return change_varchar_length_is_supported( old_field, |