From 1adc382c2fb4300059d130521a24a1dab141531e Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 12 Feb 2018 22:08:57 +0100 Subject: [PATCH 01/39] Use stunnel during rsync SST if available --- scripts/wsrep_sst_rsync.sh | 67 ++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 3d76d1780e2..bb2f3fa7d64 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -41,6 +41,8 @@ cleanup_joiner() kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || \ : rm -rf "$RSYNC_CONF" + rm -f "$STUNNEL_CONF" + rm -f "$STUNNEL_PID" rm -rf "$MAGIC_FILE" rm -rf "$RSYNC_PID" wsrep_log_info "Joiner cleanup done." @@ -75,7 +77,7 @@ check_pid_and_port() local port_info=$(lsof -i :$rsync_port -Pn 2>/dev/null | \ grep "(LISTEN)") local is_rsync=$(echo $port_info | \ - grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null) + grep -wE '^(rsync|stunnel)[[:space:]]+'"$rsync_pid" 2>/dev/null) if [ -n "$port_info" -a -z "$is_rsync" ]; then wsrep_log_error "rsync daemon port '$rsync_port' has been taken" @@ -86,6 +88,12 @@ check_pid_and_port() [ $(cat $pid_file) -eq $rsync_pid ] } +STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" +rm -f "$STUNNEL_CONF" + +STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" +rm -f "$STUNNEL_PID" + MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" rm -rf "$MAGIC_FILE" @@ -123,9 +131,28 @@ fi FILTER=(-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*') +SSTKEY=$(parse_cnf sst tkey "") +SSTCERT=$(parse_cnf sst tcert "") +STUNNEL="" +if [ -f "$SSTKEY" ] && [ -f "$SSTCERT" ] && wsrep_check_programs stunnel +then + STUNNEL="stunnel ${STUNNEL_CONF}" +fi + if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then +cat << EOF > "$STUNNEL_CONF" +CApath = ${SSTCERT%/*} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = yes +connect = ${WSREP_SST_OPT_ADDR%/*} +TIMEOUTclose = 0 +verifyPeer = yes +EOF + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then @@ -185,7 +212,8 @@ then # first, the normal directories, so that we can detect incompatible protocol RC=0 - rsync --owner --group --perms --links --specials \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT "${FILTER[@]}" "$WSREP_SST_OPT_DATA/" \ rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? @@ -208,7 +236,8 @@ then fi # second, we transfer InnoDB log files - rsync --owner --group --perms --links --specials \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? @@ -227,7 +256,8 @@ then find . -maxdepth 1 -mindepth 1 -type d -not -name "lost+found" \ -print0 | xargs -I{} -0 -P $count \ - rsync --owner --group --perms --links --specials \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --recursive --delete --quiet \ $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? @@ -250,7 +280,8 @@ then echo "continue" # now server can resume updating data echo "$STATE" > "$MAGIC_FILE" - rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR echo "done $STATE" @@ -308,8 +339,30 @@ EOF # listen at all interfaces (for firewalled setups) readonly RSYNC_PORT=${WSREP_SST_OPT_PORT:-4444} - rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & - RSYNC_REAL_PID=$! + +cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = no +[rsync] +accept = $RSYNC_PORT +exec = $(which rsync) +execargs = rsync --server --daemon --config=$RSYNC_CONF . +EOF + + if [ -z "$STUNNEL" ] + then + # listen at all interfaces (for firewalled setups) + rsync --daemon --no-detach --port $RSYNC_PORT --config "$RSYNC_CONF" & + RSYNC_REAL_PID=$! + else + stunnel "$STUNNEL_CONF" & + RSYNC_REAL_PID=$! + RSYNC_PID=$STUNNEL_PID + fi until check_pid_and_port $RSYNC_PID $RSYNC_REAL_PID $RSYNC_PORT do From 33110db0550f632408a71560d1636685c120efc5 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Tue, 31 Jul 2018 10:46:16 -0400 Subject: [PATCH 02/39] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 23e938e60e1..4acb69e9e07 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=5 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=61 +MYSQL_VERSION_PATCH=62 MYSQL_VERSION_EXTRA= From 1a7a018939e19a0037808489be0fd1680581aec3 Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Wed, 18 Jul 2018 14:57:27 +0300 Subject: [PATCH 03/39] MDEV-16557 Remove INNOBASE_SHARE::idx_trans_tbl INNOBASE_SHARE: remove check_index_consistency(): iterates through keys and looks for InnoDB and .frm mismatches. ha_innobase::innobase_get_index(): now uses dict_table_get_index_on_name() dict_table_get_index_on_name(): uses strcmp() instead of innobase_casestrcmp() as we just need to know whether strings are equal or not --- storage/innobase/dict/dict0dict.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 372 ++-------------------- storage/innobase/handler/ha_innodb.h | 43 --- storage/innobase/handler/handler0alter.cc | 6 - storage/innobase/row/row0merge.cc | 11 - 5 files changed, 32 insertions(+), 402 deletions(-) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 8dc29863367..36b19eeea46 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -6311,7 +6311,7 @@ dict_table_get_index_on_name( while (index != NULL) { if (index->is_committed() == committed - && innobase_strcasecmp(index->name, name) == 0) { + && strcmp(index->name, name) == 0) { return(index); } diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d8e805862f7..41cbca0d49d 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -176,8 +176,6 @@ static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid); static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid); #endif /* WITH_WSREP */ -/** to protect innobase_open_files */ -static mysql_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ static ulong commit_threads = 0; static mysql_cond_t commit_cond; @@ -466,8 +464,6 @@ operation, we only do it every INNOBASE_WAKE_INTERVAL'th step. */ #define INNOBASE_WAKE_INTERVAL 32 static ulong innobase_active_counter = 0; -static hash_table_t* innobase_open_tables; - /** Allowed values of innodb_change_buffering */ static const char* innobase_change_buffering_values[IBUF_USE_COUNT] = { "none", /* IBUF_USE_NONE */ @@ -567,7 +563,6 @@ const struct _ft_vft_ext ft_vft_ext_result = {innobase_fts_get_version, /* Keys to register pthread mutexes/cond in the current file with performance schema */ -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; @@ -576,7 +571,6 @@ static mysql_pfs_key_t thd_destructor_thread_key; static PSI_mutex_info all_pthread_mutexes[] = { PSI_KEY(commit_cond_mutex), PSI_KEY(pending_checkpoint_mutex), - PSI_KEY(innobase_share_mutex) }; static PSI_cond_info all_innodb_conds[] = { @@ -1230,23 +1224,6 @@ static SHOW_VAR innodb_status_variables[]= { {NullS, NullS, SHOW_LONG} }; -/************************************************************************//** -Handling the shared INNOBASE_SHARE structure that is needed to provide table -locking. Register the table name if it doesn't exist in the hash table. */ -static -INNOBASE_SHARE* -get_share( -/*======*/ - const char* table_name); /*!< in: table to lookup */ - -/************************************************************************//** -Free the shared object that was registered with get_share(). */ -static -void -free_share( -/*=======*/ - INNOBASE_SHARE* share); /*!< in/own: share to free */ - /*****************************************************************//** Frees a possible InnoDB trx object associated with the current THD. @return 0 or error number */ @@ -4413,10 +4390,6 @@ innobase_change_buffering_inited_ok: ibuf_max_size_update(srv_change_buffer_max_size); - innobase_open_tables = hash_create(200); - mysql_mutex_init(innobase_share_mutex_key, - &innobase_share_mutex, - MY_MUTEX_INIT_FAST); mysql_mutex_init(commit_cond_mutex_key, &commit_cond_m, MY_MUTEX_INIT_FAST); mysql_cond_init(commit_cond_key, &commit_cond, 0); @@ -4492,9 +4465,6 @@ innobase_end(handlerton*, ha_panic_function) } } - hash_table_free(innobase_open_tables); - innobase_open_tables = NULL; - st_my_thread_var* running = reinterpret_cast( my_atomic_loadptr_explicit( reinterpret_cast(&srv_running), @@ -4512,7 +4482,6 @@ innobase_end(handlerton*, ha_panic_function) innodb_shutdown(); innobase_space_shutdown(); - mysql_mutex_destroy(&innobase_share_mutex); mysql_mutex_destroy(&commit_cond_m); mysql_cond_destroy(&commit_cond); mysql_mutex_destroy(&pending_checkpoint_mutex); @@ -5753,6 +5722,7 @@ is consistent between KEY info from mysql and that from innodb index. @param[in] key_info Index info from mysql @param[in] index_info Index info from InnoDB @return true if all column types match. */ +static bool innobase_match_index_columns( const KEY* key_info, @@ -6042,90 +6012,34 @@ innobase_build_v_templ( s_templ->tb_name = table->s->table_name.str; } -/*******************************************************************//** -This function builds a translation table in INNOBASE_SHARE -structure for fast index location with mysql array number from its -table->key_info structure. This also provides the necessary translation -between the key order in mysql key_info and InnoDB ib_table->indexes if -they are not fully matched with each other. -Note we do not have any mutex protecting the translation table -building based on the assumption that there is no concurrent -index creation/drop and DMLs that requires index lookup. All table -handle will be closed before the index creation/drop. -@return true if index translation table built successfully */ -static -bool -innobase_build_index_translation( -/*=============================*/ - const TABLE* table, /*!< in: table in MySQL data - dictionary */ - dict_table_t* ib_table,/*!< in: table in InnoDB data - dictionary */ - INNOBASE_SHARE* share) /*!< in/out: share structure - where index translation table - will be constructed in. */ +/** Check consistency between .frm indexes and InnoDB indexes. +@param[in] table table object formed from .frm +@param[in] ib_table InnoDB table definition +@retval true if not errors were found */ +static bool +check_index_consistency(const TABLE* table, const dict_table_t* ib_table) { - DBUG_ENTER("innobase_build_index_translation"); - - bool ret = true; - - mutex_enter(&dict_sys->mutex); - - ulint mysql_num_index = table->s->keys; - ulint ib_num_index = UT_LIST_GET_LEN(ib_table->indexes); - dict_index_t** index_mapping = share->idx_trans_tbl.index_mapping; + ulint mysql_num_index = table->s->keys; + ulint ib_num_index = UT_LIST_GET_LEN(ib_table->indexes); + bool ret = true; /* If there exists inconsistency between MySQL and InnoDB dictionary (metadata) information, the number of index defined in MySQL - could exceed that in InnoDB, do not build index translation - table in such case */ + could exceed that in InnoDB, return error */ if (ib_num_index < mysql_num_index) { ret = false; goto func_exit; } - /* If index entry count is non-zero, nothing has - changed since last update, directly return TRUE */ - if (share->idx_trans_tbl.index_count) { - /* Index entry count should still match mysql_num_index */ - ut_a(share->idx_trans_tbl.index_count == mysql_num_index); - goto func_exit; - } - - /* The number of index increased, rebuild the mapping table */ - if (mysql_num_index > share->idx_trans_tbl.array_size) { - - index_mapping = reinterpret_cast( - ut_realloc(index_mapping, - mysql_num_index * sizeof(*index_mapping))); - - if (index_mapping == NULL) { - /* Report an error if index_mapping continues to be - NULL and mysql_num_index is a non-zero value */ - sql_print_error("InnoDB: fail to allocate memory for " - "index translation table. Number of " - "Index: " ULINTPF - ", array size:" ULINTPF, - mysql_num_index, - share->idx_trans_tbl.array_size); - ret = false; - goto func_exit; - } - - share->idx_trans_tbl.array_size = mysql_num_index; - } - /* For each index in the mysql key_info array, fetch its corresponding InnoDB index pointer into index_mapping array. */ for (ulint count = 0; count < mysql_num_index; count++) { - /* Fetch index pointers into index_mapping according to mysql - index sequence */ - index_mapping[count] = dict_table_get_index_on_name( - ib_table, table->key_info[count].name); + const dict_index_t* index = dict_table_get_index_on_name( + ib_table, table->key_info[count].name); - if (index_mapping[count] == 0) { + if (index == NULL) { sql_print_error("Cannot find index %s in InnoDB" " index dictionary.", table->key_info[count].name); @@ -6136,7 +6050,7 @@ innobase_build_index_translation( /* Double check fetched index has the same column info as those in mysql key_info. */ if (!innobase_match_index_columns(&table->key_info[count], - index_mapping[count])) { + index)) { sql_print_error("Found index %s whose column info" " does not match that of MariaDB.", table->key_info[count].name); @@ -6145,51 +6059,10 @@ innobase_build_index_translation( } } - /* Successfully built the translation table */ - share->idx_trans_tbl.index_count = mysql_num_index; - func_exit: - if (!ret) { - /* Build translation table failed. */ - ut_free(index_mapping); - - share->idx_trans_tbl.array_size = 0; - share->idx_trans_tbl.index_count = 0; - index_mapping = NULL; - } - - share->idx_trans_tbl.index_mapping = index_mapping; - - mutex_exit(&dict_sys->mutex); - - DBUG_RETURN(ret); + return ret; } -/*******************************************************************//** -This function uses index translation table to quickly locate the -requested index structure. -Note we do not have mutex protection for the index translatoin table -access, it is based on the assumption that there is no concurrent -translation table rebuild (fter create/drop index) and DMLs that -require index lookup. -@return dict_index_t structure for requested index. NULL if -fail to locate the index structure. */ -static -dict_index_t* -innobase_index_lookup( -/*==================*/ - INNOBASE_SHARE* share, /*!< in: share structure for index - translation table. */ - uint keynr) /*!< in: index number for the requested - index */ -{ - if (share->idx_trans_tbl.index_mapping == NULL - || keynr >= share->idx_trans_tbl.index_count) { - return(NULL); - } - - return(share->idx_trans_tbl.index_mapping[keynr]); -} /********************************************************************//** Get the upper limit of the MySQL integral and floating-point type. @return maximum allowed value for the field */ @@ -6319,11 +6192,6 @@ ha_innobase::open(const char* name, int, uint) m_user_thd = NULL; - if (!(m_share = get_share(name))) { - - DBUG_RETURN(1); - } - /* Will be allocated if it is needed in ::update_row() */ m_upd_buf = NULL; m_upd_buf_size = 0; @@ -6347,7 +6215,6 @@ ha_innobase::open(const char* name, int, uint) norm_name); } no_such_table: - free_share(m_share); set_my_errno(ENOENT); DBUG_RETURN(HA_ERR_NO_SUCH_TABLE); @@ -6430,7 +6297,6 @@ no_such_table: } if (!thd_tablespace_op(thd) && no_tablespace) { - free_share(m_share); set_my_errno(ENOENT); int ret_err = HA_ERR_NO_SUCH_TABLE; @@ -6506,9 +6372,10 @@ no_such_table: mutex_exit(&dict_sys->mutex); } - if (!innobase_build_index_translation(table, ib_table, m_share)) { - sql_print_error("Build InnoDB index translation table for" - " Table %s failed", name); + if (!check_index_consistency(table, ib_table)) { + sql_print_error("InnoDB indexes are inconsistent with what " + "defined in .frm for table %s", + name); } /* Allocate a buffer for a 'row reference'. A row reference is @@ -6604,9 +6471,6 @@ no_such_table: /* Index block size in InnoDB: used by MySQL in query optimization */ stats.block_size = UNIV_PAGE_SIZE; - /* Init table lock structure */ - thr_lock_data_init(&m_share->lock, &lock, NULL); - if (m_prebuilt->table != NULL) { /* We update the highest file format in the system table space, if this table has higher file format setting. */ @@ -6802,8 +6666,6 @@ ha_innobase::close() m_upd_buf_size = 0; } - free_share(m_share); - MONITOR_INC(MONITOR_TABLE_CLOSE); /* Tell InnoDB server that there might be work for @@ -9654,60 +9516,18 @@ ha_innobase::innobase_get_index( clustered index, even if it was internally generated by InnoDB */ { - KEY* key; + KEY* key = NULL; + dict_table_t* ib_table = m_prebuilt->table; dict_index_t* index; DBUG_ENTER("innobase_get_index"); if (keynr != MAX_KEY && table->s->keys > 0) { - - key = table->key_info + keynr; - - index = innobase_index_lookup(m_share, keynr); - - if (index != NULL) { - if (!key || ut_strcmp(index->name, key->name) != 0) { - ib::error() << " Index for key no " << keynr - << " mysql name " << (key ? key->name : "NULL") - << " InnoDB name " << index->name() - << " for table " << m_prebuilt->table->name.m_name; - - for(uint i=0; i < table->s->keys; i++) { - index = innobase_index_lookup(m_share, i); - key = table->key_info + keynr; - - if (index) { - ib::info() << " Index for key no " << keynr - << " mysql name " << (key ? key->name : "NULL") - << " InnoDB name " << index->name() - << " for table " << m_prebuilt->table->name.m_name; - } - } - - } - - ut_a(ut_strcmp(index->name, key->name) == 0); - } else { - /* Can't find index with keynr in the translation - table. Only print message if the index translation - table exists */ - if (m_share->idx_trans_tbl.index_mapping != NULL) { - sql_print_warning("InnoDB could not find" - " index %s key no %u for" - " table %s through its" - " index translation table", - key ? key->name : "NULL", - keynr, - m_prebuilt->table->name - .m_name); - } - - index = dict_table_get_index_on_name( - m_prebuilt->table, key->name); - } + key = &table->key_info[keynr]; + index = dict_table_get_index_on_name(ib_table, key->name); + ut_ad(index); } else { - key = 0; - index = dict_table_get_first_index(m_prebuilt->table); + index = dict_table_get_first_index(ib_table); } if (index == NULL) { @@ -9715,7 +9535,7 @@ ha_innobase::innobase_get_index( "InnoDB could not find key no %u with name %s" " from dict cache for table %s", keynr, key ? key->name : "NULL", - m_prebuilt->table->name.m_name); + ib_table->name.m_name); } DBUG_RETURN(index); @@ -14014,20 +13834,12 @@ innodb_set_buf_pool_size(ulonglong buf_pool_size) } /*********************************************************************//** -Calculates the key number used inside MySQL for an Innobase index. We will -first check the "index translation table" for a match of the index to get -the index number. If there does not exist an "index translation table", -or not able to find the index in the translation table, then we will fall back -to the traditional way of looping through dict_index_t list to find a -match. In this case, we have to take into account if we generated a -default clustered index for the table +Calculates the key number used inside MySQL for an Innobase index. @return the key number used inside MySQL */ static int innobase_get_mysql_key_number_for_index( /*====================================*/ - INNOBASE_SHARE* share, /*!< in: share structure for index - translation table. */ const TABLE* table, /*!< in: table in MySQL data dictionary */ dict_table_t* ib_table,/*!< in: table in InnoDB data @@ -14058,27 +13870,8 @@ innobase_get_mysql_key_number_for_index( return(i); } - /* If index translation table exists, we will first check - the index through index translation table for a match. */ - if (share->idx_trans_tbl.index_mapping != NULL) { - for (i = 0; i < share->idx_trans_tbl.index_count; i++) { - if (share->idx_trans_tbl.index_mapping[i] == index) { - return(i); - } - } - - /* Print an error message if we cannot find the index - in the "index translation table". */ - if (index->is_committed()) { - sql_print_error("Cannot find index %s in InnoDB index" - " translation table.", index->name()); - } - } - - /* If we do not have an "index translation table", or not able - to find the index in the translation table, we'll directly find - matching index with information from mysql TABLE structure and - InnoDB dict_index_t list */ + /* Directly find matching index with information from mysql TABLE + structure and InnoDB dict_index_t list */ for (i = 0; i < table->s->keys; i++) { ind = dict_table_get_index_on_name( ib_table, table->key_info[i].name); @@ -14439,11 +14232,6 @@ ha_innobase::info_low( for (i = 0; i < table->s->keys; i++) { ulong j; - /* We could get index quickly through internal - index mapping with the index translation table. - The identity of index (match up index name with - that of table->key_info[i]) is already verified in - innobase_get_index(). */ dict_index_t* index = innobase_get_index(i); if (index == NULL) { @@ -14551,7 +14339,7 @@ ha_innobase::info_low( if (err_index) { errkey = innobase_get_mysql_key_number_for_index( - m_share, table, ib_table, err_index); + table, ib_table, err_index); } else { errkey = (unsigned int) ( (m_prebuilt->trx->error_key_num @@ -16547,104 +16335,6 @@ innobase_show_status( /* Success */ return(false); } - -/************************************************************************//** -Handling the shared INNOBASE_SHARE structure that is needed to provide table -locking. Register the table name if it doesn't exist in the hash table. */ -static -INNOBASE_SHARE* -get_share( -/*======*/ - const char* table_name) -{ - INNOBASE_SHARE* share; - - mysql_mutex_lock(&innobase_share_mutex); - - ulint fold = ut_fold_string(table_name); - - HASH_SEARCH(table_name_hash, innobase_open_tables, fold, - INNOBASE_SHARE*, share, - ut_ad(share->use_count > 0), - !strcmp(share->table_name, table_name)); - - if (share == NULL) { - - uint length = (uint) strlen(table_name); - - /* TODO: invoke HASH_MIGRATE if innobase_open_tables - grows too big */ - - share = reinterpret_cast( - my_malloc(//PSI_INSTRUMENT_ME, - sizeof(*share) + length + 1, - MYF(MY_FAE | MY_ZEROFILL))); - - share->table_name = reinterpret_cast( - memcpy(share + 1, table_name, length + 1)); - - HASH_INSERT(INNOBASE_SHARE, table_name_hash, - innobase_open_tables, fold, share); - - thr_lock_init(&share->lock); - - /* Index translation table initialization */ - share->idx_trans_tbl.index_mapping = NULL; - share->idx_trans_tbl.index_count = 0; - share->idx_trans_tbl.array_size = 0; - } - - ++share->use_count; - - mysql_mutex_unlock(&innobase_share_mutex); - - return(share); -} - -/************************************************************************//** -Free the shared object that was registered with get_share(). */ -static -void -free_share( -/*=======*/ - INNOBASE_SHARE* share) /*!< in/own: table share to free */ -{ - mysql_mutex_lock(&innobase_share_mutex); - -#ifdef UNIV_DEBUG - INNOBASE_SHARE* share2; - ulint fold = ut_fold_string(share->table_name); - - HASH_SEARCH(table_name_hash, innobase_open_tables, fold, - INNOBASE_SHARE*, share2, - ut_ad(share->use_count > 0), - !strcmp(share->table_name, share2->table_name)); - - ut_a(share2 == share); -#endif /* UNIV_DEBUG */ - - --share->use_count; - - if (share->use_count == 0) { - ulint fold = ut_fold_string(share->table_name); - - HASH_DELETE(INNOBASE_SHARE, table_name_hash, - innobase_open_tables, fold, share); - - thr_lock_delete(&share->lock); - - /* Free any memory from index translation table */ - ut_free(share->idx_trans_tbl.index_mapping); - - my_free(share); - - /* TODO: invoke HASH_MIGRATE if innobase_open_tables - shrinks too much */ - } - - mysql_mutex_unlock(&innobase_share_mutex); -} - /*********************************************************************//** Returns number of THR_LOCK locks used for one instance of InnoDB table. InnoDB no longer relies on THR_LOCK locks so 0 value is returned. diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 1a47dab423f..ab1d3bbeac3 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -23,35 +23,6 @@ this program; if not, write to the Free Software Foundation, Inc., system clustered index when there is no primary key. */ extern const char innobase_index_reserve_name[]; -/* Structure defines translation table between mysql index and InnoDB -index structures */ -struct innodb_idx_translate_t { - - ulint index_count; /*!< number of valid index entries - in the index_mapping array */ - - ulint array_size; /*!< array size of index_mapping */ - - dict_index_t** index_mapping; /*!< index pointer array directly - maps to index in InnoDB from MySQL - array index */ -}; - -/** InnoDB table share */ -typedef struct st_innobase_share { - THR_LOCK lock; - const char* table_name; /*!< InnoDB table name */ - uint use_count; /*!< reference count, - incremented in get_share() - and decremented in - free_share() */ - void* table_name_hash; - /*!< hash table chain node */ - innodb_idx_translate_t - idx_trans_tbl; /*!< index translation table between - MySQL and InnoDB */ -} INNOBASE_SHARE; - /** Prebuilt structures in an InnoDB table handle used within MySQL */ struct row_prebuilt_t; @@ -492,9 +463,6 @@ protected: THR_LOCK_DATA lock; - /** information for MySQL table locking */ - INNOBASE_SHARE* m_share; - /** buffer used in updates */ uchar* m_upd_buf; @@ -631,17 +599,6 @@ trx_t* innobase_trx_allocate( MYSQL_THD thd); /*!< in: user thread handle */ -/** Match index columns between MySQL and InnoDB. -This function checks whether the index column information -is consistent between KEY info from mysql and that from innodb index. -@param[in] key_info Index info from mysql -@param[in] index_info Index info from InnoDB -@return true if all column types match. */ -bool -innobase_match_index_columns( - const KEY* key_info, - const dict_index_t* index_info); - /*********************************************************************//** This function checks each index name for a table against reserved system default primary index name 'GEN_CLUST_INDEX'. If a name diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 6e318a040ca..d4a5a43ca37 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8883,12 +8883,6 @@ foreign_fail: log_append_on_checkpoint(NULL); - /* Invalidate the index translation table. In partitioned - tables, there is no share. */ - if (m_share) { - m_share->idx_trans_tbl.index_count = 0; - } - /* Tell the InnoDB server that there might be work for utility threads: */ diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 951c16394a7..348611217cb 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -3791,17 +3791,6 @@ row_merge_drop_indexes( ut_ad(prev); ut_a(table->fts); fts_drop_index(table, index, trx); - /* Since - INNOBASE_SHARE::idx_trans_tbl - is shared between all open - ha_innobase handles to this - table, no thread should be - accessing this dict_index_t - object. Also, we should be - holding LOCK=SHARED MDL on the - table even after the MDL - upgrade timeout. */ - /* We can remove a DICT_FTS index from the cache, because we do not allow ADD FULLTEXT INDEX From 68ebfb31f215247d2fa08c8ed97a320191afc179 Mon Sep 17 00:00:00 2001 From: sachin Date: Tue, 5 Jun 2018 15:14:19 +0530 Subject: [PATCH 04/39] MDEV-16166 RBR breaks with HA_ERR_KEY_NOT_FOUND upon DELETE from table... with spatial index So the issue is since it is spatial index , at the time of searching index for key (Rows_log_event::find_row) we use wrong field image we use Field::itRAW while we should be using Field::itMBR --- mysql-test/suite/rpl/r/rpl_row_spatial.result | 14 ++++++++++++++ mysql-test/suite/rpl/t/rpl_row_spatial.test | 17 +++++++++++++++++ sql/key.cc | 3 ++- 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/rpl/r/rpl_row_spatial.result create mode 100644 mysql-test/suite/rpl/t/rpl_row_spatial.test diff --git a/mysql-test/suite/rpl/r/rpl_row_spatial.result b/mysql-test/suite/rpl/r/rpl_row_spatial.result new file mode 100644 index 00000000000..8f546fc479e --- /dev/null +++ b/mysql-test/suite/rpl/r/rpl_row_spatial.result @@ -0,0 +1,14 @@ +include/master-slave.inc +[connection master] +CREATE TABLE t1 (g POINT NOT NULL, SPATIAL INDEX(g)); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 2)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 2)')); +DELETE FROM t1 where MBREqual(g, ST_GEOMFROMTEXT('Point(1 2)')); +select count(*) from t1; +count(*) +3 +DELETE FROM t1; +drop table t1; +include/rpl_end.inc diff --git a/mysql-test/suite/rpl/t/rpl_row_spatial.test b/mysql-test/suite/rpl/t/rpl_row_spatial.test new file mode 100644 index 00000000000..00c3dd7c54d --- /dev/null +++ b/mysql-test/suite/rpl/t/rpl_row_spatial.test @@ -0,0 +1,17 @@ +--source include/have_binlog_format_row.inc +--source include/master-slave.inc + +CREATE TABLE t1 (g POINT NOT NULL, SPATIAL INDEX(g)); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 1)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(1 2)')); +INSERT INTO t1 VALUES (ST_GEOMFROMTEXT('Point(2 2)')); +DELETE FROM t1 where MBREqual(g, ST_GEOMFROMTEXT('Point(1 2)')); + +--sync_slave_with_master +select count(*) from t1; + +--connection master +DELETE FROM t1; +drop table t1; +--source include/rpl_end.inc diff --git a/sql/key.cc b/sql/key.cc index 700bf6a05a6..7e5a3309b10 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -145,7 +145,8 @@ void key_copy(uchar *to_key, uchar *from_record, KEY *key_info, { key_length-= HA_KEY_BLOB_LENGTH; length= min(key_length, key_part->length); - uint bytes= key_part->field->get_key_image(to_key, length, Field::itRAW); + uint bytes= key_part->field->get_key_image(to_key, length, + key_info->flags & HA_SPATIAL ? Field::itMBR : Field::itRAW); if (with_zerofill && bytes < length) bzero((char*) to_key + bytes, length - bytes); to_key+= HA_KEY_BLOB_LENGTH; From 1e37fa70bdab8749dd5ffd6b71ed53ca78671b10 Mon Sep 17 00:00:00 2001 From: Elena Stepanova Date: Sat, 4 Aug 2018 03:06:27 +0300 Subject: [PATCH 05/39] Updated list of unstable tests for 10.1.35 release --- mysql-test/unstable-tests | 173 ++++++++++++++++++++++++-------------- 1 file changed, 111 insertions(+), 62 deletions(-) diff --git a/mysql-test/unstable-tests b/mysql-test/unstable-tests index 9b00579944c..c59b9725754 100644 --- a/mysql-test/unstable-tests +++ b/mysql-test/unstable-tests @@ -23,7 +23,7 @@ # ############################################################################## -# Based on 10.1 c22ab56f0d690feee471e173a3d95acb642cd6dc +# Based on 10.1 701f0b8e366f957e8256e4741ca48424c84b7234 main.alter_table : Modified in 10.1.34 main.alter_table_trans : MDEV-12084 - timeout @@ -31,43 +31,62 @@ main.analyze_stmt_slow_query_log : MDEV-12237 - Wrong result main.assign_key_cache : Added in 10.1.34 main.assign_key_cache_debug : Added in 10.1.34 main.auth_named_pipe : MDEV-14724 - System error 2 -main.connect : Modified in 10.1.33 -main.connect_debug : Added in 10.1.33 +main.auto_increment : Modified in 10.1.35 +main.bootstrap : Modified in 10.1.35 +main.connect_debug : Added in 10.0.36 +main.count_distinct2 : MDEV-11768 - timeout main.create_delayed : MDEV-10605 - failed with timeout main.create_or_replace : Modified in 10.1.34 -main.ctype_ucs : Modified in 10.1.33 -main.ctype_utf16le : MDEV-10675: timeout or extra warnings -main.ctype_utf8mb4 : Modified in 10.1.33 -main.grant : Modified in 10.1.34 -main.grant_not_windows : Added in 10.1.34 +main.ctype_binary : Modified in 10.1.35 +main.ctype_eucjpms : Modified in 10.1.35 +main.ctype_euckr : Modified in 10.1.35 +main.ctype_gbk : Modified in 10.1.35 +main.ctype_latin1 : Modified in 10.1.35 +main.ctype_ucs : Modified in 10.1.35 +main.ctype_ujis : Modified in 10.1.35 +main.ctype_utf16le : Modified in 10.1.35 +main.ctype_utf16 : MDEV-10675: timeout or extra warnings; modified in 10.1.35 +main.ctype_utf32 : Modified in 10.1.35 +main.ctype_utf8 : Modified in 10.1.35 +main.ctype_utf8mb4 : Modified in 10.1.35 +main.debug_sync : MDEV-10607 - internal error +main.derived : Modified in 10.1.35 +main.derived_opt : MDEV-11768 - timeout main.events_2 : MDEV-13277 - Server crash main.events_bugs : MDEV-12892 - Crash in fill_schema_processlist main.events_slowlog : MDEV-12821 - Wrong result main.events_restart : MDEV-12236 - Server shutdown problem -main.func_misc : Modified in 10.1.33 -main.func_str : Modified in 10.1.33 +main.gis : MDEV-13411 - wrong result on P8 +main.grant : Modified in 10.1.35 +main.grant_not_windows : Added in 10.1.34 +main.grant2 : Modified in 10.0.36 +main.having : Modified in 10.1.35 main.host_cache_size_functionality : MDEV-10606 - sporadic failure on shutdown main.index_intersect_innodb : MDEV-10643 - failed with timeout main.index_merge_innodb : MDEV-7142 - Wrong execution plan, timeout with valgrind main.innodb_mysql_lock : MDEV-7861 - sporadic lock detection failure main.insert_select : Modified in 10.1.34 +main.join : Modified in 10.1.35 +main.join_cache : Modified in 10.1.35 +main.join_outer : Modified in 10.1.35 main.kill_processlist-6619 : MDEV-10793 - wrong result in processlist main.limit : Modified in 10.1.34 +main.log_tables-big : MDEV-13408 - wrong result +main.max_statement_time : Modified in 10.1.35 main.mdev-504 : MDEV-10607 - sporadic "can't connect" -main.mdev375 : MDEV-10607 - sporadic "can't connect"; modified in 10.1.33 +main.mdev375 : MDEV-10607 - sporadic "can't connect" main.merge : MDEV-10607 - sporadic "can't connect" main.myisam : Modified in 10.1.34 -main.myisam_recover : Modified in 10.1.33 main.mysql : Modified in 10.1.34 main.mysql_client_test_nonblock : MDEV-15096 - exec failed main.mysql_cp932 : Modified in 10.1.34 main.mysql_upgrade_noengine : MDEV-14355 - Plugin is busy main.mysqldump : Modified in 10.1.34 +main.mysqlhotcopy_myisam : MDEV-10995 - test hangs on debug build main.mysqlslap : MDEV-11801 - timeout; modified in 10.1.34 main.mysqltest : MDEV-9269 - fails on Alpha main.olap : Modified in 10.1.34 main.order_by_optimizer_innodb : MDEV-10683 - wrong execution plan -main.parser : Modified in 10.1.33 main.partition_debug_sync : MDEV-15669 - Deadlock found when trying to get lock main.partition_innodb_plugin : MDEV-12901 - Valgrind warnings main.ps : MDEV-11017 - sporadic wrong Prepared_stmt_count; modified in 10.1.34 @@ -75,42 +94,48 @@ main.query_cache : MDEV-12895 - Wrong result main.query_cache_debug : MDEV-15281 - Resize or similar command in progress main.range_vs_index_merge_innodb : MDEV-15283 - Server has gone away main.read_only_innodb : Modified in 10.1.34 -main.rename : Modified in 10.1.34 +main.rename : Modified in 10.1.35 main.selectivity : Modified in 10.1.34 main.set_statement : MDEV-13183 - Wrong result main.show_explain : MDEV-10674 - sporadic failure main.sp : Modified in 10.1.34 -main.sp-destruct : Modified in 10.1.33 -main.sp-innodb : Modified in 10.1.33 +main.sp-innodb : Modified in 10.0.36 +main.sp_notembedded : MDEV-10607 - internal error main.sp-security : MDEV-10607 - sporadic "can't connect" -main.stat_tables_par_innodb : MDEV-14155 - Wrong rounding -main.statistics : Modified in 10.1.33 +main.stat_tables : Modified in 10.1.35 +main.stat_tables_par_innodb : MDEV-14155 - wrong rounding +main.statistics : Modified in 10.1.35 main.statistics_close : Added in 10.1.34 main.status : MDEV-8510 - sporadic wrong result -main.subselect4 : Modified in 10.1.33 +main.subselect : Modified in 10.1.35 main.subselect_innodb : MDEV-10614 - sporadic wrong results -main.subselect_sj : Modified in 10.1.33 -main.subselect_sj2_mat : Modified in 10.1.34 -main.symlink-aria-11902 : MDEV-15098 - error 40 from storage engine -main.symlink-myisam-11902 : MDEV-15098 - error 40 from storage engine +main.subselect_sj : Modified in 10.0.36 +main.subselect_sj_mat : Modified in 10.1.35 +main.subselect_sj2_mat : Modified in 10.1.35 +main.subselect4 : Modified in 10.0.36 main.tc_heuristic_recover : MDEV-15200 - wrong error on mysqld_stub_cmd main.trigger : Modified in 10.1.34 main.type_blob : MDEV-15195 - Wrong result +main.type_datetime : MDEV-14322 - wrong result main.type_datetime_hires : MDEV-10687 - timeout -main.variables : Modified in 10.1.33 -main.view : Modified in 10.1.33 +main.union : Modified in 10.1.35 +main.xa : MDEV-11769 - lock wait timeout #---------------------------------------------------------------- archive.archive_bitfield : MDEV-11771 - Extra warning -archive.discover : MDEV-10510 - Table is marked as crashed +archive.archive_symlink : MDEV-12170 - unexpected error on rmdir +archive.discover : MDEV-10510 - Table is marked as crashed archive.mysqlhotcopy_archive : MDEV-14726 - Table is marked as crashed +archive-test_sql_discovery.discover : MDEV-16817 - Table marked as crashed + #---------------------------------------------------------------- binlog.binlog_commit_wait : MDEV-10150 - Error: too much time elapsed binlog.binlog_flush_binlogs_delete_domain : MDEV-14431 - Wrong error code binlog.binlog_killed : MDEV-12925 - Wrong result +binlog.binlog_tmp_table_row : Added in 10.1.35 binlog.binlog_xa_recover : MDEV-8517 - Extra checkpoint #---------------------------------------------------------------- @@ -125,21 +150,7 @@ binlog_encryption.rpl_typeconv : MDEV-14362 - Lost connection to MySQL serve #---------------------------------------------------------------- -connect.jdbc : Included file modified in 10.1.33 -connect.jdbc_new : Included file modified in 10.1.33 -connect.jdbc_oracle : Included file modified in 10.1.33 -connect.jdbc_postgresql : Modified in 10.1.33 -connect.json_java_2 : Included file modified in 10.1.33 -connect.json_java_3 : Included file modified in 10.1.33 -connect.json_mongo_c : Included file modified in 10.1.33 -connect.json_udf : Modified in 10.1.33 -connect.mongo_c : Included file modified in 10.1.33 -connect.mongo_java_2 : Included file modified in 10.1.33 -connect.mongo_java_3 : Included file modified in 10.1.33 -connect.mongo_test : Modified in 10.1.33 connect.pivot : MDEV-14803 - failed to discover table -connect.tbl_thread : Modified in 10.1.33 -connect.vcol : Added in 10.1.33 connect.zip : MDEV-13884 - Wrong result #---------------------------------------------------------------- @@ -150,11 +161,11 @@ encryption.encrypt_and_grep : MDEV-13765 - Wrong result encryption.innodb-bad-key-change : Modified in 10.1.34 encryption.innodb-bad-key-change2 : Modified in 10.1.34 encryption.innodb-bad-key-change4 : Modified in 10.1.34 +encryption.innodb-checksum-algorithm : MDEV-16896 - Server crash encryption.innodb-compressed-blob : MDEV-14728 - Unable to get certificate; modified in 10.1.34 encryption.innodb-discard-import : Modified in 10.1.34 encryption.innodb-encryption-disable : Modified in 10.1.34 -encryption.innodb_encryption_discard_import : MDEV-16116 - Wrong result; modified in 10.1.33 -encryption.innodb_encryption_filekeys : Modified in 10.1.33 +encryption.innodb_encryption_discard_import : MDEV-16116 - Wrong result encryption.innodb_encryption-page-compression : MDEV-12630 - crash or assertion failure encryption.innodb_encryption_row_compressed : MDEV-16113 - Crash encryption.innodb_first_page : MDEV-10689 - Crash @@ -163,10 +174,10 @@ encryption.innodb-force-corrupt : Modified in 10.1.34 encryption.innodb_lotoftables : MDEV-16111 - Wrong result encryption.innodb-missing-key : Modified in 10.1.34 encryption.innodb-page_encryption : MDEV-10641 - mutex problem -encryption.innodb-read-only : MDEV-14728 - Unable to get certificate +encryption.innodb-read-only : MDEV-14728 - Unable to get certificate; MDEV-16563 - Crash on startup encryption.innodb-redo-badkey : MDEV-12898 - Server hang on startup; modified in 10.1.34 encryption.innodb-redo-nokeys : Modified in 10.1.34 -encryption.innodb-remove-encryption : MDEV-16493 - Timeout in wait condition; a dded in 10.1.33 +encryption.innodb-remove-encryption : MDEV-16493 - Timeout in wait condition encryption.innodb_scrub : MDEV-8139 - scrubbing tests need fixing encryption.innodb_scrub_background : MDEV-8139 - scrubbing tests need fixing encryption.innodb_scrub_compressed : MDEV-8139 - scrubbing tests need fixing @@ -175,9 +186,12 @@ encryption.innodb_scrub_compressed : MDEV-8139 - scrubbing tests need f engines/iuds.* : Not maintained in timely manner engines/funcs.* : Not maintained in timely manner +engines/rr_trx.* : MDEV-10998 - tests not maintained #---------------------------------------------------------------- +federated.assisted_discovery : Include file modified in 10.0.36 +federated.federated_bug_35333 : MDEV-13410 - Wrong result federated.federated_bug_585688 : MDEV-12907 - Valgrind, MDEV-14805 - server crash federated.federated_innodb : MDEV-10617, MDEV-10417 - Wrong checksum, timeouts, fails on Mips federated.federated_partition : MDEV-10417 - Fails on Mips @@ -186,11 +200,14 @@ federated.federatedx : MDEV-10617 - Wrong checksum, timeouts #---------------------------------------------------------------- +funcs_1.is_engines_federated : Include file modified in 10.0.36 +funcs_1.memory_views : MDEV-11773 - timeout funcs_1.processlist_val_no_prot : MDEV-11223 - Wrong result funcs_1.processlist_val_ps : MDEV-12175 - Wrong plan funcs_2.memory_charset : MDEV-10290 - Timeout funcs_2.myisam_charset : MDEV-11535 - Timeout +funcs_2/charset.* : MDEV-10999 - test not maintained #---------------------------------------------------------------- @@ -215,13 +232,18 @@ handler.ps : Added in 10.1.34 #---------------------------------------------------------------- -innodb.alter_partitioned_xa : Added in 10.1.33 +heap.heap_auto_increment : Modified in 10.1.35 + +#---------------------------------------------------------------- + +innodb.alter_partitioned_xa : Added in 10.0.36 innodb.binlog_consistent : MDEV-10618 - Server fails to start innodb.doublewrite : MDEV-12905 - Lost connection to MySQL server +innodb.group_commit_crash : MDEV-11770 - checksum mismatch +innodb.group_commit_crash_no_optimize_thread : MDEV-11770 - checksum mismatch innodb.innodb-64k-crash : MDEV-13872 - Failure and crash on startup innodb.innodb-alter : Added in 10.1.34 innodb.innodb-alter-debug : MDEV-13182 - InnoDB: adjusting FSP_SPACE_FLAGS -innodb.innodb-alter-nullable : Modified in 10.1.33 innodb.innodb-alter-table : MDEV-10619 - Testcase timeout innodb.innodb-blob : MDEV-12053 - Client crash; modified in 10.1.34 innodb.innodb_bug14147491 : MDEV-11808 - wrong error codes @@ -232,24 +254,32 @@ innodb.innodb_defragment_small : Modified in 10.1.34 innodb.innodb-fk : MDEV-13832 - Assertion failure on shutdown innodb.innodb_max_recordsize_64k : MDEV-15203 - wrong result innodb.innodb-mdev7046 : Modified in 10.1.34 +innodb.innodb_monitor : MDEV-10939 - Testcase timeout innodb.innodb-page_compression_default : Modified in 10.1.34 innodb.innodb-page_compression_lzma : MDEV-14353 - wrong result on Fedora 25 innodb.innodb-page_compression_snappy : Modified in 10.1.34 innodb.innodb-page_compression_zip : MDEV-10641 - mutex problem innodb.innodb_stats : MDEV-10682 - wrong result innodb.innodb_sys_semaphore_waits : MDEV-10331 - wrong result +innodb.innodb-wl5522 : Modified in 10.1.35 innodb.innodb_zip_innochecksum2 : MDEV-13882 - Warning: difficult to find free blocks innodb.lock_deleted : Added in 10.1.34 innodb.log_file_size : MDEV-15668 - Not found pattern innodb.recovery_shutdown : MDEV-15671 - Warning: database page corruption innodb.rename_table : Added in 10.1.34 innodb.row_format_redundant : MDEV-15192 - Trying to access missing tablespace +innodb.sp_temp_table : MDEV-16647 - Could not remove temporary table innodb.table_definition_cache_debug : MDEV-14206 - Extra warning innodb.table_flags : MDEV-14363 - Operating system error number 2 +innodb.xa_recovery : MDEV-15279 - mysqld got exception #---------------------------------------------------------------- innodb_fts.basic : Added in 10.1.34 +innodb_fts.fts_kill_query : Added in 10.1.35 +innodb_fts.innodb-fts-fic : MDEV-14154 - Assertion failure +innodb_fts.innodb_fts_misc_debug : MDEV-14156 - Unexpected warning +innodb_fts.sync_ddl : Added in 10.1.35 #---------------------------------------------------------------- @@ -257,11 +287,10 @@ maria.alter : Modified in 10.1.34 maria.insert_select : MDEV-12757 - Timeout maria.insert_select-7314 : MDEV-16492 - Timeout maria.lock : Modified in 10.1.34 -maria.maria : MDEV-14430 - Wrong result; modified in 10.1.34 +maria.maria : MDEV-14430 - Wrong result; modified in 10.1.35 #---------------------------------------------------------------- -mariabackup.absolute_ibdata_paths : Added in 10.1.33 mariabackup.backup_ssl : Added in 10.1.34 mariabackup.incremental_encrypted : MDEV-15667 - Timeout mariabackup.mdev-14447 : MDEV-15201 - Timeout @@ -291,37 +320,43 @@ multi_source.status_vars : MDEV-4632 - failed while waiting for Slave_received_h #---------------------------------------------------------------- -parts.partition_alter_innodb : Include file modified in 10.1.33 -parts.partition_alter_maria : Include file modified in 10.1.33 -parts.partition_alter_myisam : Include file modified in 10.1.33 +parts.alter_data_directory_innodb : Added in 10.1.35 parts.partition_alter2_2_maria : MDEV-14364 - Lost connection to MySQL server during query parts.partition_auto_increment_archive : MDEV-16491 - Table marked as crashed parts.partition_auto_increment_maria : MDEV-14430 - Wrong result -parts.partition_debug_innodb : MDEV-15095 - table does not exist +parts.partition_exch_qa_10 : MDEV-11765 - wrong result parts.partition_innodb_status_file : MDEV-12901 - Valgrind +parts.truncate_locked : Added in 10.1.35 #---------------------------------------------------------------- perfschema.func_file_io : MDEV-5708 - fails for s390x perfschema.func_mutex : MDEV-5708 - fails for s390x -perfschema.hostcache_ipv4_max_con : Modified in 10.1.33 -perfschema.hostcache_ipv6_max_con : Modified in 10.1.33 +perfschema.hostcache_ipv6_ssl : MDEV-10696 - crash on shutdown perfschema.partition : Added in 10.1.34 perfschema.privilege_table_io : MDEV-13184 - Extra lines +perfschema.rpl_gtid_func : MDEV-16897 - Wrong result perfschema.socket_summary_by_event_name_func : MDEV-10622 - Socket summary tables do not match perfschema.stage_mdl_global : MDEV-11803 - wrong result on slow builders +perfschema.stage_mdl_procedure : MDEV-11545 - Wrong result perfschema.stage_mdl_table : MDEV-12638 - Wrong result perfschema.threads_mysql : MDEV-10677 - sporadic wrong result +perfschema_stress.* : MDEV-10996 - tests not maintained + #---------------------------------------------------------------- plugins.feedback_plugin_send : MDEV-7932 - ssl failed for url -plugins.processlist : Added in 10.1.34 +plugins.processlist : Added in 10.1.35 plugins.server_audit : MDEV-9562 - crashes on sol10-sparc; modified in 10.1.34 plugins.thread_pool_server_audit : MDEV-9562 - crashes on sol10-sparc #---------------------------------------------------------------- +roles.create_and_grant_role : MDEV-11772 - wrong result + +#---------------------------------------------------------------- + rpl.last_insert_id : MDEV-10625 - warnings in error log rpl.rename : Added in 10.1.34 rpl.rpl_auto_increment : MDEV-10417 - Fails on Mips @@ -332,6 +367,7 @@ rpl.rpl_colSize : MDEV-16112 - Server crash rpl.rpl_ddl : MDEV-10417 - Fails on Mips rpl.rpl_domain_id_filter_io_crash : MDEV-14357 - Wrong result rpl.rpl_domain_id_filter_restart : MDEV-10684 - Wrong result +rpl.rpl_drop_db_fail : MDEV-16898 - Slave fails to start rpl.rpl_gtid_basic : MDEV-10681 - server startup problem rpl.rpl_gtid_crash : MDEV-9501 - Warning: failed registering on master rpl.rpl_gtid_delete_domain : MDEV-14463 - Timeout in include @@ -343,6 +379,7 @@ rpl.rpl_innodb_bug30888 : MDEV-10417 - Fails on Mips rpl.rpl_insert : MDEV-9329 - Fails on Ubuntu/s390x rpl.rpl_insert_delayed : MDEV-9329 - Fails on Ubuntu/s390x rpl.rpl_insert_id : MDEV-15197 - Wrong result +rpl.rpl_insert_id_pk : MDEV-16567 - Assertion failure rpl.rpl_insert_ignore : MDEV-14365 - Lost connection to MySQL server during query rpl.rpl_invoked_features : MDEV-10417 - Fails on Mips rpl.rpl_mariadb_slave_capability : MDEV-11018 - sporadic wrong events in binlog @@ -350,15 +387,17 @@ rpl.rpl_mdev6020 : MDEV-10417 - Fails on Mips rpl.rpl_mixed_implicit_commit_binlog : Modified in 10.1.34 rpl.rpl_mixed_mixing_engines : MDEV-14489 - Sync slave with master failed rpl.rpl_non_direct_mixed_mixing_engines : MDEV-14489 - Sync slave with master failed +rpl.rpl_non_direct_row_mixing_engines : MDEV-16561 - Timeout in master pos wait rpl.rpl_non_direct_stm_mixing_engines : MDEV-14489 - Sync slave with master failed rpl.rpl_parallel : MDEV-10653 - Timeouts rpl.rpl_parallel_mdev6589 : MDEV-12979 - Assertion failure rpl.rpl_parallel_multilevel2 : MDEV-14723 - Timeout -rpl.rpl_parallel_optimistic : MDEV-10511 - Timeout; modified in 10.1.34 +rpl.rpl_parallel_optimistic : MDEV-10511 - Timeout; modified in 10.1.35 rpl.rpl_parallel_retry : MDEV-11119 - Server crash rpl.rpl_parallel_temptable : MDEV-10356 - Crash in close_thread_tables rpl.rpl_partition_innodb : MDEV-10417 - Fails on Mips rpl.rpl_password_boundaries : MDEV-11534 - Slave IO warnings +rpl.rpl_row_basic_11bugs : MDEV-12171 - Server failed to start rpl.rpl_row_basic_2myisam : MDEV-13875 - command "diff_files" failed rpl.rpl_row_drop_create_temp_table : MDEV-14487 - Wrong result rpl.rpl_row_img_blobs : MDEV-13875 - command "diff_files" failed @@ -384,6 +423,8 @@ rpl.rpl_sync : MDEV-10633 - Database page corruption rpl.rpl_temporary_error2 : MDEV-10634 - Wrong number of retries rpl.sec_behind_master-5114 : MDEV-13878 - Wrong result +rpl/extra/rpl_tests.* : MDEV-10994 - tests not maintained + #---------------------------------------------------------------- spider.* : MDEV-9329 - tests are too memory-consuming @@ -393,6 +434,7 @@ spider/bg.direct_aggregate_part : MDEV-7098 - Trying to unlock mutex that wasn't spider/bg.ha : MDEV-9329 - failures on s390x spider/bg.ha_part : MDEV-9329 - Fails on Ubuntu/s390x spider/bg.spider_fixes : MDEV-7098 -Mutex problem, MDEV-9329 - failures on s390x +spider/bg.spider_fixes_part : MDEV-7098 - Trying to unlock mutex that wasn't locked spider/bg.spider3_fixes : MDEV-12639 - Packets out of order spider/bg.vp_fixes : MDEV-9329 - Fails on Ubuntu/s390x @@ -415,11 +457,7 @@ stress.ddl_innodb : MDEV-10635 - Testcase timeout sys_vars.autocommit_func2 : MDEV-9329 - Fails on Ubuntu/s390x sys_vars.keep_files_on_create_basic : MDEV-10676 - timeout sys_vars.log_slow_admin_statements_func : MDEV-12235 - Server crash -sys_vars.max_prepared_stmt_count_basic : Modified in 10.1.33 sys_vars.rpl_init_slave_func : MDEV-10149 - wrong results -sys_vars.sysvars_innodb : Opt file modified in 10.1.33 -sys_vars.sysvars_server_embedded : Opt file added in 10.1.33 -sys_vars.sysvars_server_notembedded : Opt file added in 10.1.33 sys_vars.thread_cache_size_func : MDEV-11775 - Wrong result sys_vars.wait_timeout_func : MDEV-12896 - Wrong result @@ -438,18 +476,29 @@ tokudb.hotindex-insert-0 : MDEV-15271 - Timeout tokudb.hotindex-insert-1 : MDEV-13870 - Lost connection to MySQL server tokudb.hotindex-update-0 : MDEV-15198 - Timeout tokudb.hotindex-update-1 : MDEV-12640 - Crash +tokudb.locks-select-update-1 : MDEV-13406 - Lock wait timeout tokudb.rows-32m-rand-insert : MDEV-12640 - Crash tokudb.rows-32m-seq-insert : MDEV-12640 - Crash tokudb.savepoint-5 : MDEV-15280 - Wrong result tokudb.type_datetime : MDEV-15193 - Wrong result +tokudb_backup.* : MDEV-11001 - tests don't work + tokudb_bugs.checkpoint_lock : MDEV-10637 - Wrong processlist output tokudb_bugs.checkpoint_lock_3 : MDEV-10637 - Wrong processlist output -tokudb_bugs.db917 : Modified in 10.1.33 +tokudb_bugs.frm_store : MDEV-12823 - Valgrind +tokudb_bugs.frm_store2 : MDEV-12823 - Valgrind +tokudb_bugs.frm_store3 : MDEV-12823 - Valgrind tokudb_bugs.xa : MDEV-11804 - Lock wait timeout +tokudb_rpl.* : MDEV-11001 - tests don't work +tokudb_sys_vars.* : MDEV-11001 - tests don't work +rpl-tokudb.* : MDEV-14354 - Tests fail with tcmalloc + #---------------------------------------------------------------- +unit.* : suite.pm modified in 10.1.35 + unit.lf : MDEV-12897 - Signal 11 thrown unit.ma_test_loghandler : MDEV-10638 - record read not ok unit.my_atomic : MDEV-15670 - Signal 11 thrown @@ -458,10 +507,10 @@ unit.my_atomic : MDEV-15670 - Signal 11 thrown vcol.not_supported : MDEV-10639 - Testcase timeout vcol.vcol_keys_innodb : MDEV-10639 - Testcase timeout +vcol.vcol_misc : MDEV-16651 - Wrong error message; modified in 10.1.35 #---------------------------------------------------------------- -wsrep.binlog_format : MDEV-11532 - WSREP has not yet prepared node wsrep.foreign_key : MDEV-14725 - WSREP has not yet prepared node wsrep.mdev_6832 : MDEV-14195 - Failure upon check-testcase wsrep.pool_of_threads : MDEV-12234 - Library problem on Power From 50c426200224a4527e84052aa2ab32be893f43f4 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 4 Aug 2018 22:53:16 +0100 Subject: [PATCH 06/39] MDEV-16544 - crash in ha_sphinx::create() Use table_arg that was passed to the function, instead of dereferencing this->table, which is a NULL pointer. --- storage/sphinx/ha_sphinx.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/sphinx/ha_sphinx.cc b/storage/sphinx/ha_sphinx.cc index 3f6770b5d26..b496450c5d6 100644 --- a/storage/sphinx/ha_sphinx.cc +++ b/storage/sphinx/ha_sphinx.cc @@ -3440,7 +3440,7 @@ int ha_sphinx::create ( const char * name, TABLE * table_arg, HA_CREATE_INFO * ) if ( table_arg->s->keys!=1 || table_arg->key_info[0].user_defined_key_parts!=1 || - strcasecmp ( table_arg->key_info[0].key_part[0].field->field_name, table->field[2]->field_name ) ) + strcasecmp ( table_arg->key_info[0].key_part[0].field->field_name, table_arg->field[2]->field_name ) ) { my_snprintf ( sError, sizeof(sError), "%s: there must be an index on '%s' column", name, table_arg->field[2]->field_name ); From 9419908f3889e20d8edd299ca714fd779613cf5e Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Sat, 4 Aug 2018 05:57:06 +0530 Subject: [PATCH 07/39] MDEV-15433: Optimizer does not use group by optimization with distinct After the commit b76b69cd5fe634d8ddb9406aa2c82ef2a375b4d8 loose index scan for queries with DISTINCT stopped working. That is why that commit has to be reverted. Additionally this patch fixes the problem of MDEV-10880. --- mysql-test/r/bench_count_distinct.result | 2 +- mysql-test/r/distinct.result | 2 +- mysql-test/r/explain_json.result | 18 +++--- mysql-test/r/group_min_max.result | 63 ++++++++++++------- .../suite/vcol/r/vcol_select_innodb.result | 2 +- .../suite/vcol/r/vcol_select_myisam.result | 2 +- mysql-test/t/group_min_max.test | 27 ++++++++ sql/sql_select.cc | 10 ++- 8 files changed, 89 insertions(+), 37 deletions(-) diff --git a/mysql-test/r/bench_count_distinct.result b/mysql-test/r/bench_count_distinct.result index 79e12afd237..8b67e4be38a 100644 --- a/mysql-test/r/bench_count_distinct.result +++ b/mysql-test/r/bench_count_distinct.result @@ -5,7 +5,7 @@ count(distinct n) 100 explain extended select count(distinct n) from t1; id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index NULL n 4 NULL 200 100.00 Using index +1 SIMPLE t1 range NULL n 4 NULL 10 100.00 Using index for group-by Warnings: Note 1003 select count(distinct `test`.`t1`.`n`) AS `count(distinct n)` from `test`.`t1` drop table t1; diff --git a/mysql-test/r/distinct.result b/mysql-test/r/distinct.result index b5e8cefca69..d6e5a69e217 100644 --- a/mysql-test/r/distinct.result +++ b/mysql-test/r/distinct.result @@ -212,7 +212,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL PRIMARY 4 NULL 1 Using index explain SELECT distinct a from t3 order by a desc limit 2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t3 index NULL a 5 NULL 2 Using index +1 SIMPLE t3 index NULL a 5 NULL 40 Using index explain SELECT distinct a,b from t3 order by a+1; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t3 ALL NULL NULL NULL NULL 204 Using temporary; Using filesort diff --git a/mysql-test/r/explain_json.result b/mysql-test/r/explain_json.result index 9e5515f3cfa..0abbda352b7 100644 --- a/mysql-test/r/explain_json.result +++ b/mysql-test/r/explain_json.result @@ -1030,10 +1030,10 @@ Table Op Msg_type Msg_text test.t1 analyze status Table is already up to date explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 65 Using where; Using index for group-by (scanning) explain format=json select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); EXPLAIN { @@ -1041,14 +1041,14 @@ EXPLAIN "select_id": 1, "table": { "table_name": "t1", - "access_type": "index", - "key": "idx_t1_2", + "access_type": "range", + "key": "idx_t1_1", "key_length": "147", "used_key_parts": ["a1", "a2", "b"], - "rows": 128, + "rows": 17, "filtered": 100, "attached_condition": "((t1.b = 'a') and (t1.a2 >= 'b'))", - "using_index": true + "using_index_for_group_by": true } } } @@ -1059,14 +1059,14 @@ EXPLAIN "select_id": 1, "table": { "table_name": "t1", - "access_type": "index", + "access_type": "range", "key": "idx_t1_1", "key_length": "163", "used_key_parts": ["a1", "a2", "b", "c"], - "rows": 128, + "rows": 65, "filtered": 100, "attached_condition": "((t1.b = 'a') and (t1.c = 'i121') and (t1.a2 >= 'b'))", - "using_index": true + "using_index_for_group_by": "scanning" } } } diff --git a/mysql-test/r/group_min_max.result b/mysql-test/r/group_min_max.result index cd7f1014ec0..ec3f4d9bf99 100644 --- a/mysql-test/r/group_min_max.result +++ b/mysql-test/r/group_min_max.result @@ -1707,13 +1707,13 @@ select a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c') group by a1 a1 a2 b explain select distinct a1,a2,b from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by explain extended select distinct a1,a2,b,c from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 100.00 Using where; Using index +1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 50.78 Using where; Using index Warnings: Note 1003 select distinct `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c` from `test`.`t1` where ((`test`.`t1`.`b` = 'a') and (`test`.`t1`.`c` = 'i121') and (`test`.`t1`.`a2` >= 'b')) explain select distinct a1,a2,b from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); @@ -1724,13 +1724,13 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index explain select distinct a1,a2,b from t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL idx_t2_2 146 NULL # Using index +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using index for group-by explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL idx_t2_2 146 NULL # Using where; Using index +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by explain extended select distinct a1,a2,b,c from t2 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 100.00 Using where; Using index +1 SIMPLE t2 index NULL idx_t2_1 163 NULL 164 50.61 Using where; Using index Warnings: Note 1003 select distinct `test`.`t2`.`a1` AS `a1`,`test`.`t2`.`a2` AS `a2`,`test`.`t2`.`b` AS `b`,`test`.`t2`.`c` AS `c` from `test`.`t2` where ((`test`.`t2`.`b` = 'a') and (`test`.`t2`.`c` = 'i121') and (`test`.`t2`.`a2` >= 'b')) explain select distinct a1,a2,b from t2 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); @@ -1855,7 +1855,7 @@ c e d e explain select distinct a1,a2,b from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using index for group-by explain select distinct a1,a2,b from t1 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by @@ -1870,7 +1870,7 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by; Using temporary; Using filesort explain select distinct a1,a2,b from t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL idx_t2_2 146 NULL # Using index +1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using index for group-by explain select distinct a1,a2,b from t2 where (a2 >= 'b') and (b = 'a') group by a1,a2,b; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t2 range NULL idx_t2_1 146 NULL # Using where; Using index for group-by @@ -1953,10 +1953,10 @@ b a explain select count(distinct a1,a2,b) from t1 where (a2 >= 'b') and (b = 'a'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 147 NULL 17 Using where; Using index for group-by explain select count(distinct a1,a2,b,c) from t1 where (a2 >= 'b') and (b = 'a') and (c = 'i121'); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_1 163 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 163 NULL 65 Using where; Using index for group-by (scanning) explain extended select count(distinct a1,a2,b) from t1 where (a1 > 'a') and (a2 > 'a') and (b = 'c'); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE t1 range idx_t1_0,idx_t1_1,idx_t1_2 idx_t1_1 147 NULL 14 100.00 Using where; Using index for group-by @@ -2173,7 +2173,7 @@ c d explain select distinct a1 from t1 where a2 = 'b'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx_t1_2 147 NULL 128 Using where; Using index +1 SIMPLE t1 range NULL idx_t1_1 130 NULL 5 Using where; Using index for group-by select distinct a1 from t1 where a2 = 'b'; a1 a @@ -2283,7 +2283,7 @@ INSERT INTO t1 (a) VALUES ('SOUTH EAST'), ('SOUTH WEST'), ('WESTERN'); EXPLAIN SELECT DISTINCT a,a FROM t1 ORDER BY a; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 66 NULL 11 Using index +1 SIMPLE t1 range NULL a 66 NULL 6 Using index for group-by SELECT DISTINCT a,a FROM t1 ORDER BY a; a a @@ -2499,7 +2499,7 @@ INSERT INTO t1 VALUES (4), (2), (1), (2), (2), (4), (1), (4); EXPLAIN SELECT DISTINCT(a) FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx 5 NULL 16 Using index +1 SIMPLE t1 range NULL idx 5 NULL 9 Using index for group-by SELECT DISTINCT(a) FROM t1; a 1 @@ -2507,7 +2507,7 @@ a 4 EXPLAIN SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL idx 5 NULL 16 Using index +1 SIMPLE t1 range NULL idx 5 NULL 9 Using index for group-by SELECT SQL_BIG_RESULT DISTINCT(a) FROM t1; a 1 @@ -2646,7 +2646,7 @@ INSERT INTO t1 SELECT * FROM t1; INSERT INTO t1 SELECT a,b,c+1,d FROM t1; EXPLAIN SELECT DISTINCT c FROM t1 WHERE d=4; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL foo 20 NULL 32 Using where; Using index +1 SIMPLE t1 range NULL foo 10 NULL 9 Using where; Using index for group-by SELECT DISTINCT c FROM t1 WHERE d=4; c 1 @@ -3339,19 +3339,19 @@ INSERT INTO t2 SELECT a, b + 4, c,d,e,f FROM t2; INSERT INTO t2 SELECT a + 1, b, c,d,e,f FROM t2; EXPLAIN SELECT COUNT(DISTINCT a) FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 10 NULL 16 Using index +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a) FROM t1; COUNT(DISTINCT a) 2 EXPLAIN SELECT COUNT(DISTINCT a,b) FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 10 NULL 16 Using index +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a,b) FROM t1; COUNT(DISTINCT a,b) 16 EXPLAIN SELECT COUNT(DISTINCT b,a) FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 10 NULL 16 Using index +1 SIMPLE t1 range NULL a 10 NULL 9 Using index for group-by SELECT COUNT(DISTINCT b,a) FROM t1; COUNT(DISTINCT b,a) 16 @@ -3414,7 +3414,7 @@ COUNT(DISTINCT a) 2 EXPLAIN SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 10 NULL 16 Using index +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by SELECT 1 FROM t1 HAVING COUNT(DISTINCT a) < 10; 1 1 @@ -3435,19 +3435,19 @@ COUNT(DISTINCT t1_1.a) 1 EXPLAIN SELECT COUNT(DISTINCT a), 12 FROM t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL a 10 NULL 16 Using index +1 SIMPLE t1 range NULL a 5 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a), 12 FROM t1; COUNT(DISTINCT a) 12 2 12 EXPLAIN SELECT COUNT(DISTINCT a, b, c) FROM t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL a 15 NULL 16 Using index +1 SIMPLE t2 range NULL a 15 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a, b, c) FROM t2; COUNT(DISTINCT a, b, c) 16 EXPLAIN SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL a 15 NULL 16 Using index +1 SIMPLE t2 range NULL a 5 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a), SUM(DISTINCT a), AVG(DISTINCT a) FROM t2; COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT a) 2 3 1.5000 @@ -3459,7 +3459,7 @@ COUNT(DISTINCT a) SUM(DISTINCT a) AVG(DISTINCT f) 2 3 1.0000 EXPLAIN SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 index NULL a 15 NULL 16 Using index +1 SIMPLE t2 range NULL a 10 NULL 9 Using index for group-by SELECT COUNT(DISTINCT a, b), COUNT(DISTINCT b, a) FROM t2; COUNT(DISTINCT a, b) COUNT(DISTINCT b, a) 16 16 @@ -3893,5 +3893,22 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index a a 13 NULL 2 Using where; Using index drop table t1; # +# MDEV-15433: Optimizer does not use group by optimization with distinct +# +CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT NOT NULL, KEY(a)); +OPTIMIZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 optimize status OK +EXPLAIN SELECT DISTINCT a FROM t1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range NULL a 4 NULL 5 Using index for group-by +SELECT DISTINCT a FROM t1; +a +1 +2 +3 +4 +drop table t1; +# # End of 10.1 tests # diff --git a/mysql-test/suite/vcol/r/vcol_select_innodb.result b/mysql-test/suite/vcol/r/vcol_select_innodb.result index 5c29f5f8283..97bfbbe4eaf 100644 --- a/mysql-test/suite/vcol/r/vcol_select_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_select_innodb.result @@ -133,7 +133,7 @@ count(distinct c) 3 explain select count(distinct c) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 5 NULL 5 Using index +1 SIMPLE t1 range NULL c 5 NULL 6 Using index for group-by (scanning) ### ### filesort & range-based utils ### diff --git a/mysql-test/suite/vcol/r/vcol_select_myisam.result b/mysql-test/suite/vcol/r/vcol_select_myisam.result index 7c371a1008a..6dee132b3e5 100644 --- a/mysql-test/suite/vcol/r/vcol_select_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_select_myisam.result @@ -133,7 +133,7 @@ count(distinct c) 3 explain select count(distinct c) from t1; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 index NULL c 5 NULL 5 Using index +1 SIMPLE t1 range NULL c 5 NULL 6 Using index for group-by (scanning) ### ### filesort & range-based utils ### diff --git a/mysql-test/t/group_min_max.test b/mysql-test/t/group_min_max.test index b0bc42d7f8c..adad9073235 100644 --- a/mysql-test/t/group_min_max.test +++ b/mysql-test/t/group_min_max.test @@ -1608,6 +1608,33 @@ explain select min(a) from t1 where a between "a" and "Cafeeeeeeeeeeeeeeeeeeeeee explain select min(a) from t1 where a between "abbbbbbbbbbbbbbbbbbbb" and "Cafe2"; drop table t1; +--echo # +--echo # MDEV-15433: Optimizer does not use group by optimization with distinct +--echo # + +CREATE TABLE t1 (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, a INT NOT NULL, KEY(a)); +--disable_query_log +INSERT INTO t1(a) VALUES (1), (2), (3), (4); +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +INSERT INTO t1(a) SELECT a FROM t1; +--enable_query_log +OPTIMIZE TABLE t1; +EXPLAIN SELECT DISTINCT a FROM t1; +SELECT DISTINCT a FROM t1; +drop table t1; + --echo # --echo # End of 10.1 tests --echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 64d1565dec7..d1b1c17f178 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1388,6 +1388,14 @@ JOIN::optimize_inner() error= 1; DBUG_RETURN(1); } + if (!group_list) + { + /* The output has only one row */ + order=0; + simple_order=1; + group_optimized_away= 1; + select_distinct=0; + } } /* Calculate how to do the join */ @@ -5754,7 +5762,7 @@ add_group_and_distinct_keys(JOIN *join, JOIN_TAB *join_tab) Item_field *cur_item; key_map possible_keys(0); - if (join->group_list || join->simple_group) + if (join->group_list) { /* Collect all query fields referenced in the GROUP clause. */ for (cur_group= join->group_list; cur_group; cur_group= cur_group->next) (*cur_group->item)->walk(&Item::collect_item_field_processor, 0, From 998b1c0e75a9512bfec308da19096cbced4150ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Sun, 5 Aug 2018 12:11:31 +0300 Subject: [PATCH 08/39] Fix galera test MW-44 --- mysql-test/suite/galera/r/MW-44.result | 15 ++------------- mysql-test/suite/galera/t/MW-44.test | 11 ++++++----- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/mysql-test/suite/galera/r/MW-44.result b/mysql-test/suite/galera/r/MW-44.result index 459a61030a4..a1e55318422 100644 --- a/mysql-test/suite/galera/r/MW-44.result +++ b/mysql-test/suite/galera/r/MW-44.result @@ -1,21 +1,10 @@ SET GLOBAL general_log='OFF'; TRUNCATE TABLE mysql.general_log; -SELECT COUNT(*) from mysql.general_log; -COUNT(*) -0 -SELECT * FROM mysql.general_log; -event_time user_host thread_id server_id command_type argument SET GLOBAL general_log='OFF'; TRUNCATE TABLE mysql.general_log; -SELECT COUNT(*) from mysql.general_log; -COUNT(*) -0 -SELECT * FROM mysql.general_log; -event_time user_host thread_id server_id command_type argument SET GLOBAL general_log='ON'; -SELECT COUNT(*) from mysql.general_log; -COUNT(*) -1 +SELECT argument from mysql.general_log WHERE argument NOT LIKE 'SELECT%'; +argument SET SESSION wsrep_osu_method=TOI; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; SET SESSION wsrep_osu_method=RSU; diff --git a/mysql-test/suite/galera/t/MW-44.test b/mysql-test/suite/galera/t/MW-44.test index 09f444fdff4..6b5eb823985 100644 --- a/mysql-test/suite/galera/t/MW-44.test +++ b/mysql-test/suite/galera/t/MW-44.test @@ -8,18 +8,19 @@ --connection node_1 SET GLOBAL general_log='OFF'; TRUNCATE TABLE mysql.general_log; -SELECT COUNT(*) from mysql.general_log; -SELECT * FROM mysql.general_log; +--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.general_log; +--source include/wait_condition.inc --connection node_2 SET GLOBAL general_log='OFF'; TRUNCATE TABLE mysql.general_log; -SELECT COUNT(*) from mysql.general_log; -SELECT * FROM mysql.general_log; +--let $wait_condition = SELECT COUNT(*) = 0 FROM mysql.general_log; +--source include/wait_condition.inc --connection node_1 SET GLOBAL general_log='ON'; -SELECT COUNT(*) from mysql.general_log; +SELECT argument from mysql.general_log WHERE argument NOT LIKE 'SELECT%'; + SET SESSION wsrep_osu_method=TOI; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; SET SESSION wsrep_osu_method=RSU; From 3b37edee1a5121e9523fa8a7f483185f402905e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 6 Aug 2018 15:45:44 +0300 Subject: [PATCH 09/39] MDEV-13333: Deadlock failure that does not occur elsewhere InnoDB executed code that is mean to execute only when Galera is used and in bad luck one of the transactions is selected incorrectly as deadlock victim. Fixed by adding wsrep_on_trx() condition before entering actual Galera transaction handling. No always repeatable test case for this issue is known. --- storage/innobase/lock/lock0lock.cc | 5 +++-- storage/xtradb/lock/lock0lock.cc | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 441fcace7c3..3970a559a4c 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4963,7 +4963,7 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock) { + if (c_lock && wsrep_on_trx(trx)) { if (wsrep_thd_is_wsrep(trx->mysql_thd) && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { UT_LIST_INSERT_AFTER( @@ -5202,9 +5202,10 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ #ifdef WITH_WSREP - if (trx->lock.was_chosen_as_deadlock_victim) { + if (trx->lock.was_chosen_as_deadlock_victim && wsrep_on_trx(trx)) { return(DB_DEADLOCK); } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); #else lock = lock_table_create(table, mode | LOCK_WAIT, trx); diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc index 549cc411f69..2183d281b78 100644 --- a/storage/xtradb/lock/lock0lock.cc +++ b/storage/xtradb/lock/lock0lock.cc @@ -5003,7 +5003,7 @@ lock_table_create( UT_LIST_ADD_LAST(trx_locks, trx->lock.trx_locks, lock); #ifdef WITH_WSREP - if (c_lock) { + if (c_lock && wsrep_on_trx(trx)) { if (wsrep_thd_is_wsrep(trx->mysql_thd) && wsrep_thd_is_BF(trx->mysql_thd, FALSE)) { UT_LIST_INSERT_AFTER( @@ -5244,9 +5244,10 @@ lock_table_enqueue_waiting( /* Enqueue the lock request that will wait to be granted */ #ifdef WITH_WSREP - if (trx->lock.was_chosen_as_deadlock_victim) { + if (trx->lock.was_chosen_as_deadlock_victim && wsrep_on_trx(trx)) { return(DB_DEADLOCK); } + lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx); #else lock = lock_table_create(table, mode | LOCK_WAIT, trx); From ebaacf0747bad9f41686a23f0b8ba4ff9f364f47 Mon Sep 17 00:00:00 2001 From: Rasmus Johansson Date: Mon, 6 Aug 2018 16:46:19 +0300 Subject: [PATCH 10/39] Update rules --- debian/dist/Ubuntu/rules | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/debian/dist/Ubuntu/rules b/debian/dist/Ubuntu/rules index 5f3ea672770..e570a99c80a 100755 --- a/debian/dist/Ubuntu/rules +++ b/debian/dist/Ubuntu/rules @@ -1,7 +1,10 @@ #!/usr/bin/make -f export DH_VERBOSE=1 -export DEB_BUILD_HARDENING=1 +#export DEB_BUILD_HARDENING=1 +export DEB_BUILD_MAINT_OPTIONS = hardening=+all,-pie +DPKG_EXPORT_BUILDFLAGS = 1 +include /usr/share/dpkg/buildflags.mk PACKAGE=mariadb-5.5 From ad577091edf288e549c730933c514852b471991c Mon Sep 17 00:00:00 2001 From: Sachin Date: Mon, 6 Aug 2018 21:22:17 +0530 Subject: [PATCH 11/39] MDEV-16904 inline void swap(base_list &rhs) should swap list only when list is... not empty We should swap the list only when list is not empty. --- sql/sql_list.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sql/sql_list.h b/sql/sql_list.h index 08667bed02a..8956a786715 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -306,10 +306,13 @@ public: */ inline void swap(base_list &rhs) { + list_node **rhs_last=rhs.last; swap_variables(list_node *, first, rhs.first); - swap_variables(list_node **, last, rhs.last); swap_variables(uint, elements, rhs.elements); + rhs.last= last == &first ? &rhs.first : last; + last = rhs_last == &rhs.first ? &first : rhs_last; } + inline list_node* last_node() { return *last; } inline list_node* first_node() { return first;} inline void *head() { return first->info; } From 757e3b88d26f8282df83f42ea3c451d2d2dac3cf Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Tue, 7 Aug 2018 10:43:08 -0400 Subject: [PATCH 12/39] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c169837c460..f49c0084775 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=35 +MYSQL_VERSION_PATCH=36 From 0496bbc120c9b583726b839aa8dedef5a5d4b647 Mon Sep 17 00:00:00 2001 From: faust Date: Thu, 9 Aug 2018 15:05:40 -0300 Subject: [PATCH 13/39] MDEV-15869 Mariabackup is lacking some dependencies declaration (#771) * Backport from 10.4 to resolve dependency problem Using the dependency syntax from 10.4 branch because {$LIBSSL} can not be used. --- debian/control | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 3048ec78d62..71329a870c9 100644 --- a/debian/control +++ b/debian/control @@ -449,5 +449,7 @@ Description: GSSAPI authentication plugin for MariaDB client Package: mariadb-backup-10.1 Section: database Architecture: any -Depends: libarchive12 | libarchive13 +Depends: mariadb-client-core-10.1 (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} Description: Backup tool for MariaDB server From 3ff0801c7397e3ae5fc538ffca3d58891cd4f27b Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 11 Aug 2018 12:11:59 +0200 Subject: [PATCH 14/39] MDEV-16810 AddressSanitizer: stack-buffer-overflow in int10_to_str truncate incorrect values in convert_period_to_month() so that PERIOD_DIFF never returns a value outside of 2^23 range. And, for safety, increase buffer sizes for int10_to_str to be sufficienly big for any int10_to_str result. --- mysql-test/r/func_time.result | 3 +++ mysql-test/t/func_time.test | 4 ++++ sql/protocol.cc | 8 ++++---- sql/sql_time.cc | 2 +- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/mysql-test/r/func_time.result b/mysql-test/r/func_time.result index cffed8eae5b..3f0d99e1315 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -2657,6 +2657,9 @@ SEC_TO_TIME(MAKEDATE(0,RAND(~0))) 838:59:59 Warnings: Warning 1292 Truncated incorrect time value: '20000101' +SELECT PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')); +PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')) +24257 # # End of 5.5 tests # diff --git a/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 8323bd30d2c..361eff170fb 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -1629,6 +1629,10 @@ DO TO_DAYS(SEC_TO_TIME(MAKEDATE('',RAND(~(''))))); SELECT TO_DAYS(SEC_TO_TIME(MAKEDATE(0,RAND(~0)))); SELECT SEC_TO_TIME(MAKEDATE(0,RAND(~0))); +# +# MDEV-16810 AddressSanitizer: stack-buffer-overflow in int10_to_str +# +SELECT PERIOD_DIFF(2018, AES_ENCRYPT('Rae Bareli', 'Rae Bareli')); --echo # --echo # End of 5.5 tests diff --git a/sql/protocol.cc b/sql/protocol.cc index ac9fb1e9384..8602d9131c1 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -643,7 +643,7 @@ uchar *net_store_data(uchar *to, const uchar *from, size_t length) uchar *net_store_data(uchar *to,int32 from) { - char buff[20]; + char buff[22]; uint length=(uint) (int10_to_str(from,buff,10)-buff); to=net_store_length_fast(to,length); memcpy(to,buff,length); @@ -1060,7 +1060,7 @@ bool Protocol_text::store_tiny(longlong from) DBUG_ASSERT(field_types == 0 || field_types[field_pos] == MYSQL_TYPE_TINY); field_pos++; #endif - char buff[20]; + char buff[22]; return net_store_data((uchar*) buff, (size_t) (int10_to_str((int) from, buff, -10) - buff)); } @@ -1074,7 +1074,7 @@ bool Protocol_text::store_short(longlong from) field_types[field_pos] == MYSQL_TYPE_SHORT); field_pos++; #endif - char buff[20]; + char buff[22]; return net_store_data((uchar*) buff, (size_t) (int10_to_str((int) from, buff, -10) - buff)); @@ -1089,7 +1089,7 @@ bool Protocol_text::store_long(longlong from) field_types[field_pos] == MYSQL_TYPE_LONG); field_pos++; #endif - char buff[20]; + char buff[22]; return net_store_data((uchar*) buff, (size_t) (int10_to_str((long int)from, buff, (from <0)?-10:10)-buff)); diff --git a/sql/sql_time.cc b/sql/sql_time.cc index d912a7b78d6..33bb9a460b0 100644 --- a/sql/sql_time.cc +++ b/sql/sql_time.cc @@ -190,7 +190,7 @@ bool get_date_from_daynr(long daynr,uint *ret_year,uint *ret_month, ulong convert_period_to_month(ulong period) { ulong a,b; - if (period == 0) + if (period == 0 || period > 999912) return 0L; if ((a=period/100) < YY_PART_YEAR) a+=2000; From 074b672b5d94d291afce5f6541f39d68c65caa62 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 13 Aug 2018 19:43:59 +0100 Subject: [PATCH 15/39] MDEV-16963 Tighten named pipe access control Use real DACL instead of NULL DACL. Grant Everyone just read/write access to pipe (instead of all access like previously with NULL ACL) --- sql/mysqld.cc | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5a9aba7f2e4..aa749e5aaef 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -1195,9 +1195,9 @@ static NTService Service; ///< Service object for WinNT #endif /* __WIN__ */ #ifdef _WIN32 +#include /* ConvertStringSecurityDescriptorToSecurityDescriptor */ static char pipe_name[512]; static SECURITY_ATTRIBUTES saPipeSecurity; -static SECURITY_DESCRIPTOR sdPipeDescriptor; static HANDLE hPipe = INVALID_HANDLE_VALUE; #endif @@ -2238,21 +2238,20 @@ static void network_init(void) strxnmov(pipe_name, sizeof(pipe_name)-1, "\\\\.\\pipe\\", mysqld_unix_port, NullS); - bzero((char*) &saPipeSecurity, sizeof(saPipeSecurity)); - bzero((char*) &sdPipeDescriptor, sizeof(sdPipeDescriptor)); - if (!InitializeSecurityDescriptor(&sdPipeDescriptor, - SECURITY_DESCRIPTOR_REVISION)) + /* + Create a security descriptor for pipe. + - Use low integrity level, so that it is possible to connect + from any process. + - Give Everyone read/write access to pipe. + */ + if (!ConvertStringSecurityDescriptorToSecurityDescriptor( + "S:(ML;; NW;;; LW) D:(A;; FRFW;;; WD)", + SDDL_REVISION_1, &saPipeSecurity.lpSecurityDescriptor, NULL)) { sql_perror("Can't start server : Initialize security descriptor"); unireg_abort(1); } - if (!SetSecurityDescriptorDacl(&sdPipeDescriptor, TRUE, NULL, FALSE)) - { - sql_perror("Can't start server : Set security descriptor"); - unireg_abort(1); - } saPipeSecurity.nLength = sizeof(SECURITY_ATTRIBUTES); - saPipeSecurity.lpSecurityDescriptor = &sdPipeDescriptor; saPipeSecurity.bInheritHandle = FALSE; if ((hPipe= CreateNamedPipe(pipe_name, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE, @@ -5859,6 +5858,7 @@ pthread_handler_t handle_connections_namedpipes(void *arg) thd->security_ctx->host= my_strdup(my_localhost, MYF(0)); create_new_thread(thd); } + LocalFree(saPipeSecurity.lpSecurityDescriptor); CloseHandle(connectOverlapped.hEvent); DBUG_LEAVE; decrement_handler_count(); From dfb19c06b867786b5d9a9b49e7d10fc86c1d4057 Mon Sep 17 00:00:00 2001 From: mkaruza Date: Tue, 14 Aug 2018 10:34:51 +0200 Subject: [PATCH 16/39] MDEV-15933 Cannot resume Node SYNCED state when wsrep_desync is done after FTWRL Manually setting wsrep_desync after FTWRL should not be allowed. --- mysql-test/suite/galera/r/galera_var_desync_on.result | 2 -- mysql-test/suite/galera/t/galera_var_desync_on.test | 7 +++---- sql/wsrep_var.cc | 6 ++++++ 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_var_desync_on.result b/mysql-test/suite/galera/r/galera_var_desync_on.result index f286ae72308..7d86555150e 100644 --- a/mysql-test/suite/galera/r/galera_var_desync_on.result +++ b/mysql-test/suite/galera/r/galera_var_desync_on.result @@ -1,7 +1,6 @@ CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; INSERT INTO t1 VALUES (1); SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1'; -SET GLOBAL wsrep_desync = TRUE; FLUSH TABLES WITH READ LOCK; INSERT INTO t1 VALUES (2); INSERT INTO t1 VALUES (3); @@ -16,7 +15,6 @@ SET SESSION wsrep_sync_wait = 0; SELECT COUNT(*) = 1 FROM t1; COUNT(*) = 1 1 -SET GLOBAL wsrep_desync = FALSE; UNLOCK TABLES; SET SESSION wsrep_sync_wait = 1; SELECT COUNT(*) = 10 FROM t1; diff --git a/mysql-test/suite/galera/t/galera_var_desync_on.test b/mysql-test/suite/galera/t/galera_var_desync_on.test index 06c5d30a769..fbf660d3ab5 100644 --- a/mysql-test/suite/galera/t/galera_var_desync_on.test +++ b/mysql-test/suite/galera/t/galera_var_desync_on.test @@ -1,5 +1,7 @@ # -# Test wsrep_desync = ON . Node should temporarily not participate in flow control +# Desync will be done once the global read lock is acquired and resync will be done when +# it is released. +# Node should temporarily not participate in flow control # so even if fc_limit has been reached, the master should be able to continue to # commit transactions. # @@ -13,7 +15,6 @@ INSERT INTO t1 VALUES (1); --connection node_2 --let $wsrep_provider_options_orig = `SELECT @@wsrep_provider_options` SET GLOBAL wsrep_provider_options = 'gcs.fc_limit=1'; -SET GLOBAL wsrep_desync = TRUE; # Block the slave applier thread FLUSH TABLES WITH READ LOCK; @@ -37,8 +38,6 @@ SET SESSION wsrep_sync_wait = 0; # No updates have arrived after the FLUSH TABLES SELECT COUNT(*) = 1 FROM t1; -# Resync the slave -SET GLOBAL wsrep_desync = FALSE; --disable_query_log --eval SET GLOBAL wsrep_provider_options = '$wsrep_provider_options_orig'; --enable_query_log diff --git a/sql/wsrep_var.cc b/sql/wsrep_var.cc index 216bab0cdcd..3826ebed14c 100644 --- a/sql/wsrep_var.cc +++ b/sql/wsrep_var.cc @@ -587,6 +587,12 @@ bool wsrep_desync_check (sys_var *self, THD* thd, set_var* var) return true; } + if (thd->global_read_lock.is_acquired()) + { + my_message (ER_CANNOT_USER, "Global read lock acquired. Can't set 'wsrep_desync'", MYF(0)); + return true; + } + bool new_wsrep_desync= (bool) var->save_result.ulonglong_value; if (wsrep_desync == new_wsrep_desync) { if (new_wsrep_desync) { From 68eb9b1a78423b9c0a353bc1bdfa7b518977dbac Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 14 Aug 2018 22:42:46 +0200 Subject: [PATCH 17/39] MDEV-16220 Do not pass UTF8 to mysql in command line parameters, on Windows Moved parts of mysql.test to mysql_not_windows.test --- mysql-test/r/mysql.result | 2 -- mysql-test/r/mysql_not_windows.result | 2 ++ mysql-test/t/mysql.test | 5 +---- mysql-test/t/mysql_not_windows.test | 7 +++++++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/mysql.result b/mysql-test/r/mysql.result index 09f014da627..06ef7e95bc9 100644 --- a/mysql-test/r/mysql.result +++ b/mysql-test/r/mysql.result @@ -538,8 +538,6 @@ a # # End of 10.1 tests # -ERROR 1300 (HY000): Invalid utf8 character string: 'test\xF0\x9F\x98\x81 ' -ERROR 1300 (HY000): Invalid binary character string: 'test\xF0\x9F\x98\x81 ' ERROR 1300 (HY000) at line 2: Invalid utf8 character string: 'test\xF0\x9F\x98\x81' set GLOBAL sql_mode=default; diff --git a/mysql-test/r/mysql_not_windows.result b/mysql-test/r/mysql_not_windows.result index 1df62d9a12d..96210a366a6 100644 --- a/mysql-test/r/mysql_not_windows.result +++ b/mysql-test/r/mysql_not_windows.result @@ -9,3 +9,5 @@ End of tests 2 X 3 +ERROR 1300 (HY000): Invalid utf8 character string: 'test\xF0\x9F\x98\x81 ' +ERROR 1300 (HY000): Invalid binary character string: 'test\xF0\x9F\x98\x81 ' diff --git a/mysql-test/t/mysql.test b/mysql-test/t/mysql.test index fc2ae849aa6..e3219c21517 100644 --- a/mysql-test/t/mysql.test +++ b/mysql-test/t/mysql.test @@ -638,10 +638,7 @@ EOF --echo # End of 10.1 tests --echo # ---error 1 ---exec $MYSQL --default-character-set=utf8 -e "select 1" "test😁 " 2>&1 ---error 1 ---exec $MYSQL --default-character-set=binary -e "select 1" "test😁 " 2>&1 + --write_file $MYSQLTEST_VARDIR/tmp/mdev-6572.sql SET NAMES utf8; USE test😁 ; diff --git a/mysql-test/t/mysql_not_windows.test b/mysql-test/t/mysql_not_windows.test index 591de74cbbf..816160c4f3e 100644 --- a/mysql-test/t/mysql_not_windows.test +++ b/mysql-test/t/mysql_not_windows.test @@ -22,3 +22,10 @@ exec $MYSQL test -e "select let $query = select 3 as X; exec $MYSQL test -e "$query"; + +# Not ran on Windows, since non-ASCII does not work on command line. +# (MDEV-16220) +--error 1 +--exec $MYSQL --default-character-set=utf8 -e "select 1" "test😁 " 2>&1 +--error 1 +--exec $MYSQL --default-character-set=binary -e "select 1" "test😁 " 2>&1 From 75dfd4acb995789ca5f86ccbd361fff9d2797e79 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Thu, 26 Jul 2018 15:04:11 +0200 Subject: [PATCH 18/39] This is patch for the https://jira.mariadb.org/browse/MDEV-9519 issue: If we have a 2+ node cluster which is replicating from an async master and the binlog_format is set to STATEMENT and multi-row inserts are executed on a table with an auto_increment column such that values are automatically generated by MySQL, then the server node generates wrong auto_increment values, which are different from what was generated on the async master. The causes and fixes: 1. We need to improve processing of changing the auto-increment values after changing the cluster size. 2. If wsrep auto_increment_control switched on during operation of the node, then we should immediately update the auto_increment_increment and auto_increment_offset global variables, without waiting of the next invocation of the wsrep_view_handler_cb() callback. In the current version these variables retain its initial values if wsrep_auto_increment_control is switched on during operation of the node, which leads to inconsistent results on the different nodes in some scenarios. 3. If wsrep auto_increment_control switched off during operation of the node, then we must return the original values of the auto_increment_increment and auto_increment_offset global variables, as the user has set. To make this possible, we need to add a "shadow copies" of these variables (which stores the latest values set by the user). --- .../r/galera_binlog_stmt_autoinc.result | 147 ++++++++++++ .../galera/t/galera_binlog_stmt_autoinc.test | 223 ++++++++++++++++++ sql/field.h | 46 ++++ sql/handler.cc | 31 ++- sql/mysqld.cc | 14 ++ sql/sql_class.h | 11 + sql/sys_vars.cc | 93 +++++++- sql/wsrep_mysqld.h | 4 + sql/wsrep_thd.cc | 22 ++ storage/innobase/handler/ha_innodb.cc | 59 +++-- storage/xtradb/handler/ha_innodb.cc | 57 ++++- 11 files changed, 677 insertions(+), 30 deletions(-) create mode 100644 mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result create mode 100644 mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test diff --git a/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result b/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result new file mode 100644 index 00000000000..542bd156816 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_binlog_stmt_autoinc.result @@ -0,0 +1,147 @@ +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; +CREATE TABLE t1 ( +i int(11) NOT NULL AUTO_INCREMENT, +c char(32) DEFAULT 'dummy_text', +PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +insert into t1(i) values(null); +select * from t1; +i c +1 dummy_text +insert into t1(i) values(null), (null), (null); +select * from t1; +i c +1 dummy_text +3 dummy_text +5 dummy_text +7 dummy_text +select * from t1; +i c +1 dummy_text +3 dummy_text +5 dummy_text +7 dummy_text +SET GLOBAL wsrep_forced_binlog_format='none'; +SET GLOBAL wsrep_forced_binlog_format='none'; +drop table t1; +SET SESSION binlog_format='STATEMENT'; +show variables like 'binlog_format'; +Variable_name Value +binlog_format STATEMENT +SET GLOBAL wsrep_auto_increment_control='OFF'; +SET SESSION auto_increment_increment = 3; +SET SESSION auto_increment_offset = 1; +CREATE TABLE t1 ( +i int(11) NOT NULL AUTO_INCREMENT, +c char(32) DEFAULT 'dummy_text', +PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +insert into t1(i) values(null); +select * from t1; +i c +1 dummy_text +insert into t1(i) values(null), (null), (null); +select * from t1; +i c +1 dummy_text +4 dummy_text +7 dummy_text +10 dummy_text +select * from t1; +i c +1 dummy_text +4 dummy_text +7 dummy_text +10 dummy_text +SET GLOBAL wsrep_auto_increment_control='ON'; +SET SESSION binlog_format='ROW'; +show variables like 'binlog_format'; +Variable_name Value +binlog_format ROW +show variables like '%auto_increment%'; +Variable_name Value +auto_increment_increment 2 +auto_increment_offset 1 +wsrep_auto_increment_control ON +SET GLOBAL wsrep_auto_increment_control='OFF'; +show variables like '%auto_increment%'; +Variable_name Value +auto_increment_increment 3 +auto_increment_offset 1 +wsrep_auto_increment_control OFF +SET GLOBAL wsrep_auto_increment_control='ON'; +drop table t1; +SET GLOBAL wsrep_forced_binlog_format='ROW'; +SET GLOBAL wsrep_forced_binlog_format='ROW'; +CREATE TABLE t1 ( +i int(11) NOT NULL AUTO_INCREMENT, +c char(32) DEFAULT 'dummy_text', +PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +insert into t1(i) values(null); +select * from t1; +i c +1 dummy_text +insert into t1(i) values(null), (null), (null); +select * from t1; +i c +1 dummy_text +3 dummy_text +5 dummy_text +7 dummy_text +select * from t1; +i c +1 dummy_text +3 dummy_text +5 dummy_text +7 dummy_text +SET GLOBAL wsrep_forced_binlog_format='none'; +SET GLOBAL wsrep_forced_binlog_format='none'; +drop table t1; +SET SESSION binlog_format='ROW'; +show variables like 'binlog_format'; +Variable_name Value +binlog_format ROW +SET GLOBAL wsrep_auto_increment_control='OFF'; +SET SESSION auto_increment_increment = 3; +SET SESSION auto_increment_offset = 1; +CREATE TABLE t1 ( +i int(11) NOT NULL AUTO_INCREMENT, +c char(32) DEFAULT 'dummy_text', +PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; +insert into t1(i) values(null); +select * from t1; +i c +1 dummy_text +insert into t1(i) values(null), (null), (null); +select * from t1; +i c +1 dummy_text +4 dummy_text +7 dummy_text +10 dummy_text +select * from t1; +i c +1 dummy_text +4 dummy_text +7 dummy_text +10 dummy_text +SET GLOBAL wsrep_auto_increment_control='ON'; +show variables like 'binlog_format'; +Variable_name Value +binlog_format ROW +show variables like '%auto_increment%'; +Variable_name Value +auto_increment_increment 2 +auto_increment_offset 1 +wsrep_auto_increment_control ON +SET GLOBAL wsrep_auto_increment_control='OFF'; +show variables like '%auto_increment%'; +Variable_name Value +auto_increment_increment 3 +auto_increment_offset 1 +wsrep_auto_increment_control OFF +SET GLOBAL wsrep_auto_increment_control='ON'; +drop table t1; diff --git a/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test new file mode 100644 index 00000000000..aab4fea9f2e --- /dev/null +++ b/mysql-test/suite/galera/t/galera_binlog_stmt_autoinc.test @@ -0,0 +1,223 @@ +## +## Tests the auto-increment with binlog in STATEMENT mode. +## + +--source include/galera_cluster.inc +--source include/have_innodb.inc + +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +## +## Verify the correct operation of the auto-increment when the binlog +## format artificially set to the 'STATEMENT' (although this mode is +## not recommended in the current version): +## + +--connection node_2 +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; + +--connection node_1 +SET GLOBAL wsrep_forced_binlog_format='STATEMENT'; + +CREATE TABLE t1 ( + i int(11) NOT NULL AUTO_INCREMENT, + c char(32) DEFAULT 'dummy_text', + PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +insert into t1(i) values(null); + +select * from t1; + +insert into t1(i) values(null), (null), (null); + +select * from t1; + +--connection node_2 + +select * from t1; + +SET GLOBAL wsrep_forced_binlog_format='none'; + +--connection node_1 + +SET GLOBAL wsrep_forced_binlog_format='none'; + +drop table t1; + +## +## Check the operation when the automatic control over the auto-increment +## settings is switched off, that is, when we use the increment step and +## the offset specified by the user. In the current session, the binlog +## format is set to 'STATEMENT'. It is important that the values of the +## auto-increment options does not changed on other node - it allows us +## to check the correct transmission of the auto-increment options to +## other nodes: +## + +--disable_warnings +SET SESSION binlog_format='STATEMENT'; +--enable_warnings + +show variables like 'binlog_format'; + +SET GLOBAL wsrep_auto_increment_control='OFF'; + +SET SESSION auto_increment_increment = 3; +SET SESSION auto_increment_offset = 1; + +CREATE TABLE t1 ( + i int(11) NOT NULL AUTO_INCREMENT, + c char(32) DEFAULT 'dummy_text', + PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +insert into t1(i) values(null); + +select * from t1; + +insert into t1(i) values(null), (null), (null); + +select * from t1; + +--connection node_2 + +select * from t1; + +--connection node_1 + +## +## Verify the return to automatic calculation of the step +## and offset of the auto-increment: +## + +SET GLOBAL wsrep_auto_increment_control='ON'; + +SET SESSION binlog_format='ROW'; + +show variables like 'binlog_format'; +show variables like '%auto_increment%'; + +## +## Verify the recovery of original user-defined values after +## stopping the automatic control over auto-increment: +## + +SET GLOBAL wsrep_auto_increment_control='OFF'; + +show variables like '%auto_increment%'; + +## +## Restore original options and drop test table: +## + +SET GLOBAL wsrep_auto_increment_control='ON'; + +drop table t1; + +## +## Verify the correct operation of the auto-increment when the binlog +## format set to the 'ROW': +## + +--connection node_2 +SET GLOBAL wsrep_forced_binlog_format='ROW'; + +--connection node_1 +SET GLOBAL wsrep_forced_binlog_format='ROW'; + +CREATE TABLE t1 ( + i int(11) NOT NULL AUTO_INCREMENT, + c char(32) DEFAULT 'dummy_text', + PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +insert into t1(i) values(null); + +select * from t1; + +insert into t1(i) values(null), (null), (null); + +select * from t1; + +--connection node_2 + +select * from t1; + +SET GLOBAL wsrep_forced_binlog_format='none'; + +--connection node_1 + +SET GLOBAL wsrep_forced_binlog_format='none'; + +drop table t1; + +## +## Check the operation when the automatic control over the auto-increment +## settings is switched off, that is, when we use the increment step and +## the offset specified by the user. In the current session, the binlog +## format is set to 'ROW'. It is important that the values of the +## auto-increment options does not changed on other node - it allows us +## to check the correct transmission of the auto-increment options to +## other nodes: +## + +SET SESSION binlog_format='ROW'; + +show variables like 'binlog_format'; + +SET GLOBAL wsrep_auto_increment_control='OFF'; + +SET SESSION auto_increment_increment = 3; +SET SESSION auto_increment_offset = 1; + +CREATE TABLE t1 ( + i int(11) NOT NULL AUTO_INCREMENT, + c char(32) DEFAULT 'dummy_text', + PRIMARY KEY (i) +) ENGINE=InnoDB DEFAULT CHARSET=latin1; + +insert into t1(i) values(null); + +select * from t1; + +insert into t1(i) values(null), (null), (null); + +select * from t1; + +--connection node_2 + +select * from t1; + +--connection node_1 + +## +## Verify the return to automatic calculation of the step +## and offset of the auto-increment: +## + +SET GLOBAL wsrep_auto_increment_control='ON'; + +show variables like 'binlog_format'; +show variables like '%auto_increment%'; + +## +## Verify the recovery of original user-defined values after +## stopping the automatic control over auto-increment: +## + +SET GLOBAL wsrep_auto_increment_control='OFF'; + +show variables like '%auto_increment%'; + +## +## Restore original options and drop test table: +## + +SET GLOBAL wsrep_auto_increment_control='ON'; + +drop table t1; + +--source include/auto_increment_offset_restore.inc diff --git a/sql/field.h b/sql/field.h index c21bba6936f..30b4b9fd68e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1329,6 +1329,17 @@ public: /* Hash value */ virtual void hash(ulong *nr, ulong *nr2); + /** + Get the upper limit of the MySQL integral and floating-point type. + + @return maximum allowed value for the field + */ + virtual ulonglong get_max_int_value() const + { + DBUG_ASSERT(false); + return 0ULL; + } + /** Checks whether a string field is part of write_set. @@ -1796,6 +1807,11 @@ public: *to= *from; return from + 1; } + + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFULL : 0x7FULL; + } }; @@ -1837,6 +1853,10 @@ public: virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data) { return unpack_int16(to, from, from_end); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFULL : 0x7FFFULL; + } }; class Field_medium :public Field_num { @@ -1870,6 +1890,10 @@ public: { return Field::pack(to, from, max_length); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFULL : 0x7FFFFFULL; + } }; @@ -1915,6 +1939,10 @@ public: { return unpack_int32(to, from, from_end); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFFFULL : 0x7FFFFFFFULL; + } }; @@ -1964,6 +1992,10 @@ public: { return unpack_int64(to, from, from_end); } + virtual ulonglong get_max_int_value() const + { + return unsigned_flag ? 0xFFFFFFFFFFFFFFFFULL : 0x7FFFFFFFFFFFFFFFULL; + } }; @@ -1997,6 +2029,13 @@ public: uint32 pack_length() const { return sizeof(float); } uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; + virtual ulonglong get_max_int_value() const + { + /* + We use the maximum as per IEEE754-2008 standard, 2^24 + */ + return 0x1000000ULL; + } private: int do_save_field_metadata(uchar *first_byte); }; @@ -2039,6 +2078,13 @@ public: uint32 pack_length() const { return sizeof(double); } uint row_pack_length() const { return pack_length(); } void sql_type(String &str) const; + virtual ulonglong get_max_int_value() const + { + /* + We use the maximum as per IEEE754-2008 standard, 2^53 + */ + return 0x20000000000000ULL; + } private: int do_save_field_metadata(uchar *first_byte); }; diff --git a/sql/handler.cc b/sql/handler.cc index 9c319b995da..e2690023807 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -2853,9 +2853,15 @@ compute_next_insert_id(ulonglong nr,struct system_variables *variables) nr= nr + 1; // optimization of the formula below else { + /* + Calculating the number of complete auto_increment_increment extents: + */ nr= (((nr+ variables->auto_increment_increment - variables->auto_increment_offset)) / (ulonglong) variables->auto_increment_increment); + /* + Adding an offset to the auto_increment_increment extent boundary: + */ nr= (nr* (ulonglong) variables->auto_increment_increment + variables->auto_increment_offset); } @@ -2911,8 +2917,14 @@ prev_insert_id(ulonglong nr, struct system_variables *variables) } if (variables->auto_increment_increment == 1) return nr; // optimization of the formula below + /* + Calculating the number of complete auto_increment_increment extents: + */ nr= (((nr - variables->auto_increment_offset)) / (ulonglong) variables->auto_increment_increment); + /* + Adding an offset to the auto_increment_increment extent boundary: + */ return (nr * (ulonglong) variables->auto_increment_increment + variables->auto_increment_offset); } @@ -3134,10 +3146,23 @@ int handler::update_auto_increment() if (unlikely(tmp)) // Out of range value in store { /* - It's better to return an error here than getting a confusing - 'duplicate key error' later. + first test if the query was aborted due to strict mode constraints */ - result= HA_ERR_AUTOINC_ERANGE; + if (thd->killed == KILL_BAD_DATA || + nr > table->next_number_field->get_max_int_value()) + DBUG_RETURN(HA_ERR_AUTOINC_ERANGE); + + /* + field refused this value (overflow) and truncated it, use the result of + the truncation (which is going to be inserted); however we try to + decrease it to honour auto_increment_* variables. + That will shift the left bound of the reserved interval, we don't + bother shifting the right bound (anyway any other value from this + interval will cause a duplicate key). + */ + nr= prev_insert_id(table->next_number_field->val_int(), variables); + if (unlikely(table->next_number_field->store((longlong) nr, TRUE))) + nr= table->next_number_field->val_int(); } if (append) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 1e6e144ccff..d12cdb34e02 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4193,6 +4193,20 @@ static int init_common_variables() DBUG_PRINT("info",("%s Ver %s for %s on %s\n",my_progname, server_version, SYSTEM_TYPE,MACHINE_TYPE)); +#ifdef WITH_WSREP + /* + We need to initialize auxiliary variables, that will be + further keep the original values of auto-increment options + as they set by the user. These variables used to restore + user-defined values of the auto-increment options after + setting of the wsrep_auto_increment_control to 'OFF'. + */ + global_system_variables.saved_auto_increment_increment= + global_system_variables.auto_increment_increment; + global_system_variables.saved_auto_increment_offset= + global_system_variables.auto_increment_offset; +#endif /* WITH_WSREP */ + #ifdef HAVE_LARGE_PAGES /* Initialize large page size */ if (opt_large_pages) diff --git a/sql/sql_class.h b/sql/sql_class.h index 53e451511d5..f0c486bd172 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -552,6 +552,17 @@ typedef struct system_variables ha_rows max_join_size; ha_rows expensive_subquery_limit; ulong auto_increment_increment, auto_increment_offset; +#ifdef WITH_WSREP + /* + Variables with stored values of the auto_increment_increment + and auto_increment_offset options that are will be needed when + wsrep_auto_increment_control will be set to 'OFF', because the + setting it to 'ON' leads to overwriting of the original values + (which are set by the user) by calculated values (which are + based on the cluster's size): + */ + ulong saved_auto_increment_increment, saved_auto_increment_offset; +#endif /* WITH_WSREP */ ulong lock_wait_timeout; ulong join_cache_level; ulong max_allowed_packet; diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index f941794f89e..8a67c1d38f3 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -345,13 +345,56 @@ static Sys_var_long Sys_pfs_connect_attrs_size( #endif /* WITH_PERFSCHEMA_STORAGE_ENGINE */ +#ifdef WITH_WSREP + +/* + We need to keep the original values set by the user, as they will + be lost if wsrep_auto_increment_control set to 'ON': +*/ +static bool update_auto_increment_increment (sys_var *self, THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.saved_auto_increment_increment= + global_system_variables.auto_increment_increment; + else + thd->variables.saved_auto_increment_increment= + thd->variables.auto_increment_increment; + return false; +} + +#endif /* WITH_WSREP */ + static Sys_var_ulong Sys_auto_increment_increment( "auto_increment_increment", "Auto-increment columns are incremented by this", SESSION_VAR(auto_increment_increment), CMD_LINE(OPT_ARG), VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1), +#ifdef WITH_WSREP + NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_auto_increment_increment)); +#else NO_MUTEX_GUARD, IN_BINLOG); +#endif /* WITH_WSREP */ + +#ifdef WITH_WSREP + +/* + We need to keep the original values set by the user, as they will + be lost if wsrep_auto_increment_control set to 'ON': +*/ +static bool update_auto_increment_offset (sys_var *self, THD *thd, enum_var_type type) +{ + if (type == OPT_GLOBAL) + global_system_variables.saved_auto_increment_offset= + global_system_variables.auto_increment_offset; + else + thd->variables.saved_auto_increment_offset= + thd->variables.auto_increment_offset; + return false; +} + +#endif /* WITH_WSREP */ static Sys_var_ulong Sys_auto_increment_offset( "auto_increment_offset", @@ -360,7 +403,12 @@ static Sys_var_ulong Sys_auto_increment_offset( SESSION_VAR(auto_increment_offset), CMD_LINE(OPT_ARG), VALID_RANGE(1, 65535), DEFAULT(1), BLOCK_SIZE(1), +#ifdef WITH_WSREP + NO_MUTEX_GUARD, IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_auto_increment_offset)); +#else NO_MUTEX_GUARD, IN_BINLOG); +#endif /* WITH_WSREP */ static Sys_var_mybool Sys_automatic_sp_privileges( "automatic_sp_privileges", @@ -4847,11 +4895,54 @@ static Sys_var_ulong Sys_wsrep_retry_autocommit( SESSION_VAR(wsrep_retry_autocommit), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 10000), DEFAULT(1), BLOCK_SIZE(1)); +static bool update_wsrep_auto_increment_control (sys_var *self, THD *thd, enum_var_type type) +{ + if (wsrep_auto_increment_control) + { + /* + The variables that control auto increment shall be calculated + automaticaly based on the size of the cluster. This usually done + within the wsrep_view_handler_cb callback. However, if the user + manually sets the value of wsrep_auto_increment_control to 'ON', + then we should to re-calculate these variables again (because + these values may be required before wsrep_view_handler_cb will + be re-invoked, which is rarely invoked if the cluster stays in + the stable state): + */ + global_system_variables.auto_increment_increment= + wsrep_cluster_size ? wsrep_cluster_size : 1; + global_system_variables.auto_increment_offset= + wsrep_local_index >= 0 ? wsrep_local_index + 1 : 1; + thd->variables.auto_increment_increment= + global_system_variables.auto_increment_increment; + thd->variables.auto_increment_offset= + global_system_variables.auto_increment_offset; + } + else + { + /* + We must restore the last values of the variables that + are explicitly specified by the user: + */ + global_system_variables.auto_increment_increment= + global_system_variables.saved_auto_increment_increment; + global_system_variables.auto_increment_offset= + global_system_variables.saved_auto_increment_offset; + thd->variables.auto_increment_increment= + thd->variables.saved_auto_increment_increment; + thd->variables.auto_increment_offset= + thd->variables.saved_auto_increment_offset; + } + return false; +} + static Sys_var_mybool Sys_wsrep_auto_increment_control( "wsrep_auto_increment_control", "To automatically control the " "assignment of autoincrement variables", GLOBAL_VAR(wsrep_auto_increment_control), - CMD_LINE(OPT_ARG), DEFAULT(TRUE)); + CMD_LINE(OPT_ARG), DEFAULT(TRUE), + NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), + ON_UPDATE(update_wsrep_auto_increment_control)); static Sys_var_mybool Sys_wsrep_drupal_282555_workaround( "wsrep_drupal_282555_workaround", "Enable a workaround to handle the " diff --git a/sql/wsrep_mysqld.h b/sql/wsrep_mysqld.h index 272e4ac4984..cd1a8882a95 100644 --- a/sql/wsrep_mysqld.h +++ b/sql/wsrep_mysqld.h @@ -161,6 +161,10 @@ extern "C" query_id_t wsrep_thd_query_id(THD *thd); extern "C" query_id_t wsrep_thd_wsrep_last_query_id(THD *thd); extern "C" void wsrep_thd_set_wsrep_last_query_id(THD *thd, query_id_t id); +extern "C" void wsrep_thd_auto_increment_variables(THD*, + unsigned long long *offset, + unsigned long long *increment); + extern void wsrep_close_client_connections(my_bool wait_to_end); extern int wsrep_wait_committing_connections_close(int wait_time); extern void wsrep_close_applier(THD *thd); diff --git a/sql/wsrep_thd.cc b/sql/wsrep_thd.cc index eb26da61282..cd7359160d6 100644 --- a/sql/wsrep_thd.cc +++ b/sql/wsrep_thd.cc @@ -676,3 +676,25 @@ bool wsrep_thd_has_explicit_locks(THD *thd) assert(thd); return thd->mdl_context.has_explicit_locks(); } + +/* + Get auto increment variables for THD. Use global settings for + applier threads. + */ +extern "C" +void wsrep_thd_auto_increment_variables(THD* thd, + unsigned long long* offset, + unsigned long long* increment) +{ + if (thd->wsrep_exec_mode == REPL_RECV && + thd->wsrep_conflict_state != REPLAYING) + { + *offset= global_system_variables.auto_increment_offset; + *increment= global_system_variables.auto_increment_increment; + } + else + { + *offset= thd->variables.auto_increment_offset; + *increment= thd->variables.auto_increment_increment; + } +} diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 5667efea5df..3d569a2d1d7 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -8396,14 +8396,29 @@ set_max_autoinc: /* This should filter out the negative values set explicitly by the user. */ if (auto_inc <= col_max_value) { - ut_a(prebuilt->autoinc_increment > 0); - ulonglong offset; ulonglong increment; dberr_t err; - offset = prebuilt->autoinc_offset; - increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + /* Applier threads which are + processing ROW events and don't go + through server level autoinc + processing, therefore m_prebuilt + autoinc values don't get + properly assigned. Fetch values from + server side. */ + if (wsrep_on(current_thd) && + wsrep_thd_exec_mode(current_thd) == REPL_RECV) { + wsrep_thd_auto_increment_variables(current_thd, &offset, &increment); + } else { +#endif /* WITH_WSREP */ + ut_a(prebuilt->autoinc_increment > 0); + offset = prebuilt->autoinc_offset; + increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ auto_inc = innobase_next_autoinc( auto_inc, @@ -8918,16 +8933,32 @@ ha_innobase::update_row( /* We need the upper limit of the col type to check for whether we update the table autoinc counter or not. */ - col_max_value = innobase_get_int_col_max_value( - table->next_number_field); + col_max_value = + table->next_number_field->get_max_int_value(); if (auto_inc <= col_max_value && auto_inc != 0) { ulonglong offset; ulonglong increment; - offset = prebuilt->autoinc_offset; - increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + /* Applier threads which are processing + ROW events and don't go through server + level autoinc processing, therefore + m_prebuilt autoinc values don't get + properly assigned. Fetch values from + server side. */ + if (wsrep_on(current_thd) && + wsrep_thd_exec_mode(current_thd) == REPL_RECV) { + wsrep_thd_auto_increment_variables( + current_thd, &offset, &increment); + } else { +#endif /* WITH_WSREP */ + offset = prebuilt->autoinc_offset; + increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ auto_inc = innobase_next_autoinc( auto_inc, 1, increment, offset, col_max_value); @@ -16038,13 +16069,13 @@ ha_innobase::get_auto_increment( increment, thd_get_thread_id(ha_thd()), current, autoinc); - if (!wsrep_on(ha_thd())) - { - current = autoinc - prebuilt->autoinc_increment; - } - current = innobase_next_autoinc( - current, 1, increment, offset, col_max_value); + if (!wsrep_on(ha_thd())) { + current = autoinc - prebuilt->autoinc_increment; + + current = innobase_next_autoinc( + current, 1, increment, offset, col_max_value); + } dict_table_autoinc_initialize(prebuilt->table, current); diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc index 3cd7cb6977b..857fc7e66f1 100644 --- a/storage/xtradb/handler/ha_innodb.cc +++ b/storage/xtradb/handler/ha_innodb.cc @@ -8988,8 +8988,25 @@ set_max_autoinc: ulonglong increment; dberr_t err; - offset = prebuilt->autoinc_offset; - increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + /* Applier threads which are + processing ROW events and don't go + through server level autoinc + processing, therefore m_prebuilt + autoinc values don't get + properly assigned. Fetch values from + server side. */ + if (wsrep_on(current_thd) && + wsrep_thd_exec_mode(current_thd) == REPL_RECV) { + wsrep_thd_auto_increment_variables(current_thd, &offset, &increment); + } else { +#endif /* WITH_WSREP */ + ut_a(prebuilt->autoinc_increment > 0); + offset = prebuilt->autoinc_offset; + increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ auto_inc = innobase_next_autoinc( auto_inc, @@ -9502,16 +9519,32 @@ ha_innobase::update_row( /* We need the upper limit of the col type to check for whether we update the table autoinc counter or not. */ - col_max_value = innobase_get_int_col_max_value( - table->next_number_field); + col_max_value = + table->next_number_field->get_max_int_value(); if (auto_inc <= col_max_value && auto_inc != 0) { ulonglong offset; ulonglong increment; - offset = prebuilt->autoinc_offset; - increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + /* Applier threads which are processing + ROW events and don't go through server + level autoinc processing, therefore + m_prebuilt autoinc values don't get + properly assigned. Fetch values from + server side. */ + if (wsrep_on(current_thd) && + wsrep_thd_exec_mode(current_thd) == REPL_RECV) { + wsrep_thd_auto_increment_variables( + current_thd, &offset, &increment); + } else { +#endif /* WITH_WSREP */ + offset = prebuilt->autoinc_offset; + increment = prebuilt->autoinc_increment; +#ifdef WITH_WSREP + } +#endif /* WITH_WSREP */ auto_inc = innobase_next_autoinc( auto_inc, 1, increment, offset, col_max_value); @@ -16742,13 +16775,13 @@ ha_innobase::get_auto_increment( increment, thd_get_thread_id(ha_thd()), current, autoinc); - if (!wsrep_on(ha_thd())) - { - current = autoinc - prebuilt->autoinc_increment; - } - current = innobase_next_autoinc( - current, 1, increment, offset, col_max_value); + if (!wsrep_on(ha_thd())) { + current = autoinc - prebuilt->autoinc_increment; + + current = innobase_next_autoinc( + current, 1, increment, offset, col_max_value); + } dict_table_autoinc_initialize(prebuilt->table, current); From 1b797e9e6308913c2472f3e04ad253e95a35d59f Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 6 Aug 2018 15:50:22 +0200 Subject: [PATCH 19/39] MDEV-15475: Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed on EXPLAIN EXTENDED with constant table and view Print constant ISNULL value independent. Fix of printing of view FRM and CREATE VIEW output --- mysql-test/r/derived_view.result | 6 +++--- mysql-test/r/func_isnull.result | 20 ++++++++++++++++++++ mysql-test/r/subselect_mat.result | 6 +++--- mysql-test/r/subselect_sj_mat.result | 6 +++--- mysql-test/t/func_isnull.test | 16 ++++++++++++++++ sql/item.cc | 2 +- sql/item_cmpfunc.cc | 13 +++++++++++++ sql/item_cmpfunc.h | 1 + sql/sql_lex.cc | 2 +- sql/sql_show.cc | 2 +- 10 files changed, 62 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/derived_view.result b/mysql-test/r/derived_view.result index f7062473a3f..12811ebc6b3 100644 --- a/mysql-test/r/derived_view.result +++ b/mysql-test/r/derived_view.result @@ -1101,7 +1101,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 100.00 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(7))) and trigcond((((5) = 5) or isnull(5))) and trigcond((7)) and trigcond((5)))))))) +Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(/*always not null*/ 1))) and trigcond((((5) = 5) or isnull(/*always not null*/ 1))) and trigcond((7)) and trigcond((5)))))))) SELECT t.a,t.b FROM t3 RIGHT JOIN ((SELECT * FROM t1) AS t, t2) ON t2.b != 0 WHERE (t.a,t.b) NOT IN (SELECT 7, 5); a b @@ -1115,7 +1115,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 100.00 3 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(7))) and trigcond((((5) = 5) or isnull(5))) and trigcond((7)) and trigcond((5)))))))) +Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(/*always not null*/ 1))) and trigcond((((5) = 5) or isnull(/*always not null*/ 1))) and trigcond((7)) and trigcond((5)))))))) SELECT t.a,t.b FROM t3 RIGHT JOIN (v1 AS t, t2) ON t2.b != 0 WHERE (t.a,t.b) NOT IN (SELECT 7, 5); a b @@ -1129,7 +1129,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t3 system NULL NULL NULL NULL 1 100.00 2 SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(7))) and trigcond((((5) = 5) or isnull(5))) and trigcond((7)) and trigcond((5)))))))) +Note 1003 select 6 AS `a`,5 AS `b` from `test`.`t3` where (not(<6,5>(((6,5),(select 7,5 having (trigcond((((6) = 7) or isnull(/*always not null*/ 1))) and trigcond((((5) = 5) or isnull(/*always not null*/ 1))) and trigcond((7)) and trigcond((5)))))))) DROP VIEW v1; DROP TABLE t1,t2,t3; # diff --git a/mysql-test/r/func_isnull.result b/mysql-test/r/func_isnull.result index 88c5bfd5468..a97d4a67939 100644 --- a/mysql-test/r/func_isnull.result +++ b/mysql-test/r/func_isnull.result @@ -106,5 +106,25 @@ Note 1003 select `test`.`t2`.`d1` AS `d1`,`test`.`t1`.`d1` AS `d1` from `test`.` DROP VIEW v1; DROP TABLE t1,t2; # +# MDEV-15475: Assertion `!table || (!table->read_set || +# bitmap_is_set(table->read_set, field_index))' +# failed on EXPLAIN EXTENDED with constant table and view +# +CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (1); +EXPLAIN EXTENDED SELECT ISNULL(pk) FROM v1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 select isnull(/*always not null*/ 1) AS `ISNULL(pk)` from dual +EXPLAIN EXTENDED SELECT IFNULL(pk,0) FROM v1; +id select_type table type possible_keys key key_len ref rows filtered Extra +1 SIMPLE t1 system NULL NULL NULL NULL 1 100.00 +Warnings: +Note 1003 select ifnull(1,0) AS `IFNULL(pk,0)` from dual +DROP VIEW v1; +DROP TABLE t1; +# # End of 5.5 tests # diff --git a/mysql-test/r/subselect_mat.result b/mysql-test/r/subselect_mat.result index eca3b760b65..efc348a26ce 100644 --- a/mysql-test/r/subselect_mat.result +++ b/mysql-test/r/subselect_mat.result @@ -499,7 +499,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull('1 - 01')) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull('2 - 01')) and ('1 - 01') and ('2 - 01'))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull(/*always not null*/ 1)) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull(/*always not null*/ 1)) and ('1 - 01') and ('2 - 01'))))) select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01'); a1 a2 1 - 01 2 - 01 @@ -509,7 +509,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull('1 - 01')) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull('2 - 01')) and ('1 - 01') and ('2 - 01'))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull(/*always not null*/ 1)) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull(/*always not null*/ 1)) and ('1 - 01') and ('2 - 01'))))) select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01' from dual); a1 a2 1 - 01 2 - 01 @@ -1896,7 +1896,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = ``.`MAX(c)`) and ((isnull(``.`MAX(c)`)) or (``.`MAX(c)` = 7))) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = ``.`MAX(c)`) and ((isnull(/*always not null*/ 1)) or (``.`MAX(c)` = 7))) SELECT * FROM t1 WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b); a b diff --git a/mysql-test/r/subselect_sj_mat.result b/mysql-test/r/subselect_sj_mat.result index 180c182a51a..fd9435e8a39 100644 --- a/mysql-test/r/subselect_sj_mat.result +++ b/mysql-test/r/subselect_sj_mat.result @@ -520,7 +520,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull('1 - 01')) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull('2 - 01')) and ('1 - 01') and ('2 - 01'))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull(/*always not null*/ 1)) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull(/*always not null*/ 1)) and ('1 - 01') and ('2 - 01'))))) select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01'); a1 a2 1 - 01 2 - 01 @@ -530,7 +530,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where 2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL NULL No tables used Warnings: -Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull('1 - 01')) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull('2 - 01')) and ('1 - 01') and ('2 - 01'))))) +Note 1003 select `test`.`t1`.`a1` AS `a1`,`test`.`t1`.`a2` AS `a2` from `test`.`t1` where <`test`.`t1`.`a1`,`test`.`t1`.`a2`>(((`test`.`t1`.`a1`,`test`.`t1`.`a2`),(select '1 - 01','2 - 01' having ((((`test`.`t1`.`a1`) = '1 - 01') or isnull(/*always not null*/ 1)) and (((`test`.`t1`.`a2`) = '2 - 01') or isnull(/*always not null*/ 1)) and ('1 - 01') and ('2 - 01'))))) select * from t1 where (a1, a2) in (select '1 - 01', '2 - 01' from dual); a1 a2 1 - 01 2 - 01 @@ -1934,7 +1934,7 @@ id select_type table type possible_keys key key_len ref rows filtered Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 3 100.00 Using where; Using join buffer (flat, BNL join) 2 MATERIALIZED t2 ALL NULL NULL NULL NULL 3 100.00 Warnings: -Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = ``.`MAX(c)`) and ((isnull(``.`MAX(c)`)) or (``.`MAX(c)` = 7))) +Note 1003 select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from (select max(`test`.`t2`.`c`) from `test`.`t2`) join `test`.`t1` where ((`test`.`t1`.`b` = 7) and (`test`.`t1`.`a` = ``.`MAX(c)`) and ((isnull(/*always not null*/ 1)) or (``.`MAX(c)` = 7))) SELECT * FROM t1 WHERE a IN (SELECT MAX(c) FROM t2) AND b=7 AND (a IS NULL OR a=b); a b diff --git a/mysql-test/t/func_isnull.test b/mysql-test/t/func_isnull.test index 4c59fa3cbe8..7d1a7e83a1a 100644 --- a/mysql-test/t/func_isnull.test +++ b/mysql-test/t/func_isnull.test @@ -83,6 +83,22 @@ SELECT * FROM t2 LEFT JOIN v1 ON t2.d1=v1.d1 WHERE v1.d1 IS NULL; DROP VIEW v1; DROP TABLE t1,t2; + +--echo # +--echo # MDEV-15475: Assertion `!table || (!table->read_set || +--echo # bitmap_is_set(table->read_set, field_index))' +--echo # failed on EXPLAIN EXTENDED with constant table and view +--echo # + +CREATE TABLE t1 (pk INT PRIMARY KEY) ENGINE=MyISAM; +CREATE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (1); +EXPLAIN EXTENDED SELECT ISNULL(pk) FROM v1; +EXPLAIN EXTENDED SELECT IFNULL(pk,0) FROM v1; +# Cleanup +DROP VIEW v1; +DROP TABLE t1; + --echo # --echo # End of 5.5 tests --echo # diff --git a/sql/item.cc b/sql/item.cc index 33c35f8c3e0..0cf4864326f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6845,7 +6845,7 @@ Item *Item_field::update_value_transformer(uchar *select_arg) void Item_field::print(String *str, enum_query_type query_type) { if (field && field->table->const_table && - !(query_type & QT_NO_DATA_EXPANSION)) + !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL))) { print_value(str); return; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6fb650b975b..d4a2c767b15 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4850,6 +4850,19 @@ Item *and_expressions(Item *a, Item *b, Item **org_item) } +void Item_func_isnull::print(String *str, enum_query_type query_type) +{ + str->append(func_name()); + str->append('('); + if (const_item() && !args[0]->maybe_null && + !(query_type & (QT_NO_DATA_EXPANSION | QT_VIEW_INTERNAL))) + str->append("/*always not null*/ 1"); + else + args[0]->print(str, query_type); + str->append(')'); +} + + longlong Item_func_isnull::val_int() { DBUG_ASSERT(fixed == 1); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 3c8cc71370d..c4e6a53dd6b 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1389,6 +1389,7 @@ public: const_item_cache= args[0]->const_item(); } } + virtual void print(String *str, enum_query_type query_type); table_map not_null_tables() const { return 0; } optimize_type select_optimize() const { return OPTIMIZE_NULL; } Item *neg_transformer(THD *thd); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 2bf1216ec34..cfbde25314b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2414,7 +2414,7 @@ void st_select_lex::print_order(String *str, { if (order->counter_used) { - if (query_type != QT_VIEW_INTERNAL) + if (!(query_type & QT_VIEW_INTERNAL)) { char buffer[20]; size_t length= my_snprintf(buffer, 20, "%d", order->counter); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 06d5a6f570a..db33a9de781 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2085,7 +2085,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff) We can't just use table->query, because our SQL_MODE may trigger a different syntax, like when ANSI_QUOTES is defined. */ - table->view->unit.print(buff, QT_ORDINARY); + table->view->unit.print(buff, QT_VIEW_INTERNAL); if (table->with_check != VIEW_CHECK_NONE) { From b62ac161856570e9a0e92d17de1e3dd31d54410f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Wed, 15 Aug 2018 15:21:37 +0300 Subject: [PATCH 20/39] MDEV-6439: Server crashes in Explain_union::print_explain with explain in slow log, tis620 charset Item_subselect::is_expensive() used to return FALSE (Inexpensive) whenever it saw that one of SELECTs in the Subquery's UNION is degenerate. It ignored the fact that other parts of the UNION might not be inexpensive, including the case where pther parts of the UNION have no query plan yet. For a subquery in form col >= ANY (SELECT 'foo' UNION SELECT 'bar') this would cause the query to be considered inexpensive when there is no query plan for the second part of the UNION, which in turn would cause the SELECT 'foo' to compute and free itself while still inside JOIN::optimize for that SELECT (See MDEV comment for full description). --- .../r/subselect_extra_no_semijoin.result | 19 ++++++++++++ mysql-test/t/subselect_extra_no_semijoin.test | 31 ++++++++++++++++++- sql/item_subselect.cc | 2 +- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/subselect_extra_no_semijoin.result b/mysql-test/r/subselect_extra_no_semijoin.result index 79bca388181..200682b4065 100644 --- a/mysql-test/r/subselect_extra_no_semijoin.result +++ b/mysql-test/r/subselect_extra_no_semijoin.result @@ -482,3 +482,22 @@ DROP TABLE t1,t2; set optimizer_switch= @tmp_subselect_extra_derived; set optimizer_switch= @subselect_extra_no_sj_tmp; set @optimizer_switch_for_subselect_extra_test=null; +# +# MDEV-6439: Server crashes in Explain_union::print_explain with explain in slow log, tis620 charset +# +SET NAMES tis620; +set @tmp= @@global.slow_query_log; +SET GLOBAL slow_query_log = 1; +SET long_query_time = 0.000001; +SET log_slow_verbosity = 'explain'; +CREATE TABLE t1 (a VARCHAR(3)) ENGINE=MyISAM; +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo'); +a +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo' UNION SELECT 'bar' ); +ERROR HY000: Illegal mix of collations (tis620_thai_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation '<=' +create table t2 (b int); +insert into t2 values (1),(2),(3); +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo' FROM t2); +ERROR HY000: Illegal mix of collations (tis620_thai_ci,COERCIBLE) and (latin1_swedish_ci,IMPLICIT) for operation '<=' +drop table t1,t2; +SET GLOBAL slow_query_log=@tmp; diff --git a/mysql-test/t/subselect_extra_no_semijoin.test b/mysql-test/t/subselect_extra_no_semijoin.test index 8aba3dde72b..d8809c7f981 100644 --- a/mysql-test/t/subselect_extra_no_semijoin.test +++ b/mysql-test/t/subselect_extra_no_semijoin.test @@ -6,4 +6,33 @@ set @optimizer_switch_for_subselect_extra_test='semijoin=off,firstmatch=off,loo set optimizer_switch= @subselect_extra_no_sj_tmp; -set @optimizer_switch_for_subselect_extra_test=null; \ No newline at end of file +set @optimizer_switch_for_subselect_extra_test=null; + +--echo # +--echo # MDEV-6439: Server crashes in Explain_union::print_explain with explain in slow log, tis620 charset +--echo # + +## Using a separate client connection is easier than restoring state +connect(con1,localhost,root,,); + +SET NAMES tis620; +set @tmp= @@global.slow_query_log; +SET GLOBAL slow_query_log = 1; +SET long_query_time = 0.000001; +SET log_slow_verbosity = 'explain'; + +CREATE TABLE t1 (a VARCHAR(3)) ENGINE=MyISAM; +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo'); +--error ER_CANT_AGGREGATE_2COLLATIONS +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo' UNION SELECT 'bar' ); + +create table t2 (b int); +insert into t2 values (1),(2),(3); + +--error ER_CANT_AGGREGATE_2COLLATIONS +SELECT * FROM t1 WHERE a >= ANY ( SELECT 'foo' FROM t2); + +drop table t1,t2; +SET GLOBAL slow_query_log=@tmp; +disconnect con1; +connection default; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index a8dfdff9809..14b2ccd3985 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -575,7 +575,7 @@ bool Item_subselect::is_expensive() */ if (cur_join->optimized && (cur_join->zero_result_cause || !cur_join->tables_list)) - return false; + continue; /* If a subquery is not optimized we cannot estimate its cost. A subquery is From f926c5f4fa34b9db9e0da014e530381209c1af3d Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 16 Aug 2018 08:37:54 +0100 Subject: [PATCH 21/39] MDEV-16996 mariabackup --prepare does not use native AIO on Linux by default --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index a7d136be820..5673c94fb0e 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -1216,7 +1216,7 @@ struct my_option xb_server_options[] = "Use native AIO if supported on this platform.", (G_PTR*) &srv_use_native_aio, (G_PTR*) &srv_use_native_aio, 0, GET_BOOL, NO_ARG, - FALSE, 0, 0, 0, 0, 0}, + TRUE, 0, 0, 0, 0, 0}, {"innodb_page_size", OPT_INNODB_PAGE_SIZE, "The universal page size of the database.", (G_PTR*) &innobase_page_size, (G_PTR*) &innobase_page_size, 0, From 1b49c894291d3d51d6bae2821eee0bf98ee20801 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 16 Aug 2018 15:29:40 +0300 Subject: [PATCH 22/39] Re-enable the test mariabackup.unsupported_redo Remove the logic for skipping the test if a log checkpoint occurred, and the logic for tolerating failures. Thanks to MDEV-16791, MLOG_INDEX_LOAD is supposed to always work. --- mysql-test/suite/mariabackup/disabled.def | 1 - .../suite/mariabackup/unsupported_redo.result | 2 +- .../suite/mariabackup/unsupported_redo.test | 35 +------------------ 3 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 mysql-test/suite/mariabackup/disabled.def diff --git a/mysql-test/suite/mariabackup/disabled.def b/mysql-test/suite/mariabackup/disabled.def deleted file mode 100644 index a7be04bfc16..00000000000 --- a/mysql-test/suite/mariabackup/disabled.def +++ /dev/null @@ -1 +0,0 @@ -unsupported_redo : MDEV-16791 allows optimized redo \ No newline at end of file diff --git a/mysql-test/suite/mariabackup/unsupported_redo.result b/mysql-test/suite/mariabackup/unsupported_redo.result index a1f95c099cd..fbad89be0ac 100644 --- a/mysql-test/suite/mariabackup/unsupported_redo.result +++ b/mysql-test/suite/mariabackup/unsupported_redo.result @@ -7,7 +7,7 @@ call mtr.add_suppression("InnoDB: Cannot open datafile for read-only: "); call mtr.add_suppression("Table .* in the InnoDB data dictionary has tablespace id .*, but tablespace with that id or name does not exist"); CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; -# Fails during full backup +# No longer fails during full backup DROP TABLE t1; CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; INSERT INTO t1(a) select 1 union select 2 union select 3; diff --git a/mysql-test/suite/mariabackup/unsupported_redo.test b/mysql-test/suite/mariabackup/unsupported_redo.test index 319ee2c7571..b9456751b9c 100644 --- a/mysql-test/suite/mariabackup/unsupported_redo.test +++ b/mysql-test/suite/mariabackup/unsupported_redo.test @@ -11,33 +11,15 @@ let $basedir=$MYSQLTEST_VARDIR/tmp/backup; let $incremental_dir=$MYSQLTEST_VARDIR/tmp/backup_inc1; CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; ---source ../../suite/innodb/include/no_checkpoint_start.inc ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; -# Below mariabackup operation may complete successfully if checkpoint happens -# after the alter table command. - -echo # Fails during full backup; +echo # No longer fails during full backup; --disable_result_log ---error 0,1 exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; --enable_result_log DROP TABLE t1; ---let MYSQLD_DATADIR=$basedir/ -perl; -open(OUT, ">$ENV{MYSQLTEST_VARDIR}/log/check.txt") || die; -print OUT ' ---let no_checkpoint_end=1 ---let CLEANUP_IF_CHECKPOINT=rmdir $basedir; ---source ../../suite/innodb/include/no_checkpoint_end.inc ---exit Backup failed to fail despite MLOG_INDEX_LOAD record -' if (-f "$ENV{MYSQLD_DATADIR}/xtrabackup_info"); -close(OUT); -EOF ---source $MYSQLTEST_VARDIR/log/check.txt ---remove_file $MYSQLTEST_VARDIR/log/check.txt rmdir $basedir; CREATE TABLE t1(i INT PRIMARY KEY auto_increment, a int) ENGINE INNODB; @@ -50,29 +32,14 @@ INSERT INTO t1(a) select 1 union select 2 union select 3; exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$basedir; --enable_result_log ---source ../../suite/innodb/include/no_checkpoint_start.inc ALTER TABLE t1 FORCE, ALGORITHM=INPLACE; --disable_result_log ---error 0,1 exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$incremental_dir --incremental-basedir=$basedir; --enable_result_log DROP TABLE t1; ---let MYSQLD_DATADIR=$incremental_dir/ -perl; -open(OUT, ">$ENV{MYSQLTEST_VARDIR}/log/check.txt") || die; -print OUT ' ---let no_checkpoint_end=1 ---let CLEANUP_IF_CHECKPOINT=rmdir $basedir;rmdir $incremental_dir; ---source ../../suite/innodb/include/no_checkpoint_end.inc ---exit Backup failed to fail despite MLOG_INDEX_LOAD record -' if (-f "$ENV{MYSQLD_DATADIR}/xtrabackup_info"); -close(OUT); -EOF ---source $MYSQLTEST_VARDIR/log/check.txt ---remove_file $MYSQLTEST_VARDIR/log/check.txt rmdir $basedir;rmdir $incremental_dir; CREATE TABLE t1(i INT) ENGINE INNODB; From d6f7fd601637a070ccf922073c0ef9a41a129717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 16 Aug 2018 16:10:18 +0300 Subject: [PATCH 23/39] MDEV-13564: Refuse MLOG_TRUNCATE in mariabackup The MySQL 5.7 TRUNCATE TABLE is inherently incompatible with hot backup, because it is creating and deleting a separate log file, and it is not writing redo log for all changes of the InnoDB data dictionary tables. Refuse to create a corrupted backup if the unsafe form of TRUNCATE was executed. Note: Undo log tablespace truncation cannot be detected easily. Also it is incompatible with backup, for similar reasons. xtrabackup_backup_func(): "Subscribe to" the log events before the first invocation of xtrabackup_copy_logfile(). recv_parse_or_apply_log_rec_body(): If the function pointer log_truncate is set, invoke it to report MLOG_TRUNCATE. --- extra/mariabackup/xtrabackup.cc | 20 +++++++++++++------ .../mariabackup/truncate_during_backup.result | 4 ++++ .../mariabackup/truncate_during_backup.test | 19 ++++++++++++++++++ storage/innobase/include/log0recv.h | 9 +++++++-- storage/innobase/log/log0recv.cc | 13 +++++++++++- 5 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 mysql-test/suite/mariabackup/truncate_during_backup.result create mode 100644 mysql-test/suite/mariabackup/truncate_during_backup.test diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 5673c94fb0e..d9397b001b7 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -358,9 +358,8 @@ struct ddl_tracker_t { /* For DDL operation found in redo log, */ space_id_to_name_t id_to_name; }; -const space_id_t REMOVED_SPACE_ID = ULINT_MAX; -static ddl_tracker_t ddl_tracker; +static ddl_tracker_t ddl_tracker; /* Whether xtrabackup_binlog_info should be created on recovery */ static bool recover_binlog_info; @@ -618,9 +617,8 @@ void backup_file_op(ulint space_id, const byte* flags, /** Callback whenever MLOG_INDEX_LOAD happens. -@param[in] space_id space id to check -@return false */ -void backup_optimized_ddl_op(ulint space_id) +@param[in] space_id space id to check */ +static void backup_optimized_ddl_op(ulint space_id) { // TODO : handle incremental if (xtrabackup_incremental) @@ -631,6 +629,15 @@ void backup_optimized_ddl_op(ulint space_id) pthread_mutex_unlock(&backup_mutex); } +/** Callback whenever MLOG_TRUNCATE happens. */ +static void backup_truncate_fail() +{ + msg("mariabackup: Incompatible TRUNCATE operation detected.%s\n", + opt_lock_ddl_per_table + ? "" + : " Use --lock-ddl-per-table to lock all tables before backup."); +} + /* ======== Date copying thread context ======== */ typedef struct { @@ -4240,12 +4247,13 @@ fail_before_log_copying_thread_start: /* copy log file by current position */ log_copy_scanned_lsn = checkpoint_lsn_start; recv_sys->recovered_lsn = log_copy_scanned_lsn; + log_optimized_ddl_op = backup_optimized_ddl_op; + log_truncate = backup_truncate_fail; if (xtrabackup_copy_logfile()) goto fail_before_log_copying_thread_start; log_copying_stop = os_event_create(0); - log_optimized_ddl_op = backup_optimized_ddl_op; os_thread_create(log_copying_thread, NULL, &log_copying_thread_id); /* FLUSH CHANGED_PAGE_BITMAPS call */ diff --git a/mysql-test/suite/mariabackup/truncate_during_backup.result b/mysql-test/suite/mariabackup/truncate_during_backup.result new file mode 100644 index 00000000000..f9d5c785749 --- /dev/null +++ b/mysql-test/suite/mariabackup/truncate_during_backup.result @@ -0,0 +1,4 @@ +CREATE TABLE t1 ENGINE=InnoDB SELECT 1; +DROP TABLE t1; +SET GLOBAL innodb_log_checkpoint_now=1; +SET GLOBAL innodb_log_checkpoint_now=DEFAULT; diff --git a/mysql-test/suite/mariabackup/truncate_during_backup.test b/mysql-test/suite/mariabackup/truncate_during_backup.test new file mode 100644 index 00000000000..c01a74588e7 --- /dev/null +++ b/mysql-test/suite/mariabackup/truncate_during_backup.test @@ -0,0 +1,19 @@ +--source include/have_debug.inc +let $targetdir=$MYSQLTEST_VARDIR/tmp/backup; +mkdir $targetdir; + +CREATE TABLE t1 ENGINE=InnoDB SELECT 1; + +--let after_load_tablespaces=TRUNCATE test.t1 + +--disable_result_log +--error 1 +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir --dbug=+d,mariabackup_events; +--enable_result_log + +--let after_load_tablespaces= + +DROP TABLE t1; +SET GLOBAL innodb_log_checkpoint_now=1; +SET GLOBAL innodb_log_checkpoint_now=DEFAULT; +rmdir $targetdir; diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index 6716b1cbd0d..28a4327ec4d 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -153,10 +153,15 @@ bool recv_parse_log_recs(lsn_t checkpoint_lsn, store_t store, bool apply); /** Moves the parsing buffer data left to the buffer start. */ void recv_sys_justify_left_parsing_buf(); -/** Report optimized DDL operation (without redo log), corresponding to MLOG_INDEX_LOAD. +/** Report optimized DDL operation (without redo log), +corresponding to MLOG_INDEX_LOAD. @param[in] space_id tablespace identifier */ -extern void(*log_optimized_ddl_op)(ulint space_id); +extern void (*log_optimized_ddl_op)(ulint space_id); + +/** Report backup-unfriendly TRUNCATE operation (with separate log file), +corresponding to MLOG_TRUNCATE. */ +extern void (*log_truncate)(); /** Report an operation to create, delete, or rename a file during backup. @param[in] space_id tablespace identifier diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index ee4d627261a..c623b884628 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -169,11 +169,16 @@ typedef std::map< static recv_spaces_t recv_spaces; -/** Report optimized DDL operation (without redo log), corresponding to MLOG_INDEX_LOAD. +/** Report optimized DDL operation (without redo log), +corresponding to MLOG_INDEX_LOAD. @param[in] space_id tablespace identifier */ void (*log_optimized_ddl_op)(ulint space_id); +/** Report backup-unfriendly TRUNCATE operation (with separate log file), +corresponding to MLOG_TRUNCATE. */ +void (*log_truncate)(); + /** Report an operation to create, delete, or rename a file during backup. @param[in] space_id tablespace identifier @param[in] flags tablespace flags (NULL if not create) @@ -1196,6 +1201,12 @@ recv_parse_or_apply_log_rec_body( } return(ptr + 8); case MLOG_TRUNCATE: + if (log_truncate) { + ut_ad(srv_operation != SRV_OPERATION_NORMAL); + log_truncate(); + recv_sys->found_corrupt_fs = true; + return NULL; + } return(truncate_t::parse_redo_entry(ptr, end_ptr, space_id)); default: From 4eac5df3fcebb1adf52e33d9d88dc05bc1e339ce Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 17 Aug 2018 14:27:42 -0700 Subject: [PATCH 24/39] MDEV-16934 Query with very large IN clause lists runs slowly This patch introduces support for the system variable eq_range_index_dive_limit that existed in MySQL starting from 5.6. The variable sets a limit for index dives into equality ranges. Index dives are performed by optimizer to estimate the number of rows in range scans. Index dives usually provide good estimate but they are pretty expensive. To estimate the number of rows in equality ranges statistical data on indexes can be employed. Its usage gives not so good estimates but it's cheap. So if the number of equality dives required by an index scan exceeds the set limit no dives for equality ranges are performed by the optimizer for this index. As the new system variable is introduced in a stable version the default value for it is set to a special value meaning there is no limit for the number of index dives performed by the optimizer. The patch partially uses the MySQL code for WL 5957 'Statistics-based Range optimization for many ranges'. --- mysql-test/r/mysqld--help.result | 6 +++ mysql-test/r/range.result | 41 ++++++++++++++ mysql-test/r/range_mrr_icp.result | 41 ++++++++++++++ .../sys_vars/r/sysvars_server_embedded.result | 14 +++++ .../r/sysvars_server_notembedded.result | 14 +++++ mysql-test/t/range.test | 33 ++++++++++++ sql/multi_range_read.cc | 11 ++++ sql/opt_range.cc | 27 ++++++++++ sql/opt_range.h | 4 +- sql/opt_range_mrr.cc | 54 +++++++++++++------ sql/sql_class.h | 1 + sql/sql_statistics.h | 2 +- sql/sys_vars.cc | 10 ++++ 13 files changed, 239 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index 3b7d5e21c00..51ece335908 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -197,6 +197,11 @@ The following specify which files/extra groups are read (specified before remain cache, etc) --enforce-storage-engine=name Force the use of a storage engine for new tables + --eq-range-index-dive-limit=# + The optimizer will use existing index statistics instead + of doing index dives for equality ranges if the number of + equality ranges for the index is larger than or equal to + this number. If set to 0, index dives are always used. --event-scheduler[=name] Enable the event scheduler. Possible values are ON, OFF, and DISABLED (keep the event scheduler completely @@ -1259,6 +1264,7 @@ encrypt-binlog FALSE encrypt-tmp-disk-tables FALSE encrypt-tmp-files FALSE enforce-storage-engine (No default value) +eq-range-index-dive-limit 0 event-scheduler OFF expensive-subquery-limit 100 expire-logs-days 0 diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 3a71d08eb38..0c6be5e56f2 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -3002,5 +3002,46 @@ deallocate prepare stmt; set optimizer_switch=@save_optimizer_switch; drop table t1,t2,t3; # +# MDEV-16934: using system variable eq_range_index_dive_limit +# to reduce the number of index dives +# +create table t1 (a int, b varchar(31), index idx(a)); +insert into t1 values +(7,'xxxx'), (1,'yy'), (3,'aaa'), (1,'bbb'), (2,'zz'), +(4,'vvvvv'), (7,'ddd'), (9,'zzzzz'), (1,'cc'), (5,'ffff'); +insert into t1 select a+10, concat(b,'zz') from t1; +insert into t1 select a+15, concat(b,'yy') from t1; +insert into t1 select a+100, concat(b,'xx') from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select cast(count(a)/count(distinct a) as unsigned) as rec_per_key from t1; +rec_per_key +2 +set eq_range_index_dive_limit=0; +explain select * from t1 where a in (8, 15, 31, 1, 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 7 Using index condition +select * from t1 where a in (8, 15, 31, 1, 9); +a b +1 yy +1 bbb +1 cc +9 zzzzz +15 ffffzz +set eq_range_index_dive_limit=2; +explain select * from t1 where a in (8, 15, 31, 1, 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 10 Using index condition +select * from t1 where a in (8, 15, 31, 1, 9); +a b +1 yy +1 bbb +1 cc +9 zzzzz +15 ffffzz +set eq_range_index_dive_limit=default; +drop table t1; +# # End of 10.2 tests # diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 799a299e33f..93f414f1604 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -3014,6 +3014,47 @@ deallocate prepare stmt; set optimizer_switch=@save_optimizer_switch; drop table t1,t2,t3; # +# MDEV-16934: using system variable eq_range_index_dive_limit +# to reduce the number of index dives +# +create table t1 (a int, b varchar(31), index idx(a)); +insert into t1 values +(7,'xxxx'), (1,'yy'), (3,'aaa'), (1,'bbb'), (2,'zz'), +(4,'vvvvv'), (7,'ddd'), (9,'zzzzz'), (1,'cc'), (5,'ffff'); +insert into t1 select a+10, concat(b,'zz') from t1; +insert into t1 select a+15, concat(b,'yy') from t1; +insert into t1 select a+100, concat(b,'xx') from t1; +analyze table t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK +select cast(count(a)/count(distinct a) as unsigned) as rec_per_key from t1; +rec_per_key +2 +set eq_range_index_dive_limit=0; +explain select * from t1 where a in (8, 15, 31, 1, 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 7 Using index condition; Rowid-ordered scan +select * from t1 where a in (8, 15, 31, 1, 9); +a b +1 yy +1 bbb +9 zzzzz +1 cc +15 ffffzz +set eq_range_index_dive_limit=2; +explain select * from t1 where a in (8, 15, 31, 1, 9); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 10 Using index condition; Rowid-ordered scan +select * from t1 where a in (8, 15, 31, 1, 9); +a b +1 yy +1 bbb +9 zzzzz +1 cc +15 ffffzz +set eq_range_index_dive_limit=default; +drop table t1; +# # End of 10.2 tests # set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index a7a7547d73b..31a6b597edc 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -779,6 +779,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT NULL +VARIABLE_NAME EQ_RANGE_INDEX_DIVE_LIMIT +SESSION_VALUE 0 +GLOBAL_VALUE 0 +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE 0 +VARIABLE_SCOPE SESSION +VARIABLE_TYPE INT UNSIGNED +VARIABLE_COMMENT The optimizer will use existing index statistics instead of doing index dives for equality ranges if the number of equality ranges for the index is larger than or equal to this number. If set to 0, index dives are always used. +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 4294967295 +NUMERIC_BLOCK_SIZE 1 +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME ERROR_COUNT SESSION_VALUE 0 GLOBAL_VALUE NULL diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index a8f20769e30..133b1fc8969 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -793,6 +793,20 @@ NUMERIC_BLOCK_SIZE NULL ENUM_VALUE_LIST NULL READ_ONLY NO COMMAND_LINE_ARGUMENT NULL +VARIABLE_NAME EQ_RANGE_INDEX_DIVE_LIMIT +SESSION_VALUE 0 +GLOBAL_VALUE 0 +GLOBAL_VALUE_ORIGIN COMPILE-TIME +DEFAULT_VALUE 0 +VARIABLE_SCOPE SESSION +VARIABLE_TYPE INT UNSIGNED +VARIABLE_COMMENT The optimizer will use existing index statistics instead of doing index dives for equality ranges if the number of equality ranges for the index is larger than or equal to this number. If set to 0, index dives are always used. +NUMERIC_MIN_VALUE 0 +NUMERIC_MAX_VALUE 4294967295 +NUMERIC_BLOCK_SIZE 1 +ENUM_VALUE_LIST NULL +READ_ONLY NO +COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME ERROR_COUNT SESSION_VALUE 0 GLOBAL_VALUE NULL diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index ab951809b7a..ed68cfb9583 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -2045,6 +2045,39 @@ set optimizer_switch=@save_optimizer_switch; drop table t1,t2,t3; +--echo # +--echo # MDEV-16934: using system variable eq_range_index_dive_limit +--echo # to reduce the number of index dives +--echo # + +create table t1 (a int, b varchar(31), index idx(a)); + +insert into t1 values + (7,'xxxx'), (1,'yy'), (3,'aaa'), (1,'bbb'), (2,'zz'), + (4,'vvvvv'), (7,'ddd'), (9,'zzzzz'), (1,'cc'), (5,'ffff'); +insert into t1 select a+10, concat(b,'zz') from t1; +insert into t1 select a+15, concat(b,'yy') from t1; +insert into t1 select a+100, concat(b,'xx') from t1; + +analyze table t1; + +select cast(count(a)/count(distinct a) as unsigned) as rec_per_key from t1; + +let $q= +select * from t1 where a in (8, 15, 31, 1, 9); + +set eq_range_index_dive_limit=0; +eval explain $q; +eval $q; + +set eq_range_index_dive_limit=2; +eval explain $q; +eval $q; + +set eq_range_index_dive_limit=default; + +drop table t1; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 50918d8dcf2..94a96c27a0f 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -17,6 +17,7 @@ #include #include "sql_select.h" #include "key.h" +#include "sql_statistics.h" /**************************************************************************** * Default MRR implementation (MRR to non-MRR converter) @@ -67,6 +68,9 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, /* Default MRR implementation doesn't need buffer */ *bufsz= 0; + bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq, + seq_init_param); + seq_it= seq->init(seq_init_param, n_ranges, *flags); while (!seq->next(seq_it, &range)) { @@ -87,8 +91,15 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, min_endp= range.start_key.length? &range.start_key : NULL; max_endp= range.end_key.length? &range.end_key : NULL; } + int keyparts_used= my_count_bits(range.start_key.keypart_map); if ((range.range_flag & UNIQUE_RANGE) && !(range.range_flag & NULL_RANGE)) rows= 1; /* there can be at most one row */ + else if (use_statistics_for_eq_range && + !(range.range_flag & NULL_RANGE) && + (range.range_flag & EQ_RANGE) && + table->key_info[keyno].actual_rec_per_key(keyparts_used - 1) > 0.5) + rows= + (ha_rows) table->key_info[keyno].actual_rec_per_key(keyparts_used - 1); else { if (HA_POS_ERROR == (rows= this->records_in_range(keyno, min_endp, diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0d723094445..47e07016782 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -14617,6 +14617,33 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, } +/* Check whether the number for equality ranges exceeds the set threshold */ + +bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param) +{ + KEY_MULTI_RANGE range; + range_seq_t seq_it; + uint count = 0; + PARAM *param= ((SEL_ARG_RANGE_SEQ*) seq_init_param)->param; + uint limit= param->thd->variables.eq_range_index_dive_limit; + + if (limit == 0) + { + /* 'Statistics instead of index dives' feature is turned off */ + return false; + } + seq_it= seq->init(seq_init_param, 0, 0); + while (!seq->next(seq_it, &range)) + { + if ((range.range_flag & EQ_RANGE) && !(range.range_flag & NULL_RANGE)) + { + if (++count >= limit) + return true; + } + } + return false; +} + #ifndef DBUG_OFF static void print_sel_tree(PARAM *param, SEL_TREE *tree, key_map *tree_map, diff --git a/sql/opt_range.h b/sql/opt_range.h index c1f7079ce7f..6698c987e78 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -242,7 +242,7 @@ public: Number of children of this element in the RB-tree, plus 1 for this element itself. */ - uint16 elements; + uint32 elements; /* Valid only for elements which are RB-tree roots: Number of times this RB-tree is referred to (it is referred by SEL_ARG::next_key_part or by @@ -1664,6 +1664,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond); +bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param); + #ifdef WITH_PARTITION_STORAGE_ENGINE bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond); #endif diff --git a/sql/opt_range_mrr.cc b/sql/opt_range_mrr.cc index ace6208fd77..c7e4496f2c1 100644 --- a/sql/opt_range_mrr.cc +++ b/sql/opt_range_mrr.cc @@ -72,6 +72,7 @@ typedef struct st_sel_arg_range_seq range_seq_t sel_arg_range_seq_init(void *init_param, uint n_ranges, uint flags) { SEL_ARG_RANGE_SEQ *seq= (SEL_ARG_RANGE_SEQ*)init_param; + seq->param->range_count=0; seq->at_start= TRUE; seq->stack[0].key_tree= NULL; seq->stack[0].min_key= seq->param->min_key; @@ -272,25 +273,44 @@ walk_up_n_right: key_info= NULL; else key_info= &seq->param->table->key_info[seq->real_keyno]; - + /* - Conditions below: - (1) - range analysis is used for estimating condition selectivity - (2) - This is a unique key, and we have conditions for all its - user-defined key parts. - (3) - The table uses extended keys, this key covers all components, - and we have conditions for all key parts. + This is an equality range (keypart_0=X and ... and keypart_n=Z) if + (1) - There are no flags indicating open range (e.g., + "keypart_x > y") or GIS. + (2) - The lower bound and the upper bound of the range has the + same value (min_key == max_key). */ - if (!(cur->min_key_flag & ~NULL_RANGE) && !cur->max_key_flag && - (!key_info || // (1) - ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2) - key_info->flags & HA_NOSAME) || // (2) - ((key_info->flags & HA_EXT_NOSAME) && // (3) - (uint)key_tree->part+1 == key_info->ext_key_parts) // (3) - ) && - range->start_key.length == range->end_key.length && - !memcmp(seq->param->min_key,seq->param->max_key,range->start_key.length)) - range->range_flag= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); + const uint is_open_range = + (NO_MIN_RANGE | NO_MAX_RANGE | NEAR_MIN | NEAR_MAX | GEOM_FLAG); + const bool is_eq_range_pred = + !(cur->min_key_flag & is_open_range) && // (1) + !(cur->max_key_flag & is_open_range) && // (1) + range->start_key.length == range->end_key.length && // (2) + !memcmp(seq->param->min_key, seq->param->max_key, // (2) + range->start_key.length); + + if (is_eq_range_pred) + { + range->range_flag = EQ_RANGE; + + /* + Conditions below: + (1) - Range analysis is used for estimating condition selectivity + (2) - This is a unique key, and we have conditions for all its + user-defined key parts. + (3) - The table uses extended keys, this key covers all components, + and we have conditions for all key parts. + */ + if ( + !key_info || // (1) + ((uint)key_tree->part+1 == key_info->user_defined_key_parts && // (2) + key_info->flags & HA_NOSAME) || // (2) + ((key_info->flags & HA_EXT_NOSAME) && // (3) + (uint)key_tree->part+1 == key_info->ext_key_parts) // (3) + ) + range->range_flag |= UNIQUE_RANGE | (cur->min_key_flag & NULL_RANGE); + } if (seq->param->is_ror_scan) { diff --git a/sql/sql_class.h b/sql/sql_class.h index cb7523af615..4888b38bc30 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -569,6 +569,7 @@ typedef struct system_variables ha_rows max_join_size; ha_rows expensive_subquery_limit; ulong auto_increment_increment, auto_increment_offset; + uint eq_range_index_dive_limit; ulong lock_wait_timeout; ulong join_cache_level; ulong max_allowed_packet; diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index 0611c021e88..28d5cd46760 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -21,7 +21,7 @@ enum enum_use_stat_tables_mode { NEVER, COMPLEMENTARY, - PEFERABLY, + PREFERABLY, } Use_stat_tables_mode; typedef diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 841e57fa3e2..391772d1191 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -2584,6 +2584,16 @@ static Sys_var_ulong Sys_div_precincrement( SESSION_VAR(div_precincrement), CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, DECIMAL_MAX_SCALE), DEFAULT(4), BLOCK_SIZE(1)); +static Sys_var_uint Sys_eq_range_index_dive_limit( + "eq_range_index_dive_limit", + "The optimizer will use existing index statistics instead of " + "doing index dives for equality ranges if the number of equality " + "ranges for the index is larger than or equal to this number. " + "If set to 0, index dives are always used.", + SESSION_VAR(eq_range_index_dive_limit), CMD_LINE(REQUIRED_ARG), + VALID_RANGE(0, UINT_MAX32), DEFAULT(0), + BLOCK_SIZE(1)); + static Sys_var_ulong Sys_range_alloc_block_size( "range_alloc_block_size", "Allocation block size for storing ranges during optimization", From 862a97749d5a36218ba4d55c26eef30cd7b2e3cb Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 17 Aug 2018 19:29:01 -0700 Subject: [PATCH 25/39] =?UTF-8?q?MDEV-17011=20=E2=80=9Ccondition=5Fpushdow?= =?UTF-8?q?n=5Ffor=5Fderived=E2=80=9D=20optimization=20not=20used=20when?= =?UTF-8?q?=20=20=20=20=20=20=20=20=20=20=20=20using=20INSERT=20INTO?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch allows condition pushdown into a materialized derived / view when this table is used in INSERT SELECT, multi-table UPDATE and multi-table DELETE. --- mysql-test/r/derived_cond_pushdown.result | 143 ++++++++++++++++++++++ mysql-test/t/derived_cond_pushdown.test | 44 +++++++ sql/sql_select.cc | 3 +- 3 files changed, 188 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index 22b81ef48a5..839ae587839 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -9874,3 +9874,146 @@ SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, (SELECT MAX('aa') FROM DUAL LIMIT a aa DROP FUNCTION f1; +# +# MDEV-17011: condition pushdown into materialized derived used +# in INSERT SELECT, multi-table UPDATE and DELETE +# +CREATE TABLE t1 (a int ,b int) ENGINE=MyISAM; +INSERT INTO t1 VALUES +(1, 1), (1, 2), (2, 1), (2, 2), (3,1), (3,3), (4,2); +CREATE TABLE t2 (a int) ENGINE MYISAM; +INSERT INTO t2 VALUES +(3), (7), (1), (4), (1); +CREATE TABLE t3 (a int, b int) ENGINE MYISAM; +EXPLAIN FORMAT=JSON INSERT INTO t3 +SELECT * FROM (SELECT a, count(*) as c FROM t1 GROUP BY a) t WHERE a<=2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "t.a <= 2", + "materialized": { + "query_block": { + "select_id": 2, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "t1.a <= 2" + } + } + } + } + } + } + } +} +INSERT INTO t3 +SELECT * FROM (SELECT a, count(*) as c FROM t1 GROUP BY a) t WHERE a<=2; +SELECT * FROM t3; +a b +1 2 +2 2 +EXPLAIN FORMAT=JSON UPDATE t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t SET t2.a=t.c+10 +WHERE t2.a= t.c and t.a>=3; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 5, + "filtered": 100, + "attached_condition": "t2.a is not null" + }, + "table": { + "table_name": "", + "access_type": "ref", + "possible_keys": ["key0"], + "key": "key0", + "key_length": "8", + "used_key_parts": ["c"], + "ref": ["test.t2.a"], + "rows": 2, + "filtered": 100, + "attached_condition": "t2.a = t.c and t.a >= 3", + "materialized": { + "query_block": { + "select_id": 2, + "filesort": { + "sort_key": "t1.a", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "t1.a >= 3" + } + } + } + } + } + } + } +} +UPDATE t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t SET t2.a=t.c+10 +WHERE t2.a= t.c and t.a>=3; +SELECT * FROM t2; +a +3 +7 +11 +4 +11 +EXPLAIN FORMAT=JSON DELETE t2 FROM t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t +WHERE t2.a= t.c+9 and t.a=2; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "ALL", + "rows": 5, + "filtered": 100 + }, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "t.a = 2 and t2.a = t.c + 9", + "materialized": { + "query_block": { + "select_id": 2, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 7, + "filtered": 100, + "attached_condition": "t1.a = 2" + } + } + } + } + } +} +DELETE t2 FROM t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t +WHERE t2.a= t.c+9 and t.a=2; +SELECT * FROM t2; +a +3 +7 +4 +DROP TABLE t1,t2,t3; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index d9d767f53ed..f85b301de35 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1920,3 +1920,47 @@ END;$$ DELIMITER ;$$ SELECT a FROM (SELECT "aa" a) t WHERE f1(t.a, (SELECT MAX('aa') FROM DUAL LIMIT 1)); DROP FUNCTION f1; + +--echo # +--echo # MDEV-17011: condition pushdown into materialized derived used +--echo # in INSERT SELECT, multi-table UPDATE and DELETE +--echo # + +CREATE TABLE t1 (a int ,b int) ENGINE=MyISAM; +INSERT INTO t1 VALUES + (1, 1), (1, 2), (2, 1), (2, 2), (3,1), (3,3), (4,2); + +CREATE TABLE t2 (a int) ENGINE MYISAM; +INSERT INTO t2 VALUES + (3), (7), (1), (4), (1); + +CREATE TABLE t3 (a int, b int) ENGINE MYISAM; + +let $q1= +INSERT INTO t3 +SELECT * FROM (SELECT a, count(*) as c FROM t1 GROUP BY a) t WHERE a<=2; + +eval EXPLAIN FORMAT=JSON $q1; +eval $q1; + +SELECT * FROM t3; + +let $q2= +UPDATE t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t SET t2.a=t.c+10 + WHERE t2.a= t.c and t.a>=3; + +eval EXPLAIN FORMAT=JSON $q2; +eval $q2; + +SELECT * FROM t2; + +let $q3= +DELETE t2 FROM t2, (SELECT a, count(*) as c FROM t1 GROUP BY a) t + WHERE t2.a= t.c+9 and t.a=2; + +eval EXPLAIN FORMAT=JSON $q3; +eval $q3; + +SELECT * FROM t2; + +DROP TABLE t1,t2,t3; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 643ddfeba39..b94ca496b95 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1375,8 +1375,7 @@ JOIN::optimize_inner() DBUG_RETURN(1); } - if (thd->lex->sql_command == SQLCOM_SELECT && - optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) + if (optimizer_flag(thd, OPTIMIZER_SWITCH_COND_PUSHDOWN_FOR_DERIVED)) { TABLE_LIST *tbl; List_iterator_fast li(select_lex->leaf_tables); From 0de3c423cc51d362c3a9b4dc8fa90d549ce0754e Mon Sep 17 00:00:00 2001 From: Galina Shalygina Date: Mon, 20 Aug 2018 17:42:49 +0300 Subject: [PATCH 26/39] MDEV-16765: Missing rows with pushdown condition defined with CASE using Item_cond The bug appears because of the wrong pushdown into the WHERE clause of the materialized derived table/view work. For the excl_dep_on_grouping_fields() method that checks if the condition can be pushed into the WHERE clause the case when Item_cond is used is missing. For Item_cond elements this method always returns positive result (that condition can be pushed). So this condition is pushed even if is shouldn't be pushed. To fix it new Item_cond::excl_dep_on_grouping_fields() method is added. --- mysql-test/r/derived_cond_pushdown.result | 203 ++++++++++++++++++++++ mysql-test/t/derived_cond_pushdown.test | 58 +++++++ sql/item_cmpfunc.cc | 13 ++ sql/item_cmpfunc.h | 1 + 4 files changed, 275 insertions(+) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index 839ae587839..fd930d13547 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -10017,3 +10017,206 @@ a 7 4 DROP TABLE t1,t2,t3; +# +# MDEV-16765: pushdown condition with the CASE structure +# defined with Item_cond item +# +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,2), (3,4), (2,3); +SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a=1) OR (tab2.max_a=2)) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +max_a b +1 2 +1 3 +EXPLAIN FORMAT=JSON SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a=1) OR (tab2.max_a=2)) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a = 2) then 1 else 0 end = 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "case when (max_a = 1 or max_a = 2) then 1 else 0 end = 1", + "filesort": { + "sort_key": "t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } + } + } + } +} +SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a=1) OR ((tab2.max_a>2) AND (tab2.max_a<4))) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +max_a b +1 2 +1 4 +EXPLAIN FORMAT=JSON SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a=1) OR ((tab2.max_a>2) AND (tab2.max_a<4))) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when (tab2.max_a = 1 or tab2.max_a > 2 and tab2.max_a < 4) then 1 else 0 end = 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "case when (max_a = 1 or max_a > 2 and max_a < 4) then 1 else 0 end = 1", + "filesort": { + "sort_key": "t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } + } + } + } +} +SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a>1) AND ((tab2.max_a=2) OR (tab2.max_a>2))) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +max_a b +1 3 +1 4 +EXPLAIN FORMAT=JSON SELECT * +FROM +( +SELECT CASE WHEN ((tab2.max_a>1) AND ((tab2.max_a=2) OR (tab2.max_a>2))) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when (tab2.max_a > 1 and (tab2.max_a = 2 or tab2.max_a > 2)) then 1 else 0 end = 1", + "materialized": { + "query_block": { + "select_id": 3, + "having_condition": "case when (max_a > 1 and (max_a = 2 or max_a > 2)) then 1 else 0 end = 1", + "filesort": { + "sort_key": "t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100 + } + } + } + } + } + } + } +} +SELECT * +FROM +( +SELECT CASE WHEN ((tab2.b=2) OR (tab2.b=4)) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +max_a b +1 2 +1 4 +EXPLAIN FORMAT=JSON SELECT * +FROM +( +SELECT CASE WHEN ((tab2.b=2) OR (tab2.b=4)) +THEN 1 ELSE 0 END AS max_a,b +FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when (tab2.b = 2 or tab2.b = 4) then 1 else 0 end = 1", + "materialized": { + "query_block": { + "select_id": 3, + "filesort": { + "sort_key": "t1.b", + "temporary_table": { + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 3, + "filtered": 100, + "attached_condition": "case when (t1.b = 2 or t1.b = 4) then 1 else 0 end = 1" + } + } + } + } + } + } + } +} +DROP TABLE t1; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index f85b301de35..b8e74a2d5aa 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1964,3 +1964,61 @@ eval $q3; SELECT * FROM t2; DROP TABLE t1,t2,t3; + +--echo # +--echo # MDEV-16765: pushdown condition with the CASE structure +--echo # defined with Item_cond item +--echo # + +CREATE TABLE t1(a INT, b INT); +INSERT INTO t1 VALUES (1,2), (3,4), (2,3); + +LET $query= +SELECT * +FROM +( + SELECT CASE WHEN ((tab2.max_a=1) OR (tab2.max_a=2)) + THEN 1 ELSE 0 END AS max_a,b + FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EVAL $query; +EVAL EXPLAIN FORMAT=JSON $query; + +LET $query= +SELECT * +FROM +( + SELECT CASE WHEN ((tab2.max_a=1) OR ((tab2.max_a>2) AND (tab2.max_a<4))) + THEN 1 ELSE 0 END AS max_a,b + FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EVAL $query; +EVAL EXPLAIN FORMAT=JSON $query; + +LET $query= +SELECT * +FROM +( + SELECT CASE WHEN ((tab2.max_a>1) AND ((tab2.max_a=2) OR (tab2.max_a>2))) + THEN 1 ELSE 0 END AS max_a,b + FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EVAL $query; +EVAL EXPLAIN FORMAT=JSON $query; + +LET $query= +SELECT * +FROM +( + SELECT CASE WHEN ((tab2.b=2) OR (tab2.b=4)) + THEN 1 ELSE 0 END AS max_a,b + FROM (SELECT MAX(a) as max_a,b FROM t1 GROUP BY t1.b) AS tab2 +) AS tab1 +WHERE (tab1.max_a=1); +EVAL $query; +EVAL EXPLAIN FORMAT=JSON $query; + +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f176a0a8193..6834820c0b5 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4970,6 +4970,19 @@ Item *Item_cond::build_clone(THD *thd, MEM_ROOT *mem_root) } +bool Item_cond::excl_dep_on_grouping_fields(st_select_lex *sel) +{ + List_iterator_fast li(list); + Item *item; + while ((item= li++)) + { + if (!item->excl_dep_on_grouping_fields(sel)) + return false; + } + return true; +} + + void Item_cond_and::mark_as_condition_AND_part(TABLE_LIST *embedding) { List_iterator li(list); diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 41a51ee8d12..59ac5f56fe1 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -2224,6 +2224,7 @@ public: Item_transformer transformer, uchar *arg_t); bool eval_not_null_tables(void *opt_arg); Item *build_clone(THD *thd, MEM_ROOT *mem_root); + bool excl_dep_on_grouping_fields(st_select_lex *sel); }; template class LI, class T> class Item_equal_iterator; From cccdb176a6eb506426ba63724bf807cc5dfbb844 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 21 Aug 2018 08:54:21 +0300 Subject: [PATCH 27/39] MDEV-16862 build failure for WITH_INNODB_AHI=0 Fix the build, which was broken by MDEV-16515. --- storage/innobase/row/row0import.cc | 3 ++- storage/innobase/row/row0mysql.cc | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 117a2e573de..371b9aa556f 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3928,7 +3928,7 @@ row_import_for_mysql( DBUG_EXECUTE_IF("ib_import_reset_space_and_lsn_failure", err = DB_TOO_MANY_CONCURRENT_TRXS;); - +#ifdef BTR_CUR_HASH_ADAPT /* On DISCARD TABLESPACE, we did not drop any adaptive hash index entries. If we replaced the discarded tablespace with a smaller one here, there could still be some adaptive hash @@ -3945,6 +3945,7 @@ row_import_for_mysql( break; } } +#endif /* BTR_CUR_HASH_ADAPT */ if (err != DB_SUCCESS) { char table_name[MAX_FULL_NAME_LEN + 1]; diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index 5ba8d038671..e1fe6e15067 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -3433,6 +3433,7 @@ row_drop_table_for_mysql( if (!dict_table_is_temporary(table)) { if (table->space != TRX_SYS_SPACE) { +#ifdef BTR_CUR_HASH_ADAPT /* On DISCARD TABLESPACE, we would not drop the adaptive hash index entries. If the tablespace is missing here, delete-marking the record in SYS_INDEXES @@ -3454,6 +3455,7 @@ row_drop_table_for_mysql( goto funct_exit; } } +#endif /* BTR_CUR_HASH_ADAPT */ /* Delete the link file if used. */ if (DICT_TF_HAS_DATA_DIR(table->flags)) { From 45dbd47026362dc18a5d1717d33191a0e15db61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 21 Aug 2018 11:56:50 +0300 Subject: [PATCH 28/39] MDEV-17003 service_manager_extend_timeout() being called too often buf_dump(): Only generate the output when shutdown is in progress. log_write_up_to(): Only generate the output before actually writing to the redo log files. srv_purge_should_exit(): Rate-limit the output, and instead of displaying the work done, indicate the work that remains to be done until the completion of the slow shutdown. --- storage/innobase/buf/buf0dump.cc | 4 ++-- storage/innobase/log/log0log.cc | 13 +++++++------ storage/innobase/srv/srv0srv.cc | 14 +++++++++++--- storage/xtradb/buf/buf0dump.cc | 4 ++-- storage/xtradb/log/log0log.cc | 13 +++++++------ storage/xtradb/srv/srv0srv.cc | 14 +++++++++++--- 6 files changed, 40 insertions(+), 22 deletions(-) diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc index 1df75386872..74d71fd97e2 100644 --- a/storage/innobase/buf/buf0dump.cc +++ b/storage/innobase/buf/buf0dump.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -334,7 +334,7 @@ buf_dump( i + 1, srv_buf_pool_instances, j + 1, n_pages); } - if ( (j % 1024) == 0) { + if (SHUTTING_DOWN() && !(j % 1024)) { service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, "Dumping buffer pool " ULINTPF "/" ULINTPF ", " diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 6546459354b..cd00394cded 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -1443,12 +1443,6 @@ log_write_up_to( return; } - if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "log write up to: " LSN_PF, - lsn); - } - loop: ut_ad(++loop_count < 100); @@ -1561,6 +1555,13 @@ loop: log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE; log_sys->write_end_offset = log_sys->buf_free; + if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE)) { + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "InnoDB log write: " + LSN_PF "," LSN_PF, + log_sys->write_lsn, lsn); + } + group = UT_LIST_GET_FIRST(log_sys->log_groups); /* Do the write to the log files */ diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 6e8ed7893d6..87f9064c14e 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -2542,9 +2542,17 @@ srv_purge_should_exit(ulint n_purged) } /* Slow shutdown was requested. */ if (n_purged) { - service_manager_extend_timeout( - INNODB_EXTEND_TIMEOUT_INTERVAL, - "InnoDB " ULINTPF " pages purged", n_purged); +#if defined HAVE_SYSTEMD && !defined EMBEDDED_LIBRARY + static ib_time_t progress_time; + ib_time_t time = ut_time(); + if (time - progress_time >= 15) { + progress_time = time; + service_manager_extend_timeout( + INNODB_EXTEND_TIMEOUT_INTERVAL, + "InnoDB: to purge " ULINTPF " transactions", + trx_sys->rseg_history_len); + } +#endif /* The previous round still did some work. */ return(false); } diff --git a/storage/xtradb/buf/buf0dump.cc b/storage/xtradb/buf/buf0dump.cc index 90358d34b04..e9168d9f5d5 100644 --- a/storage/xtradb/buf/buf0dump.cc +++ b/storage/xtradb/buf/buf0dump.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2011, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -334,7 +334,7 @@ buf_dump( i + 1, srv_buf_pool_instances, j + 1, n_pages); } - if ( (j % 1024) == 0) { + if (SHUTTING_DOWN() && !(j % 1024)) { service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, "Dumping buffer pool " ULINTPF "/" ULINTPF ", " diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc index 1420f5a3a12..19b4ac3732a 100644 --- a/storage/xtradb/log/log0log.cc +++ b/storage/xtradb/log/log0log.cc @@ -1561,12 +1561,6 @@ log_write_up_to( return; } - if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { - service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, - "log write up to: " LSN_PF, - lsn); - } - loop: ut_ad(++loop_count < 100); @@ -1679,6 +1673,13 @@ loop: log_sys->buf_free += OS_FILE_LOG_BLOCK_SIZE; log_sys->write_end_offset = log_sys->buf_free; + if (UNIV_UNLIKELY(srv_shutdown_state != SRV_SHUTDOWN_NONE)) { + service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, + "InnoDB log write: " + LSN_PF "," LSN_PF, + log_sys->write_lsn, lsn); + } + group = UT_LIST_GET_FIRST(log_sys->log_groups); /* Do the write to the log files */ diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc index 31e87095934..abdd31333f4 100644 --- a/storage/xtradb/srv/srv0srv.cc +++ b/storage/xtradb/srv/srv0srv.cc @@ -3236,9 +3236,17 @@ srv_purge_should_exit(ulint n_purged) } /* Slow shutdown was requested. */ if (n_purged) { - service_manager_extend_timeout( - INNODB_EXTEND_TIMEOUT_INTERVAL, - "InnoDB " ULINTPF " pages purged", n_purged); +#if defined HAVE_SYSTEMD && !defined EMBEDDED_LIBRARY + static ib_time_t progress_time; + ib_time_t time = ut_time(); + if (time - progress_time >= 15) { + progress_time = time; + service_manager_extend_timeout( + INNODB_EXTEND_TIMEOUT_INTERVAL, + "InnoDB: to purge " ULINTPF " transactions", + trx_sys->rseg_history_len); + } +#endif /* The previous round still did some work. */ return(false); } From dc7c080369472f6f33344299d2e3d01619edf885 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 21 Aug 2018 12:01:44 +0300 Subject: [PATCH 29/39] MDEV-17026 Assertion srv_undo_sources || ... failed on slow shutdown trx_purge_add_update_undo_to_history(): Relax the too strict assertion by removing the condition on srv_fast_shutdown (innodb_fast_shutdown). Rollback is allowed during any form of shutdown. --- storage/innobase/trx/trx0purge.cc | 18 ++++++++++-------- storage/xtradb/trx/trx0purge.cc | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc index 9e5e90128cb..181fde958ff 100644 --- a/storage/innobase/trx/trx0purge.cc +++ b/storage/innobase/trx/trx0purge.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -243,18 +243,20 @@ trx_purge_add_update_undo_to_history( hist_size + undo->size, MLOG_4BYTES, mtr); } - /* Before any transaction-generating background threads or the + /* After the purge thread has been given permission to exit, + we may roll back transactions (trx->undo_no==0) + in THD::cleanup() invoked from unlink_thd() in fast shutdown, + or in trx_rollback_resurrected() in slow shutdown. + + Before any transaction-generating background threads or the purge have been started, recv_recovery_rollback_active() can start transactions in row_merge_drop_temp_indexes() and - fts_drop_orphaned_tables(), and roll back recovered transactions. - After the purge thread has been given permission to exit, - in fast shutdown, we may roll back transactions (trx->undo_no==0) - in THD::cleanup() invoked from unlink_thd(). */ + fts_drop_orphaned_tables(), and roll back recovered transactions. */ ut_ad(srv_undo_sources + || trx->undo_no == 0 || ((srv_startup_is_before_trx_rollback_phase || trx_rollback_or_clean_is_active) - && purge_sys->state == PURGE_STATE_INIT) - || (trx->undo_no == 0 && srv_fast_shutdown)); + && purge_sys->state == PURGE_STATE_INIT)); /* Add the log as the first in the history list */ flst_add_first(rseg_header + TRX_RSEG_HISTORY, diff --git a/storage/xtradb/trx/trx0purge.cc b/storage/xtradb/trx/trx0purge.cc index cbf783628f9..893dc8f398c 100644 --- a/storage/xtradb/trx/trx0purge.cc +++ b/storage/xtradb/trx/trx0purge.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2017, 2018, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -247,18 +247,20 @@ trx_purge_add_update_undo_to_history( hist_size + undo->size, MLOG_4BYTES, mtr); } - /* Before any transaction-generating background threads or the + /* After the purge thread has been given permission to exit, + we may roll back transactions (trx->undo_no==0) + in THD::cleanup() invoked from unlink_thd() in fast shutdown, + or in trx_rollback_resurrected() in slow shutdown. + + Before any transaction-generating background threads or the purge have been started, recv_recovery_rollback_active() can start transactions in row_merge_drop_temp_indexes() and - fts_drop_orphaned_tables(), and roll back recovered transactions. - After the purge thread has been given permission to exit, - in fast shutdown, we may roll back transactions (trx->undo_no==0) - in THD::cleanup() invoked from unlink_thd(). */ + fts_drop_orphaned_tables(), and roll back recovered transactions. */ ut_ad(srv_undo_sources + || trx->undo_no == 0 || ((srv_startup_is_before_trx_rollback_phase || trx_rollback_or_clean_is_active) - && purge_sys->state == PURGE_STATE_INIT) - || (trx->undo_no == 0 && srv_fast_shutdown)); + && purge_sys->state == PURGE_STATE_INIT)); /* Add the log as the first in the history list */ flst_add_first(rseg_header + TRX_RSEG_HISTORY, From b0ef1b388bff28b93bfdf83a97723a56c869ca34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 21 Aug 2018 16:52:59 +0300 Subject: [PATCH 30/39] After-merge fix: Revert MDEV-15511 My conflict resolution for the script did not work out after all, and apparently I was testing a wrong version. Revert MDEV-15511 from MariaDB 10.2 for now. --- scripts/wsrep_sst_rsync.sh | 80 +++++++------------------------------- 1 file changed, 14 insertions(+), 66 deletions(-) diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 2824593a0a9..88b1352db2e 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -41,8 +41,6 @@ cleanup_joiner() kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || \ : rm -rf "$RSYNC_CONF" - rm -f "$STUNNEL_CONF" - rm -f "$STUNNEL_PID" rm -rf "$MAGIC_FILE" rm -rf "$RSYNC_PID" wsrep_log_info "Joiner cleanup done." @@ -70,7 +68,7 @@ check_pid_and_port() local port_info="$(sockstat -46lp ${rsync_port} 2>/dev/null | \ grep ":${rsync_port}")" local is_rsync="$(echo $port_info | \ - grep -wE '[[:space:]]\+(rsync|stunnel)[[:space:]]\+'"$rsync_pid" 2>/dev/null)" + grep '[[:space:]]\+rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null)" ;; *) if ! which lsof > /dev/null; then @@ -81,7 +79,7 @@ check_pid_and_port() local port_info="$(lsof -i :$rsync_port -Pn 2>/dev/null | \ grep "(LISTEN)")" local is_rsync="$(echo $port_info | \ - grep -wE '^(rsync|stunnel)[[:space:]]\+'"$rsync_pid" 2>/dev/null)" + grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null)" ;; esac @@ -121,12 +119,6 @@ is_local_ip() $get_addr_bin | grep "$address" > /dev/null } -STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" -rm -f "$STUNNEL_CONF" - -STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" -rm -f "$STUNNEL_PID" - MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" rm -rf "$MAGIC_FILE" @@ -164,28 +156,9 @@ fi FILTER="-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*'" -SSTKEY=$(parse_cnf sst tkey "") -SSTCERT=$(parse_cnf sst tcert "") -STUNNEL="" -if [ -f "$SSTKEY" ] && [ -f "$SSTCERT" ] && wsrep_check_programs stunnel -then - STUNNEL="stunnel ${STUNNEL_CONF}" -fi - if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then -cat << EOF > "$STUNNEL_CONF" -CApath = ${SSTCERT%/*} -foreground = yes -pid = $STUNNEL_PID -debug = warning -client = yes -connect = ${WSREP_SST_OPT_ADDR%/*} -TIMEOUTclose = 0 -verifyPeer = yes -EOF - if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then @@ -247,8 +220,7 @@ EOF # first, the normal directories, so that we can detect incompatible protocol RC=0 - eval rsync ${STUNNEL:+--rsh="$STUNNEL"} \ - --owner --group --perms --links --specials \ + eval rsync --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT ${FILTER} "$WSREP_SST_OPT_DATA/" \ rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? @@ -271,8 +243,7 @@ EOF fi # second, we transfer InnoDB log files - rsync ${STUNNEL:+--rsh="$STUNNEL"} \ - --owner --group --perms --links --specials \ + rsync --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? @@ -292,8 +263,7 @@ EOF find . -maxdepth 1 -mindepth 1 -type d -not -name "lost+found" \ -print0 | xargs -I{} -0 -P $count \ - rsync ${STUNNEL:+--rsh="$STUNNEL"} \ - --owner --group --perms --links --specials \ + rsync --owner --group --perms --links --specials \ --ignore-times --inplace --recursive --delete --quiet \ $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? @@ -316,8 +286,7 @@ EOF echo "continue" # now server can resume updating data echo "$STATE" > "$MAGIC_FILE" - rsync ${STUNNEL:+--rsh="$STUNNEL"} \ - --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR echo "done $STATE" @@ -372,41 +341,20 @@ $SILENT path = $WSREP_LOG_DIR EOF -cat << EOF > "$STUNNEL_CONF" -key = $SSTKEY -cert = $SSTCERT -foreground = yes -pid = $STUNNEL_PID -debug = warning -client = no -[rsync] -accept = $RSYNC_PORT -exec = $(which rsync) -execargs = rsync --server --daemon --config=$RSYNC_CONF . -EOF - # rm -rf "$DATA"/ib_logfile* # we don't want old logs around readonly RSYNC_PORT=${WSREP_SST_OPT_PORT:-4444} - - if [ -z "$STUNNEL" ] + # If the IP is local listen only in it + if is_local_ip "$RSYNC_ADDR" then - # If the IP is local listen only in it - if is_local_ip "$RSYNC_ADDR" - then - rsync --daemon --no-detach --address "$RSYNC_ADDR" --port "$RSYNC_PORT" --config "$RSYNC_CONF" & - else - # Not local, possibly a NAT, listen in all interfaces - rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" & - # Overwrite address with all - RSYNC_ADDR="" - fi - RSYNC_REAL_PID=$! + rsync --daemon --no-detach --address "$RSYNC_ADDR" --port "$RSYNC_PORT" --config "$RSYNC_CONF" & else - stunnel "$STUNNEL_CONF" & - RSYNC_REAL_PID=$! - RSYNC_PID=$STUNNEL_PID + # Not local, possibly a NAT, listen in all interface + rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" & + # Overwrite address with all + RSYNC_ADDR="*" fi + RSYNC_REAL_PID=$! until check_pid_and_port "$RSYNC_PID" "$RSYNC_REAL_PID" "$RSYNC_ADDR" "$RSYNC_PORT" do From 5d650d366dbcbd49679bf8b0884b63056053fb44 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 22 Aug 2018 22:06:40 +0200 Subject: [PATCH 31/39] MDEV-16961 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed upon concurrent DELETE and DDL with virtual blob column After iterating all fields and setting PART_INDIRECT_KEY_FLAG as necessary, TABLE::mark_columns_used_by_virtual_fields() remembers in TABLE_SHARE that this operation was done and need not be repeated. But as the flag is set in TABLE_SHARE, PART_INDIRECT_KEY_FLAG must be set in TABLE_SHARE::field[], not only in TABLE::field[]. Otherwise all new TABLEs opened from this TABLE_SHARE will never have it. --- mysql-test/suite/vcol/r/index.result | 10 ++++++++++ mysql-test/suite/vcol/t/index.test | 16 ++++++++++++++++ sql/table.cc | 3 +++ 3 files changed, 29 insertions(+) diff --git a/mysql-test/suite/vcol/r/index.result b/mysql-test/suite/vcol/r/index.result index 8860a728bd1..6ab9aa5eb29 100644 --- a/mysql-test/suite/vcol/r/index.result +++ b/mysql-test/suite/vcol/r/index.result @@ -89,3 +89,13 @@ pk left(c, 10) length(c) i 1 bar bar ba 60000 11 drop table t1; disconnect c1; +CREATE TABLE t1 (b BLOB, vb TEXT AS (b) PERSISTENT, KEY(vb(64))) ENGINE=InnoDB; +INSERT INTO t1 (b) VALUES ('foo'); +connect con1,localhost,root,,test; +CREATE TABLE t2 LIKE t1; +connection default; +DELETE FROM t1; +connection con1; +disconnect con1; +connection default; +DROP TABLE t1, t2; diff --git a/mysql-test/suite/vcol/t/index.test b/mysql-test/suite/vcol/t/index.test index 72eed0a8a40..b93c337fab6 100644 --- a/mysql-test/suite/vcol/t/index.test +++ b/mysql-test/suite/vcol/t/index.test @@ -79,3 +79,19 @@ commit; select pk, left(c, 10), length(c), i from t1; drop table t1; disconnect c1; + +# +# MDEV-16961 Assertion `!table || (!table->read_set || bitmap_is_set(table->read_set, field_index))' failed upon concurrent DELETE and DDL with virtual blob column +# + +CREATE TABLE t1 (b BLOB, vb TEXT AS (b) PERSISTENT, KEY(vb(64))) ENGINE=InnoDB; +INSERT INTO t1 (b) VALUES ('foo'); +--connect (con1,localhost,root,,test) +--send CREATE TABLE t2 LIKE t1 +--connection default +DELETE FROM t1; +--connection con1 +--reap +--disconnect con1 +--connection default +DROP TABLE t1, t2; diff --git a/sql/table.cc b/sql/table.cc index 201901fd46f..efcca431e93 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -6736,7 +6736,10 @@ void TABLE::mark_columns_used_by_virtual_fields(void) for (uint i= 0 ; i < s->fields ; i++) { if (bitmap_is_set(&tmp_set, i)) + { + s->field[i]->flags|= PART_INDIRECT_KEY_FLAG; field[i]->flags|= PART_INDIRECT_KEY_FLAG; + } } bitmap_clear_all(&tmp_set); } From 9a815401c6c1972745432ff93cbc8f55cae30d0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Aug 2018 13:11:11 +0300 Subject: [PATCH 32/39] MDEV-17043 Purge of indexed virtual columns may cause hang on table-rebuilding DDL When a table is renamed to an internal #sql2 or #sql-ib name during a table-rebuilding DDL operation such as OPTIMIZE TABLE or ALTER TABLE, and shortly after that a purge operation in an index on virtual columns is attempted, the operation could fail, but purge would fail to release the table reference. innodb_acquire_mdl(): Release the reference if the table name is not valid for acquiring a meta-data lock (MDL). innodb_find_table_for_vc(): Add a debug assertion if the table name is not valid. This code path is for DML execution. The table should have a valid name for executing DML, and furthermore a MDL will prevent the table from being renamed. row_vers_build_clust_v_col(): Add a debug assertion that both indexes must belong to the same table. --- storage/innobase/handler/ha_innodb.cc | 2 ++ storage/innobase/row/row0vers.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c3a6bd663b3..35e091e0f11 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -21425,6 +21425,7 @@ static TABLE* innodb_acquire_mdl(THD* thd, dict_table_t* table) if (!table_name_parse(table->name, db_buf, tbl_buf, db_buf_len, tbl_buf_len)) { + table->release(); return NULL; } @@ -21507,6 +21508,7 @@ static TABLE* innodb_find_table_for_vc(THD* thd, dict_table_t* table) if (!table_name_parse(table->name, db_buf, tbl_buf, db_buf_len, tbl_buf_len)) { + ut_ad(!"invalid table name"); return NULL; } diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 24acd04c84b..811654fdef8 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -456,6 +456,7 @@ row_vers_build_clust_v_col( byte* record= 0; ut_ad(dict_index_has_virtual(index)); + ut_ad(index->table == clust_index->table); if (vcol_info != NULL) { vcol_info->set_used(); From c164d0cc6226db586ca62a10b925439ca8fdf086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 23 Aug 2018 17:02:50 +0300 Subject: [PATCH 33/39] fil_name_process(): Remove unused return value --- storage/innobase/log/log0recv.cc | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index c623b884628..86c415599bb 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -194,11 +194,9 @@ void (*log_file_op)(ulint space_id, const byte* flags, @param[in,out] name file name @param[in] len length of the file name @param[in] space_id the tablespace ID -@param[in] deleted whether this is a MLOG_FILE_DELETE record -@retval true if able to process file successfully. -@retval false if unable to process the file */ +@param[in] deleted whether this is a MLOG_FILE_DELETE record */ static -bool +void fil_name_process( char* name, ulint len, @@ -206,15 +204,13 @@ fil_name_process( bool deleted) { if (srv_operation == SRV_OPERATION_BACKUP) { - return true; + return; } ut_ad(srv_operation == SRV_OPERATION_NORMAL || srv_operation == SRV_OPERATION_RESTORE || srv_operation == SRV_OPERATION_RESTORE_EXPORT); - bool processed = true; - /* We will also insert space=NULL into the map, so that further checks can ensure that a MLOG_FILE_NAME record was scanned before applying any page records for the space_id. */ @@ -261,7 +257,6 @@ fil_name_process( << f.name << "' and '" << name << "'." " You must delete one of them."; recv_sys->found_corrupt_fs = true; - processed = false; } break; @@ -314,7 +309,6 @@ fil_name_process( " remove the .ibd file, you can set" " --innodb_force_recovery."; recv_sys->found_corrupt_fs = true; - processed = false; break; } @@ -325,7 +319,6 @@ fil_name_process( break; } } - return(processed); } /** Parse or process a MLOG_FILE_* record. From 1b4c5b7327e84f9c9dd86d72b5ae706d9e82d9b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 24 Aug 2018 09:38:52 +0300 Subject: [PATCH 34/39] MDEV-16868 Same query gives different results An INSERT into a temporary table would fail to set the index page as modified. If there were no other write operations (such as UPDATE or DELETE) to the page, and the page was evicted, we would read back the old contents of the page, causing corruption or loss of data. page_cur_insert_rec_write_log(): Call mtr_t::set_modified() for temporary tables. Normally this is part of the mlog_open() call, but the mlog_open() call was only present in debug builds. This regression was caused by commit 48192f963a3a85a5127da5cc5cf485f07d72bc9d which was preparation for MDEV-11369 and supposed to affect debug builds only. Thanks to Thirunarayanan Balathandayuthapani for debugging. --- storage/innobase/page/page0cur.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/storage/innobase/page/page0cur.cc b/storage/innobase/page/page0cur.cc index 3aea43bfba0..6bdb7f56842 100644 --- a/storage/innobase/page/page0cur.cc +++ b/storage/innobase/page/page0cur.cc @@ -857,7 +857,8 @@ page_cur_insert_rec_write_log( ulint i; if (dict_table_is_temporary(index->table)) { - ut_ad(!mlog_open(mtr, 0)); + mtr->set_modified(); + ut_ad(mtr->get_log_mode() == MTR_LOG_NO_REDO); return; } From 4c652fc62e76481b2b608fb35545f6ca1d5987fa Mon Sep 17 00:00:00 2001 From: benrubson Date: Mon, 12 Feb 2018 22:08:57 +0100 Subject: [PATCH 35/39] Use stunnel during rsync SST if available (cherry picked from commit 1adc382c2fb4300059d130521a24a1dab141531e) --- scripts/wsrep_sst_rsync.sh | 74 ++++++++++++++++++++++++++++++++------ 1 file changed, 64 insertions(+), 10 deletions(-) diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index 88b1352db2e..44625a549e3 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -41,6 +41,8 @@ cleanup_joiner() kill -9 $RSYNC_REAL_PID >/dev/null 2>&1 || \ : rm -rf "$RSYNC_CONF" + rm -f "$STUNNEL_CONF" + rm -f "$STUNNEL_PID" rm -rf "$MAGIC_FILE" rm -rf "$RSYNC_PID" wsrep_log_info "Joiner cleanup done." @@ -68,7 +70,7 @@ check_pid_and_port() local port_info="$(sockstat -46lp ${rsync_port} 2>/dev/null | \ grep ":${rsync_port}")" local is_rsync="$(echo $port_info | \ - grep '[[:space:]]\+rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null)" + grep -E '[[:space:]]+(rsync|stunnel)[[:space:]]+'"$rsync_pid" 2>/dev/null)" ;; *) if ! which lsof > /dev/null; then @@ -79,7 +81,7 @@ check_pid_and_port() local port_info="$(lsof -i :$rsync_port -Pn 2>/dev/null | \ grep "(LISTEN)")" local is_rsync="$(echo $port_info | \ - grep -w '^rsync[[:space:]]\+'"$rsync_pid" 2>/dev/null)" + grep -E '^(rsync|stunnel)[[:space:]]+'"$rsync_pid" 2>/dev/null)" ;; esac @@ -119,6 +121,12 @@ is_local_ip() $get_addr_bin | grep "$address" > /dev/null } +STUNNEL_CONF="$WSREP_SST_OPT_DATA/stunnel.conf" +rm -f "$STUNNEL_CONF" + +STUNNEL_PID="$WSREP_SST_OPT_DATA/stunnel.pid" +rm -f "$STUNNEL_PID" + MAGIC_FILE="$WSREP_SST_OPT_DATA/rsync_sst_complete" rm -rf "$MAGIC_FILE" @@ -156,9 +164,28 @@ fi FILTER="-f '- /lost+found' -f '- /.fseventsd' -f '- /.Trashes' -f '+ /wsrep_sst_binlog.tar' -f '+ /ib_lru_dump' -f '+ /ibdata*' -f '+ /*/' -f '- /*'" +SSTKEY=$(parse_cnf sst tkey "") +SSTCERT=$(parse_cnf sst tcert "") +STUNNEL="" +if [ -f "$SSTKEY" ] && [ -f "$SSTCERT" ] && wsrep_check_programs stunnel +then + STUNNEL="stunnel ${STUNNEL_CONF}" +fi + if [ "$WSREP_SST_OPT_ROLE" = "donor" ] then +cat << EOF > "$STUNNEL_CONF" +CApath = ${SSTCERT%/*} +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = yes +connect = ${WSREP_SST_OPT_ADDR%/*} +TIMEOUTclose = 0 +verifyPeer = yes +EOF + if [ $WSREP_SST_OPT_BYPASS -eq 0 ] then @@ -220,7 +247,8 @@ then # first, the normal directories, so that we can detect incompatible protocol RC=0 - eval rsync --owner --group --perms --links --specials \ + eval rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT ${FILTER} "$WSREP_SST_OPT_DATA/" \ rsync://$WSREP_SST_OPT_ADDR >&2 || RC=$? @@ -243,7 +271,8 @@ then fi # second, we transfer InnoDB log files - rsync --owner --group --perms --links --specials \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --dirs --delete --quiet \ $WHOLE_FILE_OPT -f '+ /ib_logfile[0-9]*' -f '- **' "$WSREP_LOG_DIR/" \ rsync://$WSREP_SST_OPT_ADDR-log_dir >&2 || RC=$? @@ -263,7 +292,8 @@ then find . -maxdepth 1 -mindepth 1 -type d -not -name "lost+found" \ -print0 | xargs -I{} -0 -P $count \ - rsync --owner --group --perms --links --specials \ + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --owner --group --perms --links --specials \ --ignore-times --inplace --recursive --delete --quiet \ $WHOLE_FILE_OPT --exclude '*/ib_logfile*' "$WSREP_SST_OPT_DATA"/{}/ \ rsync://$WSREP_SST_OPT_ADDR/{} >&2 || RC=$? @@ -286,7 +316,8 @@ then echo "continue" # now server can resume updating data echo "$STATE" > "$MAGIC_FILE" - rsync --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR + rsync ${STUNNEL:+--rsh="$STUNNEL"} \ + --archive --quiet --checksum "$MAGIC_FILE" rsync://$WSREP_SST_OPT_ADDR echo "done $STATE" @@ -347,14 +378,37 @@ EOF # If the IP is local listen only in it if is_local_ip "$RSYNC_ADDR" then - rsync --daemon --no-detach --address "$RSYNC_ADDR" --port "$RSYNC_PORT" --config "$RSYNC_CONF" & + RSYNC_EXTRA_ARGS="--address $RSYNC_ADDR" + STUNNEL_ACCEPT="$RSYNC_ADDR:$RSYNC_PORT" else - # Not local, possibly a NAT, listen in all interface - rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" & + # Not local, possibly a NAT, listen on all interfaces + RSYNC_EXTRA_ARGS="" + STUNNEL_ACCEPT="$RSYNC_PORT" # Overwrite address with all RSYNC_ADDR="*" fi - RSYNC_REAL_PID=$! + + if [ -z "$STUNNEL" ] + then + rsync --daemon --no-detach --port "$RSYNC_PORT" --config "$RSYNC_CONF" ${RSYNC_EXTRA_ARGS} & + RSYNC_REAL_PID=$! + else + cat << EOF > "$STUNNEL_CONF" +key = $SSTKEY +cert = $SSTCERT +foreground = yes +pid = $STUNNEL_PID +debug = warning +client = no +[rsync] +accept = $STUNNEL_ACCEPT +exec = $(which rsync) +execargs = rsync --server --daemon --config=$RSYNC_CONF . +EOF + stunnel "$STUNNEL_CONF" & + RSYNC_REAL_PID=$! + RSYNC_PID=$STUNNEL_PID + fi until check_pid_and_port "$RSYNC_PID" "$RSYNC_REAL_PID" "$RSYNC_ADDR" "$RSYNC_PORT" do From c826b6b8da3c9ee89ab457155bae96310213e5a1 Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Fri, 24 Aug 2018 20:53:00 -0700 Subject: [PATCH 36/39] Added a new parameter for the function eq_ranges_exceeds_limit() introduced in the patch fo MDEV-16934. --- sql/multi_range_read.cc | 8 +++++--- sql/opt_range.cc | 5 ++--- sql/opt_range.h | 3 ++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/sql/multi_range_read.cc b/sql/multi_range_read.cc index 94a96c27a0f..9b6d0e86f90 100644 --- a/sql/multi_range_read.cc +++ b/sql/multi_range_read.cc @@ -64,13 +64,15 @@ handler::multi_range_read_info_const(uint keyno, RANGE_SEQ_IF *seq, ha_rows rows, total_rows= 0; uint n_ranges=0; THD *thd= table->in_use; + uint limit= thd->variables.eq_range_index_dive_limit; + bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq, + seq_init_param, + limit); + /* Default MRR implementation doesn't need buffer */ *bufsz= 0; - bool use_statistics_for_eq_range= eq_ranges_exceeds_limit(seq, - seq_init_param); - seq_it= seq->init(seq_init_param, n_ranges, *flags); while (!seq->next(seq_it, &range)) { diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 47e07016782..2c015c1a5da 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -14619,13 +14619,12 @@ void QUICK_GROUP_MIN_MAX_SELECT::add_keys_and_lengths(String *key_names, /* Check whether the number for equality ranges exceeds the set threshold */ -bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param) +bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param, + uint limit) { KEY_MULTI_RANGE range; range_seq_t seq_it; uint count = 0; - PARAM *param= ((SEL_ARG_RANGE_SEQ*) seq_init_param)->param; - uint limit= param->thd->variables.eq_range_index_dive_limit; if (limit == 0) { diff --git a/sql/opt_range.h b/sql/opt_range.h index 6698c987e78..9e0bd3ae9ff 100644 --- a/sql/opt_range.h +++ b/sql/opt_range.h @@ -1664,7 +1664,8 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables, bool calculate_cond_selectivity_for_table(THD *thd, TABLE *table, Item **cond); -bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param); +bool eq_ranges_exceeds_limit(RANGE_SEQ_IF *seq, void *seq_init_param, + uint limit); #ifdef WITH_PARTITION_STORAGE_ENGINE bool prune_partitions(THD *thd, TABLE *table, Item *pprune_cond); From 2a361ebe1b9c52eadfe811a219a89df6a0d6e3ea Mon Sep 17 00:00:00 2001 From: zhzhzoo Date: Sat, 17 Mar 2018 01:22:53 +0800 Subject: [PATCH 37/39] MDEV-15204: lag/lead function order list mandatory --- mysql-test/r/win.result | 4 ++-- mysql-test/r/win_lead_lag.result | 11 +++++++++++ mysql-test/t/win.test | 4 ++-- mysql-test/t/win_lead_lag.test | 13 +++++++++++++ sql/item_windowfunc.h | 2 ++ 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index b519b2bb223..e4b2d223a02 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -3219,8 +3219,8 @@ DROP TABLE fv_test, fv_result; # CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (0),(1),(2); -SELECT LEAD(a) OVER (PARTITION BY a) as lead, -a AND LEAD(a) OVER (PARTITION BY a) AS a_and_lead_part +SELECT LEAD(a) OVER (PARTITION BY a ORDER BY a) as lead, +a AND LEAD(a) OVER (PARTITION BY a ORDER BY a) AS a_and_lead_part FROM t1; lead a_and_lead_part NULL 0 diff --git a/mysql-test/r/win_lead_lag.result b/mysql-test/r/win_lead_lag.result index 5ead58fa11a..f3c0b8f7ef2 100644 --- a/mysql-test/r/win_lead_lag.result +++ b/mysql-test/r/win_lead_lag.result @@ -226,4 +226,15 @@ pk a b a+b lag(a + b) over (partition by a order by pk) + pk 9 2 2 4 12 10 2 0 2 14 11 2 10 12 13 +# +# MDEV-15204 - LAG function doesn't require ORDER BY in OVER clause +# +select pk, +lag(pk, 1) over () +from t1; +ERROR HY000: No order list in window specification for 'lag' +select pk, +lead(pk, 1) over () +from t1; +ERROR HY000: No order list in window specification for 'lead' drop table t1; diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index b354a55d0d6..f47237ee59e 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -2000,8 +2000,8 @@ DROP TABLE fv_test, fv_result; CREATE TABLE t1 (a int); INSERT INTO t1 VALUES (0),(1),(2); -SELECT LEAD(a) OVER (PARTITION BY a) as lead, - a AND LEAD(a) OVER (PARTITION BY a) AS a_and_lead_part +SELECT LEAD(a) OVER (PARTITION BY a ORDER BY a) as lead, + a AND LEAD(a) OVER (PARTITION BY a ORDER BY a) AS a_and_lead_part FROM t1; SELECT a OR LEAD(a) OVER (ORDER BY a) AS a_or_lead_order diff --git a/mysql-test/t/win_lead_lag.test b/mysql-test/t/win_lead_lag.test index 2824f83789c..d154244ecd0 100644 --- a/mysql-test/t/win_lead_lag.test +++ b/mysql-test/t/win_lead_lag.test @@ -107,4 +107,17 @@ select pk, a, b, a+b, from t1 order by pk asc; +--echo # +--echo # MDEV-15204 - LAG function doesn't require ORDER BY in OVER clause +--echo # +--error ER_NO_ORDER_LIST_IN_WINDOW_SPEC +select pk, + lag(pk, 1) over () +from t1; + +--error ER_NO_ORDER_LIST_IN_WINDOW_SPEC +select pk, + lead(pk, 1) over () +from t1; + drop table t1; diff --git a/sql/item_windowfunc.h b/sql/item_windowfunc.h index e5afb9e1555..21270733051 100644 --- a/sql/item_windowfunc.h +++ b/sql/item_windowfunc.h @@ -792,6 +792,8 @@ public: case Item_sum::DENSE_RANK_FUNC: case Item_sum::PERCENT_RANK_FUNC: case Item_sum::CUME_DIST_FUNC: + case Item_sum::LAG_FUNC: + case Item_sum::LEAD_FUNC: return true; default: return false; From 2b76f6f61dba93fd920456a0dd9efd366a6dc6b1 Mon Sep 17 00:00:00 2001 From: Ming Lin Date: Thu, 16 Aug 2018 10:28:29 -0700 Subject: [PATCH 38/39] MDEV-16703: Update AUTO_INCREMENT in the UPDATE statement Currently RocksDB engine doesn't update AUTO_INCREMENT in the UPDATE statement. For example, CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB; INSERT INTO t1 (a) VALUES (1); UPDATE t1 SET pk = 3; ==> AUTO_INCREMENT should be updated to 4. Without this fix, it hits the Assertion `dd_val >= last_val' failed in myrocks::ha_rocksdb::load_auto_incr_value_from_index. (cherry picked from commit f7154242b8807fdaa74ed0b89c3de8c35ee35edb) --- storage/rocksdb/ha_rocksdb.cc | 2 +- .../rocksdb/mysql-test/rocksdb/r/autoinc_vars.result | 8 ++++++++ storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test | 10 ++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/storage/rocksdb/ha_rocksdb.cc b/storage/rocksdb/ha_rocksdb.cc index c1c3191514f..adef71e4e4a 100644 --- a/storage/rocksdb/ha_rocksdb.cc +++ b/storage/rocksdb/ha_rocksdb.cc @@ -9553,7 +9553,7 @@ int ha_rocksdb::update_pk(const Rdb_key_def &kd, } } - if (table->next_number_field) { + if (table->found_next_number_field) { update_auto_incr_val_from_field(); } diff --git a/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result b/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result index 8cc9b070a70..0c496227006 100644 --- a/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result +++ b/storage/rocksdb/mysql-test/rocksdb/r/autoinc_vars.result @@ -150,3 +150,11 @@ CREATE TABLE t0(c0 BLOB) ENGINE=ROCKSDB; INSERT INTO t0 VALUES(0); ALTER TABLE t0 AUTO_INCREMENT=0; DROP TABLE t0; +#--------------------------------------------------------------- +# MDEV-16703 Assertion failed in load_auto_incr_value_from_index +#--------------------------------------------------------------- +CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB; +INSERT INTO t1 (a) VALUES (1); +UPDATE t1 SET pk = 3; +ALTER TABLE t1 AUTO_INCREMENT 2; +DROP TABLE t1; diff --git a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test index 9d7f0365d07..86a0a7f2a53 100644 --- a/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test +++ b/storage/rocksdb/mysql-test/rocksdb/t/autoinc_vars.test @@ -116,3 +116,13 @@ CREATE TABLE t0(c0 BLOB) ENGINE=ROCKSDB; INSERT INTO t0 VALUES(0); ALTER TABLE t0 AUTO_INCREMENT=0; DROP TABLE t0; + +--echo #--------------------------------------------------------------- +--echo # MDEV-16703 Assertion failed in load_auto_incr_value_from_index +--echo #--------------------------------------------------------------- + +CREATE TABLE t1 (pk INT AUTO_INCREMENT, a INT, PRIMARY KEY(pk)) ENGINE=RocksDB; +INSERT INTO t1 (a) VALUES (1); +UPDATE t1 SET pk = 3; +ALTER TABLE t1 AUTO_INCREMENT 2; +DROP TABLE t1; From 55163ba1bdb1a05daadc66c41c959994231b361c Mon Sep 17 00:00:00 2001 From: Galina Shalygina Date: Wed, 1 Aug 2018 20:44:59 +0300 Subject: [PATCH 39/39] MDEV-16803: Pushdown Item_func_in item that uses vectors in several SELECTs The bug appears because of the Item_func_in::build_clone() method. The 'array' field for the Item_func_in item that can be pushed into the materialized view/derived table was built in the wrong way. It becomes lame after the pushdown of the condition into the first SELECT that defines that view/derived table. The server crashes in the pushdown into the next SELECT while trying to use already lame 'array' field. To fix it Item_func_in::build_clone() was changed. --- mysql-test/r/derived_cond_pushdown.result | 21 +++++++++++++++++++++ mysql-test/t/derived_cond_pushdown.test | 20 ++++++++++++++++++++ sql/item_cmpfunc.cc | 3 +-- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index fd930d13547..9ef3488e06d 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -10220,3 +10220,24 @@ EXPLAIN } } DROP TABLE t1; +# +# MDEV-16803: pushdown condition with IN predicate in the derived table +# defined with several SELECT statements +# +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,2),(3,2),(1,1); +SELECT * FROM +( +SELECT a,b,1 as c +FROM t1 +UNION ALL +SELECT a,b,2 as c +FROM t1 +) AS tab +WHERE ((a,b) IN ((1,2),(3,2))); +a b c +1 2 1 +3 2 1 +1 2 2 +3 2 2 +DROP TABLE t1; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index b8e74a2d5aa..23109662c6d 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -2022,3 +2022,23 @@ EVAL $query; EVAL EXPLAIN FORMAT=JSON $query; DROP TABLE t1; + +--echo # +--echo # MDEV-16803: pushdown condition with IN predicate in the derived table +--echo # defined with several SELECT statements +--echo # + +CREATE TABLE t1 (a INT, b INT); +INSERT INTO t1 VALUES (1,2),(3,2),(1,1); + +SELECT * FROM +( + SELECT a,b,1 as c + FROM t1 + UNION ALL + SELECT a,b,2 as c + FROM t1 +) AS tab +WHERE ((a,b) IN ((1,2),(3,2))); + +DROP TABLE t1; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 577a98df0d2..69ebeb2b95c 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -4436,9 +4436,8 @@ Item *Item_func_in::build_clone(THD *thd, MEM_ROOT *mem_root) Item_func_in *clone= (Item_func_in *) Item_func::build_clone(thd, mem_root); if (clone) { - if (array && clone->create_array(thd)) - return NULL; bzero(&clone->cmp_items, sizeof(cmp_items)); + clone->fix_length_and_dec(); } return clone; }