From c35b8c46b404d035e54a23d667da5dff6502fc2e Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Thu, 15 Dec 2016 11:03:34 +1100 Subject: [PATCH 01/26] Travis: parallel_jobs=3 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 0671841f622..66bc3c51f8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -67,7 +67,7 @@ script: - export MYSQL_BUILD_CC=/usr/bin/gcc-${GCC_VERSION} MYSQL_BUILD_CXX=/usr/bin/g++-${GCC_VERSION} - ${MYSQL_BUILD_CC} --version ; ${MYSQL_BUILD_CXX} --version - cd "${TRAVIS_BUILD_DIR}" - - env DEB_BUILD_OPTIONS="parallel=4" debian/autobake-deb.sh; + - env DEB_BUILD_OPTIONS="parallel=3" debian/autobake-deb.sh; notifications: irc: From 8375a2c1cec3c386f6db797d75f64b8f03c83b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 16 Dec 2016 16:36:54 +0200 Subject: [PATCH 02/26] MDEV-11585 Hard-code the shared InnoDB temporary tablespace ID at -1 MySQL 5.7 supports only one shared temporary tablespace. MariaDB 10.2 does not support any other shared InnoDB tablespaces than the two predefined tablespaces: the persistent InnoDB system tablespace (default file name ibdata1) and the temporary tablespace (default file name ibtmp1). InnoDB is unnecessarily allocating a tablespace ID for the predefined temporary tablespace on every startup, and it is in several places testing whether a tablespace ID matches this dynamically generated ID. We should use a compile-time constant to reduce code size and to avoid unnecessary updates to the DICT_HDR page at every startup. Using a hard-coded tablespace ID will should make it easier to remove the TEMPORARY flag from FSP_SPACE_FLAGS in MDEV-11202. --- .../encryption/r/debug_key_management.result | 8 +-- .../r/innodb-bad-key-change4.result | 2 +- .../encryption/t/innodb-bad-key-change4.test | 1 + storage/innobase/btr/btr0btr.cc | 2 +- storage/innobase/buf/buf0buf.cc | 2 +- storage/innobase/dict/dict0crea.cc | 3 +- storage/innobase/fil/fil0fil.cc | 11 ++-- storage/innobase/fsp/fsp0fsp.cc | 53 ++++++++----------- storage/innobase/fsp/fsp0space.cc | 11 ---- storage/innobase/ibuf/ibuf0ibuf.cc | 3 +- storage/innobase/include/fsp0space.h | 5 +- storage/innobase/include/fsp0sysspace.h | 11 ++-- storage/innobase/include/fsp0types.h | 13 ++++- storage/innobase/include/srv0start.h | 3 -- storage/innobase/row/row0trunc.cc | 2 +- storage/innobase/srv/srv0start.cc | 41 ++++++-------- storage/innobase/trx/trx0sys.cc | 3 +- 17 files changed, 76 insertions(+), 98 deletions(-) diff --git a/mysql-test/suite/encryption/r/debug_key_management.result b/mysql-test/suite/encryption/r/debug_key_management.result index e185740aa25..8793e6ba363 100644 --- a/mysql-test/suite/encryption/r/debug_key_management.result +++ b/mysql-test/suite/encryption/r/debug_key_management.result @@ -9,13 +9,13 @@ innodb_encryption_threads 4 select space,name,current_key_version from information_schema.innodb_tablespaces_encryption order by space; space name current_key_version 0 NULL 1 -2 mysql/innodb_table_stats 1 -3 mysql/innodb_index_stats 1 +1 mysql/innodb_table_stats 1 +2 mysql/innodb_index_stats 1 set global debug_key_management_version=10; select space,name,current_key_version from information_schema.innodb_tablespaces_encryption order by space; space name current_key_version 0 NULL 10 -2 mysql/innodb_table_stats 10 -3 mysql/innodb_index_stats 10 +1 mysql/innodb_table_stats 10 +2 mysql/innodb_index_stats 10 set global innodb_encrypt_tables=OFF; set global debug_key_management_version=1; diff --git a/mysql-test/suite/encryption/r/innodb-bad-key-change4.result b/mysql-test/suite/encryption/r/innodb-bad-key-change4.result index 3ced393f38b..369a8c7989c 100644 --- a/mysql-test/suite/encryption/r/innodb-bad-key-change4.result +++ b/mysql-test/suite/encryption/r/innodb-bad-key-change4.result @@ -16,7 +16,7 @@ Warning 131 Using innodb_file_format is deprecated and the parameter may be remo SET GLOBAL innodb_file_per_table = ON; CHECK TABLE t1; Table Op Msg_type Msg_text -test.t1 check Warning Table test/t1 in tablespace 7 is encrypted but encryption service or used key_id is not available. Can't continue reading table. +test.t1 check Warning Table test/t1 in tablespace # is encrypted but encryption service or used key_id is not available. Can't continue reading table. test.t1 check Warning Table test/t1 is encrypted but encryption service or used key_id is not available. Can't continue checking table. test.t1 check error Corrupt SHOW WARNINGS; diff --git a/mysql-test/suite/encryption/t/innodb-bad-key-change4.test b/mysql-test/suite/encryption/t/innodb-bad-key-change4.test index 96f9563fb3b..82da3bbcf70 100644 --- a/mysql-test/suite/encryption/t/innodb-bad-key-change4.test +++ b/mysql-test/suite/encryption/t/innodb-bad-key-change4.test @@ -59,6 +59,7 @@ EOF SET GLOBAL innodb_file_format = `Barracuda`; SET GLOBAL innodb_file_per_table = ON; +--replace_regex /tablespace [0-9]*/tablespace #/ CHECK TABLE t1; SHOW WARNINGS; diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index e5284ee802a..31ba56d2993 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -1097,7 +1097,7 @@ btr_free_root_check( index_id_t index_id, mtr_t* mtr) { - ut_ad(page_id.space() != srv_tmp_space.space_id()); + ut_ad(page_id.space() != SRV_TMP_SPACE_ID); ut_ad(index_id != BTR_FREED_INDEX_ID); buf_block_t* block = buf_page_get( diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index d3b4f12e69b..43683d63c97 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -6092,7 +6092,7 @@ corrupt: #endif /* MYSQL_COMPRESSION */ && !recv_no_ibuf_operations && !Tablespace::is_undo_tablespace(bpage->id.space()) - && bpage->id.space() != srv_tmp_space.space_id() + && bpage->id.space() != SRV_TMP_SPACE_ID && !srv_is_tablespace_truncated(bpage->id.space()) && fil_page_get_type(frame) == FIL_PAGE_INDEX && page_is_leaf(frame)) { diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc index 2d891854c03..cfea64d51c2 100644 --- a/storage/innobase/dict/dict0crea.cc +++ b/storage/innobase/dict/dict0crea.cc @@ -571,8 +571,7 @@ dict_build_tablespace_for_table( supports Redundant and Compact */ ut_ad(dict_tf_get_rec_format(table->flags) != REC_FORMAT_COMPRESSED); - table->space = static_cast( - srv_tmp_space.space_id()); + table->space = SRV_TMP_SPACE_ID; } else { /* Create in the system tablespace. */ ut_ad(table->space == srv_sys_space.space_id()); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 596c6bdfdb0..26e0593b266 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -185,7 +185,7 @@ fil_is_user_tablespace_id( ulint space_id) { return(space_id > srv_undo_tablespaces_open - && space_id != srv_tmp_space.space_id()); + && space_id != SRV_TMP_SPACE_ID); } #ifdef UNIV_DEBUG @@ -1313,7 +1313,7 @@ fil_space_create( /* This warning is not applicable while MEB scanning the redo logs */ #ifndef UNIV_HOTBACKUP - if (fil_type_is_data(purpose) + if ((purpose == FIL_TYPE_TABLESPACE || purpose == FIL_TYPE_IMPORT) && !recv_recovery_on && id > fil_system->max_assigned_id) { @@ -5104,10 +5104,13 @@ retry: ulint pages_per_mb = (1024 * 1024) / page_size; ulint size_in_pages = ((node->size / pages_per_mb) * pages_per_mb); - if (space->id == srv_sys_space.space_id()) { + switch (space->id) { + case TRX_SYS_SPACE: srv_sys_space.set_last_file_size(size_in_pages); - } else if (space->id == srv_tmp_space.space_id()) { + break; + case SRV_TMP_SPACE_ID: srv_tmp_space.set_last_file_size(size_in_pages); + break; } #else ib::trace() << "extended space : " << space->name << " from " diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc index 9dc99f3f09d..f2a4c6bf218 100644 --- a/storage/innobase/fsp/fsp0fsp.cc +++ b/storage/innobase/fsp/fsp0fsp.cc @@ -338,16 +338,6 @@ err_exit: return (false); } -/** Check if tablespace is system temporary. -@param[in] space_id tablespace ID -@return true if tablespace is system temporary. */ -bool -fsp_is_system_temporary( - ulint space_id) -{ - return(space_id == srv_tmp_space.space_id()); -} - /** Check if checksum is disabled for the given space. @param[in] space_id tablespace ID @return true if checksum is disabled for given space. */ @@ -803,8 +793,7 @@ fsp_space_modify_check( #ifdef UNIV_DEBUG { const fil_type_t type = fil_space_get_type(id); - ut_a(id == srv_tmp_space.space_id() - || srv_is_tablespace_truncated(id) + ut_a(srv_is_tablespace_truncated(id) || fil_space_is_being_truncated(id) || fil_space_get_flags(id) == ULINT_UNDEFINED || type == FIL_TYPE_TEMPORARY @@ -814,10 +803,7 @@ fsp_space_modify_check( #endif /* UNIV_DEBUG */ return; case MTR_LOG_ALL: - /* We must not write redo log for the shared temporary - tablespace. */ - ut_ad(id != srv_tmp_space.space_id()); - /* If we write redo log, the tablespace must exist. */ + /* We may only write redo log for a persistent tablespace. */ ut_ad(fil_space_get_type(id) == FIL_TYPE_TABLESPACE); ut_ad(mtr->is_named_space(id)); return; @@ -1549,15 +1535,14 @@ fsp_try_extend_data_file( const page_size_t page_size( mach_read_from_4(header + FSP_SPACE_FLAGS)); - if (space->id == srv_sys_space.space_id()) { - + switch (space->id) { + case TRX_SYS_SPACE: size_increase = srv_sys_space.get_increment(); - - } else if (space->id == srv_tmp_space.space_id()) { - + break; + case SRV_TMP_SPACE_ID: size_increase = srv_tmp_space.get_increment(); - - } else { + break; + default: ulint extent_pages = fsp_get_extent_size_in_pages(page_size); if (size < extent_pages) { @@ -1679,11 +1664,17 @@ fsp_fill_free_list( const page_size_t page_size(flags); if (size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) { - if ((!init_space && !is_system_tablespace(space->id)) - || (space->id == srv_sys_space.space_id() - && srv_sys_space.can_auto_extend_last_file()) - || (space->id == srv_tmp_space.space_id() - && srv_tmp_space.can_auto_extend_last_file())) { + bool skip_resize = init_space; + switch (space->id) { + case TRX_SYS_SPACE: + skip_resize = !srv_sys_space.can_auto_extend_last_file(); + break; + case SRV_TMP_SPACE_ID: + skip_resize = srv_tmp_space.can_auto_extend_last_file(); + break; + } + + if (!skip_resize) { ulint n_pages = 0; fsp_try_extend_data_file(space, header, mtr, &n_pages); size = space->size_in_header; @@ -1733,7 +1724,7 @@ fsp_fill_free_list( order, and we must be able to release its latch. Note: Insert-Buffering is disabled for tables that reside in the temp-tablespace. */ - if (space->id != srv_tmp_space.space_id()) { + if (space->purpose != FIL_TYPE_TEMPORARY) { mtr_t ibuf_mtr; mtr_start(&ibuf_mtr); @@ -1741,9 +1732,7 @@ fsp_fill_free_list( /* Avoid logging while truncate table fix-up is active. */ - if (space->purpose == FIL_TYPE_TEMPORARY - || srv_is_tablespace_truncated( - space->id)) { + if (srv_is_tablespace_truncated(space->id)) { mtr_set_log_mode( &ibuf_mtr, MTR_LOG_NO_REDO); } diff --git a/storage/innobase/fsp/fsp0space.cc b/storage/innobase/fsp/fsp0space.cc index f66f7b8fc78..371baee627c 100644 --- a/storage/innobase/fsp/fsp0space.cc +++ b/storage/innobase/fsp/fsp0space.cc @@ -207,17 +207,6 @@ Tablespace::delete_files() } } -/** Check if undo tablespace. -@return true if undo tablespace */ -bool -Tablespace::is_undo_tablespace( - ulint id) -{ - return(id <= srv_undo_tablespaces_open - && id != srv_sys_space.space_id() - && id != srv_tmp_space.space_id()); -} - /** Use the ADD DATAFILE path to create a Datafile object and add it to the front of m_files. Parse the datafile path into a path and a filename with extension 'ibd'. diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index e9ad1a9d8c0..4b1c3704123 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -3727,9 +3727,10 @@ ibuf_insert( op, page_id.space(), page_id.page_no())); ut_ad(dtuple_check_typed(entry)); - ut_ad(page_id.space() != srv_tmp_space.space_id()); + ut_ad(page_id.space() != SRV_TMP_SPACE_ID); ut_a(!dict_index_is_clust(index)); + ut_ad(!dict_table_is_temporary(index->table)); no_counter = use <= IBUF_USE_INSERT; diff --git a/storage/innobase/include/fsp0space.h b/storage/innobase/include/fsp0space.h index 603c71b4aa6..31a1a4abc75 100644 --- a/storage/innobase/include/fsp0space.h +++ b/storage/innobase/include/fsp0space.h @@ -219,7 +219,10 @@ public: /** Check if undo tablespace. @return true if undo tablespace */ - static bool is_undo_tablespace(ulint id); + static bool is_undo_tablespace(ulint id) + { + return(id <= srv_undo_tablespaces_open); + } private: /** @param[in] filename Name to lookup in the data files. diff --git a/storage/innobase/include/fsp0sysspace.h b/storage/innobase/include/fsp0sysspace.h index 226d53ebd50..c25093491a2 100644 --- a/storage/innobase/include/fsp0sysspace.h +++ b/storage/innobase/include/fsp0sysspace.h @@ -291,11 +291,9 @@ extern SysTablespace srv_tmp_space; @return true if id is a system tablespace, false if not. */ UNIV_INLINE bool -is_system_tablespace( - ulint id) +is_system_tablespace(ulint id) { - return(id == srv_sys_space.space_id() - || id == srv_tmp_space.space_id()); + return(id == TRX_SYS_SPACE || id == SRV_TMP_SPACE_ID); } /** Check if shared-system or undo tablespace. @@ -305,8 +303,7 @@ bool is_system_or_undo_tablespace( ulint id) { - return(id == srv_sys_space.space_id() - || id <= srv_undo_tablespaces_open); + return(id <= srv_undo_tablespaces_open); } /** Check if predefined shared tablespace. @@ -319,6 +316,6 @@ is_predefined_tablespace( ut_ad(srv_sys_space.space_id() == TRX_SYS_SPACE); ut_ad(TRX_SYS_SPACE == 0); return(id <= srv_undo_tablespaces_open - || id == srv_tmp_space.space_id()); + || id == SRV_TMP_SPACE_ID); } #endif /* fsp0sysspace_h */ diff --git a/storage/innobase/include/fsp0types.h b/storage/innobase/include/fsp0types.h index 21951acf72b..f9197394bd7 100644 --- a/storage/innobase/include/fsp0types.h +++ b/storage/innobase/include/fsp0types.h @@ -29,6 +29,12 @@ Created May 26, 2009 Vasil Dimov #ifndef UNIV_INNOCHECKSUM +/** The fil_space_t::id of the redo log. All persistent tablespaces +have a smaller fil_space_t::id. */ +#define SRV_LOG_SPACE_FIRST_ID 0xFFFFFFF0U +/** The fil_space_t::id of the innodb_temporary tablespace. */ +#define SRV_TMP_SPACE_ID 0xFFFFFFFFU + #include "univ.i" #include "ut0byte.h" @@ -196,9 +202,12 @@ fsp_flags_is_valid( /** Check if tablespace is system temporary. @param[in] space_id verify is checksum is enabled for given space. @return true if tablespace is system temporary. */ +inline bool -fsp_is_system_temporary( - ulint space_id); +fsp_is_system_temporary(ulint space_id) +{ + return(space_id == SRV_TMP_SPACE_ID); +} /** Check if checksum is disabled for the given space. @param[in] space_id verify is checksum is enabled for given space. diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h index 82b5446c62a..708a90247e3 100644 --- a/storage/innobase/include/srv0start.h +++ b/storage/innobase/include/srv0start.h @@ -46,9 +46,6 @@ struct dict_table_t; } while (0) #endif /* DBUG_OFF */ -/** Log 'spaces' have id's >= this */ -#define SRV_LOG_SPACE_FIRST_ID 0xFFFFFFF0UL - /** If buffer pool is less than the size, only one buffer pool instance is used. */ #define BUF_POOL_SIZE_THRESHOLD (1024 * 1024 * 1024) diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index 25dc274b0c5..1c118dabc61 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -2278,7 +2278,7 @@ truncate_t::fixup_tables_in_non_system_tablespace() "id (" << (*it)->m_space_id << ")"; /* Temp-tables in temp-tablespace are never restored.*/ - ut_ad((*it)->m_space_id != srv_tmp_space.space_id()); + ut_ad((*it)->m_space_id != SRV_TMP_SPACE_ID); err = fil_recreate_table( (*it)->m_space_id, diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 96c2d8fa8c4..49c9feb6ac5 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1123,76 +1123,67 @@ srv_start_wait_for_purge_to_start() /** Create the temporary file tablespace. @param[in] create_new_db whether we are creating a new database -@param[in,out] tmp_space Shared Temporary SysTablespace @return DB_SUCCESS or error code. */ static dberr_t -srv_open_tmp_tablespace( - bool create_new_db, - SysTablespace* tmp_space) +srv_open_tmp_tablespace(bool create_new_db) { ulint sum_of_new_sizes; /* Will try to remove if there is existing file left-over by last unclean shutdown */ - tmp_space->set_sanity_check_status(true); - tmp_space->delete_files(); - tmp_space->set_ignore_read_only(true); + srv_tmp_space.set_sanity_check_status(true); + srv_tmp_space.delete_files(); + srv_tmp_space.set_ignore_read_only(true); ib::info() << "Creating shared tablespace for temporary tables"; bool create_new_temp_space; - ulint temp_space_id = ULINT_UNDEFINED; - dict_hdr_get_new_id(NULL, NULL, &temp_space_id, NULL, true); - - tmp_space->set_space_id(temp_space_id); + srv_tmp_space.set_space_id(SRV_TMP_SPACE_ID); RECOVERY_CRASH(100); - dberr_t err = tmp_space->check_file_spec( - &create_new_temp_space, 12 * 1024 * 1024); + dberr_t err = srv_tmp_space.check_file_spec( + &create_new_temp_space, 12 * 1024 * 1024); if (err == DB_FAIL) { - ib::error() << "The " << tmp_space->name() + ib::error() << "The " << srv_tmp_space.name() << " data file must be writable!"; err = DB_ERROR; } else if (err != DB_SUCCESS) { ib::error() << "Could not create the shared " - << tmp_space->name() << "."; + << srv_tmp_space.name() << "."; - } else if ((err = tmp_space->open_or_create( + } else if ((err = srv_tmp_space.open_or_create( true, create_new_db, &sum_of_new_sizes, NULL)) != DB_SUCCESS) { ib::error() << "Unable to create the shared " - << tmp_space->name(); + << srv_tmp_space.name(); } else { mtr_t mtr; - ulint size = tmp_space->get_sum_of_sizes(); - - ut_a(temp_space_id != ULINT_UNDEFINED); - ut_a(tmp_space->space_id() == temp_space_id); + ulint size = srv_tmp_space.get_sum_of_sizes(); /* Open this shared temp tablespace in the fil_system so that it stays open until shutdown. */ - if (fil_space_open(tmp_space->name())) { + if (fil_space_open(srv_tmp_space.name())) { /* Initialize the header page */ mtr_start(&mtr); mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - fsp_header_init(tmp_space->space_id(), size, &mtr); + fsp_header_init(SRV_TMP_SPACE_ID, size, &mtr); mtr_commit(&mtr); } else { /* This file was just opened in the code above! */ - ib::error() << "The " << tmp_space->name() + ib::error() << "The " << srv_tmp_space.name() << " data file cannot be re-opened" " after check_file_spec() succeeded!"; @@ -2439,7 +2430,7 @@ files_checked: /* Open temp-tablespace and keep it open until shutdown. */ - err = srv_open_tmp_tablespace(create_new_db, &srv_tmp_space); + err = srv_open_tmp_tablespace(create_new_db); if (err != DB_SUCCESS) { return(srv_init_abort(err)); diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index a253ea72e95..0dd5e0a6335 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -983,8 +983,7 @@ trx_sys_create_noredo_rsegs( Slot-1....Slot-N: reserved for temp-tablespace. Slot-N+1....Slot-127: reserved for system/undo-tablespace. */ for (ulint i = 0; i < n_nonredo_rseg; i++) { - ulint space = srv_tmp_space.space_id(); - if (trx_rseg_create(space, i) == NULL) { + if (trx_rseg_create(SRV_TMP_SPACE_ID, i) == NULL) { break; } ++n_created; From a01bfc9fc251d02e2a6152276eb805e07d213210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 19 Dec 2016 15:57:41 +0200 Subject: [PATCH 03/26] MDEV-11602 InnoDB leaks foreign key metadata on DDL operations Essentially revert MDEV-6759, which addressed a double free of memory by removing the freeing altogether, introducing the memory leaks. No double free was observed when running the test suite -DWITH_ASAN. Replace some mem_heap_free(foreign->heap) with dict_foreign_free(foreign) so that the calls can be located and instrumented more easily when needed. --- storage/innobase/dict/dict0dict.cc | 12 ++++++------ storage/innobase/dict/dict0load.cc | 2 +- storage/xtradb/dict/dict0dict.cc | 8 ++++---- storage/xtradb/dict/dict0load.cc | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 4f77d2168f4..c19e0864b04 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1701,6 +1701,7 @@ struct dict_foreign_remove_partial if (table != NULL) { table->referenced_set.erase(foreign); } + dict_foreign_free(foreign); } }; @@ -3759,7 +3760,6 @@ dict_foreign_add_to_cache( } if (for_in_cache) { - /* Free the foreign object */ dict_foreign_free(foreign); } else { for_in_cache = foreign; @@ -3789,10 +3789,9 @@ dict_foreign_add_to_cache( "referenced table do not match" " the ones in table."); - if (for_in_cache == foreign) { - mem_heap_free(foreign->heap); - } - + if (for_in_cache == foreign) { + dict_foreign_free(foreign); + } DBUG_RETURN(DB_CANNOT_ADD_CONSTRAINT); } @@ -3846,7 +3845,8 @@ dict_foreign_add_to_cache( elements removed must be one */ } - mem_heap_free(foreign->heap); + + dict_foreign_free(foreign); } DBUG_RETURN(DB_CANNOT_ADD_CONSTRAINT); diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc index 946919097c1..b40d659e362 100644 --- a/storage/innobase/dict/dict0load.cc +++ b/storage/innobase/dict/dict0load.cc @@ -493,7 +493,7 @@ err_len: } /* This receives a dict_foreign_t* that points to a stack variable. - So mem_heap_free(foreign->heap) is not used as elsewhere. + So dict_foreign_free(foreign) is not used as elsewhere. Since the heap used here is freed elsewhere, foreign->heap is not assigned. */ foreign->id = mem_heap_strdupl(heap, (const char*) field, len); diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc index 47dfa2e009d..1b6194ca098 100644 --- a/storage/xtradb/dict/dict0dict.cc +++ b/storage/xtradb/dict/dict0dict.cc @@ -1643,6 +1643,7 @@ struct dict_foreign_remove_partial if (table != NULL) { table->referenced_set.erase(foreign); } + dict_foreign_free(foreign); } }; @@ -3597,8 +3598,7 @@ dict_foreign_add_to_cache( } if (for_in_cache) { - /* Free the foreign object */ - mem_heap_free(foreign->heap); + dict_foreign_free(foreign); } else { for_in_cache = foreign; } @@ -3622,7 +3622,7 @@ dict_foreign_add_to_cache( " the ones in table."); if (for_in_cache == foreign) { - mem_heap_free(foreign->heap); + dict_foreign_free(foreign); } return(DB_CANNOT_ADD_CONSTRAINT); @@ -3678,7 +3678,7 @@ dict_foreign_add_to_cache( be one */ } - mem_heap_free(foreign->heap); + dict_foreign_free(foreign); } return(DB_CANNOT_ADD_CONSTRAINT); diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc index a1cf462b11c..45f314f8c67 100644 --- a/storage/xtradb/dict/dict0load.cc +++ b/storage/xtradb/dict/dict0load.cc @@ -490,7 +490,7 @@ err_len: } /* This receives a dict_foreign_t* that points to a stack variable. - So mem_heap_free(foreign->heap) is not used as elsewhere. + So dict_foreign_free(foreign) is not used as elsewhere. Since the heap used here is freed elsewhere, foreign->heap is not assigned. */ foreign->id = mem_heap_strdupl(heap, (const char*) field, len); From da4babb86cebef74e86b330922288eb10272b47e Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 19 Dec 2016 15:47:01 -0500 Subject: [PATCH 04/26] Fix failing galera tests. --- mysql-test/suite/galera/r/MW-292.result | 9 +++ .../r/galera_forced_binlog_format.result | 2 +- .../galera/r/galera_ist_restart_joiner.result | 4 + .../suite/galera/r/galera_split_brain.result | 2 +- .../galera/r/galera_transaction_replay.result | 10 +++ .../r/galera_var_cluster_address.result | 45 ++++------- .../galera/t/galera_forced_binlog_format.test | 2 +- .../suite/galera/t/galera_split_brain.test | 5 +- .../galera/t/galera_var_cluster_address.test | 81 ++++++------------- .../r/galera_ist_gcache_rollover.result | 17 ++++ .../t/galera_ist_gcache_rollover.test | 12 +++ .../mysql-test/wsrep_info/r/plugin.result | 4 +- .../mysql-test/wsrep_info/t/plugin.test | 4 +- 13 files changed, 98 insertions(+), 99 deletions(-) diff --git a/mysql-test/suite/galera/r/MW-292.result b/mysql-test/suite/galera/r/MW-292.result index f038f880efa..5b9214ace2a 100644 --- a/mysql-test/suite/galera/r/MW-292.result +++ b/mysql-test/suite/galera/r/MW-292.result @@ -2,20 +2,28 @@ CREATE TABLE rand_table (f1 FLOAT); CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); INSERT INTO t1 VALUES (1, 'a'); INSERT INTO t1 VALUES (2, 'a'); +connection node_1; SET AUTOCOMMIT=ON; START TRANSACTION; UPDATE t1 SET f2 = 'b' WHERE f1 = 1; SELECT * FROM t1 WHERE f1 = 2 FOR UPDATE; f1 f2 2 a +connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1; SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync'; +connection node_1; COMMIT;; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; +connection node_2; UPDATE t1 SET f2 = 'c' WHERE f1 = 2; +connection node_1a; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync'; +connection node_1; SELECT TIMEDIFF(SYSDATE(), NOW()) < 2; TIMEDIFF(SYSDATE(), NOW()) < 2 1 @@ -26,5 +34,6 @@ COUNT(DISTINCT f1) = 10 1 wsrep_local_replays 1 +connection node_2; DROP TABLE t1; DROP TABLE rand_table; diff --git a/mysql-test/suite/galera/r/galera_forced_binlog_format.result b/mysql-test/suite/galera/r/galera_forced_binlog_format.result index 01f738f6109..86789a1b8e9 100644 --- a/mysql-test/suite/galera/r/galera_forced_binlog_format.result +++ b/mysql-test/suite/galera/r/galera_forced_binlog_format.result @@ -9,7 +9,7 @@ SET SESSION binlog_format = 'MIXED'; Warnings: Warning 1105 MariaDB Galera does not support binlog format: MIXED INSERT INTO t1 VALUES (2); -SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 249; +SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256; Log_name Pos Event_type Server_id End_log_pos Info mysqld-bin.000001 Gtid_list 1 [] mysqld-bin.000001 Binlog_checkpoint 1 mysqld-bin.000001 diff --git a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result index 01544843d2d..78fc5b2baf3 100644 --- a/mysql-test/suite/galera/r/galera_ist_restart_joiner.result +++ b/mysql-test/suite/galera/r/galera_ist_restart_joiner.result @@ -1,3 +1,5 @@ +connection node_1; +connection node_2; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 CHAR(1)); INSERT INTO t1 VALUES (1, 'a'), (2, 'a'), (3, 'a'), (4, 'a'), (5, 'a'),(6, 'a'); connection node_2; @@ -52,3 +54,5 @@ COUNT(*) = 0 1 connection node_1; DROP TABLE t1, t2, t3; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_split_brain.result b/mysql-test/suite/galera/r/galera_split_brain.result index e770f15d630..1f9b67eeff3 100644 --- a/mysql-test/suite/galera/r/galera_split_brain.result +++ b/mysql-test/suite/galera/r/galera_split_brain.result @@ -7,7 +7,7 @@ Killing server ... connection node_1; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; ERROR 40001: Deadlock found when trying to get lock; try restarting transaction -SET GLOBAL wsrep_cluster_address = ''; +connection node_2; connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2; disconnect node_2; disconnect node_1; diff --git a/mysql-test/suite/galera/r/galera_transaction_replay.result b/mysql-test/suite/galera/r/galera_transaction_replay.result index e932e4aed02..7fd837433d2 100644 --- a/mysql-test/suite/galera/r/galera_transaction_replay.result +++ b/mysql-test/suite/galera/r/galera_transaction_replay.result @@ -39,6 +39,7 @@ SELECT COUNT(*) = 1 FROM t1 WHERE f2 = 'c'; COUNT(*) = 1 1 DROP TABLE t1; +connection node_1; CREATE TABLE t1 (i int primary key, j int) ENGINE=INNODB; INSERT INTO t1 VALUES (1, 0), (3, 0); SELECT * FROM t1; @@ -46,23 +47,32 @@ i j 1 0 3 0 PREPARE stmt1 FROM "UPDATE t1 SET j = 1 where i > 0"; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug=d,commit_monitor_enter_sync'; +connection node_1; EXECUTE stmt1;; +connection node_1a; SET SESSION wsrep_sync_wait = 0; SET SESSION wsrep_on = 0; SET SESSION wsrep_on = 1; +connection node_2; INSERT INTO t1 VALUES(2,2); +connection node_1a; +connection node_1a; SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'signal=commit_monitor_enter_sync'; +connection node_1; SELECT * FROM t1; i j 1 1 2 2 3 1 +connection node_2; SELECT * FROM t1; i j 1 1 2 2 3 1 +connection node_1; DEALLOCATE PREPARE stmt1; DROP TABLE t1; diff --git a/mysql-test/suite/galera/r/galera_var_cluster_address.result b/mysql-test/suite/galera/r/galera_var_cluster_address.result index 09971c08580..ef75cf21a79 100644 --- a/mysql-test/suite/galera/r/galera_var_cluster_address.result +++ b/mysql-test/suite/galera/r/galera_var_cluster_address.result @@ -1,9 +1,9 @@ connection node_1; connection node_2; -connection node_1; +connection node_2; SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; +SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; ERROR 08S01: WSREP has not yet prepared node for application use SHOW STATUS LIKE 'wsrep_ready'; Variable_name Value @@ -17,16 +17,14 @@ wsrep_local_state 0 SHOW STATUS LIKE 'wsrep_local_state_comment'; Variable_name Value wsrep_local_state_comment Initialized -connection node_2; +connection node_1; SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 1 1 SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' 1 -connection node_1; connection node_2; -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; connection node_1; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' @@ -34,29 +32,16 @@ VARIABLE_VALUE = 'Primary' SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; VARIABLE_VALUE = 2 1 -connection node_1; -SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1'; -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; -ERROR 08S01: WSREP has not yet prepared node for application use -SHOW STATUS LIKE 'wsrep_ready'; -Variable_name Value -wsrep_ready OFF -SHOW STATUS LIKE 'wsrep_cluster_status'; -Variable_name Value -wsrep_cluster_status non-Primary -SHOW STATUS LIKE 'wsrep_local_state'; -Variable_name Value -wsrep_local_state 0 -SHOW STATUS LIKE 'wsrep_local_state_comment'; -Variable_name Value -wsrep_local_state_comment Initialized -connection node_1; connection node_2; -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; -connection node_1; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -VARIABLE_VALUE = 'Primary' -1 -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -VARIABLE_VALUE = 2 -1 +CALL mtr.add_suppression("Backend not supported: foo"); +CALL mtr.add_suppression("Failed to initialize backend using 'foo"); +CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo"); +CALL mtr.add_suppression("gcs connect failed: Socket type not supported"); +CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7"); +CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)"); +CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110"); +CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)"); +CALL mtr.add_suppression("gcs connect failed: Connection timed out"); +CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7"); +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera/t/galera_forced_binlog_format.test b/mysql-test/suite/galera/t/galera_forced_binlog_format.test index 982276cc317..364f41529a4 100644 --- a/mysql-test/suite/galera/t/galera_forced_binlog_format.test +++ b/mysql-test/suite/galera/t/galera_forced_binlog_format.test @@ -20,7 +20,7 @@ INSERT INTO t1 VALUES (2); --replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/ --replace_column 2 5 -SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 249; +SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 256; DROP TABLE t1; diff --git a/mysql-test/suite/galera/t/galera_split_brain.test b/mysql-test/suite/galera/t/galera_split_brain.test index 22f6370241c..a85a2ad9b8d 100644 --- a/mysql-test/suite/galera/t/galera_split_brain.test +++ b/mysql-test/suite/galera/t/galera_split_brain.test @@ -25,11 +25,8 @@ CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB; # Reset the master and restart the slave so that post-test checks can run -SET GLOBAL wsrep_cluster_address = ''; ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_orig'; ---enable_query_log +--connection node_2 --source include/start_mysqld.inc --sleep 5 --source include/wait_until_connected_again.inc diff --git a/mysql-test/suite/galera/t/galera_var_cluster_address.test b/mysql-test/suite/galera/t/galera_var_cluster_address.test index dfd84002dd6..4e5d138ae0a 100644 --- a/mysql-test/suite/galera/t/galera_var_cluster_address.test +++ b/mysql-test/suite/galera/t/galera_var_cluster_address.test @@ -6,17 +6,15 @@ --source include/have_innodb.inc # Save original auto_increment_offset values. ---connection node_1 -let $auto_increment_offset_node_1 = `SELECT @@global.auto_increment_offset`; ---connection node_2 -let $auto_increment_offset_node_2 = `SELECT @@global.auto_increment_offset`; - +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc # # Set to invalid value # ---connection node_1 ---let $wsrep_cluster_address_node1 = `SELECT @@wsrep_cluster_address` +--connection node_2 +--let $wsrep_cluster_address_node2 = `SELECT @@wsrep_cluster_address` SET GLOBAL wsrep_cluster_address = 'foo://'; # With wsrep_sync_wait, this returns an error @@ -26,7 +24,7 @@ SET GLOBAL wsrep_cluster_address = 'foo://'; SET SESSION wsrep_sync_wait=0; --error ER_UNKNOWN_COM_ERROR -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; +SELECT COUNT(*) > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS; # Must return 'OFF' SHOW STATUS LIKE 'wsrep_ready'; @@ -38,9 +36,9 @@ SHOW STATUS LIKE 'wsrep_cluster_status'; SHOW STATUS LIKE 'wsrep_local_state'; SHOW STATUS LIKE 'wsrep_local_state_comment'; ---connection node_2 +--connection node_1 --sleep 1 -# Node #2 thinks that it is now part of a single-node primary cluster +# Node #1 thinks that it is now part of a single-node primary cluster SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; @@ -48,13 +46,10 @@ SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VA # Reset everything as it was # ---connection node_1 ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1'; ---enable_query_log - --connection node_2 -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; +--disable_query_log +--eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node2'; +--enable_query_log --source include/wait_until_connected_again.inc @@ -62,49 +57,19 @@ SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; -# -# Set to invalid host -# - ---connection node_1 -SET GLOBAL wsrep_cluster_address = 'gcomm://192.0.2.1'; - ---error ER_UNKNOWN_COM_ERROR -SELECT * FROM INFORMATION_SCHEMA.GLOBAL_STATUS; - -# Must return 'OFF' -SHOW STATUS LIKE 'wsrep_ready'; - -# Must return 'Non-primary' -SHOW STATUS LIKE 'wsrep_cluster_status'; - -# Must return 0 = 'Initialized' -SHOW STATUS LIKE 'wsrep_local_state'; -SHOW STATUS LIKE 'wsrep_local_state_comment'; - -# -# Reset everything as it was -# - ---connection node_1 ---disable_query_log ---eval SET GLOBAL wsrep_cluster_address = '$wsrep_cluster_address_node1'; ---enable_query_log - --connection node_2 -SET GLOBAL wsrep_cluster_address = @@wsrep_cluster_address; ---sleep 1 - ---connection node_1 -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +CALL mtr.add_suppression("Backend not supported: foo"); +CALL mtr.add_suppression("Failed to initialize backend using 'foo"); +CALL mtr.add_suppression("Failed to open channel 'my_wsrep_cluster' at 'foo"); +CALL mtr.add_suppression("gcs connect failed: Socket type not supported"); +CALL mtr.add_suppression("wsrep::connect\\(\\) failed: 7"); +CALL mtr.add_suppression("gcs_caused\\(\\) returned -103 \\(Software caused connection abort\\)"); +CALL mtr.add_suppression("failed to open gcomm backend connection: 110: failed to reach primary view: 110"); +CALL mtr.add_suppression("Failed to open backend connection: -110 \\(Connection timed out\\)"); +CALL mtr.add_suppression("gcs connect failed: Connection timed out"); +CALL mtr.add_suppression("WSREP: wsrep::connect\\(foo://\\) failed: 7"); # Restore original auto_increment_offset values. ---disable_query_log ---connection node_1 ---eval SET @@global.auto_increment_offset = $auto_increment_offset_node_1; ---connection node_2 ---eval SET @@global.auto_increment_offset = $auto_increment_offset_node_2; ---enable_query_log - +--source include/auto_increment_offset_restore.inc +--source include/galera_end.inc diff --git a/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result index 6c66bf4a891..3d4dbcc00b0 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ist_gcache_rollover.result @@ -1,13 +1,23 @@ +connection node_1; +connection node_2; +connection node_3; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); INSERT INTO t1 VALUES (01), (02), (03), (04), (05); +connection node_2; Unloading wsrep provider ... SET GLOBAL wsrep_provider = 'none'; +connection node_3; Unloading wsrep provider ... SET GLOBAL wsrep_provider = 'none'; +connection node_1; INSERT INTO t1 VALUES (11), (12), (13), (14), (15); INSERT INTO t1 VALUES (21), (22), (23), (24), (25); SET GLOBAL wsrep_provider_options = 'dbug=d,ist_sender_send_after_get_buffers'; +connection node_2; +connection node_1; INSERT INTO t1 VALUES (31), (32), (33), (34), (35); +connection node_3; +connection node_1; SHOW STATUS LIKE 'wsrep_debug_sync_waiters'; Variable_name Value wsrep_debug_sync_waiters ist_sender_send_after_get_buffers ist_sender_send_after_get_buffers @@ -19,6 +29,9 @@ INSERT INTO t2 VALUES (REPEAT('x', 512 * 1024)); SET GLOBAL wsrep_provider_options = 'dbug='; SET GLOBAL wsrep_provider_options = 'signal=ist_sender_send_after_get_buffers'; INSERT INTO t1 VALUES (51), (52), (53), (54), (55); +connection node_2; +connection node_3; +connection node_2; SELECT COUNT(*) = 30 FROM t1; COUNT(*) = 30 1 @@ -31,6 +44,7 @@ LENGTH(f1) = 512 * 1024 1 1 CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled"); +connection node_3; SELECT COUNT(*) = 30 FROM t1; COUNT(*) = 30 1 @@ -44,3 +58,6 @@ LENGTH(f1) = 512 * 1024 1 CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled"); DROP TABLE t1, t2; +disconnect node_3; +disconnect node_2; +disconnect node_1; diff --git a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test index 8575d99f066..a67b30e3fa1 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ist_gcache_rollover.test @@ -17,6 +17,12 @@ --let $galera_server_number = 3 --source include/galera_connect.inc +# Save original auto_increment_offset values. +--let $node_1=node_1 +--let $node_2=node_2 +--let $node_3=node_3 +--source ../galera/include/auto_increment_offset_save.inc + CREATE TABLE t1 (f1 INTEGER PRIMARY KEY); INSERT INTO t1 VALUES (01), (02), (03), (04), (05); @@ -99,3 +105,9 @@ SELECT LENGTH(f1) = 512 * 1024 FROM t2; CALL mtr.add_suppression("WSREP: Unsupported protocol downgrade: incremental data collection disabled"); DROP TABLE t1, t2; + +# Restore original auto_increment_offset values. +--source ../galera/include/auto_increment_offset_restore.inc + +--let $galera_cluster_size=3 +--source include/galera_end.inc diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result index 12baf6c941b..f33a628d428 100644 --- a/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result +++ b/plugin/wsrep_info/mysql-test/wsrep_info/r/plugin.result @@ -2,7 +2,7 @@ connection node_1; SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION - Synced Primary 2 0 2 NO 3 + Synced Primary 2 0 NO 3 SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME; INDEX UUID NAME ADDRESS test-node-1
@@ -11,7 +11,7 @@ INDEX UUID NAME ADDRESS connection node_2; SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; NODE_INDEX NODE_STATUS CLUSTER_STATUS CLUSTER_SIZE CLUSTER_STATE_UUID CLUSTER_STATE_SEQNO CLUSTER_CONF_ID GAP PROTOCOL_VERSION - Synced Primary 2 0 2 YES 3 + Synced Primary 2 0 YES 3 SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME; INDEX UUID NAME ADDRESS test-node-1
diff --git a/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test index 9b06f15b125..9ae783a957e 100644 --- a/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test +++ b/plugin/wsrep_info/mysql-test/wsrep_info/t/plugin.test @@ -4,7 +4,7 @@ --echo # On node 1 --connection node_1 ---replace_column 1 5 +--replace_column 1 5 7 SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; --replace_column 1 2 4
@@ -13,7 +13,7 @@ SELECT * FROM INFORMATION_SCHEMA.WSREP_MEMBERSHIP ORDER BY NAME; --echo # On node 2 --connection node_2 ---replace_column 1 5 +--replace_column 1 5 7 SELECT * FROM INFORMATION_SCHEMA.WSREP_STATUS; --replace_column 1 2 4
From 9d8ec1468ad94f56c7a0e12b596c18c5a842b8e3 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 19 Dec 2016 15:50:33 -0500 Subject: [PATCH 05/26] MDEV-11082: Fix mysql_client_test.c (by Elena) --- tests/mysql_client_test.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 228e3227649..58e3dda2b0d 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -15386,6 +15386,9 @@ static void test_bug14169() rc= mysql_query(mysql, "drop table t1"); myquery(rc); + + rc= mysql_query(mysql, "set session group_concat_max_len=@@global.group_concat_max_len"); + myquery(rc); } /* From d51e7f90bfb59676e21c128cf84cf54c2023b058 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 19 Dec 2016 15:55:55 -0500 Subject: [PATCH 06/26] MDEV-10957: Assertion failure when dropping a myisam table ... with wsrep_replicate_myisam enabled Internal updates to system statistical tables could wrongly trigger an additional total-order replication if wsrep_repli -cate_myisam is enabled. Fixed by adding a check to skip total-order replication for stat tables. --- sql/sql_base.cc | 1 + sql/sql_statistics.cc | 18 ++++++++++++++++++ sql/sql_statistics.h | 1 + 3 files changed, 20 insertions(+) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 1ca7e9c1574..0a39d74cbf8 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4068,6 +4068,7 @@ restart: (*start) && (*start)->table && (*start)->table->file->ht == myisam_hton && + !is_stat_table((*start)->db, (*start)->alias) && sqlcom_can_generate_row_events(thd) && thd->get_command() != COM_STMT_PREPARE) { diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index e557a009686..adbc52d1eec 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -3849,3 +3849,21 @@ double Histogram::point_selectivity(double pos, double avg_sel) return sel; } +/* + Check whether the table is one of the persistent statistical tables. +*/ +bool is_stat_table(const char *db, const char *table) +{ + DBUG_ASSERT(db && table); + + if (!memcmp(db, stat_tables_db_name.str, stat_tables_db_name.length)) + { + for (uint i= 0; i < STATISTICS_TABLES; i ++) + { + if (!memcmp(table, stat_table_name[i].str, stat_table_name[i].length)) + return true; + } + } + return false; +} + diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index 46e5cef22d1..daffd792ba0 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -107,6 +107,7 @@ double get_column_range_cardinality(Field *field, key_range *min_endp, key_range *max_endp, uint range_flag); +bool is_stat_table(const char *db, const char *table); class Histogram { From b800264e495d5a61d47dacaf6005cb65e5d05b72 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 19 Dec 2016 16:11:27 -0500 Subject: [PATCH 07/26] MDEV-11152: wsrep_replicate_myisam: SELECT gets replicated ... using TO Fixed the 'wsrep_replicate_myisam' check to allow only limited set of commands. Added a debug assert to discover such cases. --- .../r/galera_var_replicate_myisam_on.result | 10 ++++++++ .../t/galera_var_replicate_myisam_on.test | 10 ++++++++ sql/sql_base.cc | 24 ++++++++++++------- sql/sql_parse.cc | 4 ++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result index bf5a09f6a77..87f8862df7e 100644 --- a/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result +++ b/mysql-test/suite/galera/r/galera_var_replicate_myisam_on.result @@ -94,6 +94,16 @@ connection node_1; COMMIT; DROP TABLE t1; DROP TABLE t2; +# +# MDEV-11152: wsrep_replicate_myisam: SELECT gets replicated using TO +# +connection node_1; +CREATE TABLE t1 (i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +SELECT * FROM t1; +i +1 +DROP TABLE t1; connection node_1; SET GLOBAL wsrep_replicate_myisam = 0; connection node_2; diff --git a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test index 9cb0edf1810..90c786f0af0 100644 --- a/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test +++ b/mysql-test/suite/galera/t/galera_var_replicate_myisam_on.test @@ -132,6 +132,16 @@ COMMIT; DROP TABLE t1; DROP TABLE t2; +--echo # +--echo # MDEV-11152: wsrep_replicate_myisam: SELECT gets replicated using TO +--echo # +--connection node_1 +CREATE TABLE t1 (i INT) ENGINE=INNODB; +INSERT INTO t1 VALUES(1); +# This command should not get replicated. +SELECT * FROM t1; +DROP TABLE t1; + --connection node_1 --eval SET GLOBAL wsrep_replicate_myisam = $wsrep_replicate_myisam_orig diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 0a39d74cbf8..5e9ca14c2db 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -4063,14 +4063,22 @@ restart: } } - if (WSREP_ON && - wsrep_replicate_myisam && - (*start) && - (*start)->table && - (*start)->table->file->ht == myisam_hton && - !is_stat_table((*start)->db, (*start)->alias) && - sqlcom_can_generate_row_events(thd) && - thd->get_command() != COM_STMT_PREPARE) + if (WSREP_ON && + wsrep_replicate_myisam && + (*start) && + (*start)->table && + (*start)->table->file->ht == myisam_hton && + wsrep_thd_exec_mode(thd) == LOCAL_STATE && + !is_stat_table((*start)->db, (*start)->alias) && + thd->get_command() != COM_STMT_PREPARE && + ((thd->lex->sql_command == SQLCOM_INSERT || + thd->lex->sql_command == SQLCOM_INSERT_SELECT || + thd->lex->sql_command == SQLCOM_REPLACE || + thd->lex->sql_command == SQLCOM_REPLACE_SELECT || + thd->lex->sql_command == SQLCOM_UPDATE || + thd->lex->sql_command == SQLCOM_UPDATE_MULTI || + thd->lex->sql_command == SQLCOM_LOAD || + thd->lex->sql_command == SQLCOM_DELETE))) { WSREP_TO_ISOLATION_BEGIN(NULL, NULL, (*start)); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 6dc91928ded..796c8f3386e 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3350,6 +3350,10 @@ mysql_execute_command(THD *thd) case SQLCOM_SHOW_STORAGE_ENGINES: case SQLCOM_SHOW_PROFILE: { +#ifdef WITH_WSREP + DBUG_ASSERT(thd->wsrep_exec_mode != REPL_RECV); +#endif /* WITH_WSREP */ + thd->status_var.last_query_cost= 0.0; /* From 2c734e7be3bd09a3d44b5be23dd250a4cdd14af8 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Mon, 19 Dec 2016 16:12:26 -0500 Subject: [PATCH 08/26] MDEV-10993: wsrep.mdev_10186 result depends on location of ... galera library Update test case. --- mysql-test/suite/wsrep/r/mdev_10186.result | 2 +- mysql-test/suite/wsrep/t/mdev_10186.test | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/wsrep/r/mdev_10186.result b/mysql-test/suite/wsrep/r/mdev_10186.result index f966c443569..778c064d208 100644 --- a/mysql-test/suite/wsrep/r/mdev_10186.result +++ b/mysql-test/suite/wsrep/r/mdev_10186.result @@ -7,5 +7,5 @@ SELECT @@wsrep_on; 0 SELECT @@GLOBAL.wsrep_provider; @@GLOBAL.wsrep_provider -/usr/lib/galera/libgalera_smm.so +libgalera_smm.so SET @@GLOBAL.wsrep_cluster_address='gcomm://'; diff --git a/mysql-test/suite/wsrep/t/mdev_10186.test b/mysql-test/suite/wsrep/t/mdev_10186.test index 90665d3c97f..98ea5192634 100644 --- a/mysql-test/suite/wsrep/t/mdev_10186.test +++ b/mysql-test/suite/wsrep/t/mdev_10186.test @@ -7,7 +7,7 @@ --echo # SELECT @@wsrep_on; ---replace_result /usr/lib64/ /usr/lib/ +--replace_regex /.*libgalera_smm.so/libgalera_smm.so/ SELECT @@GLOBAL.wsrep_provider; SET @@GLOBAL.wsrep_cluster_address='gcomm://'; From 5c69879f3b504861484b3649b83f95216aaa20aa Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Dec 2016 00:36:59 -0800 Subject: [PATCH 09/26] Fixed bug mdev-11593. When a condition containing NULLIF is pushed into a materialized view/derived table the clone of the Item_func_nullif item must be processed in a special way to guarantee that the first argument points to the same item as the third argument. --- mysql-test/r/derived_cond_pushdown.result | 38 +++++++++++++++++++++++ mysql-test/t/derived_cond_pushdown.test | 16 ++++++++++ sql/item_cmpfunc.h | 11 +++++++ 3 files changed, 65 insertions(+) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index 7c672c12f03..c2bc5daeb4d 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -8140,3 +8140,41 @@ EXPLAIN } } DROP TABLE t1,t2; +# +# MDEV-11593: pushdown of condition with NULLIF +# +CREATE TABLE t1 (i INT); +CREATE OR REPLACE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (2), (1); +SELECT * FROM v1 WHERE NULLIF(1, i); +i +2 +EXPLAIN FORMAT=JSON +SELECT * FROM v1 WHERE NULLIF(1, i); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "nullif(1,v1.i)", + "materialized": { + "query_block": { + "select_id": 2, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "nullif(1,t1.i)" + } + } + } + } + } +} +DROP VIEW v1; +DROP TABLE t1; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index 1457bd1f784..68117c71db6 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1273,3 +1273,19 @@ SELECT * FROM ( SELECT DISTINCT * FROM t1 ) AS sq WHERE i IN ( SELECT MIN(j) FROM t2 ); DROP TABLE t1,t2; + +--echo # +--echo # MDEV-11593: pushdown of condition with NULLIF +--echo # + +CREATE TABLE t1 (i INT); +CREATE OR REPLACE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; + +INSERT INTO t1 VALUES (2), (1); + +SELECT * FROM v1 WHERE NULLIF(1, i); +EXPLAIN FORMAT=JSON +SELECT * FROM v1 WHERE NULLIF(1, i); + +DROP VIEW v1; +DROP TABLE t1; diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 69b95c669a3..c691797e2c5 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1070,6 +1070,11 @@ class Item_func_nullif :public Item_func_hybrid_field_type */ Item_cache *m_cache; int compare(); + void reset_first_arg_if_needed() + { + if (arg_count == 3 && args[0] != args[2]) + args[0]= args[2]; + } public: /* Here we pass three arguments to the parent constructor, as NULLIF @@ -1120,6 +1125,12 @@ public: } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } + Item *derived_field_transformer_for_having(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *derived_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } + Item *derived_grouping_field_transformer_for_where(THD *thd, uchar *arg) + { reset_first_arg_if_needed(); return this; } }; From 1152b076d432a1cb3ff6f53bf152e693497d1ecd Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Dec 2016 00:42:13 -0800 Subject: [PATCH 10/26] Corrected a test from func_date_add.test --- mysql-test/r/func_date_add.result | 1 + mysql-test/t/func_date_add.test | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mysql-test/r/func_date_add.result b/mysql-test/r/func_date_add.result index 83fe5c3b551..fa45353e094 100644 --- a/mysql-test/r/func_date_add.result +++ b/mysql-test/r/func_date_add.result @@ -147,4 +147,5 @@ v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VI select 30 + (20010101 + interval 2 day), x from v1; 30 + (20010101 + interval 2 day) x 20010133 20010133 +drop view v1; End of 10.2 tests diff --git a/mysql-test/t/func_date_add.test b/mysql-test/t/func_date_add.test index f1805f2ccda..3106889fde6 100644 --- a/mysql-test/t/func_date_add.test +++ b/mysql-test/t/func_date_add.test @@ -128,4 +128,6 @@ create or replace view v1 as select 30 + (20010101 + interval 2 day) as x; show create view v1; select 30 + (20010101 + interval 2 day), x from v1; +drop view v1; + --echo End of 10.2 tests From 83dbb2d43ae77a87ea483127f77d69345541e271 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Dec 2016 12:07:33 +0200 Subject: [PATCH 11/26] MDEV-11487 Revert InnoDB internal temporary tables from WL#7682 Post-push fix: Remove the orphaned file sess0sess.h. --- storage/innobase/include/sess0sess.h | 146 --------------------------- 1 file changed, 146 deletions(-) delete mode 100644 storage/innobase/include/sess0sess.h diff --git a/storage/innobase/include/sess0sess.h b/storage/innobase/include/sess0sess.h deleted file mode 100644 index 3778a45d64f..00000000000 --- a/storage/innobase/include/sess0sess.h +++ /dev/null @@ -1,146 +0,0 @@ -/***************************************************************************** - -Copyright (c) 2013, 2014, Oracle and/or its affiliates. All Rights Reserved. - -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 -Foundation; version 2 of the License. - -This program is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with -this program; if not, write to the Free Software Foundation, Inc., -51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA - -*****************************************************************************/ - -/**************************************************//** -@file include/sess0sess.h -InnoDB session state tracker. -Multi file, shared, system tablespace implementation. - -Created 2014-04-30 by Krunal Bauskar -*******************************************************/ - -#ifndef sess0sess_h -#define sess0sess_h - -#include "univ.i" -#include "dict0mem.h" -#include "ut0new.h" - -#include - -class dict_intrinsic_table_t { - -public: - /** Constructor - @param[in,out] handler table handler. */ - dict_intrinsic_table_t(dict_table_t* handler) - : - m_handler(handler) - { - /* Do nothing. */ - } - - /** Destructor */ - ~dict_intrinsic_table_t() - { - m_handler = NULL; - } - -public: - - /* Table Handler holding other metadata information commonly needed - for any table. */ - dict_table_t* m_handler; -}; - -/** InnoDB private data that is cached in THD */ -typedef std::map< - std::string, - dict_intrinsic_table_t*, - std::less, - ut_allocator > > - table_cache_t; - -class innodb_session_t { -public: - /** Constructor */ - innodb_session_t() - : m_trx(), - m_open_tables() - { - /* Do nothing. */ - } - - /** Destructor */ - ~innodb_session_t() - { - m_trx = NULL; - - for (table_cache_t::iterator it = m_open_tables.begin(); - it != m_open_tables.end(); - ++it) { - delete(it->second); - } - } - - /** Cache table handler. - @param[in] table_name name of the table - @param[in,out] table table handler to register */ - void register_table_handler( - const char* table_name, - dict_table_t* table) - { - ut_ad(lookup_table_handler(table_name) == NULL); - m_open_tables.insert(table_cache_t::value_type( - table_name, new dict_intrinsic_table_t(table))); - } - - /** Lookup for table handler given table_name. - @param[in] table_name name of the table to lookup */ - dict_table_t* lookup_table_handler( - const char* table_name) - { - table_cache_t::iterator it = m_open_tables.find(table_name); - return((it == m_open_tables.end()) - ? NULL : it->second->m_handler); - } - - /** Remove table handler entry. - @param[in] table_name name of the table to remove */ - void unregister_table_handler( - const char* table_name) - { - table_cache_t::iterator it = m_open_tables.find(table_name); - if (it == m_open_tables.end()) { - return; - } - - delete(it->second); - m_open_tables.erase(table_name); - } - - /** Count of register table handler. - @return number of register table handlers */ - uint count_register_table_handler() const - { - return(static_cast(m_open_tables.size())); - } - -public: - - /** transaction handler. */ - trx_t* m_trx; - - /** Handler of tables that are created or open but not added - to InnoDB dictionary as they are session specific. - Currently, limited to intrinsic temporary tables only. */ - table_cache_t m_open_tables; -}; - - -#endif /* sess0sess_h */ From 95228dc80b016cd068925795ace324fcf463593d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Tue, 20 Dec 2016 17:32:08 +0400 Subject: [PATCH 12/26] MDEV-11570 JSON_MERGE returns incorrect result. JSON merging fixed. --- mysql-test/r/func_json.result | 3 +++ mysql-test/t/func_json.test | 1 + sql/item_jsonfunc.cc | 42 ++++++++++++++++++++++++++--------- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index a704274a112..460ff8fa1d2 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -315,6 +315,9 @@ Warning 4038 Syntax error in JSON text in argument 1 to function 'json_merge' at select json_merge('{"a":"b"}','{"c":"d"}'); json_merge('{"a":"b"}','{"c":"d"}') {"a":"b", "c":"d"} +SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); +JSON_MERGE('[1, 2]', '{"id": 47}') +[1, 2, {"id": 47}] select json_type('{"k1":123, "k2":345}'); json_type('{"k1":123, "k2":345}') OBJECT diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index a1d3d819adf..72b7b946536 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -123,6 +123,7 @@ select json_merge('{"1": 2}', '{"true": false}', '{"3": 4}'); select json_merge(NULL,json_object('foo', 1)); select json_merge('a','b'); select json_merge('{"a":"b"}','{"c":"d"}'); +SELECT JSON_MERGE('[1, 2]', '{"id": 47}'); select json_type('{"k1":123, "k2":345}'); select json_type('[123, "k2", 345]'); diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 42570984e8d..4d87aec669f 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1522,12 +1522,10 @@ String *Item_func_json_merge::val_str(String *str) goto error_return; str->length(0); - if ((je1.value_type == JSON_VALUE_ARRAY && - je2.value_type == JSON_VALUE_ARRAY) || - (je1.value_type == JSON_VALUE_OBJECT && - je2.value_type == JSON_VALUE_OBJECT)) + if (je1.value_type == JSON_VALUE_OBJECT && + je2.value_type == JSON_VALUE_OBJECT) { - /* Merge the adjancent arrays or objects. */ + /* Wrap as a single objects. */ if (json_skip_level(&je1)) goto error_return; if (str->append(js1->ptr(), @@ -1539,11 +1537,35 @@ String *Item_func_json_merge::val_str(String *str) } else { - /* Wrap as an array. */ - if (str->append("[", 1) || - str->append(js1->ptr(), js1->length()) || - str->append(", ", 2) || - str->append(js2->ptr(), js2->length()) || + const char *end1, *beg2; + + /* Merge as a single array. */ + if (je1.value_type == JSON_VALUE_ARRAY) + { + if (json_skip_level(&je1)) + goto error_return; + end1= (const char *) (je1.s.c_str - je1.sav_c_len); + } + else + { + if (str->append("[", 1)) + goto error_return; + end1= js1->end(); + } + + if (str->append(js1->ptr(), end1 - js1->ptr()), + str->append(", ", 2)) + goto error_return; + + if (je2.value_type == JSON_VALUE_ARRAY) + beg2= (const char *) je2.s.c_str; + else + beg2= js2->ptr(); + + if (str->append(beg2, js2->end() - beg2)) + goto error_return; + + if (je2.value_type != JSON_VALUE_ARRAY && str->append("]", 1)) goto error_return; } From 9b27d3e86e8437acb3eb4b227ca0285555ffcc9c Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Tue, 20 Dec 2016 11:08:50 -0800 Subject: [PATCH 13/26] Fixed bug mdev-11608. The fix for bug mdev-11488 introduced the virtual method convert_to_basic_const_item for the class Item_cache. The implementation of this method for the class Item_cache_str was not quite correct: the server could crash if the cached item was null. A similar problem could appear for the implementation of this method for the class Item_cache_decimal. Although I could not reproduce the problem I decided to change the code appropriately. --- mysql-test/r/derived_cond_pushdown.result | 63 +++++++++++++++++++++++ mysql-test/t/derived_cond_pushdown.test | 30 +++++++++++ sql/item.cc | 19 ++++--- 3 files changed, 104 insertions(+), 8 deletions(-) diff --git a/mysql-test/r/derived_cond_pushdown.result b/mysql-test/r/derived_cond_pushdown.result index c2bc5daeb4d..813c3aab83d 100644 --- a/mysql-test/r/derived_cond_pushdown.result +++ b/mysql-test/r/derived_cond_pushdown.result @@ -8178,3 +8178,66 @@ EXPLAIN } DROP VIEW v1; DROP TABLE t1; +# +# MDEV-11608: pushdown of the predicate with cached null value +# +CREATE TABLE t1 (c VARCHAR(3)); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES ('foo'),('bar'); +CREATE TABLE t2 (c VARCHAR(3)); +INSERT INTO t2 VALUES ('foo'),('xyz'); +SELECT * FROM v1 WHERE v1.c IN ( SELECT MIN(c) FROM t2 WHERE 0 ); +c +EXPLAIN FORMAT=JSON +SELECT * FROM v1 WHERE v1.c IN ( SELECT MIN(c) FROM t2 WHERE 0 ); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "", + "access_type": "system", + "rows": 1, + "filtered": 100, + "materialized": { + "unique": 1, + "query_block": { + "select_id": 2, + "table": { + "message": "Impossible WHERE" + } + } + } + }, + "table": { + "table_name": "", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "v1.c = NULL", + "materialized": { + "query_block": { + "select_id": 3, + "table": { + "table_name": "t1", + "access_type": "ALL", + "rows": 2, + "filtered": 100, + "attached_condition": "t1.c = NULL" + } + } + } + } + } +} +DROP VIEW v1; +DROP TABLE t1,t2; +CREATE TABLE t1 (d DECIMAL(10,2)); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (5.37),(1.1); +CREATE TABLE t2 (d DECIMAL(10,2)); +INSERT INTO t2 VALUES ('1.1'),('2.23'); +SELECT * FROM v1 WHERE v1.d IN ( SELECT MIN(d) FROM t2 WHERE 0 ); +d +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/mysql-test/t/derived_cond_pushdown.test b/mysql-test/t/derived_cond_pushdown.test index 68117c71db6..e43751472db 100644 --- a/mysql-test/t/derived_cond_pushdown.test +++ b/mysql-test/t/derived_cond_pushdown.test @@ -1289,3 +1289,33 @@ SELECT * FROM v1 WHERE NULLIF(1, i); DROP VIEW v1; DROP TABLE t1; + +--echo # +--echo # MDEV-11608: pushdown of the predicate with cached null value +--echo # + +CREATE TABLE t1 (c VARCHAR(3)); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES ('foo'),('bar'); + +CREATE TABLE t2 (c VARCHAR(3)); +INSERT INTO t2 VALUES ('foo'),('xyz'); + +SELECT * FROM v1 WHERE v1.c IN ( SELECT MIN(c) FROM t2 WHERE 0 ); +EXPLAIN FORMAT=JSON +SELECT * FROM v1 WHERE v1.c IN ( SELECT MIN(c) FROM t2 WHERE 0 ); + +DROP VIEW v1; +DROP TABLE t1,t2; + +CREATE TABLE t1 (d DECIMAL(10,2)); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +INSERT INTO t1 VALUES (5.37),(1.1); + +CREATE TABLE t2 (d DECIMAL(10,2)); +INSERT INTO t2 VALUES ('1.1'),('2.23'); + +SELECT * FROM v1 WHERE v1.d IN ( SELECT MIN(d) FROM t2 WHERE 0 ); + +DROP VIEW v1; +DROP TABLE t1,t2; diff --git a/sql/item.cc b/sql/item.cc index ead45f84305..6d9274759e4 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -9703,12 +9703,15 @@ my_decimal *Item_cache_decimal::val_decimal(my_decimal *val) Item *Item_cache_decimal::convert_to_basic_const_item(THD *thd) { Item *new_item; - my_decimal decimal_value; - my_decimal *result= val_decimal(&decimal_value); DBUG_ASSERT(value_cached || example != 0); - new_item= null_value ? - (Item*) new (thd->mem_root) Item_null(thd) : - (Item*) new (thd->mem_root) Item_decimal(thd, result); + if (null_value) + new_item= (Item*) new (thd->mem_root) Item_null(thd); + else + { + my_decimal decimal_value; + my_decimal *result= val_decimal(&decimal_value); + new_item= (Item*) new (thd->mem_root) Item_decimal(thd, result); + } return new_item; } @@ -9795,14 +9798,14 @@ bool Item_cache_row::allocate(THD *thd, uint num) Item *Item_cache_str::convert_to_basic_const_item(THD *thd) { Item *new_item; - char buff[MAX_FIELD_WIDTH]; - String tmp(buff, sizeof(buff), value->charset()); - String *result= val_str(&tmp); DBUG_ASSERT(value_cached || example != 0); if (null_value) new_item= (Item*) new (thd->mem_root) Item_null(thd); else { + char buff[MAX_FIELD_WIDTH]; + String tmp(buff, sizeof(buff), value->charset()); + String *result= val_str(&tmp); uint length= result->length(); char *tmp_str= thd->strmake(result->ptr(), length); new_item= new (thd->mem_root) Item_string(thd, tmp_str, length, From 229dd711d40a25dbbbabcc0f7cef06b01638fd43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Dec 2016 22:42:13 +0200 Subject: [PATCH 14/26] MDEV-11585 Hard-code the shared InnoDB temporary tablespace ID Try hard-coding the ID as -2 instead of -1, so that they will not be confused with ULINT_UNDEFINED on 32-bit platforms. --- storage/innobase/include/fsp0types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/include/fsp0types.h b/storage/innobase/include/fsp0types.h index f9197394bd7..c264fe1b595 100644 --- a/storage/innobase/include/fsp0types.h +++ b/storage/innobase/include/fsp0types.h @@ -33,7 +33,7 @@ Created May 26, 2009 Vasil Dimov have a smaller fil_space_t::id. */ #define SRV_LOG_SPACE_FIRST_ID 0xFFFFFFF0U /** The fil_space_t::id of the innodb_temporary tablespace. */ -#define SRV_TMP_SPACE_ID 0xFFFFFFFFU +#define SRV_TMP_SPACE_ID 0xFFFFFFFEU #include "univ.i" #include "ut0byte.h" From 561b6d213c2c03d92a5b951d6e434604cf79dbf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 20 Dec 2016 22:46:29 +0200 Subject: [PATCH 15/26] Revert "Merge pull request #275 from grooverdan/10.2-MDEV-11075-crc32-runtime-detect-getauxval" This reverts commit edf4cc7519b84a2e00b5284761781352b3d376f3, reversing changes made to 9320d8ae30c18420bef659618175836221d363ea. --- storage/innobase/ut/ut0crc32.cc | 16 ++-------------- storage/xtradb/ut/ut0crc32.cc | 10 ++-------- 2 files changed, 4 insertions(+), 22 deletions(-) diff --git a/storage/innobase/ut/ut0crc32.cc b/storage/innobase/ut/ut0crc32.cc index 1a5890eed42..386d32f6a60 100644 --- a/storage/innobase/ut/ut0crc32.cc +++ b/storage/innobase/ut/ut0crc32.cc @@ -83,12 +83,6 @@ mysys/my_perf.c, contributed by Facebook under the following license. #include "my_config.h" #include -#if defined(__linux__) && defined(HAVE_CRC32_VPMSUM) -/* Used to detect at runtime if we have vpmsum instructions (PowerISA 2.07) */ -#include -#include -#endif - #include "univ.i" #include "ut0crc32.h" @@ -746,14 +740,8 @@ ut_crc32_init() } #elif defined(HAVE_CRC32_VPMSUM) -#if defined(__linux__) - if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) { -#endif - ut_crc32 = ut_crc32_power8; - ut_crc32_implementation = "Using POWER8 crc32 instructions"; -#if defined(__linux__) - } -#endif + ut_crc32 = ut_crc32_power8; + ut_crc32_implementation = "Using POWER8 crc32 instructions"; #endif } diff --git a/storage/xtradb/ut/ut0crc32.cc b/storage/xtradb/ut/ut0crc32.cc index f8981ee544d..15ed6bfadee 100644 --- a/storage/xtradb/ut/ut0crc32.cc +++ b/storage/xtradb/ut/ut0crc32.cc @@ -336,13 +336,7 @@ ut_crc32_init() } #elif defined(HAVE_CRC32_VPMSUM) -#if defined(__linux__) - if (getauxval(AT_HWCAP2) & PPC_FEATURE2_ARCH_2_07) { -#endif - ut_crc32 = ut_crc32_power8; - ut_crc32_implementation = "Using POWER8 crc32 instructions"; -#if defined(__linux__) - } -#endif + ut_crc32 = ut_crc32_power8; + ut_crc32_implementation = "Using POWER8 crc32 instructions"; #endif } From 8774a02364600279908bd9fb8b92d61dc4fcf60e Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 8 Dec 2016 14:20:46 +0400 Subject: [PATCH 16/26] MDEV-11227 - mysqlimport -l doesn't issue UNLOCK TABLES Implementation of MDEV-7660 introduced unwanted incompatible change: modifications under LOCK TABLES with autocommit enabled are rolled back on disconnect. Previously everything was committed, because LOCK TABLES didn't adjust autocommit setting. This patch restores original behavior by reverting some changes done in MDEV-7660: - sql/sql_parse.cc: do not reset autocommit on LOCK TABLES - sql/sql_base.cc: do not set autocommit on UNLOCK TABLES - test cases: main.lock_tables_lost_commit, main.partition_explicit_prune, rpl.rpl_switch_stm_row_mixed, tokudb.nested_txn_implicit_commit, tokudb_bugs.db806 But it makes InnoDB tables under LOCK TABLES ... READ [LOCAL] not protected against DML. To restore protection some changes from WL#6671 were merged, specifically MDL_SHARED_READ_ONLY and test cases. WL#6671 merge highlights: - Not all tests merged. - In MySQL LOCK TABLES ... READ acquires MDL_SHARED_READ_ONLY for all engines, in MariaDB MDL_SHARED_READ is always acquired first and then upgraded to MDL_SHARED_READ_ONLY for InnoDB only. - The above allows us to omit MDL_SHARED_WRITE_LOW_PRIO implementation in MariaDB, which is rather useless with InnoDB. In MySQL it is needed to preserve locking behavior between low priority writes and LOCK TABLES ... READ for non-InnoDB engines (covered by sys_vars.sql_low_priority_updates_func). - Omitted HA_NO_READ_LOCAL_LOCK, we rely on lock_count() instead. - Omitted "piglets": in MariaDB stream of DML against InnoDB table may lead to concurrent LOCK TABLES ... READ starvation. - HANDLER ... OPEN acquires MDL_SHARED_READ instead of MDL_SHARED in MariaDB. - Omitted SNRW->X MDL lock upgrade for IMPORT/DISCARD TABLESPAECE under LOCK TABLES. - Omitted strong locks for views, triggers and SP under LOCK TABLES. - Omitted IX schema lock for LOCK TABLES READ. - Omitted deadlock weight juggling for LOCK TABLES. Full WL#6671 merge status: - innodb.innodb-lock: fully merged - main.alter_table: not merged due to different HANDLER solution - main.debug_sync: fully merged - main.handler_innodb: not merged due to different HANDLER solution - main.handler_myisam: not merged due to different HANDLER solution - main.innodb_mysql_lock: fully merged - main.insert_notembedded: fully merged - main.lock: not merged (due to no strong locks for views) - main.lock_multi: not merged - main.lock_sync: fully merged (partially in MDEV-7660) - main.mdl_sync: not merged - main.partition_debug_sync: not merged due to different HANDLER solution - main.status: fully merged - main.view: fully merged - perfschema.mdl_func: not merged (no such test in MariaDB) - perfschema.table_aggregate_global_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_global_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_global_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_global_4u_3t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_hist_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_hist_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_hist_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_hist_4u_3t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_thread_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_thread_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_thread_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_aggregate_thread_4u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_global_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_global_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_global_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_global_4u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_hist_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_hist_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_hist_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_hist_4u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_thread_2u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_thread_2u_3t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_thread_4u_2t: not merged (didn't fail in MariaDB) - perfschema.table_lock_aggregate_thread_4u_3t: not merged (didn't fail in MariaDB) - sys_vars.sql_low_priority_updates_func: not merged - include/thr_rwlock.h: not merged, rw_pr_lock_assert_write_owner and rw_pr_lock_assert_not_write_owner are macros in MariaDB - sql/handler.h: not merged (HA_NO_READ_LOCAL_LOCK) - sql/mdl.cc: partially merged (MDL_SHARED_READ_ONLY only) - sql/mdl.h: partially merged (MDL_SHARED_READ_ONLY only) - sql/lock.cc: fully merged - sql/sp_head.cc: not merged - sql/sp_head.h: not merged - sql/sql_base.cc: partially merged (MDL_SHARED_READ_ONLY only) - sql/sql_base.h: not merged - sql/sql_class.cc: fully merged - sql/sql_class.h: fully merged - sql/sql_handler.cc: merged partially (different solution in MariaDB) - sql/sql_parse.cc: partially merged, mostly omitted low priority write part - sql/sql_reload.cc: not merged comment change - sql/sql_table.cc: not merged SNRW->X upgrade for IMPORT/DISCARD TABLESPACE - sql/sql_view.cc: not merged - sql/sql_yacc.yy: not merged (MDL_SHARED_WRITE_LOW_PRIO, MDL_SHARED_READ_ONLY) - sql/table.cc: not merged (MDL_SHARED_WRITE_LOW_PRIO) - sql/table.h: not merged (MDL_SHARED_WRITE_LOW_PRIO) - sql/trigger.cc: not merged - storage/innobase/handler/ha_innodb.cc: merged store_lock()/lock_count() changes (in MDEV-7660), didn't merge HA_NO_READ_LOCAL_LOCK - storage/innobase/handler/ha_innodb.h: fully merged in MDEV-7660 - storage/myisammrg/ha_myisammrg.cc: not merged comment change - storage/perfschema/table_helper.cc: not merged (no MDL support in MariaDB PFS) - unittest/gunit/mdl-t.cc: not merged - unittest/gunit/mdl_sync-t.cc: not merged MariaDB specific changes: - handler.heap: different HANDLER solution, MDEV-7660 - handler.innodb: different HANDLER solution, MDEV-7660 - handler.interface: different HANDLER solution, MDEV-7660 - handler.myisam: different HANDLER solution, MDEV-7660 - main.mdl_sync: MDEV-7660 specific changes - main.partition_debug_sync: removed test due to different HANDLER solution, MDEV-7660 - main.truncate_coverage: removed test due to different HANDLER solution, MDEV-7660 - mysql-test/include/mtr_warnings.sql: additional cleanup, MDEV-7660 - mysql-test/lib/v1/mtr_report.pl: additional cleanup, MDEV-7660 - plugin/metadata_lock_info/metadata_lock_info.cc: not in MySQL - sql/sql_handler.cc: MariaDB specific fix for mysql_ha_read(), MDEV-7660 --- mysql-test/r/debug_sync.result | 20 +++- mysql-test/r/innodb_mysql_lock.result | 29 +----- mysql-test/r/insert_notembedded.result | 28 ------ mysql-test/r/lock_sync.result | 71 ++++++++++++++ mysql-test/r/lock_tables_lost_commit.result | 1 + mysql-test/r/partition_explicit_prune.result | 12 +-- mysql-test/r/status.result | 26 +++-- mysql-test/r/view.result | 21 ++-- mysql-test/suite/innodb/r/innodb-lock.result | 45 ++++----- mysql-test/suite/innodb/t/innodb-lock.test | 39 +++++--- .../rpl/r/rpl_switch_stm_row_mixed.result | 1 - .../suite/rpl/t/rpl_switch_stm_row_mixed.test | 1 - mysql-test/t/debug_sync.test | 43 ++++++--- mysql-test/t/innodb_mysql_lock.test | 49 +--------- mysql-test/t/insert_notembedded.test | 36 ------- mysql-test/t/lock_sync.test | 96 +++++++++++++++++++ mysql-test/t/status.test | 33 ++++--- mysql-test/t/view.test | 21 ++-- .../metadata_lock_info/metadata_lock_info.cc | 1 + sql/lock.cc | 8 +- sql/mdl.cc | 92 ++++++++++-------- sql/mdl.h | 19 ++++ sql/sql_base.cc | 15 +-- sql/sql_class.cc | 22 +++++ sql/sql_class.h | 24 +++++ sql/sql_handler.cc | 52 +--------- sql/sql_parse.cc | 76 ++++++++++++--- .../r/nested_txn_implicit_commit.result | 4 + .../mysql-test/tokudb_bugs/r/db806.result | 2 +- .../mysql-test/tokudb_bugs/t/db806.test | 4 +- 30 files changed, 538 insertions(+), 353 deletions(-) diff --git a/mysql-test/r/debug_sync.result b/mysql-test/r/debug_sync.result index 8498a908000..bb9ae1a417d 100644 --- a/mysql-test/r/debug_sync.result +++ b/mysql-test/r/debug_sync.result @@ -265,17 +265,31 @@ connection default; DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (c1 INT); -LOCK TABLE t1 READ; +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT GET_LOCK('mysqltest_lock', 100); +GET_LOCK('mysqltest_lock', 100) +1 connect con1,localhost,root,,; +# Sending: +UPDATE t1 SET c1=GET_LOCK('mysqltest_lock', 100);; +connect con2,localhost,root,,; SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; INSERT INTO t1 VALUES (1); connection default; SET DEBUG_SYNC= 'now WAIT_FOR locked'; -UNLOCK TABLES; +SELECT RELEASE_LOCK('mysqltest_lock'); +RELEASE_LOCK('mysqltest_lock') +1 connection con1; +# Reaping UPDATE +SELECT RELEASE_LOCK('mysqltest_lock'); +RELEASE_LOCK('mysqltest_lock') +1 +connection con2; retrieve INSERT result. disconnect con1; +disconnect con2; connection default; DROP TABLE t1; SET DEBUG_SYNC= 'RESET'; diff --git a/mysql-test/r/innodb_mysql_lock.result b/mysql-test/r/innodb_mysql_lock.result index 6d2eef2e62e..110fa50d544 100644 --- a/mysql-test/r/innodb_mysql_lock.result +++ b/mysql-test/r/innodb_mysql_lock.result @@ -36,6 +36,7 @@ connection con3; set @@autocommit=1; connection default; disconnect con1; +disconnect con2; disconnect con3; # # Test for bug #37346 "innodb does not detect deadlock between update @@ -72,34 +73,6 @@ connection default; disconnect con37346; drop table t1; # -# Bug #42147 Concurrent DML and LOCK TABLE ... READ for InnoDB -# table cause warnings in errlog -# -# -# Note that this test for now relies on a global suppression of -# the warning "Found lock of type 6 that is write and read locked" -# This suppression rule can be removed once Bug#42147 is properly -# fixed. See bug page for more info. -# -DROP TABLE IF EXISTS t1; -CREATE TABLE t1 (i INT) engine= innodb; -# Get user-level lock -connection con2; -SELECT get_lock('bug42147_lock', 60); -get_lock('bug42147_lock', 60) -1 -connection default; -INSERT INTO t1 SELECT get_lock('bug42147_lock', 60); -connection con2; -LOCK TABLES t1 READ; -SELECT release_lock('bug42147_lock'); -release_lock('bug42147_lock') -1 -UNLOCK TABLES; -connection default; -disconnect con2; -DROP TABLE t1; -# # Bug#53798 OPTIMIZE TABLE breaks repeatable read # DROP TABLE IF EXISTS t1; diff --git a/mysql-test/r/insert_notembedded.result b/mysql-test/r/insert_notembedded.result index d7ec70d36f8..d2733eac061 100644 --- a/mysql-test/r/insert_notembedded.result +++ b/mysql-test/r/insert_notembedded.result @@ -119,33 +119,5 @@ DROP USER user20989@localhost; disconnect root; connection default; DROP DATABASE meow; -connection: default -set low_priority_updates=1; -drop table if exists t1; -create table t1 (a int, b int, unique key t1$a (a)); -lock table t1 read; -connect update,localhost,root,,; -connection update; -connection: update -set low_priority_updates=1; -show variables like 'low_priority_updates'; -Variable_name Value -low_priority_updates ON -insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2;; -connection default; -connect select,localhost,root,,; -connection: select -select * from t1; -a b -connection default; -connection: default -select * from t1; -a b -connection default; -disconnect update; -disconnect select; -unlock tables; -drop table t1; -set low_priority_updates=default; set local sql_mode=default; set global sql_mode=default; diff --git a/mysql-test/r/lock_sync.result b/mysql-test/r/lock_sync.result index 4cd726f0efc..7b61c5994b6 100644 --- a/mysql-test/r/lock_sync.result +++ b/mysql-test/r/lock_sync.result @@ -784,3 +784,74 @@ DROP VIEW v1; DROP TABLE t1; disconnect con1; disconnect con2; +# +# Bug#28587 SELECT is blocked by INSERT waiting on read lock, even with low_priority_updates +# +set low_priority_updates=1; +drop table if exists t1; +drop table if exists t2; +set debug_sync='RESET'; +create table t1 (a int, b int, unique key t1$a (a)); +create table t2 (j int, k int); +set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go'; +# Sending: +insert into t2 select * from t1;; +connect update,localhost,root,,; +connection update; +set debug_sync='now WAIT_FOR parked'; +set low_priority_updates=1; +show variables like 'low_priority_updates'; +Variable_name Value +low_priority_updates ON +insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2;; +connect select,localhost,root,,; +select * from t1; +a b +set debug_sync='now SIGNAL go'; +connection default; +disconnect update; +disconnect select; +# Reaping INSERT SELECT +drop tables t1, t2; +set low_priority_updates=default; +set debug_sync='RESET'; +# +# Additional test coverage for LOCK TABLES ... READ LOCAL +# for InnoDB tables. +# +# Check that we correctly handle deadlocks which can occur +# during metadata lock upgrade which happens when one tries +# to use LOCK TABLES ... READ LOCAL for InnoDB tables. +CREATE TABLE t1 (i INT) ENGINE=InnoDB; +CREATE TABLE t2 (j INT) ENGINE=InnoDB; +# Execute LOCK TABLE READ LOCK which will pause after acquiring +# SR metadata lock and before upgrading it to SRO lock. +SET DEBUG_SYNC="after_open_table_mdl_shared SIGNAL locked WAIT_FOR go"; +# Sending: +LOCK TABLE t1 READ LOCAL; +connect con1, localhost, root; +SET DEBUG_SYNC="now WAIT_FOR locked"; +# Execute RENAME TABLE which will try to acquire X lock. +# Sending: +RENAME TABLE t1 TO t3, t2 TO t1, t3 TO t2; +connect con2, localhost, root; +# Wait until RENAME TABLE is blocked. +# Resume LOCK TABLE statement. It should try to +# upgrade SR lock to SRO lock which will create +# deadlock due to presence of pending X lock. +# Deadlock should be detected and LOCK TABLES should +# release its MDL and retry opening of tables. +SET DEBUG_SYNC="now SIGNAL go"; +connection con1; +# RENAME TABLE should be able to complete. Reap it. +connection default; +# Reap LOCK TABLES. +# Check that we see new version of table. +SELECT * FROM t1; +j +UNLOCK TABLES; +# Clean-up. +SET DEBUG_SYNC="RESET"; +disconnect con1; +disconnect con2; +DROP TABLES t1, t2; diff --git a/mysql-test/r/lock_tables_lost_commit.result b/mysql-test/r/lock_tables_lost_commit.result index 394ef0a9d1c..769e9734c7a 100644 --- a/mysql-test/r/lock_tables_lost_commit.result +++ b/mysql-test/r/lock_tables_lost_commit.result @@ -9,6 +9,7 @@ disconnect con1; connection con2; SELECT * FROM t1; a +10 DROP TABLE t1; connection default; disconnect con2; diff --git a/mysql-test/r/partition_explicit_prune.result b/mysql-test/r/partition_explicit_prune.result index 65b8e8083fe..1a3f5029978 100644 --- a/mysql-test/r/partition_explicit_prune.result +++ b/mysql-test/r/partition_explicit_prune.result @@ -281,7 +281,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 3 +HANDLER_COMMIT 2 HANDLER_READ_RND_NEXT 54 HANDLER_TMP_WRITE 75 HANDLER_WRITE 2 @@ -440,7 +440,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 6 +HANDLER_COMMIT 5 HANDLER_READ_FIRST 3 HANDLER_READ_NEXT 4 HANDLER_READ_RND_NEXT 108 @@ -665,7 +665,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 6 +HANDLER_COMMIT 5 HANDLER_DELETE 2 HANDLER_READ_FIRST 1 HANDLER_READ_KEY 3 @@ -758,7 +758,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 3 +HANDLER_COMMIT 2 HANDLER_READ_RND_NEXT 54 HANDLER_TMP_WRITE 75 HANDLER_WRITE 10 @@ -953,7 +953,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 4 +HANDLER_COMMIT 3 HANDLER_DELETE 1 HANDLER_READ_KEY 2 HANDLER_READ_RND 2 @@ -1039,7 +1039,7 @@ UNLOCK TABLES; SELECT * FROM INFORMATION_SCHEMA.SESSION_STATUS WHERE VARIABLE_NAME LIKE 'HANDLER_%' AND VARIABLE_VALUE > 0; VARIABLE_NAME VARIABLE_VALUE -HANDLER_COMMIT 4 +HANDLER_COMMIT 3 HANDLER_DELETE 2 HANDLER_READ_KEY 3 HANDLER_READ_NEXT 1 diff --git a/mysql-test/r/status.result b/mysql-test/r/status.result index 9d75a262592..4966418dbfd 100644 --- a/mysql-test/r/status.result +++ b/mysql-test/r/status.result @@ -4,6 +4,7 @@ SET @old_log_output = @@global.log_output; SET GLOBAL LOG_OUTPUT = 'FILE'; connect con1,localhost,root,,; connect con2,localhost,root,,; +connection default; flush status; show status like 'Table_lock%'; Variable_name Value @@ -13,33 +14,42 @@ select * from information_schema.session_status where variable_name like 'Table_ VARIABLE_NAME VARIABLE_VALUE TABLE_LOCKS_IMMEDIATE 0 TABLE_LOCKS_WAITED 0 -connection con1; set sql_log_bin=0; set @old_general_log = @@global.general_log; set global general_log = 'OFF'; drop table if exists t1; create table t1(n int) engine=myisam; insert into t1 values(1); -select 1; -1 +select get_lock('mysqltest_lock', 100); +get_lock('mysqltest_lock', 100) 1 connection con2; -lock tables t1 read; -unlock tables; -lock tables t1 read; +# Sending: +update t1 set n = get_lock('mysqltest_lock', 100); connection con1; +# Wait for the first UPDATE to get blocked. +# Sending: update t1 set n = 3; +connection default; +# wait for the second UPDATE to get blocked +select release_lock('mysqltest_lock'); +release_lock('mysqltest_lock') +1 connection con2; -unlock tables; +# Reaping first UPDATE +select release_lock('mysqltest_lock'); +release_lock('mysqltest_lock') +1 connection con1; +# Reaping second UPDATE show status like 'Table_locks_waited'; Variable_name Value Table_locks_waited 1 +connection default; drop table t1; set global general_log = @old_general_log; disconnect con2; disconnect con1; -connection default; select 1; 1 1 diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result index c1ec95beef7..78cb251ad11 100644 --- a/mysql-test/r/view.result +++ b/mysql-test/r/view.result @@ -4792,21 +4792,24 @@ DROP TABLE t1, t2; # Bug#48315 Metadata lock is not taken for merged views that # use an INFORMATION_SCHEMA table # -DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; DROP PROCEDURE IF EXISTS p1; connect con2, localhost, root; connect con3, localhost, root; connection default; CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata; -CREATE TABLE t1 (str VARCHAR(50)); -CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1; +CREATE PROCEDURE p1() SELECT COUNT(*), GET_LOCK('blocker', 100) FROM v1; # CALL p1() so the view is merged. CALL p1(); +SELECT RELEASE_LOCK('blocker'); +RELEASE_LOCK('blocker') +1 connection con3; -LOCK TABLE t1 READ; +SELECT GET_LOCK('blocker', 100); +GET_LOCK('blocker', 100) +1 connection default; -# Try to CALL p1() again, this time it should block for t1. +# Try to CALL p1() again, this time it should block on "blocker". # Sending: CALL p1(); connection con2; @@ -4815,14 +4818,18 @@ connection con2; DROP VIEW v1; connection con3; # Now allow CALL p1() to complete -UNLOCK TABLES; +SELECT RELEASE_LOCK('blocker'); +RELEASE_LOCK('blocker') +1 connection default; # Reaping: CALL p1() +SELECT RELEASE_LOCK('blocker'); +RELEASE_LOCK('blocker') +1 connection con2; # Reaping: DROP VIEW v1 connection default; DROP PROCEDURE p1; -DROP TABLE t1; disconnect con2; disconnect con3; # diff --git a/mysql-test/suite/innodb/r/innodb-lock.result b/mysql-test/suite/innodb/r/innodb-lock.result index 6604f2396a3..e63a7cd1505 100644 --- a/mysql-test/suite/innodb/r/innodb-lock.result +++ b/mysql-test/suite/innodb/r/innodb-lock.result @@ -36,8 +36,11 @@ drop table t1; # Old lock method (where LOCK TABLE was ignored by InnoDB) no longer # works when LOCK TABLE ... WRITE is used due to fix for bugs #46272 # "MySQL 5.4.4, new MDL: unnecessary and bug #37346 "innodb does not -# detect deadlock between update and alter table". But it still works -# for LOCK TABLE ... READ. +# detect deadlock between update and alter table". +# After WL#6671 "Improve scalability by not using thr_lock.c locks +# for InnoDB tables" was implemented it no longer works for LOCK TABLES +# ,,, READ as well. +# LOCK TABLES locks are now completely handled by MDL subsystem. # set @@innodb_table_locks=0; create table t1 (id integer primary key, x integer) engine=INNODB; @@ -73,28 +76,26 @@ select * from t1 where id = 0 for update; id x 0 1 connection con2; -# The below statement should not be blocked as LOCK TABLES ... READ -# does not take strong SQL-level lock on t1. SELECTs which do not -# conflict with transaction in the first connections should not be -# blocked. -lock table t1 read; -select * from t1; -id x -0 1 -1 1 -2 2 -select * from t1 where id = 1 lock in share mode; -id x -1 1 -unlock tables; -select * from t1; -id x -0 1 -1 1 -2 2 -commit; +# The following statement should block because SQL-level lock +# is taken on t1 which will wait until concurrent transaction +# is commited. +# Sending: +lock table t1 read;; connection con1; +# Wait until LOCK TABLE is blocked on SQL-level lock. +# We should be able to do UPDATEs and SELECTs within transaction. +update t1 set x=2 where id = 0; +select * from t1; +id x +0 2 +1 1 +2 2 +# Unblock LOCK TABLE. commit; +connection con2; +# Reap LOCK TABLE. +unlock tables; +connection default; drop table t1; # #Bug#12842206 INNODB LOCKING REGRESSION FOR INSERT IGNORE diff --git a/mysql-test/suite/innodb/t/innodb-lock.test b/mysql-test/suite/innodb/t/innodb-lock.test index 47246c53759..3e9b3dd7fe4 100644 --- a/mysql-test/suite/innodb/t/innodb-lock.test +++ b/mysql-test/suite/innodb/t/innodb-lock.test @@ -60,8 +60,11 @@ drop table t1; --echo # Old lock method (where LOCK TABLE was ignored by InnoDB) no longer --echo # works when LOCK TABLE ... WRITE is used due to fix for bugs #46272 --echo # "MySQL 5.4.4, new MDL: unnecessary and bug #37346 "innodb does not ---echo # detect deadlock between update and alter table". But it still works ---echo # for LOCK TABLE ... READ. +--echo # detect deadlock between update and alter table". +--echo # After WL#6671 "Improve scalability by not using thr_lock.c locks +--echo # for InnoDB tables" was implemented it no longer works for LOCK TABLES +--echo # ,,, READ as well. +--echo # LOCK TABLES locks are now completely handled by MDL subsystem. --echo # set @@innodb_table_locks=0; @@ -104,20 +107,32 @@ connection con1; select * from t1 where id = 0 for update; connection con2; ---echo # The below statement should not be blocked as LOCK TABLES ... READ ---echo # does not take strong SQL-level lock on t1. SELECTs which do not ---echo # conflict with transaction in the first connections should not be ---echo # blocked. -lock table t1 read; -select * from t1; -select * from t1 where id = 1 lock in share mode; -unlock tables; -select * from t1; -commit; +--echo # The following statement should block because SQL-level lock +--echo # is taken on t1 which will wait until concurrent transaction +--echo # is commited. +--echo # Sending: +--send lock table t1 read; connection con1; +--echo # Wait until LOCK TABLE is blocked on SQL-level lock. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "lock table t1 read"; +--source include/wait_condition.inc +--echo # We should be able to do UPDATEs and SELECTs within transaction. +update t1 set x=2 where id = 0; +select * from t1; +--echo # Unblock LOCK TABLE. commit; +connection con2; +--echo # Reap LOCK TABLE. +--reap +unlock tables; + +connection default; + drop table t1; # End of 4.1 tests diff --git a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result index 3b5f67efe78..6c709945111 100644 --- a/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result +++ b/mysql-test/suite/rpl/r/rpl_switch_stm_row_mixed.result @@ -410,7 +410,6 @@ LOCK TABLES t11 WRITE; SET SESSION BINLOG_FORMAT=ROW; INSERT INTO t11 VALUES('Several Species of Small Furry Animals Gathered Together in a Cave and Grooving With a Pict'); SET SESSION BINLOG_FORMAT=STATEMENT; -ERROR HY000: Cannot modify @@session.binlog_format inside a transaction INSERT INTO t11 VALUES('Careful With That Axe, Eugene'); UNLOCK TABLES; SELECT * FROM t11; diff --git a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test index e5e2f7a381d..575fdb2e89d 100644 --- a/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test +++ b/mysql-test/suite/rpl/t/rpl_switch_stm_row_mixed.test @@ -524,7 +524,6 @@ CREATE TABLE t11 (song VARCHAR(255)); LOCK TABLES t11 WRITE; SET SESSION BINLOG_FORMAT=ROW; INSERT INTO t11 VALUES('Several Species of Small Furry Animals Gathered Together in a Cave and Grooving With a Pict'); ---error ER_INSIDE_TRANSACTION_PREVENTS_SWITCH_BINLOG_FORMAT SET SESSION BINLOG_FORMAT=STATEMENT; INSERT INTO t11 VALUES('Careful With That Axe, Eugene'); UNLOCK TABLES; diff --git a/mysql-test/t/debug_sync.test b/mysql-test/t/debug_sync.test index aead6f3ac2e..89414939f59 100644 --- a/mysql-test/t/debug_sync.test +++ b/mysql-test/t/debug_sync.test @@ -381,21 +381,40 @@ DROP TABLE IF EXISTS t1; --enable_warnings # # Test. -CREATE TABLE t1 (c1 INT); -LOCK TABLE t1 READ; - connect (con1,localhost,root,,); - # Retain action after use. First used by general_log. - SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; - send INSERT INTO t1 VALUES (1); +CREATE TABLE t1 (c1 INT) ENGINE=MyISAM; +INSERT INTO t1 VALUES (1); +SELECT GET_LOCK('mysqltest_lock', 100); + +connect (con1,localhost,root,,); +--echo # Sending: +--send UPDATE t1 SET c1=GET_LOCK('mysqltest_lock', 100); + +connect (con2,localhost,root,,); +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "User lock" and + info = "UPDATE t1 SET c1=GET_LOCK('mysqltest_lock', 100)"; +--source include/wait_condition.inc + +# Retain action after use. First used by general_log. +SET DEBUG_SYNC= 'wait_for_lock SIGNAL locked EXECUTE 2'; +send INSERT INTO t1 VALUES (1); + connection default; # Wait until INSERT waits for lock. SET DEBUG_SYNC= 'now WAIT_FOR locked'; -# let INSERT continue. -UNLOCK TABLES; - connection con1; - --echo retrieve INSERT result. - reap; - disconnect con1; +# let UPDATE continue. +SELECT RELEASE_LOCK('mysqltest_lock'); +connection con1; +--echo # Reaping UPDATE +reap; +SELECT RELEASE_LOCK('mysqltest_lock'); + +connection con2; +--echo retrieve INSERT result. +reap; +disconnect con1; +disconnect con2; connection default; DROP TABLE t1; diff --git a/mysql-test/t/innodb_mysql_lock.test b/mysql-test/t/innodb_mysql_lock.test index 85ba41860df..39ea7e5df88 100644 --- a/mysql-test/t/innodb_mysql_lock.test +++ b/mysql-test/t/innodb_mysql_lock.test @@ -64,6 +64,7 @@ set @@autocommit=1; connection default; disconnect con1; +disconnect con2; disconnect con3; @@ -116,54 +117,6 @@ connection default; disconnect con37346; drop table t1; - ---echo # ---echo # Bug #42147 Concurrent DML and LOCK TABLE ... READ for InnoDB ---echo # table cause warnings in errlog ---echo # - ---echo # ---echo # Note that this test for now relies on a global suppression of ---echo # the warning "Found lock of type 6 that is write and read locked" ---echo # This suppression rule can be removed once Bug#42147 is properly ---echo # fixed. See bug page for more info. ---echo # - ---disable_warnings -DROP TABLE IF EXISTS t1; ---enable_warnings - -CREATE TABLE t1 (i INT) engine= innodb; - ---echo # Get user-level lock -connection con2; -SELECT get_lock('bug42147_lock', 60); - -connection default; ---send INSERT INTO t1 SELECT get_lock('bug42147_lock', 60) - -connection con2; -let $wait_condition= - SELECT COUNT(*) > 0 FROM information_schema.processlist - WHERE state = 'User lock' - AND info = 'INSERT INTO t1 SELECT get_lock(\'bug42147_lock\', 60)'; ---source include/wait_condition.inc -LOCK TABLES t1 READ; -SELECT release_lock('bug42147_lock'); -let $wait_condition= - SELECT COUNT(*) > 0 FROM information_schema.processlist - WHERE state = 'executing' - AND info = 'INSERT INTO t1 SELECT get_lock(\'bug42147_lock\', 60)'; ---source include/wait_condition.inc -UNLOCK TABLES; - -connection default; ---reap - -disconnect con2; -DROP TABLE t1; - - --echo # --echo # Bug#53798 OPTIMIZE TABLE breaks repeatable read --echo # diff --git a/mysql-test/t/insert_notembedded.test b/mysql-test/t/insert_notembedded.test index 713eaf5db40..2769aee8d8a 100644 --- a/mysql-test/t/insert_notembedded.test +++ b/mysql-test/t/insert_notembedded.test @@ -156,41 +156,5 @@ connection default; DROP DATABASE meow; -# -# Bug#28587 SELECT is blocked by INSERT waiting on read lock, even with low_priority_updates -# ---echo connection: default -set low_priority_updates=1; ---disable_warnings -drop table if exists t1; ---enable_warnings -create table t1 (a int, b int, unique key t1$a (a)); -lock table t1 read; -connect (update,localhost,root,,); -connection update; ---echo connection: update -set low_priority_updates=1; -show variables like 'low_priority_updates'; -let $ID= `select connection_id()`; ---send insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2; -connection default; -# we must wait till the insert opens and locks the table -let $wait_condition= - select count(*) = 1 from information_schema.processlist - where state = "Waiting for table level lock" and id = $ID; ---source include/wait_condition.inc -connect (select,localhost,root,,); ---echo connection: select -select * from t1; -connection default; ---echo connection: default -select * from t1; -connection default; -disconnect update; -disconnect select; -unlock tables; -drop table t1; -set low_priority_updates=default; - set local sql_mode=default; set global sql_mode=default; diff --git a/mysql-test/t/lock_sync.test b/mysql-test/t/lock_sync.test index 07c16acc72a..af8435f7fbb 100644 --- a/mysql-test/t/lock_sync.test +++ b/mysql-test/t/lock_sync.test @@ -998,6 +998,102 @@ DROP TABLE t1; disconnect con1; disconnect con2; + +--echo # +--echo # Bug#28587 SELECT is blocked by INSERT waiting on read lock, even with low_priority_updates +--echo # +set low_priority_updates=1; +--disable_warnings +drop table if exists t1; +drop table if exists t2; +--enable_warnings +set debug_sync='RESET'; +create table t1 (a int, b int, unique key t1$a (a)); +create table t2 (j int, k int); +set debug_sync='after_lock_tables_takes_lock SIGNAL parked WAIT_FOR go'; +--echo # Sending: +--send insert into t2 select * from t1; +connect (update,localhost,root,,); +connection update; +set debug_sync='now WAIT_FOR parked'; +set low_priority_updates=1; +show variables like 'low_priority_updates'; +let $ID= `select connection_id()`; +--send insert into t1 values (1, 2) ON DUPLICATE KEY UPDATE b = 2; +connect (select,localhost,root,,); +# we must wait till the insert opens and locks the table +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table level lock" and id = $ID; +--source include/wait_condition.inc +select * from t1; +set debug_sync='now SIGNAL go'; +connection default; +disconnect update; +disconnect select; +--echo # Reaping INSERT SELECT +--reap +drop tables t1, t2; +set low_priority_updates=default; +set debug_sync='RESET'; + + +--echo # +--echo # Additional test coverage for LOCK TABLES ... READ LOCAL +--echo # for InnoDB tables. +--echo # +--echo # Check that we correctly handle deadlocks which can occur +--echo # during metadata lock upgrade which happens when one tries +--echo # to use LOCK TABLES ... READ LOCAL for InnoDB tables. + +--enable_connect_log +CREATE TABLE t1 (i INT) ENGINE=InnoDB; +CREATE TABLE t2 (j INT) ENGINE=InnoDB; + +--echo # Execute LOCK TABLE READ LOCK which will pause after acquiring +--echo # SR metadata lock and before upgrading it to SRO lock. +SET DEBUG_SYNC="after_open_table_mdl_shared SIGNAL locked WAIT_FOR go"; +--echo # Sending: +--send LOCK TABLE t1 READ LOCAL + +connect (con1, localhost, root); +SET DEBUG_SYNC="now WAIT_FOR locked"; +--echo # Execute RENAME TABLE which will try to acquire X lock. +--echo # Sending: +--send RENAME TABLE t1 TO t3, t2 TO t1, t3 TO t2 + +connect (con2, localhost, root); +--echo # Wait until RENAME TABLE is blocked. +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where state = "Waiting for table metadata lock" and + info = "RENAME TABLE t1 TO t3, t2 TO t1, t3 TO t2"; +--source include/wait_condition.inc +--echo # Resume LOCK TABLE statement. It should try to +--echo # upgrade SR lock to SRO lock which will create +--echo # deadlock due to presence of pending X lock. +--echo # Deadlock should be detected and LOCK TABLES should +--echo # release its MDL and retry opening of tables. +SET DEBUG_SYNC="now SIGNAL go"; + +connection con1; +--echo # RENAME TABLE should be able to complete. Reap it. +--reap + +connection default; +--echo # Reap LOCK TABLES. +--reap +--echo # Check that we see new version of table. +SELECT * FROM t1; +UNLOCK TABLES; + +--echo # Clean-up. +SET DEBUG_SYNC="RESET"; +disconnect con1; +disconnect con2; +DROP TABLES t1, t2; +--disable_connect_log + # Check that all connections opened by test cases in this file are really # gone so execution of other tests won't be affected by their presence. --source include/wait_until_count_sessions.inc diff --git a/mysql-test/t/status.test b/mysql-test/t/status.test index e0b0d9c8838..7ab32241bcb 100644 --- a/mysql-test/t/status.test +++ b/mysql-test/t/status.test @@ -23,13 +23,13 @@ SET GLOBAL LOG_OUTPUT = 'FILE'; connect (con1,localhost,root,,); connect (con2,localhost,root,,); +connection default; flush status; show status like 'Table_lock%'; select * from information_schema.session_status where variable_name like 'Table_lock%'; -connection con1; set sql_log_bin=0; set @old_general_log = @@global.general_log; set global general_log = 'OFF'; @@ -39,35 +39,46 @@ drop table if exists t1; create table t1(n int) engine=myisam; insert into t1 values(1); -# Execute dummy select in order to ensure that tables used in the -# previous statement are unlocked and closed. -select 1; +select get_lock('mysqltest_lock', 100); connection con2; -lock tables t1 read; -unlock tables; -lock tables t1 read; +--echo # Sending: +--send update t1 set n = get_lock('mysqltest_lock', 100) connection con1; +--echo # Wait for the first UPDATE to get blocked. +let $wait_condition= select count(*) from INFORMATION_SCHEMA.PROCESSLIST + where STATE = "User lock" and + INFO = "update t1 set n = get_lock('mysqltest_lock', 100)"; +--source include/wait_condition.inc + let $ID= `select connection_id()`; +--echo # Sending: --send update t1 set n = 3 -connection con2; -# wait for the other query to start executing +connection default; +--echo # wait for the second UPDATE to get blocked let $wait_condition= select 1 from INFORMATION_SCHEMA.PROCESSLIST where ID = $ID and STATE = "Waiting for table level lock"; --source include/wait_condition.inc -unlock tables; +select release_lock('mysqltest_lock'); + +connection con2; +--echo # Reaping first UPDATE +--reap +select release_lock('mysqltest_lock'); connection con1; +--echo # Reaping second UPDATE reap; show status like 'Table_locks_waited'; + +connection default; drop table t1; set global general_log = @old_general_log; disconnect con2; disconnect con1; -connection default; # End of 4.1 tests diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test index 59ff87f0bad..c3f462eab18 100644 --- a/mysql-test/t/view.test +++ b/mysql-test/t/view.test @@ -4636,7 +4636,6 @@ DROP TABLE t1, t2; --echo # --disable_warnings -DROP TABLE IF EXISTS t1; DROP VIEW IF EXISTS v1; DROP PROCEDURE IF EXISTS p1; --enable_warnings @@ -4647,25 +4646,27 @@ connect (con3, localhost, root); connection default; CREATE VIEW v1 AS SELECT schema_name FROM information_schema.schemata; -CREATE TABLE t1 (str VARCHAR(50)); -CREATE PROCEDURE p1() INSERT INTO t1 SELECT * FROM v1; +CREATE PROCEDURE p1() SELECT COUNT(*), GET_LOCK('blocker', 100) FROM v1; --echo # CALL p1() so the view is merged. +--disable_result_log CALL p1(); +--enable_result_log +SELECT RELEASE_LOCK('blocker'); connection con3; -LOCK TABLE t1 READ; +SELECT GET_LOCK('blocker', 100); connection default; ---echo # Try to CALL p1() again, this time it should block for t1. +--echo # Try to CALL p1() again, this time it should block on "blocker". --echo # Sending: --send CALL p1() connection con2; let $wait_condition= SELECT COUNT(*) = 1 from information_schema.processlist - WHERE state = "Waiting for table level lock" AND - info = "INSERT INTO t1 SELECT * FROM v1"; + WHERE state = "User lock" AND + info = "SELECT COUNT(*), GET_LOCK('blocker', 100) FROM v1"; --source include/wait_condition.inc --echo # ... then try to drop the view. This should block. --echo # Sending: @@ -4677,11 +4678,14 @@ let $wait_condition= WHERE state = "Waiting for table metadata lock" AND info = "DROP VIEW v1"; --source include/wait_condition.inc --echo # Now allow CALL p1() to complete -UNLOCK TABLES; +SELECT RELEASE_LOCK('blocker'); connection default; --echo # Reaping: CALL p1() +--disable_result_log --reap +--enable_result_log +SELECT RELEASE_LOCK('blocker'); connection con2; --echo # Reaping: DROP VIEW v1 @@ -4689,7 +4693,6 @@ connection con2; connection default; DROP PROCEDURE p1; -DROP TABLE t1; disconnect con2; disconnect con3; diff --git a/plugin/metadata_lock_info/metadata_lock_info.cc b/plugin/metadata_lock_info/metadata_lock_info.cc index 6a9f6ef3f6c..d5308acb013 100644 --- a/plugin/metadata_lock_info/metadata_lock_info.cc +++ b/plugin/metadata_lock_info/metadata_lock_info.cc @@ -39,6 +39,7 @@ static const LEX_STRING metadata_lock_info_lock_mode[] = { { C_STRING_WITH_LEN("MDL_SHARED_READ") }, { C_STRING_WITH_LEN("MDL_SHARED_WRITE") }, { C_STRING_WITH_LEN("MDL_SHARED_UPGRADABLE") }, + { C_STRING_WITH_LEN("MDL_SHARED_READ_ONLY") }, { C_STRING_WITH_LEN("MDL_SHARED_NO_WRITE") }, { C_STRING_WITH_LEN("MDL_SHARED_NO_READ_WRITE") }, { C_STRING_WITH_LEN("MDL_EXCLUSIVE") }, diff --git a/sql/lock.cc b/sql/lock.cc index 2de2a80c95a..a51c34365fa 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -164,18 +164,12 @@ lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags) write we must own metadata lock of MDL_SHARED_WRITE or stronger type. For table to be locked for read we must own metadata lock of MDL_SHARED_READ or stronger type). - The only exception are HANDLER statements which are allowed to - lock table for read while having only MDL_SHARED lock on it. */ DBUG_ASSERT(t->s->tmp_table || thd->mdl_context.is_lock_owner(MDL_key::TABLE, t->s->db.str, t->s->table_name.str, t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE ? - MDL_SHARED_WRITE : MDL_SHARED_READ) || - (t->open_by_handler && - thd->mdl_context.is_lock_owner(MDL_key::TABLE, - t->s->db.str, t->s->table_name.str, - MDL_SHARED))); + MDL_SHARED_WRITE : MDL_SHARED_READ)); /* Prevent modifications to base tables if READ_ONLY is activated. diff --git a/sql/mdl.cc b/sql/mdl.cc index 1d6b4f6ffc3..c05fdc0157b 100644 --- a/sql/mdl.cc +++ b/sql/mdl.cc @@ -391,7 +391,11 @@ public: virtual const bitmap_t *incompatible_waiting_types_bitmap() const { return m_waiting_incompatible; } virtual bool needs_notification(const MDL_ticket *ticket) const - { return (ticket->get_type() >= MDL_SHARED_NO_WRITE); } + { + return ticket->get_type() == MDL_SHARED_NO_WRITE || + ticket->get_type() == MDL_SHARED_NO_READ_WRITE || + ticket->get_type() == MDL_EXCLUSIVE; + } /** Notify threads holding a shared metadata locks on object which @@ -1413,7 +1417,8 @@ const MDL_lock::bitmap_t MDL_lock::MDL_scoped_lock::m_granted_incompatible[MDL_TYPE_END]= { MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED), - MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE), 0, 0, 0, 0, 0, 0, + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_INTENTION_EXCLUSIVE), + 0, 0, 0, 0, 0, 0, 0, MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED) | MDL_BIT(MDL_INTENTION_EXCLUSIVE) }; @@ -1421,7 +1426,7 @@ const MDL_lock::bitmap_t MDL_lock::MDL_scoped_lock::m_waiting_incompatible[MDL_TYPE_END]= { MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED), - MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0, 0 + MDL_BIT(MDL_EXCLUSIVE), 0, 0, 0, 0, 0, 0, 0, 0 }; @@ -1433,39 +1438,41 @@ MDL_lock::MDL_scoped_lock::m_waiting_incompatible[MDL_TYPE_END]= The first array specifies if particular type of request can be satisfied if there is granted lock of certain type. - Request | Granted requests for lock | - type | S SH SR SW SU SNW SNRW X | - ----------+----------------------------------+ - S | + + + + + + + - | - SH | + + + + + + + - | - SR | + + + + + + - - | - SW | + + + + + - - - | - SU | + + + + - - - - | - SNW | + + + - - - - - | - SNRW | + + - - - - - - | - X | - - - - - - - - | - SU -> X | - - - - 0 0 0 0 | - SNW -> X | - - - 0 0 0 0 0 | - SNRW -> X | - - 0 0 0 0 0 0 | + Request | Granted requests for lock | + type | S SH SR SW SU SRO SNW SNRW X | + ----------+---------------------------------------+ + S | + + + + + + + + - | + SH | + + + + + + + + - | + SR | + + + + + + + - - | + SW | + + + + + - - - - | + SU | + + + + - + - - - | + SRO | + + + - + + + - - | + SNW | + + + - - + - - - | + SNRW | + + - - - - - - - | + X | - - - - - - - - - | + SU -> X | - - - - 0 - 0 0 0 | + SNW -> X | - - - 0 0 - 0 0 0 | + SNRW -> X | - - 0 0 0 0 0 0 0 | The second array specifies if particular type of request can be satisfied if there is waiting request for the same lock of certain type. In other words it specifies what is the priority of different lock types. - Request | Pending requests for lock | - type | S SH SR SW SU SNW SNRW X | - ----------+---------------------------------+ - S | + + + + + + + - | - SH | + + + + + + + + | - SR | + + + + + + - - | - SW | + + + + + - - - | - SU | + + + + + + + - | - SNW | + + + + + + + - | - SNRW | + + + + + + + - | - X | + + + + + + + + | - SU -> X | + + + + + + + + | - SNW -> X | + + + + + + + + | - SNRW -> X | + + + + + + + + | + Request | Pending requests for lock | + type | S SH SR SW SU SRO SNW SNRW X | + ----------+--------------------------------------+ + S | + + + + + + + + - | + SH | + + + + + + + + + | + SR | + + + + + + + - - | + SW | + + + + + + - - - | + SU | + + + + + + + + - | + SRO | + + + - + + + - - | + SNW | + + + + + + + + - | + SNRW | + + + + + + + + - | + X | + + + + + + + + + | + SU -> X | + + + + + + + + + | + SNW -> X | + + + + + + + + + | + SNRW -> X | + + + + + + + + + | Here: "+" -- means that request can be satisfied "-" -- means that request can't be satisfied and should wait @@ -1487,19 +1494,23 @@ MDL_lock::MDL_object_lock::m_granted_incompatible[MDL_TYPE_END]= MDL_BIT(MDL_EXCLUSIVE), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | - MDL_BIT(MDL_SHARED_NO_WRITE), + MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE), + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | + MDL_BIT(MDL_SHARED_WRITE), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | - MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE) | - MDL_BIT(MDL_SHARED_WRITE) | MDL_BIT(MDL_SHARED_READ), + MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) | + MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE) | + MDL_BIT(MDL_SHARED_READ), MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | - MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_UPGRADABLE) | - MDL_BIT(MDL_SHARED_WRITE) | MDL_BIT(MDL_SHARED_READ) | - MDL_BIT(MDL_SHARED_HIGH_PRIO) | MDL_BIT(MDL_SHARED) + MDL_BIT(MDL_SHARED_NO_WRITE) | MDL_BIT(MDL_SHARED_READ_ONLY) | + MDL_BIT(MDL_SHARED_UPGRADABLE) | MDL_BIT(MDL_SHARED_WRITE) | + MDL_BIT(MDL_SHARED_READ) | MDL_BIT(MDL_SHARED_HIGH_PRIO) | + MDL_BIT(MDL_SHARED) }; @@ -1513,6 +1524,8 @@ MDL_lock::MDL_object_lock::m_waiting_incompatible[MDL_TYPE_END]= MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | MDL_BIT(MDL_SHARED_NO_WRITE), MDL_BIT(MDL_EXCLUSIVE), + MDL_BIT(MDL_EXCLUSIVE) | MDL_BIT(MDL_SHARED_NO_READ_WRITE) | + MDL_BIT(MDL_SHARED_WRITE), MDL_BIT(MDL_EXCLUSIVE), MDL_BIT(MDL_EXCLUSIVE), 0 @@ -2306,10 +2319,11 @@ MDL_context::upgrade_shared_lock(MDL_ticket *mdl_ticket, if (mdl_ticket->has_stronger_or_equal_type(new_type)) DBUG_RETURN(FALSE); - /* Only allow upgrades from SHARED_UPGRADABLE/NO_WRITE/NO_READ_WRITE */ + /* Only allow upgrades from SHARED_UPGRADABLE/NO_WRITE/NO_READ_WRITE/READ */ DBUG_ASSERT(mdl_ticket->m_type == MDL_SHARED_UPGRADABLE || mdl_ticket->m_type == MDL_SHARED_NO_WRITE || - mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE); + mdl_ticket->m_type == MDL_SHARED_NO_READ_WRITE || + mdl_ticket->m_type == MDL_SHARED_READ); mdl_xlock_request.init(&mdl_ticket->m_lock->key, new_type, MDL_TRANSACTION); diff --git a/sql/mdl.h b/sql/mdl.h index 7d659af86bc..97216b8e7b1 100644 --- a/sql/mdl.h +++ b/sql/mdl.h @@ -195,6 +195,12 @@ enum enum_mdl_type { To be used for the first phase of ALTER TABLE. */ MDL_SHARED_UPGRADABLE, + /* + A shared metadata lock for cases when we need to read data from table + and block all concurrent modifications to it (for both data and metadata). + Used by LOCK TABLES READ statement. + */ + MDL_SHARED_READ_ONLY, /* An upgradable shared metadata lock which blocks all attempts to update table data, allowing reads. @@ -467,6 +473,19 @@ public: type= type_arg; } + /** + Is this a request for a lock which allow data to be updated? + + @note This method returns true for MDL_SHARED_UPGRADABLE type of + lock. Even though this type of lock doesn't allow updates + it will always be upgraded to one that does. + */ + bool is_write_lock_request() const + { + return (type >= MDL_SHARED_WRITE && + type != MDL_SHARED_READ_ONLY); + } + /* This is to work around the ugliness of TABLE_LIST compiler-generated assignment operator. It is currently used diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 5e9ca14c2db..e947e9dd90a 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1495,7 +1495,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) Note that we allow write locks on log tables as otherwise logging to general/slow log would be disabled in read only transactions. */ - if (table_list->mdl_request.type >= MDL_SHARED_WRITE && + if (table_list->mdl_request.is_write_lock_request() && thd->tx_read_only && !(flags & (MYSQL_LOCK_LOG_TABLE | MYSQL_OPEN_HAS_MDL_LOCK))) { @@ -1654,7 +1654,7 @@ bool open_table(THD *thd, TABLE_LIST *table_list, Open_table_context *ot_ctx) pre-acquiring metadata locks at the beggining of open_tables() call. */ - if (table_list->mdl_request.type >= MDL_SHARED_WRITE && + if (table_list->mdl_request.is_write_lock_request() && ! (flags & (MYSQL_OPEN_IGNORE_GLOBAL_READ_LOCK | MYSQL_OPEN_FORCE_SHARED_MDL | MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL | @@ -2146,11 +2146,6 @@ Locked_tables_list::unlock_locked_tables(THD *thd) request for metadata locks and TABLE_LIST elements. */ reset(); - if (thd->variables.option_bits & OPTION_AUTOCOMMIT) - { - thd->variables.option_bits&= ~(OPTION_NOT_AUTOCOMMIT); - thd->server_status|= SERVER_STATUS_AUTOCOMMIT; - } } @@ -3605,6 +3600,7 @@ lock_table_names(THD *thd, const DDL_options_st &options, table= table->next_global) { if (table->mdl_request.type < MDL_SHARED_UPGRADABLE || + table->mdl_request.type == MDL_SHARED_READ_ONLY || table->open_type == OT_TEMPORARY_ONLY || (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table))) { @@ -3728,6 +3724,11 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start, for (table= tables_start; table && table != tables_end; table= table->next_global) { + /* + Check below needs to be updated if this function starts + called for SRO locks. + */ + DBUG_ASSERT(table->mdl_request.type != MDL_SHARED_READ_ONLY); if (table->mdl_request.type < MDL_SHARED_UPGRADABLE || table->open_type == OT_TEMPORARY_ONLY || (table->open_type == OT_TEMPORARY_OR_BASE && is_temporary_table(table))) diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 1b6692d9d2c..d7d2944ba89 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -650,6 +650,28 @@ bool Drop_table_error_handler::handle_condition(THD *thd, } +/** + Handle an error from MDL_context::upgrade_lock() and mysql_lock_tables(). + Ignore ER_LOCK_ABORTED and ER_LOCK_DEADLOCK errors. +*/ + +bool +MDL_deadlock_and_lock_abort_error_handler:: +handle_condition(THD *thd, + uint sql_errno, + const char *sqlstate, + Sql_condition::enum_warning_level level, + const char* msg, + Sql_condition **cond_hdl) +{ + *cond_hdl= NULL; + if (sql_errno == ER_LOCK_ABORTED || sql_errno == ER_LOCK_DEADLOCK) + m_need_reopen= true; + + return m_need_reopen; +} + + /** Send timeout to thread. diff --git a/sql/sql_class.h b/sql/sql_class.h index f2e6f131f5f..f0052f8fe57 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1744,6 +1744,30 @@ private: }; +/** + Internal error handler to process an error from MDL_context::upgrade_lock() + and mysql_lock_tables(). Used by implementations of HANDLER READ and + LOCK TABLES LOCAL. +*/ + +class MDL_deadlock_and_lock_abort_error_handler: public Internal_error_handler +{ +public: + virtual + bool handle_condition(THD *thd, + uint sql_errno, + const char *sqlstate, + Sql_condition::enum_warning_level level, + const char* msg, + Sql_condition **cond_hdl); + + bool need_reopen() const { return m_need_reopen; }; + void init() { m_need_reopen= FALSE; }; +private: + bool m_need_reopen; +}; + + /** Tables that were locked with LOCK TABLES statement. diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index 735adeadb11..58db104ec96 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -485,56 +485,6 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables) } -/** - A helper class to process an error from mysql_lock_tables(). - HANDLER READ statement's attempt to lock the subject table - may get aborted if there is a pending DDL. In that case - we close the table, reopen it, and try to read again. - This is implicit and obscure, since HANDLER position - is lost in the process, but it's the legacy server - behaviour we should preserve. -*/ - -class Sql_handler_lock_error_handler: public Internal_error_handler -{ -public: - virtual - bool handle_condition(THD *thd, - uint sql_errno, - const char *sqlstate, - Sql_condition::enum_warning_level level, - const char* msg, - Sql_condition **cond_hdl); - - bool need_reopen() const { return m_need_reopen; }; - void init() { m_need_reopen= FALSE; }; -private: - bool m_need_reopen; -}; - - -/** - Handle an error from mysql_lock_tables(). - Ignore ER_LOCK_ABORTED errors. -*/ - -bool -Sql_handler_lock_error_handler:: -handle_condition(THD *thd, - uint sql_errno, - const char *sqlstate, - Sql_condition::enum_warning_level level, - const char* msg, - Sql_condition **cond_hdl) -{ - *cond_hdl= NULL; - if (sql_errno == ER_LOCK_ABORTED) - m_need_reopen= TRUE; - - return m_need_reopen; -} - - /** Finds an open HANDLER table. @@ -731,7 +681,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, int error, keyno; uint num_rows; uchar *UNINIT_VAR(key); - Sql_handler_lock_error_handler sql_handler_lock_error; + MDL_deadlock_and_lock_abort_error_handler sql_handler_lock_error; DBUG_ENTER("mysql_ha_read"); DBUG_PRINT("enter",("'%s'.'%s' as '%s'", tables->db, tables->table_name, tables->alias)); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 796c8f3386e..370a4bd7400 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2728,27 +2728,76 @@ bool sp_process_definer(THD *thd) static bool lock_tables_open_and_lock_tables(THD *thd, TABLE_LIST *tables) { Lock_tables_prelocking_strategy lock_tables_prelocking_strategy; + MDL_deadlock_and_lock_abort_error_handler deadlock_handler; + MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint(); uint counter; TABLE_LIST *table; thd->in_lock_tables= 1; +retry: + if (open_tables(thd, &tables, &counter, 0, &lock_tables_prelocking_strategy)) goto err; - /* - We allow to change temporary tables even if they were locked for read - by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK - TABLES time and by the statement which is later executed under LOCK TABLES - we ensure that for temporary tables we always request a write lock (such - discrepancy can cause problems for the storage engine). - We don't set TABLE_LIST::lock_type in this case as this might result in - extra warnings from THD::decide_logging_format() even though binary logging - is totally irrelevant for LOCK TABLES. - */ for (table= tables; table; table= table->next_global) - if (!table->placeholder() && table->table->s->tmp_table) - table->table->reginfo.lock_type= TL_WRITE; + { + if (!table->placeholder()) + { + if (table->table->s->tmp_table) + { + /* + We allow to change temporary tables even if they were locked for read + by LOCK TABLES. To avoid a discrepancy between lock acquired at LOCK + TABLES time and by the statement which is later executed under LOCK + TABLES we ensure that for temporary tables we always request a write + lock (such discrepancy can cause problems for the storage engine). + We don't set TABLE_LIST::lock_type in this case as this might result + in extra warnings from THD::decide_logging_format() even though + binary logging is totally irrelevant for LOCK TABLES. + */ + table->table->reginfo.lock_type= TL_WRITE; + } + else if (table->mdl_request.type == MDL_SHARED_READ && + ! table->prelocking_placeholder && + table->table->file->lock_count() == 0) + { + /* + In case when LOCK TABLE ... READ LOCAL was issued for table with + storage engine which doesn't support READ LOCAL option and doesn't + use THR_LOCK locks we need to upgrade weak SR metadata lock acquired + in open_tables() to stronger SRO metadata lock. + This is not needed for tables used through stored routines or + triggers as we always acquire SRO (or even stronger SNRW) metadata + lock for them. + */ + deadlock_handler.init(); + thd->push_internal_handler(&deadlock_handler); + + bool result= thd->mdl_context.upgrade_shared_lock( + table->table->mdl_ticket, + MDL_SHARED_READ_ONLY, + thd->variables.lock_wait_timeout); + + thd->pop_internal_handler(); + + if (deadlock_handler.need_reopen()) + { + /* + Deadlock occurred during upgrade of metadata lock. + Let us restart acquring and opening tables for LOCK TABLES. + */ + close_tables_for_reopen(thd, &tables, mdl_savepoint); + if (thd->open_temporary_tables(tables)) + goto err; + goto retry; + } + + if (result) + goto err; + } + } + } if (lock_tables(thd, tables, counter, 0) || thd->locked_tables_list.init_locked_tables(thd)) @@ -4789,8 +4838,7 @@ end_with_restore_list: if (lock_tables_precheck(thd, all_tables)) goto error; - thd->variables.option_bits|= OPTION_TABLE_LOCK | OPTION_NOT_AUTOCOMMIT; - thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT; + thd->variables.option_bits|= OPTION_TABLE_LOCK; res= lock_tables_open_and_lock_tables(thd, all_tables); diff --git a/storage/tokudb/mysql-test/tokudb/r/nested_txn_implicit_commit.result b/storage/tokudb/mysql-test/tokudb/r/nested_txn_implicit_commit.result index f1ea7e20147..ac1a13d5523 100644 --- a/storage/tokudb/mysql-test/tokudb/r/nested_txn_implicit_commit.result +++ b/storage/tokudb/mysql-test/tokudb/r/nested_txn_implicit_commit.result @@ -46,6 +46,7 @@ a b 1 10 2 20 3 30 +4 40 insert into t2 values (1); ERROR HY000: Table 't2' was not locked with LOCK TABLES commit; @@ -58,6 +59,7 @@ a b 1 10 2 20 3 30 +4 40 select * from t2; a 1 @@ -70,6 +72,7 @@ a b 1 10 2 20 3 30 +4 40 5 50 select * from t2; a @@ -81,6 +84,7 @@ a b 1 10 2 20 3 30 +4 40 5 50 select * from t2; a diff --git a/storage/tokudb/mysql-test/tokudb_bugs/r/db806.result b/storage/tokudb/mysql-test/tokudb_bugs/r/db806.result index 8578bb3b36c..ae87dbab281 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/r/db806.result +++ b/storage/tokudb/mysql-test/tokudb_bugs/r/db806.result @@ -2,8 +2,8 @@ drop table if exists t1,t3; CREATE TABLE t3(a int,c int,d int)engine=TOKUDB; lock table t3 read; create temporary table t1 engine=tokudb as SELECT 1; -unlock tables; select * from t1; 1 1 +unlock tables; drop table t1,t3; diff --git a/storage/tokudb/mysql-test/tokudb_bugs/t/db806.test b/storage/tokudb/mysql-test/tokudb_bugs/t/db806.test index 8dcebe1bb6b..3815e59f78c 100644 --- a/storage/tokudb/mysql-test/tokudb_bugs/t/db806.test +++ b/storage/tokudb/mysql-test/tokudb_bugs/t/db806.test @@ -7,7 +7,7 @@ enable_warnings; CREATE TABLE t3(a int,c int,d int)engine=TOKUDB; lock table t3 read; create temporary table t1 engine=tokudb as SELECT 1; -unlock tables; select * from t1; +unlock tables; -drop table t1,t3; +drop table t1,t3; \ No newline at end of file From 27f20d192c118c3c8ae03d8e29759f343e46ad78 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 21 Dec 2016 13:21:38 +0400 Subject: [PATCH 17/26] Updated test results --- mysql-test/suite/parts/r/rpl_partition.result | 2 +- mysql-test/suite/rpl/r/rpl_innodb_bug28430.result | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/parts/r/rpl_partition.result b/mysql-test/suite/parts/r/rpl_partition.result index 38bca0b931f..0afe1cb478d 100644 --- a/mysql-test/suite/parts/r/rpl_partition.result +++ b/mysql-test/suite/parts/r/rpl_partition.result @@ -128,7 +128,7 @@ show create table t3; Table t3 Create Table CREATE TABLE `t3` ( `id` mediumint(9) NOT NULL AUTO_INCREMENT, - `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `dt` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `user` char(255) DEFAULT NULL, `uuidf` longblob DEFAULT NULL, `fkid` mediumint(9) DEFAULT NULL, diff --git a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result index ea48173dc76..eef77303c9a 100644 --- a/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result +++ b/mysql-test/suite/rpl/r/rpl_innodb_bug28430.result @@ -114,7 +114,7 @@ show create table test.byrange_tbl; Table byrange_tbl Create Table CREATE TABLE `byrange_tbl` ( `id` mediumint(9) NOT NULL AUTO_INCREMENT, - `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `dt` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), `user` char(255) DEFAULT NULL, `uuidf` longblob DEFAULT NULL, `fkid` mediumint(9) DEFAULT NULL, From 9b10b4181f70634c9fab96ff0a225147b64396d7 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 22 Dec 2016 10:17:26 +0100 Subject: [PATCH 18/26] update libmariadb, and fix debian packaging for client libs --- debian/libmariadb-dev.install | 1 - debian/libmariadb3.install | 2 +- debian/rules | 8 ++++---- libmariadb | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/debian/libmariadb-dev.install b/debian/libmariadb-dev.install index 2097df6b99c..e11eceb704e 100644 --- a/debian/libmariadb-dev.install +++ b/debian/libmariadb-dev.install @@ -1,5 +1,4 @@ usr/bin/mysql_config -usr/include/mariadb usr/include/mysql/*.h usr/include/mysql/psi/*.h usr/lib/*/libmariadb.so diff --git a/debian/libmariadb3.install b/debian/libmariadb3.install index 0e0c0cdc82f..cdb1e5918df 100644 --- a/debian/libmariadb3.install +++ b/debian/libmariadb3.install @@ -1,5 +1,5 @@ usr/lib/*/libmariadbclient.so.* usr/lib/*/libmysqlclient.so.* -usr/lib/mariadb/libmariadb.so.* +usr/lib/*/libmariadb.so.* usr/lib/mysql/plugin/dialog.so usr/lib/mysql/plugin/mysql_clear_password.so diff --git a/debian/rules b/debian/rules index 003acdcbffe..707857a0bac 100755 --- a/debian/rules +++ b/debian/rules @@ -158,12 +158,12 @@ override_dh_auto_install: install -D -m 644 debian/mariadb-server-10.2.py $(TMP)/usr/share/apport/package-hooks/source_mariadb-10.2.py # Install libmariadbclient18 compatibility links - ln -s /usr/lib/mariadb/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadbclient.so.18 + ln -s $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadbclient.so.18 # Install libmysqlclientclientXX compatibility links - ln -s /usr/lib/mariadb/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.18 - ln -s /usr/lib/mariadb/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.19 - ln -s /usr/lib/mariadb/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.20 + ln -s $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.18 + ln -s $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.19 + ln -s $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmysqlclient.so.20 touch $@ diff --git a/libmariadb b/libmariadb index 3837442cbc6..cae391f7bf4 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 3837442cbc62c867198091b43dff40198fb6b762 +Subproject commit cae391f7bf47f17fb246cded8ddf0ef19dbfbdec From 0c3791caae769e0e0a219ad092f81ef254960ecd Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 22 Dec 2016 14:02:27 +0400 Subject: [PATCH 19/26] MDEV-11227 - mysqlimport -l doesn't issue UNLOCK TABLES Merged fix for innodb_mysql from 5.7. --- mysql-test/include/mix1.inc | 4 +++- mysql-test/suite/innodb/r/innodb_mysql.result | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 7eae4235baa..5e6797e69ff 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -654,9 +654,11 @@ INSERT INTO t2 VALUES (1); CONNECTION c2; SET AUTOCOMMIT=0; +SET @old_lock_wait_timeout= @@lock_wait_timeout; +SET lock_wait_timeout= 1; --error ER_LOCK_WAIT_TIMEOUT LOCK TABLES t1 READ, t2 READ; - +SET @@lock_wait_timeout= @old_lock_wait_timeout; CONNECTION c1; COMMIT; INSERT INTO t1 VALUES (1); diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index a057719d18b..28f68eaa04b 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -678,8 +678,11 @@ SET AUTOCOMMIT=0; INSERT INTO t2 VALUES (1); connection c2; SET AUTOCOMMIT=0; +SET @old_lock_wait_timeout= @@lock_wait_timeout; +SET lock_wait_timeout= 1; LOCK TABLES t1 READ, t2 READ; ERROR HY000: Lock wait timeout exceeded; try restarting transaction +SET @@lock_wait_timeout= @old_lock_wait_timeout; connection c1; COMMIT; INSERT INTO t1 VALUES (1); From d6a1f9f10f21bfb5198b81c40e09755651013e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Dec 2016 10:23:42 +0200 Subject: [PATCH 20/26] MDEV-11630 Call mutex_free() before freeing the mutex list fil_space_crypt_cleanup(): Call mutex_free() to pair with fil_space_crypt_init(). fil_space_destroy_crypt_data(): Call mutex_free() to pair with fil_space_create_crypt_data() and fil_space_read_crypt_data(). fil_crypt_threads_cleanup(): Call mutex_free() to pair with fil_crypt_threads_init(). fil_space_free_low(): Invoke fil_space_destroy_crypt_data(). fil_close(): Invoke fil_space_crypt_cleanup(), just like fil_init() invoked fil_space_crypt_init(). Datafile::shutdown(): Set m_crypt_info=NULL without dereferencing the pointer. The object will be freed along with the fil_space_t in fil_space_free_low(). Remove some unnecessary conditions (ut_free(NULL) is OK). srv_shutdown_all_bg_threads(): Shut down the encryption threads by calling fil_crypt_threads_end(). srv_shutdown_bg_undo_sources(): Do not prematurely call fil_crypt_threads_end(). Many pages can still be written by change buffer merge, rollback of incomplete transactions, and purge, especially in slow shutdown (innodb_fast_shutdown=0). innobase_shutdown_for_mysql(): Call fil_crypt_threads_cleanup() also when innodb_read_only=1, because the threads will have been created also in that case. sync_check_close(): Re-enable the invocation of sync_latch_meta_destroy() to free the mutex list. --- storage/innobase/fil/fil0crypt.cc | 13 +++++-------- storage/innobase/fil/fil0fil.cc | 3 +++ storage/innobase/fsp/fsp0file.cc | 25 ++++++++++--------------- storage/innobase/include/fil0fil.h | 2 -- storage/innobase/srv/srv0start.cc | 8 ++------ storage/innobase/sync/sync0debug.cc | 4 ---- 6 files changed, 20 insertions(+), 35 deletions(-) diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 9062bf1586b..75efcdfdab0 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -138,6 +138,8 @@ fil_space_crypt_cleanup() /*=====================*/ { os_event_destroy(fil_crypt_throttle_sleep_event); + mutex_free(&fil_crypt_key_mutex); + mutex_free(&crypt_stat_mutex); } /****************************************************************** @@ -335,15 +337,9 @@ fil_space_destroy_crypt_data( and make it unawailable, this does not fully avoid the race between drop table and crypt thread */ mutex_enter(&fil_crypt_threads_mutex); - mutex_enter(&(*crypt_data)->mutex); - (*crypt_data)->inited = false; - mutex_exit(&(*crypt_data)->mutex); - /* JAN: TODO: - mutex_free(& (*crypt_data)->mutex); - memset(*crypt_data, 0, sizeof(fil_space_crypt_t)); + mutex_free(&(*crypt_data)->mutex); free(*crypt_data); - (*crypt_data) = NULL; - */ + *crypt_data = NULL; mutex_exit(&fil_crypt_threads_mutex); } } @@ -2468,6 +2464,7 @@ fil_crypt_threads_cleanup() { os_event_destroy(fil_crypt_event); os_event_destroy(fil_crypt_threads_event); + mutex_free(&fil_crypt_threads_mutex); fil_crypt_threads_inited = false; } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 26e0593b266..3df1e5e0fef 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1199,6 +1199,7 @@ fil_space_free_low( ut_ad(space->size == 0); rw_lock_free(&space->latch); + fil_space_destroy_crypt_data(&space->crypt_data); ut_free(space->name); ut_free(space); @@ -6226,6 +6227,8 @@ fil_close(void) ut_free(fil_system); fil_system = NULL; + + fil_space_crypt_cleanup(); } } diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc index 501a8e58622..3c12bde0acf 100644 --- a/storage/innobase/fsp/fsp0file.cc +++ b/storage/innobase/fsp/fsp0file.cc @@ -63,22 +63,17 @@ Datafile::shutdown() ut_free(m_name); m_name = NULL; + ut_free(m_encryption_key); + m_encryption_key = NULL; + + /* The fil_space_t::crypt_data was freed in + fil_space_free_low(). Invalidate our redundant pointer. */ + m_crypt_info = NULL; + + ut_free(m_encryption_iv); + m_encryption_iv = NULL; + free_filepath(); - - if (m_encryption_key != NULL) { - ut_free(m_encryption_key); - m_encryption_key = NULL; - } - - if (m_crypt_info) { - fil_space_destroy_crypt_data(&m_crypt_info); - } - - if (m_encryption_iv != NULL) { - ut_free(m_encryption_iv); - m_encryption_iv = NULL; - } - free_first_page(); } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index bc1121d1530..bd31ed58283 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -97,8 +97,6 @@ extern const char general_space_name[]; struct trx_t; class page_id_t; class truncate_t; -struct fil_node_t; -struct fil_space_t; struct btr_create_t; /* structure containing encryption specification */ diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 49c9feb6ac5..3eeb698d5f6 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1226,6 +1226,7 @@ srv_shutdown_all_bg_threads() ulint i; srv_shutdown_state = SRV_SHUTDOWN_EXIT_THREADS; + fil_crypt_threads_end(); if (!srv_start_state) { return; @@ -2769,9 +2770,6 @@ srv_shutdown_bg_undo_sources(void) { fts_optimize_shutdown(); dict_stats_shutdown(); - - /* Shutdown key rotation threads */ - fil_crypt_threads_end(); } @@ -2839,9 +2837,7 @@ innobase_shutdown_for_mysql(void) } } - if (!srv_read_only_mode) { - fil_crypt_threads_cleanup(); - } + fil_crypt_threads_cleanup(); /* Cleanup data for datafile scrubbing */ btr_scrub_cleanup(); diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc index 072555750dc..c9b37cbbb09 100644 --- a/storage/innobase/sync/sync0debug.cc +++ b/storage/innobase/sync/sync0debug.cc @@ -1582,7 +1582,6 @@ sync_latch_meta_init() } /** Destroy the latch meta data */ -#ifdef JAN_DISABLED_FOR_NOW_AS_THIS_CAUSES_CRASH static void sync_latch_meta_destroy() @@ -1596,7 +1595,6 @@ sync_latch_meta_destroy() latch_meta.clear(); } -#endif /** Track mutex file creation name and line number. This is to avoid storing { const char* name; uint16_t line; } in every instance. This results in the @@ -1810,8 +1808,6 @@ sync_check_close() create_tracker = NULL; -#ifdef JAN_DISABLED_FOR_NOW_AS_THIS_CAUSES_CRASH sync_latch_meta_destroy(); -#endif } From 08f79bdeda89f5b8e09d99e7dc07fc9c4f8ef14f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 22 Dec 2016 16:48:49 +0200 Subject: [PATCH 21/26] MDEV-11635 innodb.innodb_mysql test hangs Copy and adapt the test from MySQL 5.7.17. --- mysql-test/include/mix1.inc | 114 ++++++++++++++++-- mysql-test/suite/innodb/r/innodb_mysql.result | 18 +-- mysql-test/suite/innodb/t/innodb_mysql.test | 14 ++- 3 files changed, 121 insertions(+), 25 deletions(-) diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc index 5e6797e69ff..ea7bc3f5327 100644 --- a/mysql-test/include/mix1.inc +++ b/mysql-test/include/mix1.inc @@ -236,6 +236,15 @@ create table t2i (a int); insert into t2m values (5); insert into t2i values (5); +-- disable_query_log +-- disable_result_log +analyze table t1i; +analyze table t1m; +analyze table t2i; +analyze table t2m; +-- enable_result_log +-- enable_query_log + # test with $engine_type select min(a) from t1i; select min(7) from t1i; @@ -411,6 +420,13 @@ if ($test_foreign_keys) INSERT INTO t1 VALUES (1,'A1'),(2,'A2'),(3,'B'); INSERT INTO t2 VALUES (1,1),(2,2),(3,2),(4,3),(5,3); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +ANALYZE TABLE t2; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT COUNT(*) FROM t2 LEFT JOIN t1 ON t2.fkey = t1.id WHERE t1.name LIKE 'A%'; @@ -572,12 +588,22 @@ OPTIMIZE TABLE t1; SELECT COUNT(*) FROM t1; SELECT COUNT(*) FROM t1 WHERE acct_id=785; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT COUNT(*) FROM t1 WHERE stat_id IN (1,3) AND acct_id=785; INSERT INTO t2 SELECT * FROM t1; OPTIMIZE TABLE t2; -EXPLAIN SELECT COUNT(*) FROM t2 WHERE stat_id IN (1,3) AND acct_id=785; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t2; +-- enable_result_log +-- enable_query_log DROP TABLE t1,t2; @@ -704,6 +730,13 @@ INSERT INTO t1(b,c) SELECT b,c FROM t2; UPDATE t2 SET c='2007-01-03'; INSERT INTO t1(b,c) SELECT b,c FROM t2; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +ANALYZE TABLE t2; +-- enable_result_log +-- enable_query_log + set @@sort_buffer_size=8192; SELECT COUNT(*) FROM t1; @@ -793,6 +826,12 @@ INSERT INTO t1 SELECT a + 16, MOD(a + 16, 20), 1 FROM t1; INSERT INTO t1 SELECT a + 32, MOD(a + 32, 20), 1 FROM t1; INSERT INTO t1 SELECT a + 64, MOD(a + 64, 20), 1 FROM t1; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT b, SUM(c) FROM t1 GROUP BY b; EXPLAIN SELECT SQL_BIG_RESULT b, SUM(c) FROM t1 GROUP BY b; DROP TABLE t1; @@ -855,6 +894,11 @@ CREATE TABLE t1 (a int, b int, PRIMARY KEY (a), KEY bkey (b)) ENGINE=InnoDB; INSERT INTO t1 VALUES (1,2),(3,2),(2,2),(4,2),(5,2),(6,2),(7,2),(8,2); INSERT INTO t1 SELECT a + 8, 2 FROM t1; INSERT INTO t1 SELECT a + 16, 1 FROM t1; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log query_vertical EXPLAIN SELECT * FROM t1 WHERE b=2 ORDER BY a; SELECT * FROM t1 WHERE b=2 ORDER BY a; query_vertical EXPLAIN SELECT * FROM t1 WHERE b BETWEEN 1 AND 2 ORDER BY a; @@ -868,6 +912,12 @@ INSERT INTO t2 VALUES (1,1,1),(3,1,1),(2,1,1),(4,1,1); INSERT INTO t2 SELECT a + 4, 1, 1 FROM t2; INSERT INTO t2 SELECT a + 8, 1, 1 FROM t2; +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t2; +-- enable_result_log +-- enable_query_log + query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 ORDER BY a; SELECT * FROM t2 WHERE b=1 ORDER BY a; query_vertical EXPLAIN SELECT * FROM t2 WHERE b=1 AND c=1 ORDER BY a; @@ -959,7 +1009,7 @@ SELECT * FROM t1 WHERE b=20 FOR UPDATE; --connect (conn2, localhost, root,,test) -# This statement gives a "failed: 1205: Lock wait timeout exceeded; try +# This statement gives a "failed: 1205: Lock wait timeout exceeded; try # restarting transaction" message when the bug is present. START TRANSACTION; SELECT * FROM t1 WHERE b=10 ORDER BY A FOR UPDATE; @@ -984,6 +1034,12 @@ CREATE TABLE t1( INSERT INTO t1 VALUES (1,1,1,50), (1,2,3,40), (2,1,3,4); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d; SELECT c,b,d FROM t1 GROUP BY c,b,d; EXPLAIN SELECT c,b,d FROM t1 GROUP BY c,b,d ORDER BY NULL; @@ -1004,6 +1060,12 @@ DROP TABLE t1; CREATE TABLE t1 (a INT, b INT, PRIMARY KEY (a), INDEX b (b)) ENGINE=InnoDB; INSERT INTO t1(a,b) VALUES (1,1), (2,2), (3,2); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + #The two queries below should produce different results, but they don't. query_vertical EXPLAIN SELECT * FROM t1 WHERE b=2 ORDER BY a ASC; SELECT * FROM t1 WHERE b=2 ORDER BY a ASC; @@ -1087,6 +1149,12 @@ CREATE TABLE t1 (id int, type char(6), d int, INDEX idx(id,d)) ENGINE=InnoDB; INSERT INTO t1 VALUES (191, 'member', 1), (NULL, 'member', 3), (NULL, 'member', 4), (201, 'member', 2); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; SELECT * FROM t1 WHERE id=191 OR id IS NULL ORDER BY d; @@ -1115,12 +1183,13 @@ CREATE TABLE t1 (a int, b int, c int, PRIMARY KEY (a), KEY t1_b (b)) INSERT INTO t1 (a,b,c) VALUES (1,1,1), (2,1,1), (3,1,1), (4,1,1); INSERT INTO t1 (a,b,c) SELECT a+4,b,c FROM t1; -# should be range access +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log -# -# InnoDB uses "where", while xtradb "index condition" -# ---replace_regex /where/index condition/ +# should be range access EXPLAIN SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; # should produce '8 7 6 5 4' for a @@ -1514,6 +1583,12 @@ INSERT INTO t1 VALUES (4,1,3,'pk',NULL),(5,1,3,'c2',NULL), (2,1,4,'c_extra',NULL),(3,1,4,'c_extra',NULL); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + EXPLAIN SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; SELECT * FROM t1 FORCE INDEX (PRIMARY) WHERE tid = 1 AND vid = 3 ORDER BY idx DESC; @@ -1531,6 +1606,12 @@ CREATE TABLE t1 (c1 INT, c2 INT, c3 INT, KEY (c3), KEY (c2, c3)) ENGINE=$engine_type; INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; EXPLAIN @@ -1544,6 +1625,12 @@ CREATE TABLE t1 (c1 REAL, c2 REAL, c3 REAL, KEY (c3), KEY (c2, c3)) ENGINE=$engine_type; INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; EXPLAIN @@ -1558,6 +1645,12 @@ CREATE TABLE t1 (c1 DECIMAL(12,2), c2 DECIMAL(12,2), c3 DECIMAL(12,2), ENGINE=$engine_type; INSERT INTO t1 VALUES (1,1,1), (1,1,1), (1,1,2), (1,1,1), (1,1,2); +-- disable_query_log +-- disable_result_log +ANALYZE TABLE t1; +-- enable_result_log +-- enable_query_log + SELECT 1 FROM (SELECT COUNT(DISTINCT c1) FROM t1 WHERE c2 IN (1, 1) AND c3 = 2 GROUP BY c2) x; EXPLAIN @@ -1585,6 +1678,13 @@ CREATE TABLE t2 ( insert into t1 values (0),(1),(2),(3),(4); insert into t2 select A.a + 10 *B.a, 1, 'filler' from t1 A, t1 B; +-- disable_query_log +-- disable_result_log +analyze table t1; +analyze table t2; +-- enable_result_log +-- enable_query_log + explain select * from t1, t2 where t2.a=t1.a and t2.b + 1; select * from t1, t2 where t2.a=t1.a and t2.b + 1; diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result index 28f68eaa04b..72e8c30f96f 100644 --- a/mysql-test/suite/innodb/r/innodb_mysql.result +++ b/mysql-test/suite/innodb/r/innodb_mysql.result @@ -1,9 +1,3 @@ -set global innodb_support_xa=default; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. -set session innodb_support_xa=default; -Warnings: -Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. SET SESSION DEFAULT_STORAGE_ENGINE = InnoDB; drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4; drop procedure if exists p1; @@ -614,9 +608,6 @@ OPTIMIZE TABLE t2; Table Op Msg_type Msg_text test.t2 optimize note Table does not support optimize, doing recreate + analyze instead test.t2 optimize status OK -EXPLAIN SELECT COUNT(*) FROM t2 WHERE stat_id IN (1,3) AND acct_id=785; -id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t2 range idx1,idx2 idx1 9 NULL 2 Using where; Using index DROP TABLE t1,t2; create table t1(a int) engine=innodb; alter table t1 comment '123'; @@ -1433,7 +1424,7 @@ INSERT INTO t1 (a,b,c) VALUES (1,1,1), (2,1,1), (3,1,1), (4,1,1); INSERT INTO t1 (a,b,c) SELECT a+4,b,c FROM t1; EXPLAIN SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range t1_b t1_b 5 NULL 8 Using index condition +1 SIMPLE t1 range t1_b t1_b 5 NULL 8 Using where SELECT a, b, c FROM t1 WHERE b = 1 ORDER BY a DESC LIMIT 5; a b c 8 1 1 @@ -2278,7 +2269,7 @@ INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6); INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); INSERT INTO t3 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105), (6, 106); INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); -UPDATE t1, t2 SET t1.a = t1.a + 100, t2.b = t1.a + 10 +UPDATE t2 straight_join t1 SET t1.a = t1.a + 100, t2.b = t1.a + 10 WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b; SELECT * FROM t2; a b @@ -2287,7 +2278,7 @@ a b 3 13 4 14 5 5 -UPDATE t3, t4 SET t3.a = t3.a + 100, t4.b = t3.a + 10 +UPDATE t4 straight_join t3 SET t3.a = t3.a + 100, t4.b = t3.a + 10 WHERE t3.a BETWEEN 2 AND 4 AND t4.a = t3.b - 100; SELECT * FROM t4; a b @@ -2338,6 +2329,9 @@ INSERT INTO t1 SELECT c1+1000,c2+1000,c3+1000 from t1; INSERT INTO t1 SELECT c1+10000,c2+10000,c3+10000 from t1; INSERT INTO t1 SELECT c1+100000,c2+100000,c3+100000 from t1; INSERT INTO t1 SELECT c1+1000000,c2+1000000,c3+1000000 from t1; +ANALYZE TABLE t1; +Table Op Msg_type Msg_text +test.t1 analyze status OK SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3; c1 c2 c3 EXPLAIN SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3; diff --git a/mysql-test/suite/innodb/t/innodb_mysql.test b/mysql-test/suite/innodb/t/innodb_mysql.test index ee3975fd350..dc247a96468 100644 --- a/mysql-test/suite/innodb/t/innodb_mysql.test +++ b/mysql-test/suite/innodb/t/innodb_mysql.test @@ -13,10 +13,8 @@ -- source include/have_innodb.inc let $engine_type= InnoDB; let $other_engine_type= MEMORY; -# InnoDB does support FOREIGN KEYFOREIGN KEYs +# InnoDB does support FOREIGN KEYs let $test_foreign_keys= 1; -set global innodb_support_xa=default; -set session innodb_support_xa=default; --source include/mix1.inc --disable_warnings @@ -359,12 +357,16 @@ INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); INSERT INTO t3 VALUES (1, 101), (2, 102), (3, 103), (4, 104), (5, 105), (6, 106); INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3), (4, 4), (5, 5); -UPDATE t1, t2 SET t1.a = t1.a + 100, t2.b = t1.a + 10 +# Because t1.a changes and t2.b changes based on t1.a, the result +# depends on join order, so STRAIGHT_JOIN is used to have it repeatable. +UPDATE t2 straight_join t1 SET t1.a = t1.a + 100, t2.b = t1.a + 10 WHERE t1.a BETWEEN 2 AND 4 AND t2.a = t1.b; --sorted_result SELECT * FROM t2; -UPDATE t3, t4 SET t3.a = t3.a + 100, t4.b = t3.a + 10 +# Because t1.a changes and t2.b changes based on t1.a, the result +# depends on join order, so STRAIGHT_JOIN is used to have it repeatable. +UPDATE t4 straight_join t3 SET t3.a = t3.a + 100, t4.b = t3.a + 10 WHERE t3.a BETWEEN 2 AND 4 AND t4.a = t3.b - 100; --sorted_result SELECT * FROM t4; @@ -420,7 +422,7 @@ INSERT INTO t1 SELECT c1+1000,c2+1000,c3+1000 from t1; INSERT INTO t1 SELECT c1+10000,c2+10000,c3+10000 from t1; INSERT INTO t1 SELECT c1+100000,c2+100000,c3+100000 from t1; INSERT INTO t1 SELECT c1+1000000,c2+1000000,c3+1000000 from t1; - +ANALYZE TABLE t1; # query and no rows will match the c1 condition, whereas all will match c3 SELECT * FROM t1 WHERE c1 = 99999999 AND c3 > 1 ORDER BY c3; From bbb3fb318ebeec4c5e5e932d9b20bd86def753e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 23 Dec 2016 09:19:39 +0200 Subject: [PATCH 22/26] Follow-up for MDEV-11630 Call mutex_free() before freeing the mutex list fil_tablespace_iterate(): Call fil_space_destroy_crypt_data() to invoke mutex_free() for the mutex_create() that was done in fil_space_read_crypt_data(). Also, remember to free iter.crypt_io_buffer. The failure to call mutex_free() would cause sync_latch_meta_destroy() to access freed memory on shutdown. This affected the IMPORT of encrypted tablespaces. --- storage/innobase/fil/fil0fil.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 3df1e5e0fef..ab7c6a87f5e 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -6685,18 +6685,18 @@ fil_tablespace_iterate( iter.io_buffer = static_cast( ut_align(io_buffer, UNIV_PAGE_SIZE)); - /** Add an exta buffer for encryption */ - void* crypt_io_buffer = NULL; - if (iter.crypt_data != NULL) { - crypt_io_buffer = ut_malloc_nokey( - iter.n_io_buffers * UNIV_PAGE_SIZE); - iter.crypt_io_buffer = static_cast( - crypt_io_buffer); - } + iter.crypt_io_buffer = iter.crypt_data + ? static_cast( + ut_malloc_nokey(iter.n_io_buffers + * UNIV_PAGE_SIZE)) + : NULL; err = fil_iterate(iter, block, callback); ut_free(io_buffer); + ut_free(iter.crypt_io_buffer); + + fil_space_destroy_crypt_data(&iter.crypt_data); } } From 4d10273b4fd4e4fa8c479bf23afdd0d01cb3b0b5 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sat, 24 Dec 2016 10:51:43 +0400 Subject: [PATCH 23/26] MDEV-11571 JSON_EXTRACT returns wrong results. Array counter didn't increment after an item was found. --- mysql-test/r/func_json.result | 3 +++ mysql-test/t/func_json.test | 1 + strings/json_lib.c | 5 +---- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index 460ff8fa1d2..cace2f985ac 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -209,6 +209,9 @@ json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]') select json_extract('1', '$'); json_extract('1', '$') 1 +select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]'); +json_extract('[10, 20, [30, 40], 1, 10]', '$[1]') +20 select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word'); json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word') {"a":1, "b":{"c":1, "k1":"word"}, "d":[1, 2]} diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 72b7b946536..7e10a4fb203 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -77,6 +77,7 @@ select json_extract(json_object('foo', 'foobar'),'$'); select json_extract('[10, 20, [30, 40]]', '$[2][*]'); select json_extract('[10, 20, [{"a":3}, 30, 40]]', '$[2][*]'); select json_extract('1', '$'); +select json_extract('[10, 20, [30, 40], 1, 10]', '$[1]'); select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.b.k1', 'word'); select json_insert('{"a":1, "b":{"c":1}, "d":[1, 2]}', '$.d[3]', 3); diff --git a/strings/json_lib.c b/strings/json_lib.c index a93200cd4dd..47a3e37fa4c 100644 --- a/strings/json_lib.c +++ b/strings/json_lib.c @@ -1270,7 +1270,7 @@ int json_find_path(json_engine_t *je, case JST_VALUE: DBUG_ASSERT(cur_step->type & JSON_PATH_ARRAY); if (cur_step->type & JSON_PATH_WILD || - cur_step->n_item == array_counters[cur_step - p->steps]) + cur_step->n_item == array_counters[cur_step - p->steps]++) { /* Array item matches. */ if (cur_step == p->last_step || @@ -1278,10 +1278,7 @@ int json_find_path(json_engine_t *je, goto exit; } else - { json_skip_array_item(je); - array_counters[cur_step - p->steps]++; - } break; case JST_OBJ_END: case JST_ARRAY_END: From 3a1772798def80e9ddb6233960341cda60a06801 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Sat, 24 Dec 2016 11:40:31 +0400 Subject: [PATCH 24/26] MDEV-11573 JSON_LENGTH returns incorrect results. Item_func_json_length fixed. --- mysql-test/r/func_json.result | 6 ++++ mysql-test/t/func_json.test | 2 ++ sql/item_jsonfunc.cc | 66 ++++++++++++++++++++++++++++++++--- sql/item_jsonfunc.h | 14 ++++---- 4 files changed, 77 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/func_json.result b/mysql-test/r/func_json.result index cace2f985ac..6c1987cc3e7 100644 --- a/mysql-test/r/func_json.result +++ b/mysql-test/r/func_json.result @@ -425,6 +425,12 @@ json_length('{}') select json_length('[1, 2, {"a": 3}]'); json_length('[1, 2, {"a": 3}]') 3 +select json_length('{"a": 1, "b": {"c": 30}}', '$.b'); +json_length('{"a": 1, "b": {"c": 30}}', '$.b') +1 +select json_length('{"a": 1, "b": {"c": 30}}'); +json_length('{"a": 1, "b": {"c": 30}}') +2 create table json (j INT); show create table json; Table Create Table diff --git a/mysql-test/t/func_json.test b/mysql-test/t/func_json.test index 7e10a4fb203..7ab136f177c 100644 --- a/mysql-test/t/func_json.test +++ b/mysql-test/t/func_json.test @@ -170,6 +170,8 @@ select json_depth('[10, {"a": 20}]'); select json_length(''); select json_length('{}'); select json_length('[1, 2, {"a": 3}]'); +select json_length('{"a": 1, "b": {"c": 30}}', '$.b'); +select json_length('{"a": 1, "b": {"c": 30}}'); create table json (j INT); show create table json; diff --git a/sql/item_jsonfunc.cc b/sql/item_jsonfunc.cc index 4d87aec669f..9b9490a0cbc 100644 --- a/sql/item_jsonfunc.cc +++ b/sql/item_jsonfunc.cc @@ -1599,29 +1599,85 @@ null_return: } +void Item_func_json_length::fix_length_and_dec() +{ + if (arg_count > 1) + path.set_constant_flag(args[1]->const_item()); +} + + longlong Item_func_json_length::val_int() { String *js= args[0]->val_str(&tmp_js); json_engine_t je; uint length= 0; + uint array_counters[JSON_DEPTH_LIMIT]; if ((null_value= args[0]->null_value)) return 0; - json_scan_start(&je, js->charset(),(const uchar *) js->ptr(), (const uchar *) js->ptr() + js->length()); - do + if (arg_count > 1) { - if (je.state == JST_VALUE) + /* Path specified - let's apply it. */ + if (!path.parsed) + { + String *s_p= args[1]->val_str(&tmp_path); + if (s_p && + json_path_setup(&path.p, s_p->charset(), (const uchar *) s_p->ptr(), + (const uchar *) s_p->ptr() + s_p->length())) + { + report_path_error(s_p, &path.p, 2); + goto null_return; + } + path.parsed= path.constant; + } + if (args[1]->null_value) + goto null_return; + + path.cur_step= path.p.steps; + if (json_find_path(&je, &path.p, &path.cur_step, array_counters)) + { + if (je.s.error) + goto err_return; + goto null_return; + } + } + + + if (json_read_value(&je)) + goto err_return; + + if (json_value_scalar(&je)) + return 1; + + while (json_scan_next(&je) == 0 && + je.state != JST_OBJ_END && je.state != JST_ARRAY_END) + { + switch (je.state) + { + case JST_VALUE: + case JST_KEY: length++; - } while (json_scan_next(&je) == 0); + break; + case JST_OBJ_START: + case JST_ARRAY_START: + if (json_skip_level(&je)) + goto err_return; + break; + default: + break; + }; + } if (!je.s.error) - return length - 1; + return length; +err_return: report_json_error(js, &je, 0); +null_return: null_value= 1; return 0; } diff --git a/sql/item_jsonfunc.h b/sql/item_jsonfunc.h index e6f26d95b13..07741536f55 100644 --- a/sql/item_jsonfunc.h +++ b/sql/item_jsonfunc.h @@ -67,8 +67,8 @@ protected: String tmp_js, tmp_path; public: - Item_func_json_exists(THD *thd, Item *js, Item *path): - Item_int_func(thd, js, path) {} + Item_func_json_exists(THD *thd, Item *js, Item *i_path): + Item_int_func(thd, js, i_path) {} const char *func_name() const { return "json_exists"; } bool is_bool_type() { return true; } void fix_length_and_dec(); @@ -85,8 +85,8 @@ protected: String tmp_js, tmp_path; public: - Item_func_json_value(THD *thd, Item *js, Item *path): - Item_str_func(thd, js, path) {} + Item_func_json_value(THD *thd, Item *js, Item *i_path): + Item_str_func(thd, js, i_path) {} const char *func_name() const { return "json_value"; } void fix_length_and_dec(); String *val_str(String *); @@ -99,8 +99,8 @@ public: class Item_func_json_query: public Item_func_json_value { public: - Item_func_json_query(THD *thd, Item *js, Item *path): - Item_func_json_value(thd, js, path) {} + Item_func_json_query(THD *thd, Item *js, Item *i_path): + Item_func_json_value(thd, js, i_path) {} const char *func_name() const { return "json_query"; } bool check_and_get_value(json_engine_t *je, String *res, int *error); Item *get_copy(THD *thd, MEM_ROOT *mem_root) @@ -291,12 +291,14 @@ public: class Item_func_json_length: public Item_int_func { protected: + json_path_with_flags path; String tmp_js; String tmp_path; public: Item_func_json_length(THD *thd, List &list): Item_int_func(thd, list) {} const char *func_name() const { return "json_length"; } + void fix_length_and_dec(); longlong val_int(); Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } From f5c4f1eb384a4e120fe12a3c9b879ec276b7c28b Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Sat, 24 Dec 2016 09:54:23 -0500 Subject: [PATCH 25/26] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 73750e953b1..bfea448d129 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=2 -MYSQL_VERSION_PATCH=3 +MYSQL_VERSION_PATCH=4 From 143d512a2202dbd320ec9b9e37dafc36fc2b36d8 Mon Sep 17 00:00:00 2001 From: Nirbhay Choubey Date: Sat, 24 Dec 2016 11:31:04 -0500 Subject: [PATCH 26/26] MDEV-11035: Re-enable galera_var_innodb_disallow_writes test --- mysql-test/suite/galera/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 934ac121e6c..82e4ef06784 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -30,7 +30,6 @@ galera_gcs_fragment : Incorrect arguments to SET galera_flush_local : Fails sporadically galera_binlog_stmt_autoinc : TODO: investigate galera_concurrent_ctas : Test times out, investigate -galera_var_innodb_disallow_writes : MDEV-11035 MW-286 : TODO: investigate galera_sst_xtrabackup-v2-options : TODO: Fix test case galera_sst_xtrabackup-v2 : MDEV-11208