From 9de7386f6f029985e65e02a1d98240f6808020aa Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 31 Mar 2017 16:01:37 +0000 Subject: [PATCH 1/6] AWS KMS plugin : Fix building in case AWS C++ SDK was preinstalled into non-standard compiler/linker path (e.g vcpkg on Windows). Also fix linking with static preinstalled aws c++ sdk libraries --- plugin/aws_key_management/CMakeLists.txt | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 62d359569c6..31ddcd7e038 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -61,10 +61,11 @@ ENDIF() FIND_LIBRARY(AWS_CPP_SDK_CORE NAMES aws-cpp-sdk-core PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") FIND_LIBRARY(AWS_CPP_SDK_KMS NAMES aws-cpp-sdk-kms PATH_SUFFIXES "${SDK_INSTALL_BINARY_PREFIX}") SET(CMAKE_REQUIRED_FLAGS ${CXX11_FLAGS}) -CHECK_INCLUDE_FILE_CXX(aws/kms/KMSClient.h HAVE_AWS_HEADERS) +FIND_PATH(AWS_CPP_SDK_INCLUDE_DIR NAMES aws/kms/KMSClient.h) -IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND HAVE_AWS_HEADERS) - # AWS C++ SDK installed +IF(AWS_CPP_SDK_CORE AND AWS_CPP_SDK_KMS AND AWS_CPP_SDK_INCLUDE_DIR) + # AWS C++ SDK installed + INCLUDE_DIRECTORIES(${AWS_CPP_SDK_INCLUDE_DIR}) SET(AWS_SDK_LIBS ${AWS_CPP_SDK_CORE} ${AWS_CPP_SDK_KMS}) ELSE() # Build from source, using ExternalProject_Add @@ -95,7 +96,7 @@ ELSE() ENDIF() ENDIF() IF(MSVC) - SET(EXTRA_SDK_CMAKE_FLAGS -DCMAKE_CXX_FLAGS_DEBUGOPT="" -DCMAKE_EXE_LINKER_FLAGS_DEBUGOPT="" "-DCMAKE_CXX_FLAGS=/wd4530 /WX-") + SET(EXTRA_SDK_CMAKE_FLAGS -DCMAKE_CXX_FLAGS_DEBUGOPT="" -DCMAKE_EXE_LINKER_FLAGS_DEBUGOPT="" "-DCMAKE_CXX_FLAGS=/wd4530 /wd4577 /WX-") ENDIF() IF(CMAKE_CXX_COMPILER) SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) @@ -128,11 +129,6 @@ ELSE() ADD_DEPENDENCIES(${lib} aws_sdk_cpp) SET(loc "${CMAKE_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) - IF(WIN32) - SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "bcrypt;winhttp;wininet;userenv") - ELSE() - SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES "${SSL_LIBRARIES};${CURL_LIBRARIES};${UUID_LIBRARIES}") - ENDIF() ENDFOREACH() IF(CMAKE_SYSTEM_NAME MATCHES "Linux") @@ -145,4 +141,12 @@ ENDIF() ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") -TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS}) + +IF(WIN32) + SET(AWS_CPP_SDK_DEPENDENCIES bcrypt winhttp wininet userenv version) +ELSE() + SET(AWS_CPP_SDK_DEPENDENCIES ${SSL_LIBRARIES} ${CURL_LIBRARIES} ${UUID_LIBRARIES}) +ENDIF() + +TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES}) + From 31896aa6e21fd112b929350156b2995b4033506d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Mar 2017 15:25:35 +0200 Subject: [PATCH 2/6] put all aws_key_management plugin files into plugin/aws_key_management that is, download AWS SDK there, not into the builddir root. and .gitignore them all. --- .gitignore | 3 +++ plugin/aws_key_management/CMakeLists.txt | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 5d882f268ff..44832c99c6b 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,9 @@ pcre/pcre_chartables.c pcre/pcregrep pcre/pcretest pcre/test*grep +plugin/aws_key_management/aws-sdk-cpp +plugin/aws_key_management/aws_sdk_cpp +plugin/aws_key_management/aws_sdk_cpp-prefix scripts/comp_sql scripts/make_binary_distribution scripts/msql2mysql diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 31ddcd7e038..38e1b35d949 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -108,7 +108,7 @@ ELSE() GIT_REPOSITORY "https://github.com/awslabs/aws-sdk-cpp.git" GIT_TAG "1.0.8" UPDATE_COMMAND "" - SOURCE_DIR "${CMAKE_BINARY_DIR}/aws-sdk-cpp" + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/aws-sdk-cpp" CMAKE_ARGS -DBUILD_ONLY=kms -DBUILD_SHARED_LIBS=OFF @@ -118,7 +118,7 @@ ELSE() "-DCMAKE_CXX_FLAGS_RELEASE=${CMAKE_CXX_FLAGS_RELEASE} ${PIC_FLAG}" "-DCMAKE_CXX_FLAGS_MINSIZEREL=${CMAKE_CXX_FLAGS_MINSIZEREL} ${PIC_FLAG}" ${EXTRA_SDK_CMAKE_FLAGS} - -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/aws_sdk_cpp + -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp TEST_COMMAND "" ) SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) @@ -127,7 +127,7 @@ ELSE() FOREACH(lib ${AWS_SDK_LIBS}) ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) ADD_DEPENDENCIES(${lib} aws_sdk_cpp) - SET(loc "${CMAKE_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") + SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) ENDFOREACH() @@ -136,7 +136,7 @@ ELSE() SET(AWS_SDK_LIBS -Wl,--whole-archive ${AWS_SDK_LIBS} -Wl,--no-whole-archive) ENDIF() SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) - INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/aws_sdk_cpp/include) + INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/include) ENDIF() ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized From ac8218a0be280ac834904e5579554d9ea3f92aeb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Fri, 31 Mar 2017 17:40:42 +0200 Subject: [PATCH 3/6] fix Ninja builds for AWS SDK specify BUILD_BYPRODUCTS, ninja needs it --- plugin/aws_key_management/CMakeLists.txt | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 38e1b35d949..1ad96dd9f19 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -102,6 +102,17 @@ ELSE() SET(EXTRA_SDK_CMAKE_FLAGS ${EXTRA_SDK_CMAKE_FLAGS} -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}) ENDIF() + SET(byproducts ) + # We do not need to build the whole SDK , just 2 of its libs + set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms) + FOREACH(lib ${AWS_SDK_LIBS}) + ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) + ADD_DEPENDENCIES(${lib} aws_sdk_cpp) + SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") + SET(byproducts ${byproducts} BUILD_BYPRODUCTS ${loc}) + SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) + ENDFOREACH() + SET(AWS_SDK_PATCH_COMMAND ) ExternalProject_Add( aws_sdk_cpp @@ -109,7 +120,8 @@ ELSE() GIT_TAG "1.0.8" UPDATE_COMMAND "" SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/aws-sdk-cpp" - CMAKE_ARGS + ${byproducts} + CMAKE_ARGS -DBUILD_ONLY=kms -DBUILD_SHARED_LIBS=OFF -DFORCE_SHARED_CRT=OFF @@ -122,14 +134,6 @@ ELSE() TEST_COMMAND "" ) SET_TARGET_PROPERTIES(aws_sdk_cpp PROPERTIES EXCLUDE_FROM_ALL TRUE) - # We do not need to build the whole SDK , just 2 of its libs - set(AWS_SDK_LIBS aws-cpp-sdk-core aws-cpp-sdk-kms) - FOREACH(lib ${AWS_SDK_LIBS}) - ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) - ADD_DEPENDENCIES(${lib} aws_sdk_cpp) - SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") - SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) - ENDFOREACH() IF(CMAKE_SYSTEM_NAME MATCHES "Linux") # Need whole-archive , otherwise static libraries are not linked @@ -149,4 +153,3 @@ ELSE() ENDIF() TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES}) - From 9505c9683930290c1e028043940ae8512a6ca040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 3 Apr 2017 19:36:54 +0300 Subject: [PATCH 4/6] MDEV-12428 SIGSEGV in buf_page_decrypt_after_read() during DDL Also, some MDEV-11738/MDEV-11581 post-push fixes. In MariaDB 10.1, there is no fil_space_t::is_being_truncated field, and the predicates fil_space_t::stop_new_ops and fil_space_t::is_stopping() are interchangeable. I requested the fil_space_t::is_stopping() to be added in the review, but some added checks for fil_space_t::stop_new_ops were not replaced with calls to fil_space_t::is_stopping(). buf_page_decrypt_after_read(): In this low-level I/O operation, we must look up the tablespace if it exists, even though future I/O operations have been blocked on it due to a pending DDL operation, such as DROP TABLE or TRUNCATE TABLE or other table-rebuilding operations (ALTER, OPTIMIZE). Pass a parameter to fil_space_acquire_low() telling that we are performing a low-level I/O operation and the fil_space_t::is_stopping() status should be ignored. --- storage/innobase/btr/btr0scrub.cc | 35 +++++++++----------- storage/innobase/buf/buf0buf.cc | 9 +++--- storage/innobase/fil/fil0fil.cc | 52 ++++++++++++++---------------- storage/innobase/include/fil0fil.h | 17 +++++----- storage/xtradb/btr/btr0scrub.cc | 35 +++++++++----------- storage/xtradb/buf/buf0buf.cc | 10 +++--- storage/xtradb/fil/fil0fil.cc | 52 ++++++++++++++---------------- storage/xtradb/include/fil0fil.h | 17 +++++----- 8 files changed, 108 insertions(+), 119 deletions(-) diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc index 560d2ece6c0..e9434c9f778 100644 --- a/storage/innobase/btr/btr0scrub.cc +++ b/storage/innobase/btr/btr0scrub.cc @@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table, * if we don't lock to close a table, we check if space * is closing, and then instead give up */ - if (lock_to_close_table == false) { - fil_space_t* space = fil_space_acquire(space_id); - if (!space || space->stop_new_ops) { - if (space) { - fil_space_release(space); - } + if (lock_to_close_table) { + } else if (fil_space_t* space = fil_space_acquire(space_id)) { + bool stopping = space->is_stopping(); + fil_space_release(space); + if (stopping) { return false; } - fil_space_release(space); + } else { + return false; } os_thread_sleep(250000); @@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread( return; } - fil_space_t* space = fil_space_acquire(scrub_data->space); - - /* If tablespace is not marked as stopping perform - the actual close. */ - if (space && !space->is_stopping()) { - mutex_enter(&dict_sys->mutex); - /* perform the actual closing */ - btr_scrub_table_close(scrub_data->current_table); - mutex_exit(&dict_sys->mutex); - } - - if (space) { + if (fil_space_t* space = fil_space_acquire(scrub_data->space)) { + /* If tablespace is not marked as stopping perform + the actual close. */ + if (!space->is_stopping()) { + mutex_enter(&dict_sys->mutex); + /* perform the actual closing */ + btr_scrub_table_close(scrub_data->current_table); + mutex_exit(&dict_sys->mutex); + } fil_space_release(space); } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index c7e2183fa7b..589fd734ba3 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -6250,13 +6250,12 @@ buf_page_decrypt_after_read( return (true); } - fil_space_t* space = fil_space_acquire(bpage->space); - fil_space_crypt_t* crypt_data = space->crypt_data; + fil_space_t* space = fil_space_acquire(bpage->space, true); /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true also for pages first compressed and then encrypted. */ - if (!crypt_data) { + if (!space || !space->crypt_data) { key_version = 0; } @@ -6340,6 +6339,8 @@ buf_page_decrypt_after_read( } } - fil_space_release(space); + if (space != NULL) { + fil_space_release(space); + } return (success); } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 627a63aaae0..6fec41839ee 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -6325,16 +6325,12 @@ fil_flush( { mutex_enter(&fil_system->mutex); - fil_space_t* space = fil_space_get_by_id(space_id); - - if (!space || space->stop_new_ops) { - mutex_exit(&fil_system->mutex); - - return; + if (fil_space_t* space = fil_space_get_by_id(space_id)) { + if (!space->is_stopping()) { + fil_flush_low(space); + } } - fil_flush_low(space); - mutex_exit(&fil_system->mutex); } @@ -6374,8 +6370,7 @@ fil_flush_file_spaces( space; space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { - if (space->purpose == purpose && !space->stop_new_ops) { - + if (space->purpose == purpose && !space->is_stopping()) { space_ids[n_space_ids++] = space->id; } } @@ -7276,12 +7271,13 @@ Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID @param[in] silent whether to silently ignore missing tablespaces -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ inline fil_space_t* -fil_space_acquire_low( - ulint id, - bool silent) +fil_space_acquire_low(ulint id, bool silent, bool for_io = false) { fil_space_t* space; @@ -7294,7 +7290,7 @@ fil_space_acquire_low( ib_logf(IB_LOG_LEVEL_WARN, "Trying to access missing" " tablespace " ULINTPF ".", id); } - } else if (space->stop_new_ops) { + } else if (!for_io && space->is_stopping()) { space = NULL; } else { space->n_pending_ops++; @@ -7309,22 +7305,24 @@ fil_space_acquire_low( Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ fil_space_t* -fil_space_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io) { - return(fil_space_acquire_low(id, false)); + return(fil_space_acquire_low(id, false, for_io)); } /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@return the tablespace +@retval NULL if missing or being deleted */ fil_space_t* -fil_space_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) { return(fil_space_acquire_low(id, true)); } @@ -7332,8 +7330,7 @@ fil_space_acquire_silent( /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space) +fil_space_release(fil_space_t* space) { mutex_enter(&fil_system->mutex); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); @@ -7351,8 +7348,7 @@ If NULL, use the first fil_space_t on fil_system->space_list. @return pointer to the next fil_space_t. @retval NULL if this was the last*/ fil_space_t* -fil_space_next( - fil_space_t* prev_space) +fil_space_next(fil_space_t* prev_space) { fil_space_t* space=prev_space; @@ -7375,8 +7371,8 @@ fil_space_next( fil_ibd_create(), or dropped, or !tablespace. */ while (space != NULL && (UT_LIST_GET_LEN(space->chain) == 0 - || space->stop_new_ops - || space->purpose != FIL_TABLESPACE)) { + || space->is_stopping() + || space->purpose != FIL_TABLESPACE)) { space = UT_LIST_GET_NEXT(space_list, space); } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index b4ee931fdbe..3d7ae49f8ae 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -645,27 +645,28 @@ fil_write_flushed_lsn_to_data_files( Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ fil_space_t* -fil_space_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io = false) MY_ATTRIBUTE((warn_unused_result)); /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@return the tablespace +@retval NULL if missing or being deleted */ fil_space_t* -fil_space_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) MY_ATTRIBUTE((warn_unused_result)); /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space); +fil_space_release(fil_space_t* space); /** Return the next fil_space_t. Once started, the caller must keep calling this until it returns NULL. diff --git a/storage/xtradb/btr/btr0scrub.cc b/storage/xtradb/btr/btr0scrub.cc index 560d2ece6c0..e9434c9f778 100644 --- a/storage/xtradb/btr/btr0scrub.cc +++ b/storage/xtradb/btr/btr0scrub.cc @@ -129,15 +129,15 @@ btr_scrub_lock_dict_func(ulint space_id, bool lock_to_close_table, * if we don't lock to close a table, we check if space * is closing, and then instead give up */ - if (lock_to_close_table == false) { - fil_space_t* space = fil_space_acquire(space_id); - if (!space || space->stop_new_ops) { - if (space) { - fil_space_release(space); - } + if (lock_to_close_table) { + } else if (fil_space_t* space = fil_space_acquire(space_id)) { + bool stopping = space->is_stopping(); + fil_space_release(space); + if (stopping) { return false; } - fil_space_release(space); + } else { + return false; } os_thread_sleep(250000); @@ -197,18 +197,15 @@ btr_scrub_table_close_for_thread( return; } - fil_space_t* space = fil_space_acquire(scrub_data->space); - - /* If tablespace is not marked as stopping perform - the actual close. */ - if (space && !space->is_stopping()) { - mutex_enter(&dict_sys->mutex); - /* perform the actual closing */ - btr_scrub_table_close(scrub_data->current_table); - mutex_exit(&dict_sys->mutex); - } - - if (space) { + if (fil_space_t* space = fil_space_acquire(scrub_data->space)) { + /* If tablespace is not marked as stopping perform + the actual close. */ + if (!space->is_stopping()) { + mutex_enter(&dict_sys->mutex); + /* perform the actual closing */ + btr_scrub_table_close(scrub_data->current_table); + mutex_exit(&dict_sys->mutex); + } fil_space_release(space); } diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc index 5016445b8e7..5b448999cca 100644 --- a/storage/xtradb/buf/buf0buf.cc +++ b/storage/xtradb/buf/buf0buf.cc @@ -6410,14 +6410,12 @@ buf_page_decrypt_after_read( return (true); } - fil_space_t* space = fil_space_acquire(bpage->space); - - fil_space_crypt_t* crypt_data = space->crypt_data; + fil_space_t* space = fil_space_acquire(bpage->space, true); /* Page is encrypted if encryption information is found from tablespace and page contains used key_version. This is true also for pages first compressed and then encrypted. */ - if (!crypt_data) { + if (!space || !space->crypt_data) { key_version = 0; } @@ -6501,6 +6499,8 @@ buf_page_decrypt_after_read( } } - fil_space_release(space); + if (space != NULL) { + fil_space_release(space); + } return (success); } diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index a116bfad99d..e7244d719c8 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -6389,16 +6389,12 @@ fil_flush( { mutex_enter(&fil_system->mutex); - fil_space_t* space = fil_space_get_by_id(space_id); - - if (!space || space->stop_new_ops) { - mutex_exit(&fil_system->mutex); - - return; + if (fil_space_t* space = fil_space_get_by_id(space_id)) { + if (!space->is_stopping()) { + fil_flush_low(space); + } } - fil_flush_low(space); - mutex_exit(&fil_system->mutex); } @@ -6438,8 +6434,7 @@ fil_flush_file_spaces( space; space = UT_LIST_GET_NEXT(unflushed_spaces, space)) { - if (space->purpose == purpose && !space->stop_new_ops) { - + if (space->purpose == purpose && !space->is_stopping()) { space_ids[n_space_ids++] = space->id; } } @@ -7388,12 +7383,13 @@ Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID @param[in] silent whether to silently ignore missing tablespaces -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ inline fil_space_t* -fil_space_acquire_low( - ulint id, - bool silent) +fil_space_acquire_low(ulint id, bool silent, bool for_io = false) { fil_space_t* space; @@ -7407,7 +7403,7 @@ fil_space_acquire_low( " tablespace " ULINTPF ".", id); ut_error; } - } else if (space->stop_new_ops) { + } else if (!for_io && space->is_stopping()) { space = NULL; } else { space->n_pending_ops++; @@ -7422,22 +7418,24 @@ fil_space_acquire_low( Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ fil_space_t* -fil_space_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io) { - return(fil_space_acquire_low(id, false)); + return(fil_space_acquire_low(id, false, for_io)); } /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@return the tablespace +@retval NULL if missing or being deleted */ fil_space_t* -fil_space_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) { return(fil_space_acquire_low(id, true)); } @@ -7445,8 +7443,7 @@ fil_space_acquire_silent( /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space) +fil_space_release(fil_space_t* space) { mutex_enter(&fil_system->mutex); ut_ad(space->magic_n == FIL_SPACE_MAGIC_N); @@ -7464,8 +7461,7 @@ If NULL, use the first fil_space_t on fil_system->space_list. @return pointer to the next fil_space_t. @retval NULL if this was the last*/ fil_space_t* -fil_space_next( - fil_space_t* prev_space) +fil_space_next(fil_space_t* prev_space) { fil_space_t* space=prev_space; @@ -7488,8 +7484,8 @@ fil_space_next( fil_ibd_create(), or dropped, or !tablespace. */ while (space != NULL && (UT_LIST_GET_LEN(space->chain) == 0 - || space->stop_new_ops - || space->purpose != FIL_TABLESPACE)) { + || space->is_stopping() + || space->purpose != FIL_TABLESPACE)) { space = UT_LIST_GET_NEXT(space_list, space); } diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index b80df057351..698039afede 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -650,27 +650,28 @@ fil_write_flushed_lsn_to_data_files( Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@param[in] for_io whether to look up the tablespace while performing I/O + (possibly executing TRUNCATE) +@return the tablespace +@retval NULL if missing or being deleted or truncated */ fil_space_t* -fil_space_acquire( - ulint id) +fil_space_acquire(ulint id, bool for_io = false) MY_ATTRIBUTE((warn_unused_result)); /** Acquire a tablespace that may not exist. Used by background threads that do not necessarily hold proper locks for concurrency control. @param[in] id tablespace ID -@return the tablespace, or NULL if missing or being deleted */ +@return the tablespace +@retval NULL if missing or being deleted */ fil_space_t* -fil_space_acquire_silent( - ulint id) +fil_space_acquire_silent(ulint id) MY_ATTRIBUTE((warn_unused_result)); /** Release a tablespace acquired with fil_space_acquire(). @param[in,out] space tablespace to release */ void -fil_space_release( - fil_space_t* space); +fil_space_release(fil_space_t* space); /** Return the next fil_space_t. Once started, the caller must keep calling this until it returns NULL. From 00ab154d49853e20f48a516897e14bf67c58671e Mon Sep 17 00:00:00 2001 From: Igor Babaev Date: Mon, 3 Apr 2017 15:59:38 -0700 Subject: [PATCH 5/6] Fixed bug mdev-10454. The patch actually fixes the old defect of the optimizer that could not extract keys for range access from IN predicates with row arguments. This problem was resolved in the mysql-5.7 code. The patch supersedes what was done there: - it can build range access when not all components of the first row argument are refer to the columns of the table for which the range access is constructed. - it can use equality predicates to build range access to the table that is not referred to in this argument. --- mysql-test/r/range.result | 674 +++++++++++++++++++++++++++++ mysql-test/r/range_mrr_icp.result | 684 ++++++++++++++++++++++++++++++ mysql-test/t/range.test | 192 +++++++++ sql/item_cmpfunc.h | 3 + sql/item_row.h | 7 + sql/opt_range.cc | 217 +++++++++- sql/sql_select.cc | 58 ++- 7 files changed, 1822 insertions(+), 13 deletions(-) diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result index 5027fffe047..28f5cf635d0 100644 --- a/mysql-test/r/range.result +++ b/mysql-test/r/range.result @@ -2332,3 +2332,677 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# MDEV-10454: range access keys extracted +# from IN () +# +create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam; +insert into t1 values +(1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'), +(2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'), +(2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'), +(3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'), +(13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'), +(17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'), +(12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'), +(15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'), +(1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'), +(1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'), +(3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'), +(22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'), +(34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'), +(5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'), +(82,12,'wxa'), (85,15,'xd'); +# range access to t1 by 2-component keys for index idx +explain select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 10 NULL 7 Using where +explain format=json select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "10", + "used_key_parts": ["a", "b"], + "rows": 7, + "filtered": 100, + "attached_condition": "(t1.a,t1.b) in (((2,3)),((3,3)),((8,8)),((7,7)))" + } + } +} +select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +a b c +2 3 yy +2 3 ww +2 3 ya +2 3 wa +3 3 zzzz +3 3 zyxw +3 3 zzza +3 3 zyxa +7 7 xxxyy +7 7 xxxya +prepare stmt from "select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7))"; +execute stmt; +a b c +2 3 yy +2 3 ww +2 3 ya +2 3 wa +3 3 zzzz +3 3 zyxw +3 3 zzza +3 3 zyxa +7 7 xxxyy +7 7 xxxya +execute stmt; +a b c +2 3 yy +2 3 ww +2 3 ya +2 3 wa +3 3 zzzz +3 3 zyxw +3 3 zzza +3 3 zyxa +7 7 xxxyy +7 7 xxxya +deallocate prepare stmt; +# range access to t1 by 1-component keys for index idx +explain select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 5 Using where +explain format=json select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a,t1.b + t1.a) in (((4,9)),((8,8)),((7,7)))" + } + } +} +select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +a b c +4 5 ww +4 5 wa +# range access to t1 by 1-component keys for index idx +explain select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 5 Using where +explain format=json select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a,t1.b) in ((4,t1.a - 1),(8,t1.a + 8),(7,t1.a + 7))" + } + } +} +select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +a b c +4 3 zyx +4 3 zya +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_merge=off'; +create table t2( +d int, e int, key idx1(d), key idx2(e), f varchar(32) +) engine=myisam; +insert into t2 values +(9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'), +(6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'), +(9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'), +(6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja'); +# join order: (t2,t1) with ref access of t1 +# range access to t1 by keys for index idx1 +explain select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx1,idx2 idx1 5 NULL 3 Using index condition; Using where +1 SIMPLE t1 ref idx idx 5 test.t2.d 8 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx1", "idx2"], + "key": "idx1", + "key_length": "5", + "used_key_parts": ["d"], + "rows": 3, + "filtered": 100, + "index_condition": "t2.d is not null", + "attached_condition": "(t2.d,t2.e) in (((3,3)),((7,7)),((2,2)))" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 8, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +a b c d e f +2 1 w 2 2 da +2 1 wb 2 2 da +2 2 yyy 2 2 da +2 2 wxz 2 2 da +2 2 yya 2 2 da +2 2 wxa 2 2 da +2 3 yy 2 2 da +2 3 ww 2 2 da +2 3 ya 2 2 da +2 3 wa 2 2 da +3 2 uuuw 3 3 i +3 2 uuua 3 3 i +3 3 zzzz 3 3 i +3 3 zyxw 3 3 i +3 3 zzza 3 3 i +3 3 zyxa 3 3 i +insert into t2 values +(4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'), +(2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'), +(4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'), +(2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'), +(4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'), +(2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'), +(14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'), +(12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'), +(24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'), +(22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'), +(34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'), +(32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'), +(44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'), +(42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l'); +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 6 Using index condition +1 SIMPLE t2 ref idx1,idx2 idx1 5 test.t1.a 12 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 6, + "filtered": 100, + "index_condition": "t1.a is not null" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx1", "idx2"], + "key": "idx1", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 12, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +a b c d e f +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +prepare stmt from "select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1"; +execute stmt; +a b c d e f +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +execute stmt; +a b c d e f +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +deallocate prepare stmt; +insert into t1 select * from t1; +# join order: (t2,t1) with ref access of t1 +# range access to t2 by keys for index idx2 +explain select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx1,idx2 idx2 5 NULL 6 Using where +1 SIMPLE t1 ref idx idx 5 test.t2.d 11 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx1", "idx2"], + "key": "idx2", + "key_length": "5", + "used_key_parts": ["e"], + "rows": 6, + "filtered": 100, + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1 and t2.d is not null" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 11, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +alter table t2 drop index idx1, drop index idx2, add index idx3(d,e); +# join order: (t2,t1) with ref access of t1 +# range access to t2 by 2-component keys for index idx3 +explain select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx3 idx3 10 NULL 5 Using index condition; Using where +1 SIMPLE t1 ref idx idx 5 test.t2.d 11 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "10", + "used_key_parts": ["d", "e"], + "rows": 5, + "filtered": 100, + "index_condition": "t2.d is not null", + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 11, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 15 Using index condition +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 15, + "filtered": 100, + "index_condition": "t1.a is not null" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +a b c d e f +4 3 zyx 4 5 a +4 3 zya 4 5 a +4 3 zyx 4 5 a +4 3 zya 4 5 a +4 5 ww 4 5 a +4 5 wa 4 5 a +4 5 ww 4 5 a +4 5 wa 4 5 a +7 7 xxxyy 7 8 b +7 7 xxxya 7 8 b +7 7 xxxyy 7 8 b +7 7 xxxya 7 8 b +7 8 xxxxx 7 8 b +7 8 xxxxa 7 8 b +7 8 xxxxx 7 8 b +7 8 xxxxa 7 8 b +# join order: (t1,t2) with ref access of t2 +# no range access +explain select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL idx NULL NULL NULL 144 Using where +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "possible_keys": ["idx"], + "rows": 144, + "filtered": 100, + "attached_condition": "t1.a is not null" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 13, + "filtered": 100, + "index_condition": "t1.a is not null", + "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +prepare stmt from "select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1"; +execute stmt; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +execute stmt; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +deallocate prepare stmt; +create table t3 (id int primary key, v int) engine=myisam; +insert into t3 values +(3,2), (1,1), (4,12), (2,15); +# join order: (t3,t1,t2) with const t3 and ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "const", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["id"], + "ref": ["const"], + "rows": 1, + "filtered": 100 + }, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 13, + "filtered": 100, + "index_condition": "t1.a is not null", + "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "length(t2.f) = 1" + } + } +} +select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +a b c d e f id v +2 1 w 2 1 e 1 1 +2 1 w 2 2 k 1 1 +2 1 w 2 3 g 1 1 +2 1 w 2 1 e 1 1 +2 1 w 2 2 k 1 1 +2 1 w 2 3 g 1 1 +# IN predicate is always FALSE +explain select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((9,9),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +prepare stmt from "select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((9,9),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1"; +execute stmt; +a b c d e f id v +execute stmt; +a b c d e f id v +deallocate prepare stmt; +set optimizer_switch=@save_optimizer_switch; +drop table t1,t2,t3; +# +# End of 10.2 tests +# diff --git a/mysql-test/r/range_mrr_icp.result b/mysql-test/r/range_mrr_icp.result index 7d009070150..f2860aaab76 100644 --- a/mysql-test/r/range_mrr_icp.result +++ b/mysql-test/r/range_mrr_icp.result @@ -2334,4 +2334,688 @@ DROP TABLE t1; # # End of 10.1 tests # +# +# MDEV-10454: range access keys extracted +# from IN () +# +create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam; +insert into t1 values +(1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'), +(2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'), +(2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'), +(3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'), +(13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'), +(17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'), +(12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'), +(15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'), +(1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'), +(1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'), +(3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'), +(22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'), +(34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'), +(5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'), +(82,12,'wxa'), (85,15,'xd'); +# range access to t1 by 2-component keys for index idx +explain select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 10 NULL 7 Using where; Rowid-ordered scan +explain format=json select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "10", + "used_key_parts": ["a", "b"], + "rows": 7, + "filtered": 100, + "attached_condition": "(t1.a,t1.b) in (((2,3)),((3,3)),((8,8)),((7,7)))", + "mrr_type": "Rowid-ordered scan" + } + } +} +select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +a b c +3 3 zzzz +2 3 yy +2 3 ww +7 7 xxxyy +3 3 zyxw +3 3 zzza +2 3 ya +2 3 wa +7 7 xxxya +3 3 zyxa +prepare stmt from "select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7))"; +execute stmt; +a b c +3 3 zzzz +2 3 yy +2 3 ww +7 7 xxxyy +3 3 zyxw +3 3 zzza +2 3 ya +2 3 wa +7 7 xxxya +3 3 zyxa +execute stmt; +a b c +3 3 zzzz +2 3 yy +2 3 ww +7 7 xxxyy +3 3 zyxw +3 3 zzza +2 3 ya +2 3 wa +7 7 xxxya +3 3 zyxa +deallocate prepare stmt; +# range access to t1 by 1-component keys for index idx +explain select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 5 Using where; Rowid-ordered scan +explain format=json select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a,t1.b + t1.a) in (((4,9)),((8,8)),((7,7)))", + "mrr_type": "Rowid-ordered scan" + } + } +} +select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +a b c +4 5 ww +4 5 wa +# range access to t1 by 1-component keys for index idx +explain select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 5 Using where; Rowid-ordered scan +explain format=json select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 5, + "filtered": 100, + "attached_condition": "(t1.a,t1.b) in ((4,t1.a - 1),(8,t1.a + 8),(7,t1.a + 7))", + "mrr_type": "Rowid-ordered scan" + } + } +} +select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +a b c +4 3 zyx +4 3 zya +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_merge=off'; +create table t2( +d int, e int, key idx1(d), key idx2(e), f varchar(32) +) engine=myisam; +insert into t2 values +(9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'), +(6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'), +(9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'), +(6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja'); +# join order: (t2,t1) with ref access of t1 +# range access to t1 by keys for index idx1 +explain select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx1,idx2 idx1 5 NULL 3 Using index condition; Using where; Rowid-ordered scan +1 SIMPLE t1 ref idx idx 5 test.t2.d 8 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx1", "idx2"], + "key": "idx1", + "key_length": "5", + "used_key_parts": ["d"], + "rows": 3, + "filtered": 100, + "index_condition": "t2.d is not null", + "attached_condition": "(t2.d,t2.e) in (((3,3)),((7,7)),((2,2)))", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 8, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(2,2)); +a b c d e f +3 2 uuuw 3 3 i +3 2 uuua 3 3 i +3 3 zzzz 3 3 i +3 3 zyxw 3 3 i +3 3 zzza 3 3 i +3 3 zyxa 3 3 i +2 1 w 2 2 da +2 1 wb 2 2 da +2 2 yyy 2 2 da +2 2 wxz 2 2 da +2 2 yya 2 2 da +2 2 wxa 2 2 da +2 3 yy 2 2 da +2 3 ww 2 2 da +2 3 ya 2 2 da +2 3 wa 2 2 da +insert into t2 values +(4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'), +(2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'), +(4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'), +(2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'), +(4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'), +(2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'), +(14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'), +(12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'), +(24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'), +(22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'), +(34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'), +(32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'), +(44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'), +(42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l'); +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 6 Using index condition; Rowid-ordered scan +1 SIMPLE t2 ref idx1,idx2 idx1 5 test.t1.a 12 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 6, + "filtered": 100, + "index_condition": "t1.a is not null", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx1", "idx2"], + "key": "idx1", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 12, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in (((3,3)),((7,7)),((8,8))) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +a b c d e f +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +prepare stmt from "select * from t1,t2 +where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1"; +execute stmt; +a b c d e f +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +execute stmt; +a b c d e f +3 3 zzzz 3 3 i +3 3 zzzz 3 3 i +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +3 3 zyxw 3 3 i +3 3 zyxw 3 3 i +3 2 uuuw 3 3 i +3 2 uuuw 3 3 i +3 3 zzza 3 3 i +3 3 zzza 3 3 i +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +3 3 zyxa 3 3 i +3 3 zyxa 3 3 i +3 2 uuua 3 3 i +3 2 uuua 3 3 i +deallocate prepare stmt; +insert into t1 select * from t1; +# join order: (t2,t1) with ref access of t1 +# range access to t2 by keys for index idx2 +explain select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx1,idx2 idx2 5 NULL 6 Using where; Rowid-ordered scan +1 SIMPLE t1 ref idx idx 5 test.t2.d 11 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx1", "idx2"], + "key": "idx2", + "key_length": "5", + "used_key_parts": ["e"], + "rows": 6, + "filtered": 100, + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1 and t2.d is not null", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 11, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +alter table t2 drop index idx1, drop index idx2, add index idx3(d,e); +# join order: (t2,t1) with ref access of t1 +# range access to t2 by 2-component keys for index idx3 +explain select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 range idx3 idx3 10 NULL 5 Using index condition; Using where; Rowid-ordered scan +1 SIMPLE t1 ref idx idx 5 test.t2.d 11 +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t2", + "access_type": "range", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "10", + "used_key_parts": ["d", "e"], + "rows": 5, + "filtered": 100, + "index_condition": "t2.d is not null", + "attached_condition": "(t2.d,t2.e) in (((4,4)),((7,7)),((8,8))) and length(t2.f) = 1", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t1", + "access_type": "ref", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "ref": ["test.t2.d"], + "rows": 11, + "filtered": 100 + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 7 xxxyy 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +7 8 xxxxx 7 7 h +7 8 xxxxa 7 7 h +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 15 Using index condition; Rowid-ordered scan +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 15, + "filtered": 100, + "index_condition": "t1.a is not null", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in ((4,t1.a + 1),(7,t1.a + 1),(8,t1.a + 1)) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +a b c d e f +4 5 ww 4 5 a +7 8 xxxxx 7 8 b +4 3 zyx 4 5 a +7 7 xxxyy 7 8 b +4 5 wa 4 5 a +7 8 xxxxa 7 8 b +4 3 zya 4 5 a +7 7 xxxya 7 8 b +4 5 ww 4 5 a +7 8 xxxxx 7 8 b +4 3 zyx 4 5 a +7 7 xxxyy 7 8 b +4 5 wa 4 5 a +7 8 xxxxa 7 8 b +4 3 zya 4 5 a +7 7 xxxya 7 8 b +# join order: (t1,t2) with ref access of t2 +# no range access +explain select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL idx NULL NULL NULL 144 Using where +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "ALL", + "possible_keys": ["idx"], + "rows": 144, + "filtered": 100, + "attached_condition": "t1.a is not null" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "(t1.a,t2.e) in ((t2.e,t1.a + 1),((7,7)),((8,8))) and length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +a b c d e f +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +7 8 xxxxx 7 7 h +7 7 xxxyy 7 7 h +7 8 xxxxa 7 7 h +7 7 xxxya 7 7 h +# join order: (t1,t2) with ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where; Rowid-ordered scan +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 13, + "filtered": 100, + "index_condition": "t1.a is not null", + "attached_condition": "(t1.a,2) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "length(t2.f) = 1" + } + } +} +select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +prepare stmt from "select * from t1,t2 +where a = d and (a,2) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1"; +execute stmt; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +execute stmt; +a b c d e f +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +2 1 w 2 1 e +2 1 w 2 2 k +2 1 w 2 3 g +deallocate prepare stmt; +create table t3 (id int primary key, v int) engine=myisam; +insert into t3 values +(3,2), (1,1), (4,12), (2,15); +# join order: (t3,t1,t2) with const t3 and ref access of t2 +# range access to t1 by 1-component keys for index idx +explain select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t3 const PRIMARY PRIMARY 4 const 1 +1 SIMPLE t1 range idx idx 5 NULL 13 Using index condition; Using where; Rowid-ordered scan +1 SIMPLE t2 ref idx3 idx3 5 test.t1.a 3 Using where +explain format=json select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +EXPLAIN +{ + "query_block": { + "select_id": 1, + "table": { + "table_name": "t3", + "access_type": "const", + "possible_keys": ["PRIMARY"], + "key": "PRIMARY", + "key_length": "4", + "used_key_parts": ["id"], + "ref": ["const"], + "rows": 1, + "filtered": 100 + }, + "table": { + "table_name": "t1", + "access_type": "range", + "possible_keys": ["idx"], + "key": "idx", + "key_length": "5", + "used_key_parts": ["a"], + "rows": 13, + "filtered": 100, + "index_condition": "t1.a is not null", + "attached_condition": "(t1.a,1 + 1) in (((2,2)),((7,7)),((8,8))) and length(t1.c) = 1", + "mrr_type": "Rowid-ordered scan" + }, + "table": { + "table_name": "t2", + "access_type": "ref", + "possible_keys": ["idx3"], + "key": "idx3", + "key_length": "5", + "used_key_parts": ["d"], + "ref": ["test.t1.a"], + "rows": 3, + "filtered": 100, + "attached_condition": "length(t2.f) = 1" + } + } +} +select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((2,2),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +a b c d e f id v +2 1 w 2 1 e 1 1 +2 1 w 2 2 k 1 1 +2 1 w 2 3 g 1 1 +2 1 w 2 1 e 1 1 +2 1 w 2 2 k 1 1 +2 1 w 2 3 g 1 1 +# IN predicate is always FALSE +explain select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((9,9),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables +prepare stmt from "select * from t1,t2,t3 +where id = 1 and a = d and +(a,v+1) in ((9,9),(7,7),(8,8)) and +length(c) = 1 and length(f) = 1"; +execute stmt; +a b c d e f id v +execute stmt; +a b c d e f id v +deallocate prepare stmt; +set optimizer_switch=@save_optimizer_switch; +drop table t1,t2,t3; +# +# End of 10.2 tests +# set optimizer_switch=@mrr_icp_extra_tmp; diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test index 30f4419bd7e..ab951809b7a 100644 --- a/mysql-test/t/range.test +++ b/mysql-test/t/range.test @@ -1857,3 +1857,195 @@ DROP TABLE t1; --echo # --echo # End of 10.1 tests --echo # + +--echo # +--echo # MDEV-10454: range access keys extracted +--echo # from IN () +--echo # + +create table t1(a int, b int, c varchar(16), key idx(a,b)) engine=myisam; + +insert into t1 values + (1,1,'xx'), (2,2,'yyy'), (3,3,'zzzz'), (1,2,'zz'), (1,3,'x'), + (2,3,'yy'), (4,5,'ww'), (7,8,'xxxxx'), (4,3,'zyx'), (1,2,'uuu'), + (2,1,'w'), (5,5,'wx'), (2,3,'ww'), (7,7,'xxxyy'), (3,3,'zyxw'), + (3,2,'uuuw'), (2,2,'wxz'), (5,5,'xw'), (12,12,'xx'), (12,12,'y'), + (13,13,'z'), (11,12,'zz'), (11,13,'x'), (12,13,'y'), (14,15,'w'), + (17,18,'xx'), (14,13,'zx'), (11,12,'u'), (12,11,'w'), (5,5,'wx'), + (12,13,'ww'), (17,17,'xxxyy'), (13,13,'zyxw'), (13,12,'uuuw'), (12,12,'wxz'), + (15,15,'xw'), (1,1,'xa'), (2,2,'yya'), (3,3,'zzza'), (1,2,'za'), + (1,3,'xb'), (2,3,'ya'), (4,5,'wa'), (7,8,'xxxxa'), (4,3,'zya'), + (1,2,'uua'), (2,1,'wb'), (5,5,'wc'), (2,3,'wa'), (7,7,'xxxya'), + (3,3,'zyxa'), (3,2,'uuua'), (2,2,'wxa'), (5,5,'xa'), (12,12,'xa'), + (22,12,'yb'), (23,13,'zb'), (21,12,'za'), (24,13,'c'), (32,13,'d'), + (34,15,'wd'), (47,18,'xa'), (54,13,'za'), (51,12,'ub'), (52,11,'wc'), + (5,5,'wd'), (62,13,'wa'), (67,17,'xxxya'), (63,13,'zyxa'), (73,12,'uuua'), + (82,12,'wxa'), (85,15,'xd'); + +--echo # range access to t1 by 2-component keys for index idx +let $q1= +select * from t1 where (a,b) IN ((2, 3),(3,3),(8,8),(7,7)); +eval explain $q1; +eval explain format=json $q1; +eval $q1; +eval prepare stmt from "$q1"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +--echo # range access to t1 by 1-component keys for index idx +let $q2= +select * from t1 where (a,b+a) IN ((4,9),(8,8),(7,7)); +eval explain $q2; +eval explain format=json $q2; +eval $q2; + +--echo # range access to t1 by 1-component keys for index idx +let $q3= +select * from t1 where (a,b) IN ((4,a-1),(8,a+8),(7,a+7)); +eval explain $q3; +eval explain format=json $q3; +eval $q3; + +# this setting should be removed after fixes for mdev-12186, mdev-12187 +set @save_optimizer_switch=@@optimizer_switch; +set optimizer_switch='index_merge=off'; + +create table t2( + d int, e int, key idx1(d), key idx2(e), f varchar(32) +) engine=myisam; + +insert into t2 values + (9,5,'a'), (9,8,'b'), (9,3,'c'), (9,2,'d'), (9,1,'e'), + (6,5,'f'), (6,3,'g'), (6,7,'h'), (3,3,'i'), (6,2,'j'), + (9,5,'aa'), (9,8,'ba'), (9,3,'ca'), (2,2,'da'), (9,1,'ea'), + (6,5,'fa'), (6,3,'ga'), (6,7,'ha'), (9,3,'ia'), (6,2,'ja'); + +--echo # join order: (t2,t1) with ref access of t1 +--echo # range access to t1 by keys for index idx1 +let $q4= +select * from t1,t2 + where a = d and (a,e) in ((3,3),(7,7),(2,2)); +eval explain $q4; +eval explain format=json $q4; +eval $q4; + +insert into t2 values + (4,5,'a'), (7,8,'b'), (4,3,'c'), (1,2,'d'), (2,1,'e'), (5,5,'f'), + (2,3,'g'), (7,7,'h'), (3,3,'i'), (3,2,'j'), (2,2,'k'), (5,5,'l'), + (4,5,'aa'), (7,8,'bb'), (4,3,'cc'), (1,2,'dd'), (2,1,'ee'), (9,5,'ff'), + (2,3,'gg'), (7,7,'hh'), (3,3,'ii'), (3,2,'jj'), (2,2,'kk'), (9,5,'ll'), + (4,5,'aaa'), (7,8,'bbb'), (4,3,'ccc'), (1,2,'ddd'), (2,1,'eee'), (5,5,'fff'), + (2,3,'ggg'), (7,7,'hhh'), (3,3,'iii'), (3,2,'jjj'), (2,2,'kkk'), (5,5,'lll'), + (14,15,'a'), (17,18,'b'), (14,13,'c'), (11,12,'d'), (12,11,'e'), (15,15,'f'), + (12,13,'g'), (17,17,'h'), (13,13,'i'), (13,12,'j'), (12,12,'k'), (15,15,'l'), + (24,25,'a'), (27,28,'b'), (24,23,'c'), (21,22,'d'), (22,21,'e'), (25,25,'f'), + (22,23,'g'), (27,27,'h'), (23,23,'i'), (23,22,'j'), (22,22,'k'), (25,25,'l'), + (34,35,'a'), (37,38,'b'), (34,33,'c'), (31,32,'d'), (32,31,'e'), (35,35,'f'), + (32,33,'g'), (37,37,'h'), (33,33,'i'), (33,32,'j'), (32,32,'k'), (35,35,'l'), + (44,45,'a'), (47,48,'b'), (44,43,'c'), (41,42,'d'), (42,41,'e'), (45,45,'f'), + (42,43,'g'), (47,47,'h'), (43,43,'i'), (43,42,'j'), (42,42,'k'), (45,45,'l'); + +--echo # join order: (t1,t2) with ref access of t2 +--echo # range access to t1 by 1-component keys for index idx +let $q5= +select * from t1,t2 + where a = d and (a,e) in ((3,3),(7,7),(8,8)) and length(f) = 1; +eval explain $q5; +eval explain format=json $q5; +eval $q5; +eval prepare stmt from "$q5"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +insert into t1 select * from t1; + +--echo # join order: (t2,t1) with ref access of t1 +--echo # range access to t2 by keys for index idx2 +let $q6= +select * from t1,t2 + where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +eval explain $q6; +eval explain format=json $q6; +eval $q6; + +alter table t2 drop index idx1, drop index idx2, add index idx3(d,e); + +--echo # join order: (t2,t1) with ref access of t1 +--echo # range access to t2 by 2-component keys for index idx3 +let $q7= +select * from t1,t2 + where a = d and (a,e) in ((4,4),(7,7),(8,8)) and length(f) = 1; +eval explain $q7; +eval explain format=json $q7; +eval $q7; + +--echo # join order: (t1,t2) with ref access of t2 +--echo # range access to t1 by 1-component keys for index idx +let $q8= +select * from t1,t2 + where a = d and (a,e) in ((4,d+1),(7,d+1),(8,d+1)) and length(f) = 1; +eval explain $q8; +eval explain format=json $q8; +eval $q8; + +--echo # join order: (t1,t2) with ref access of t2 +--echo # no range access +let $q9= +select * from t1,t2 + where a = d and (a,e) in ((e,d+1),(7,7),(8,8)) and length(f) = 1; +eval explain $q9; +eval explain format=json $q9; +eval $q9; + +--echo # join order: (t1,t2) with ref access of t2 +--echo # range access to t1 by 1-component keys for index idx +let $q10= +select * from t1,t2 + where a = d and (a,2) in ((2,2),(7,7),(8,8)) and + length(c) = 1 and length(f) = 1; +eval explain $q10; +eval explain format=json $q10; +eval $q10; +eval prepare stmt from "$q10"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +create table t3 (id int primary key, v int) engine=myisam; + +insert into t3 values + (3,2), (1,1), (4,12), (2,15); + +--echo # join order: (t3,t1,t2) with const t3 and ref access of t2 +--echo # range access to t1 by 1-component keys for index idx +let $q11= +select * from t1,t2,t3 + where id = 1 and a = d and + (a,v+1) in ((2,2),(7,7),(8,8)) and + length(c) = 1 and length(f) = 1; +eval explain $q11; +eval explain format=json $q11; +eval $q11; + +--echo # IN predicate is always FALSE +let $q12= +select * from t1,t2,t3 + where id = 1 and a = d and + (a,v+1) in ((9,9),(7,7),(8,8)) and + length(c) = 1 and length(f) = 1; +eval explain $q12; +eval prepare stmt from "$q12"; +execute stmt; +execute stmt; +deallocate prepare stmt; + +set optimizer_switch=@save_optimizer_switch; + +drop table t1,t2,t3; + +--echo # +--echo # End of 10.2 tests +--echo # + diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 1a2cc3a6c81..9c277220771 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -1662,6 +1662,7 @@ public: void add_key_fields(JOIN *join, KEY_FIELD **key_fields, uint *and_level, table_map usable_tables, SARGABLE_PARAM **sargables); SEL_TREE *get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr); + SEL_TREE *get_func_row_mm_tree(RANGE_OPT_PARAM *param, Item_row *key_row); Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) { /* @@ -1714,6 +1715,7 @@ public: cmp_item *make_same(); void store_value_by_template(THD *thd, cmp_item *tmpl, Item *); friend void Item_func_in::fix_length_and_dec(); + cmp_item *get_comparator(uint i) { return comparators[i]; } }; @@ -1727,6 +1729,7 @@ public: uchar *get_value(Item *item); friend void Item_func_in::fix_length_and_dec(); Item_result result_type() { return ROW_RESULT; } + cmp_item *get_cmp_item() { return &tmp; } }; /* Functions used by where clause */ diff --git a/sql/item_row.h b/sql/item_row.h index bbfebb56010..26468336dc8 100644 --- a/sql/item_row.h +++ b/sql/item_row.h @@ -119,6 +119,13 @@ public: bool check_cols(uint c); bool null_inside() { return with_null; }; void bring_value(); + + Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond) + { + Item_args::propagate_equal_fields(thd, Context_identity(), cond); + return this; + } + bool check_vcol_func_processor(void *arg) {return FALSE; } Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return get_item_copy(thd, mem_root, this); } diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 6d088cad91e..d5de96b860a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -7210,6 +7210,205 @@ SEL_TREE *Item_func_in::get_func_mm_tree(RANGE_OPT_PARAM *param, } +/* + The structure Key_col_info is purely auxiliary and is used + only in the method Item_func_in::get_func_row_mm_tree +*/ +struct Key_col_info { + Field *field; /* If != NULL the column can be used for keys */ + cmp_item *comparator; /* If != 0 the column can be evaluated */ +}; + +/** + Build SEL_TREE for the IN predicate whose arguments are rows + + @param param PARAM from SQL_SELECT::test_quick_select + @param key_row First operand of the IN predicate + + @note + The function builds a SEL_TREE for in IN predicate in the case + when the predicate uses row arguments. First the function + detects among the components of the key_row (c[1],...,c[n]) taken + from in the left part the predicate those that can be usable + for building SEL_TREE (c[i1],...,c[ik]). They have to contain + items whose real items are field items referring to the current + table or equal to the items referring to the current table. + For the remaining components of the row it checks whether they + can be evaluated. The result of the analysis is put into the + array of structures of the type Key_row_col_info. + + After this the function builds the SEL_TREE for the following + formula that can be inferred from the given IN predicate: + c[i11]=a[1][i11] AND ... AND c[i1k1]=a[1][i1k1] + OR + ... + OR + c[im1]=a[m][im1] AND ... AND c[imkm]=a[m][imkm]. + Here a[1],...,a[m] are all arguments of the IN predicate from + the right part and for each j ij1,...,ijkj is a subset of + i1,...,ik such that a[j][ij1],...,a[j][ijkj] can be evaluated. + + If for some j there no a[j][i1],...,a[j][ik] can be evaluated + then no SEL_TREE can be built for this predicate and the + function immediately returns 0. + + If for some j by using evaluated values of key_row it can be + proven that c[ij1]=a[j][ij1] AND ... AND c[ijkj]=a[j][ijkj] + is always FALSE then this disjunct is omitted. + + @returns + the built SEL_TREE if it can be constructed + 0 - otherwise. +*/ + +SEL_TREE *Item_func_in::get_func_row_mm_tree(RANGE_OPT_PARAM *param, + Item_row *key_row) +{ + DBUG_ENTER("Item_func_in::get_func_row_mm_tree"); + + if (negated) + DBUG_RETURN(0); + + SEL_TREE *res_tree= 0; + uint used_key_cols= 0; + uint col_comparators= 0; + table_map param_comp= ~(param->prev_tables | param->read_tables | + param->current_table); + uint row_cols= key_row->cols(); + Dynamic_array key_cols_info(row_cols); + cmp_item_row *row_cmp_item= (cmp_item_row *) + (array ? ((in_row *) array)->get_cmp_item() : + cmp_items[(uint) ROW_RESULT]); + + Item **key_col_ptr= key_row->addr(0); + for(uint i= 0; i < row_cols; i++, key_col_ptr++) + { + Key_col_info key_col_info= {0, NULL}; + Item *key_col= *key_col_ptr; + if (key_col->real_item()->type() == Item::FIELD_ITEM) + { + /* + The i-th component of key_row can be used for key access if + key_col->real_item() points to a field of the current table or + if it is equal to a field item pointing to such a field. + */ + Item_field *col_field_item= (Item_field *) (key_col->real_item()); + Field *key_col_field= col_field_item->field; + if (key_col_field->table->map != param->current_table) + { + Item_equal *item_equal= col_field_item->item_equal; + if (item_equal) + { + Item_equal_fields_iterator it(*item_equal); + while (it++) + { + key_col_field= it.get_curr_field(); + if (key_col_field->table->map == param->current_table) + break; + } + } + } + if (key_col_field->table->map == param->current_table) + { + key_col_info.field= key_col_field; + used_key_cols++; + } + } + else if (!(key_col->used_tables() & (param_comp | param->current_table)) + && !key_col->is_expensive()) + { + /* The i-th component of key_row can be evaluated */ + + /* See the comment in Item::get_mm_tree_for_const */ + MEM_ROOT *tmp_root= param->mem_root; + param->thd->mem_root= param->old_root; + + key_col->bring_value(); + key_col_info.comparator= row_cmp_item->get_comparator(i); + key_col_info.comparator->store_value(key_col); + col_comparators++; + + param->thd->mem_root= tmp_root; + } + key_cols_info.push(key_col_info); + } + + if (!used_key_cols) + DBUG_RETURN(0); + + uint omitted_tuples= 0; + Item **arg_start= arguments() + 1; + Item **arg_end= arg_start + argument_count() - 1; + for (Item **arg= arg_start ; arg < arg_end; arg++) + { + uint i; + + /* + First check whether the disjunct constructed for *arg + is really needed + */ + Item_row *arg_tuple= (Item_row *) (*arg); + if (col_comparators) + { + MEM_ROOT *tmp_root= param->mem_root; + param->thd->mem_root= param->old_root; + for (i= 0; i < row_cols; i++) + { + Key_col_info *key_col_info= &key_cols_info.at(i); + if (key_col_info->comparator) + { + Item *arg_col= arg_tuple->element_index(i); + if (!(arg_col->used_tables() & (param_comp | param->current_table)) && + !arg_col->is_expensive() && + key_col_info->comparator->cmp(arg_col)) + { + omitted_tuples++; + break; + } + } + } + param->thd->mem_root= tmp_root; + if (i < row_cols) + continue; + } + + /* The disjunct for *arg is needed: build it. */ + SEL_TREE *and_tree= 0; + Item **arg_col_ptr= arg_tuple->addr(0); + for (uint i= 0; i < row_cols; i++, arg_col_ptr++) + { + Key_col_info *key_col_info= &key_cols_info.at(i); + if (!key_col_info->field) + continue; + Item *arg_col= *arg_col_ptr; + if (!(arg_col->used_tables() & (param_comp | param->current_table)) && + !arg_col->is_expensive()) + { + and_tree= tree_and(param, and_tree, + get_mm_parts(param, + key_col_info->field, + Item_func::EQ_FUNC, + arg_col->real_item())); + } + } + if (!and_tree) + { + res_tree= 0; + break; + } + /* Join the disjunct the the OR tree that is being constructed */ + res_tree= !res_tree ? and_tree : tree_or(param, res_tree, and_tree); + } + if (omitted_tuples == argument_count() - 1) + { + /* It's turned out that all disjuncts are always FALSE */ + res_tree= new (param->mem_root) SEL_TREE(SEL_TREE::IMPOSSIBLE, + param->mem_root, param->keys); + } + DBUG_RETURN(res_tree); +} + + /* Build conjunction of all SEL_TREEs for a simple predicate applying equalities @@ -7544,12 +7743,22 @@ SEL_TREE *Item_func_in::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) if (const_item()) DBUG_RETURN(get_mm_tree_for_const(param)); - if (key_item()->real_item()->type() != Item::FIELD_ITEM) + SEL_TREE *tree= 0; + switch (key_item()->real_item()->type()) { + case Item::FIELD_ITEM: + tree= get_full_func_mm_tree(param, + (Item_field*) (key_item()->real_item()), + NULL); + break; + case Item::ROW_ITEM: + tree= get_func_row_mm_tree(param, + (Item_row *) (key_item()->real_item())); + break; + default: DBUG_RETURN(0); - Item_field *field= (Item_field*) (key_item()->real_item()); - SEL_TREE *tree= get_full_func_mm_tree(param, field, NULL); + } DBUG_RETURN(tree); -} +} SEL_TREE *Item_equal::get_mm_tree(RANGE_OPT_PARAM *param, Item **cond_ptr) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 54b0b01559b..151e341c49f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -4709,6 +4709,8 @@ static uint get_semi_join_select_list_index(Field *field) @param num_values Number of values[] that we are comparing against @param usable_tables Tables which can be used for key optimization @param sargables IN/OUT Array of found sargable candidates + @param row_col_no if = n that > 0 then field is compared only + against the n-th component of row values @note If we are doing a NOT NULL comparison on a NOT NULL field in a outer join @@ -4722,7 +4724,8 @@ static void add_key_field(JOIN *join, KEY_FIELD **key_fields,uint and_level, Item_bool_func *cond, Field *field, bool eq_func, Item **value, uint num_values, - table_map usable_tables, SARGABLE_PARAM **sargables) + table_map usable_tables, SARGABLE_PARAM **sargables, + uint row_col_no= 0) { uint optimize= 0; if (eq_func && @@ -4751,7 +4754,15 @@ add_key_field(JOIN *join, bool optimizable=0; for (uint i=0; iused_tables(); + Item *curr_val; + if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM) + { + Item_row *value_tuple= (Item_row *) (value[i]->real_item()); + curr_val= value_tuple->element_index(row_col_no - 1); + } + else + curr_val= value[i]; + table_map value_used_tables= curr_val->used_tables(); used_tables|= value_used_tables; if (!(value_used_tables & (field->table->map | RAND_TABLE_BIT))) optimizable=1; @@ -4789,7 +4800,15 @@ add_key_field(JOIN *join, bool is_const=1; for (uint i=0; iconst_item())) + Item *curr_val; + if (row_col_no && value[i]->real_item()->type() == Item::ROW_ITEM) + { + Item_row *value_tuple= (Item_row *) (value[i]->real_item()); + curr_val= value_tuple->element_index(row_col_no - 1); + } + else + curr_val= value[i]; + if (!(is_const&= curr_val->const_item())) break; } if (is_const) @@ -4856,12 +4875,14 @@ add_key_field(JOIN *join, @param key_fields Pointer to add key, if usable @param and_level And level, to be stored in KEY_FIELD @param cond Condition predicate - @param field Field used in comparision + @param field_item Field item used for comparison @param eq_func True if we used =, <=> or IS NULL - @param value Value used for comparison with field - Is NULL for BETWEEN and IN + @param value Value used for comparison with field_item + @param num_values Number of values[] that we are comparing against @param usable_tables Tables which can be used for key optimization @param sargables IN/OUT Array of found sargable candidates + @param row_col_no if = n that > 0 then field is compared only + against the n-th component of row values @note If field items f1 and f2 belong to the same multiple equality and @@ -4876,11 +4897,12 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level, Item_bool_func *cond, Item *field_item, bool eq_func, Item **val, uint num_values, table_map usable_tables, - SARGABLE_PARAM **sargables) + SARGABLE_PARAM **sargables, uint row_col_no= 0) { Field *field= ((Item_field *) (field_item->real_item()))->field; add_key_field(join, key_fields, and_level, cond, field, - eq_func, val, num_values, usable_tables, sargables); + eq_func, val, num_values, usable_tables, sargables, + row_col_no); Item_equal *item_equal= field_item->get_item_equal(); if (item_equal) { @@ -4896,7 +4918,7 @@ add_key_equal_fields(JOIN *join, KEY_FIELD **key_fields, uint and_level, { add_key_field(join, key_fields, and_level, cond, equal_field, eq_func, val, num_values, usable_tables, - sargables); + sargables, row_col_no); } } } @@ -5078,6 +5100,24 @@ Item_func_in::add_key_fields(JOIN *join, KEY_FIELD **key_fields, (Item_field*) (args[0]->real_item()), false, args + 1, arg_count - 1, usable_tables, sargables); } + else if (key_item()->type() == Item::ROW_ITEM && + !(used_tables() & OUTER_REF_TABLE_BIT)) + { + Item_row *key_row= (Item_row *) key_item(); + Item **key_col= key_row->addr(0); + uint row_cols= key_row->cols(); + for (uint i= 0; i < row_cols; i++, key_col++) + { + if (is_local_field(*key_col)) + { + Item_field *field_item= (Item_field *)((*key_col)->real_item()); + add_key_equal_fields(join, key_fields, *and_level, this, + field_item, false, args + 1, arg_count - 1, + usable_tables, sargables, i + 1); + } + } + } + } From 6d417a0bad205a6bacfee10dbc46dd631b093e75 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 4 Apr 2017 08:50:01 +0000 Subject: [PATCH 6/6] Fix aws_key_management compilation after mismerge Also do not use BUILD_BYPRODUCTS in ExternalPeoject for older cmake --- plugin/aws_key_management/CMakeLists.txt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/plugin/aws_key_management/CMakeLists.txt b/plugin/aws_key_management/CMakeLists.txt index 1c80b44ede7..66b8074406f 100644 --- a/plugin/aws_key_management/CMakeLists.txt +++ b/plugin/aws_key_management/CMakeLists.txt @@ -103,7 +103,9 @@ ELSE() ADD_LIBRARY(${lib} STATIC IMPORTED GLOBAL) ADD_DEPENDENCIES(${lib} aws_sdk_cpp) SET(loc "${CMAKE_CURRENT_BINARY_DIR}/aws_sdk_cpp/lib/${CMAKE_STATIC_LIBRARY_PREFIX}${lib}${CMAKE_STATIC_LIBRARY_SUFFIX}") - SET(byproducts ${byproducts} BUILD_BYPRODUCTS ${loc}) + IF(CMAKE_VERSION VERSION_GREATER "3.1") + SET(byproducts ${byproducts} BUILD_BYPRODUCTS ${loc}) + ENDIF() SET_TARGET_PROPERTIES(${lib} PROPERTIES IMPORTED_LOCATION ${loc}) ENDFOREACH() @@ -139,14 +141,13 @@ ENDIF() ADD_DEFINITIONS(${SSL_DEFINES}) # Need to know whether openssl should be initialized SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CXX11_FLAGS}") -MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc - LINK_LIBRARIES ${AWS_SDK_LIBS} - COMPONENT aws-key-management) - IF(WIN32) SET(AWS_CPP_SDK_DEPENDENCIES bcrypt winhttp wininet userenv version) ELSE() SET(AWS_CPP_SDK_DEPENDENCIES ${SSL_LIBRARIES} ${CURL_LIBRARIES} ${UUID_LIBRARIES}) ENDIF() +MYSQL_ADD_PLUGIN(aws_key_management aws_key_management_plugin.cc + LINK_LIBRARIES ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES} + COMPONENT aws-key-management) + -TARGET_LINK_LIBRARIES(aws_key_management ${AWS_SDK_LIBS} ${AWS_CPP_SDK_DEPENDENCIES})