diff --git a/.gitignore b/.gitignore index 39affa8f2..59cf60a56 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .vs out CMakeUserPresets.json +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt index 341ed2de7..3abc8ce7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -271,11 +271,35 @@ endif() # TODO: Fix these warnings. # -if(MSVC) +# TODO: Also cover linker warnings + +add_config_option(WERROR BOOL ADVANCED DEFAULT OFF + "Turn compile warnings into errors" +) + +# +# Note: If WERROR is enabled we change its value to be the actual compiler +# option to be used on the current platform. That is used for easier +# propagation to external builds. +# +# Note: In more recent cmake there is CMAKE_COMPILE_WARNING_AS_ERROR variable +# but at the moment we can't ensure using that recent cmake. +# + +if(WERROR) + set(WERROR -Werror) +endif() + +if(MSVC OR TOOLSET_MSVC) add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) if(CXX_FRONTEND_MSVC) + + if(WERROR) + set(WERROR /WX) # MSVC equivalent of -Werror + endif() + # Disable MSVC unreachable code warnings unless requested. add_compile_options(/wd4702) @@ -283,12 +307,14 @@ if(MSVC) # Seehttps://connect.microsoft.com/VisualStudio/feedback/details/897611/incorrect-warning-of-c4297-for-destructor-with-try-catch-statement add_compile_options(/wd4297) + endif() -endif() +elseif(SUNPRO) + # Note: For simplicity we do not handle WERROR on SunOS -if(SUNPRO) + set(WERROR) add_compile_options( -errtags=yes -erroff=hidevf,wvarhidemem @@ -296,10 +322,26 @@ if(SUNPRO) endif() -if (CMAKE_COMPILER_IS_GNUCC AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 12.0) +if(NOT WERROR) + # clear if WERROR was set to something like OFF or FALSE + # message(STATUS "WERROR: cleared") + unset(WERROR CACHE) +else() + # overwrite cache entry with changed value + set(WERROR "${WERROR}" CACHE INTERNAL "WERROR flags" FORCE) +endif() + +# message(STATUS "WERROR: ${WERROR}") +add_compile_options(${WERROR}) + + +if (GCC AND GCC VERSION_GREATER 11) # Silence a warning produced by a regression in GCC 12.0 and newer # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106199 + # Note: The stringop-overflow warnings are shown also during linking phase + # (observed with GCC 14.2) add_compile_options(-Wno-stringop-overflow) + add_link_options(-Wno-stringop-overflow) endif() @@ -380,7 +422,8 @@ if(MAINTAINER_MODE) # (and this is the case for MSVC 2015). # See: http://en.cppreference.com/w/cpp/language/copy_assignment - add_compile_options(/W4 /wd4512 /wd4127) + set_warnings_level(4) + add_compile_options(/wd4512 /wd4127) elseif(SUNPRO) else() diff --git a/LICENSE.txt b/LICENSE.txt index ddcd86cb1..8256a84c6 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ Licensing Information User Manual -MySQL Connector/C++ 9.1.0 Community +MySQL Connector/C++ 9.3.0 Community __________________________________________________________________ Introduction @@ -8,18 +8,18 @@ Introduction This License Information User Manual contains Oracle's product license and other licensing information, including licensing information for third-party software which may be included in this distribution of - MySQL Connector/C++ 9.1.0 Community. + MySQL Connector/C++ 9.3.0 Community. - Last updated: September 2024 + Last updated: March 2025 Licensing Information - This release of MySQL Connector/C++ 9.1.0 Community is brought to you + This release of MySQL Connector/C++ 9.3.0 Community is brought to you by the MySQL team at Oracle. This software is released under version 2 of the GNU General Public License (GPLv2), as set forth below, with the following additional permissions: - This distribution of MySQL Connector/C++ 9.1.0 Community is designed to + This distribution of MySQL Connector/C++ 9.3.0 Community is designed to work with certain software (including but not limited to OpenSSL) that is licensed under separate terms, as designated in a particular file or component or in the license documentation. Without limiting your rights @@ -34,7 +34,7 @@ Licensing Information a copy of which is reproduced below and can also be found along with its FAQ at http://oss.oracle.com/licenses/universal-foss-exception. - Copyright (c) 2008, 2024, Oracle and/or its affiliates. + Copyright (c) 2008, 2025, Oracle and/or its affiliates. Election of GPLv2 @@ -570,6 +570,15 @@ documentation and/or software. Google Protocol Buffers +You may be receiving a copy of abseil-cpp as part of this product in object code + form. +The terms of the Oracle license do NOT apply to abseil-cpp. +abseil-cpp is licensed under the Apache 2.0 license, separate from the Oracle pr +oduct. +If you do not wish to install this library, you may remove it, but the Oracle pr +ogram +might not operate properly or at all without it. + Copyright 2008 Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -637,7 +646,14 @@ in the 'Standard Licenses' section. Kerberos5 -Kerberos5 +You may be receiving a copy of the kerberos documentation as part of this +product. The terms of the Oracle license do NOT apply to Kerberos documentation. + +Kerberos documentation is licensed under the CC-BY-SA 3.0 license, separate from + +the Oracle product. +If you do not wish to install this library, you may remove it, but +the Oracle program might not operate properly or at all without it. Copyright (C) 1985-2019 by the Massachusetts Institute of Technology. @@ -2126,49 +2142,20 @@ but the Oracle program might not operate properly or at all without it. // SPDX-License-Identifier: Apache-2.0 LICENSE: - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ -A copy of the Apache License v2.0, January 2004 license can be found -in the 'Standard Licenses' section. - - -4th party code included -======================= -exporters/etw -------------- -TraceLogging Dynamic for Windows - -Copyright (c) Microsoft Corporation. All rights reserved. -MIT License - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ +A copy of the Apache License v2.0, January 2004 license can be found +in the 'Standard Licenses' section. -4th Party Libraries -=================== +4th Party Dependencies +====================== opentelemetry-proto ------------------- // Copyright 2019, OpenTelemetry Authors -// Copyright 2020, OpenTelemetry Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -2182,48 +2169,75 @@ opentelemetry-proto // See the License for the specific language governing permissions and // limitations under the License. -Apache License Text as listed above +Some files include +// Copyright 2020, OpenTelemetry Authors +(same license header) + +A copy of the Apache License v2.0, January 2004 license can be found +in the 'Standard Licenses' section. + +================================================================================ +== ------------------------------------------------------------------------------- protobuf -------- +COPYRIGHT AND PERMISSION NOTICE -Copyright 2008 Google Inc. All rights reserved. +Copyright (c) 1996 - 2024, Daniel Stenberg, , and many +contributors, see the THANKS file. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: +All rights reserved. - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. +Permission to use, copy, modify, and distribute this software for any purpose +with or without fee is hereby granted, provided that the above copyright +notice and this permission notice appear in all copies. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN +NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE +OR OTHER DEALINGS IN THE SOFTWARE. -Code generated by the Protocol Buffer compiler is owned by the owner -of the input file used when generating it. This code is not -standalone and requires a support library to be linked with it. This -support library is itself covered by the above license. +Except as contained in this notice, the name of a copyright holder shall not +be used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization of the copyright holder. + +Protobuf dependency - abseil-cpp +-------------------------------- +=== Header in source files: +// Copyright 2017 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// This header file contains C++11 versions of standard header +// abstractions available within C++14 and C++17, and are designed to be drop-in +// replacement for code compliant with C++14 and C++17. + +=== License File + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + +A copy of the Apache License v2.0, January 2004 license can be found +in the 'Standard Licenses' section. +================================================================================ +== ------------------------------------------------------------------------------- json (nlohmann) ---- + MIT License Copyright (c) 2013-2022 Niels Lohmann @@ -2246,14 +2260,14 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ------------------------------------------------------------------------------- - +================================================================================ +== curl ---- COPYRIGHT AND PERMISSION NOTICE -Copyright (c) 1996 - 2023, Daniel Stenberg, , and many +Copyright (c) 1996 - 2024, Daniel Stenberg, , and many contributors, see the THANKS file. All rights reserved. diff --git a/README.txt b/README.txt index ffdc35cbe..d8d6abc47 100644 --- a/README.txt +++ b/README.txt @@ -1,4 +1,4 @@ -Copyright (c) 2008, 2024, Oracle and/or its affiliates. +Copyright (c) 2008, 2025, Oracle and/or its affiliates. This is a release of MySQL Connector/C++, the C++ interface for communicating with MySQL servers. diff --git a/buildinfo.cmake b/buildinfo.cmake index db73ce5bf..7a791671f 100644 --- a/buildinfo.cmake +++ b/buildinfo.cmake @@ -42,10 +42,10 @@ function(generate_cmake_config) ) install( - FILES + FILES "${CMAKE_BINARY_DIR}/mysql-concpp${suffix}.cmake" DESTINATION . - COMPONENT Readme + COMPONENT DevCommon ) endforeach() diff --git a/cdk/CMakeLists.txt b/cdk/CMakeLists.txt index dc8e3adc6..1e0fb41a7 100644 --- a/cdk/CMakeLists.txt +++ b/cdk/CMakeLists.txt @@ -28,9 +28,9 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 3.8) +CMAKE_MINIMUM_REQUIRED(VERSION 3.15) -cmake_policy(VERSION 3.0) +cmake_policy(VERSION 3.15) if(POLICY CMP0022) cmake_policy(SET CMP0022 NEW) # consistently use INTERFACE_LINK_LIBRARIES property @@ -150,7 +150,7 @@ IF(MSVC) # TODO: move to /Wall when code base is ready for this - add_compile_options(/W4) + set_warnings_level(4) # Note: We disable warnings related to C++11 language because we want this # to be pure C++ code. diff --git a/cdk/cmake/DepFindProtobuf.cmake b/cdk/cmake/DepFindProtobuf.cmake index 1fc785e31..6e020fc87 100644 --- a/cdk/cmake/DepFindProtobuf.cmake +++ b/cdk/cmake/DepFindProtobuf.cmake @@ -115,7 +115,7 @@ function(mysqlx_protobuf_generate_cpp SRCS HDRS) ELSEIF(MSVC) set_source_files_properties(${srcs} APPEND_STRING PROPERTY COMPILE_FLAGS - "/W1 /wd4018 /wd4996 /wd4244 /wd4267" + "/wd4018 /wd4996 /wd4244 /wd4267" ) ENDIF() diff --git a/cdk/cmake/compiler/MSVC.cmake b/cdk/cmake/compiler/MSVC.cmake index 5a6d3d80d..71e8e10c6 100644 --- a/cdk/cmake/compiler/MSVC.cmake +++ b/cdk/cmake/compiler/MSVC.cmake @@ -89,6 +89,16 @@ function(set_visibility) endfunction() +function(set_warnings_level N) + + # Note: The /Wn flag must be set only once, otherwise msvc shows warnings + + string(REGEX REPLACE "/W[123456789]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W${N}") + +endfunction() + + function(set_msvcrt TYPE) if(TYPE MATCHES "^(STATIC|Static|static)$") diff --git a/cdk/cmake/dependency.cmake b/cdk/cmake/dependency.cmake index e3fec4ee2..1f4410329 100644 --- a/cdk/cmake/dependency.cmake +++ b/cdk/cmake/dependency.cmake @@ -60,6 +60,7 @@ set(EXT_FWD CMAKE_SYSTEM_PROCESSOR CMAKE_C_COMPILER CMAKE_CXX_COMPILER MSVC + WERROR ) set(EXT_DIR ${CMAKE_CURRENT_LIST_DIR}/ext CACHE INTERNAL "external project utils location") @@ -129,7 +130,7 @@ function(add_ext NAME HEADER) "${EXT_LIB} library name" ) - + #show_config_options() # Handle non-path value of WITH_X option diff --git a/cdk/cmake/gtest.cmake b/cdk/cmake/gtest.cmake index 3a79ad3a3..3e53ba29a 100644 --- a/cdk/cmake/gtest.cmake +++ b/cdk/cmake/gtest.cmake @@ -32,9 +32,6 @@ # Set up gtest for use by targets in given folder and its sub-folders. # MACRO(SETUP_GTEST) - IF (WITH_GTEST) - INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS}) - ENDIF (WITH_GTEST) ENDMACRO(SETUP_GTEST) @@ -135,6 +132,14 @@ MESSAGE("gtest_main location: ${gtest_main_location}") add_library(gtest STATIC IMPORTED) add_library(gtest_main STATIC IMPORTED) +target_include_directories(gtest INTERFACE ${GTEST_INCLUDE_DIRS}) + +# See: https://stackoverflow.com/questions/42847103/stdtr1-with-visual-studio-2017 + +target_compile_definitions(gtest INTERFACE + -DGTEST_LANG_CXX11=1 +) + set_target_properties(gtest PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" IMPORTED_LOCATION "${gtest_location}" diff --git a/cdk/cmake/platform.cmake b/cdk/cmake/platform.cmake index e76a45e7c..fc3fe6c00 100644 --- a/cdk/cmake/platform.cmake +++ b/cdk/cmake/platform.cmake @@ -115,6 +115,17 @@ macro(add_flags LANG) set(CMAKE_${LANG}_FLAGS "${CMAKE_${LANG}_FLAGS}" PARENT_SCOPE) endmacro() +include(CheckCXXCompilerFlag) + +# Set single compiler flag only if it is supported, ignore otherwise + +macro(set_compiler_flag FLAG) + unset(flag_supported CACHE) + CHECK_CXX_COMPILER_FLAG(${FLAG} flag_supported) + if(flag_supported) + add_compile_options(${FLAG}) + endif() +endmacro() # ----------------------------------------------------------------- diff --git a/cdk/cmake/testing.cmake b/cdk/cmake/testing.cmake index bfdc8d92c..662fba98d 100644 --- a/cdk/cmake/testing.cmake +++ b/cdk/cmake/testing.cmake @@ -144,6 +144,7 @@ IF(WITH_TESTS) set_global(test_tests ${test_tests}) add_library(${TEST} OBJECT ${ARGN}) + target_link_libraries(${TEST} gtest) set_target_properties(${TEST} PROPERTIES FOLDER "Tests") target_include_directories(${TEST} PRIVATE ${test_includes}) @@ -153,12 +154,11 @@ IF(WITH_TESTS) if (MSVC) target_compile_definitions(${TEST} PRIVATE + -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING ) target_compile_options(${TEST} PRIVATE - /W3 /wd4244 /wd4267 /wd4701 @@ -166,8 +166,6 @@ IF(WITH_TESTS) /wd4456 # declaration of hides previous local declaration ) - target_compile_options(${TEST} PUBLIC /std:c++14) - if(STATIC_TESTS_MSVCRT) target_compile_options(${TEST} PRIVATE $<$:/MTd> @@ -295,10 +293,7 @@ IF(WITH_TESTS) if (MSVC) - target_compile_definitions(${target_run_unit_tests} PRIVATE - -D_SCL_SECURE_NO_WARNINGS - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - ) + set_warnings_level(3) target_compile_options(${target_run_unit_tests} PRIVATE /wd4244 diff --git a/cdk/core/session.cc b/cdk/core/session.cc index 7a00cc1fe..feb642e8e 100644 --- a/cdk/core/session.cc +++ b/cdk/core/session.cc @@ -53,7 +53,7 @@ struct Session_builder struct ReportStatus { - //False if not able to connect, true if all is good. + // False if not able to connect, true if all is good. option_t m_status = false; Session_builder::ep_filter_t m_filter; size_t m_id; @@ -63,6 +63,12 @@ struct Session_builder , m_id(id) {} + /* + Note: The only reason for ReportStatus object is to use RAII to invoke + m_filter() on destruction to report session creation status. So this + is part of logic of methods that use such object and as such is allowed + to throw errors from the dtor. + */ ~ReportStatus() { @@ -481,7 +487,7 @@ Session::Session(ds::Unix_socket &ds, const ds::Unix_socket::Options &options) #endif //#ifndef WIN32 -Session::~Session() +Session::~Session() NOEXCEPT { delete m_session; delete m_connection; diff --git a/cdk/extra/lz4/CMakeLists.txt b/cdk/extra/lz4/CMakeLists.txt index 7e5db8567..ebcf76173 100644 --- a/cdk/extra/lz4/CMakeLists.txt +++ b/cdk/extra/lz4/CMakeLists.txt @@ -34,6 +34,10 @@ include(platform) enable_pic() +if(WERROR) + add_compile_options(${WERROR}) +endif() + add_library(lz4 STATIC lib/lz4.c lib/lz4frame.c diff --git a/cdk/extra/protobuf/CMakeLists.txt b/cdk/extra/protobuf/CMakeLists.txt index adc19f55d..a787985f5 100644 --- a/cdk/extra/protobuf/CMakeLists.txt +++ b/cdk/extra/protobuf/CMakeLists.txt @@ -73,6 +73,10 @@ SET(PROTO_SRC_DIR "${PROJECT_SOURCE_DIR}/protobuf-3.19.6") enable_pic() enable_cxx17() +if(WERROR) + add_compile_options(${WERROR}) +endif() + # -O3 using GCC on SPARC leds to segfault on protoc if(SPARC AND GCC) foreach(LANG C CXX) @@ -90,12 +94,22 @@ endif() set_visibility(hidden) -if(NOT TOOLSET_MSVC AND NOT APPLE) - add_compile_options(-Wno-stringop-overflow -Wno-stringop-overread) +if(GCC AND GCC VERSION_GREATER 11) + # See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106199 + set_compiler_flag(-Wno-stringop-overflow) + set_compiler_flag(-Wno-stringop-overread) +endif() + +if(NOT MSVC OR CLANG) + set_compiler_flag(-Wno-unused-const-variable) +endif() + +if(WIN32) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS) endif() if(APPLE) - add_compile_options(-Wno-deprecated-declarations) + set_compiler_flag(-Wno-deprecated-declarations) endif() diff --git a/cdk/extra/zlib/CMakeLists.txt b/cdk/extra/zlib/CMakeLists.txt index b3ebd214d..2c6928d25 100644 --- a/cdk/extra/zlib/CMakeLists.txt +++ b/cdk/extra/zlib/CMakeLists.txt @@ -7,8 +7,32 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) set(VERSION "1.3.1") project(zlib VERSION ${VERSION} LANGUAGES C) +include(../setup.cmake) +include(platform) -option(ZLIB_BUILD_EXAMPLES "Enable Zlib Examples" ON) +enable_pic() + +if(WERROR) + add_compile_options(${WERROR}) +endif() + +if(WIN32) + + add_compile_definitions(_CRT_SECURE_NO_WARNINGS _SCL_SECURE_NO_WARNINGS) + + # warning triggered by one of the sources: + # The POSIX name for this item is deprecated. Instead, use the ISO C and C++ + # conformant name: _open. See online help for details. + + if(CLANG) + add_compile_options(-Wno-deprecated-declarations) + else() + add_compile_options(/wd4996) + endif() + +endif() + +option(ZLIB_BUILD_EXAMPLES "Enable Zlib Examples" OFF) IF(DISABLE_THESE_LINES) set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") @@ -148,8 +172,6 @@ file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) -add_compile_options(-fPIC) - add_library(zlib STATIC ${ZLIB_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) target_include_directories(zlib PUBLIC diff --git a/cdk/extra/zstd/CMakeLists.txt b/cdk/extra/zstd/CMakeLists.txt index 0ed58f630..af505f3b0 100644 --- a/cdk/extra/zstd/CMakeLists.txt +++ b/cdk/extra/zstd/CMakeLists.txt @@ -15,6 +15,16 @@ include(platform) enable_pic() +if(WERROR) + add_compile_options(${WERROR}) +endif() + +if(WIN32 AND CLANG) + # This warning shows only when building with clang on Win (clang 18): + # lib\compress\huf_compress.c(519,16): error : unused function 'HUF_isSorted' + set_compiler_flag(-Wno-unused-function) +endif() + SET(ZSTD_LIB_DIR "${PROJECT_SOURCE_DIR}/lib") diff --git a/cdk/foundation/connection_openssl.cc b/cdk/foundation/connection_openssl.cc index 24dc71469..e0f2e09aa 100644 --- a/cdk/foundation/connection_openssl.cc +++ b/cdk/foundation/connection_openssl.cc @@ -265,12 +265,12 @@ class connection_TLS_impl , m_options(options) {} - ~connection_TLS_impl() + ~connection_TLS_impl() NOEXCEPT { if (m_tls) { /* - Server is expecting a SSL quiet shutdown. + Server is expecting a SSL quiet shutdown. */ SSL_set_quiet_shutdown(m_tls, 1); SSL_shutdown(m_tls); @@ -697,7 +697,7 @@ class safe_X509 : m_X509(obj) {} - ~safe_X509() + ~safe_X509() NOEXCEPT { if (std::is_same::value) { diff --git a/cdk/foundation/connection_tcpip.cc b/cdk/foundation/connection_tcpip.cc index cb4374dd4..7a8bfe366 100644 --- a/cdk/foundation/connection_tcpip.cc +++ b/cdk/foundation/connection_tcpip.cc @@ -138,7 +138,7 @@ class Socket_system_initializer detail::initialize_socket_system(); } - ~Socket_system_initializer() + ~Socket_system_initializer() NOEXCEPT { try { diff --git a/cdk/foundation/connection_tcpip_base.h b/cdk/foundation/connection_tcpip_base.h index 6a4dc4cc0..9bfb12cb4 100644 --- a/cdk/foundation/connection_tcpip_base.h +++ b/cdk/foundation/connection_tcpip_base.h @@ -110,9 +110,9 @@ class Socket_base::Impl return detail::poll_one(m_sock, detail::POLL_MODE_WRITE, false) > 0; } - virtual ~Impl() + virtual ~Impl() NOEXCEPT { - close(); + try { close(); } catch (...) {} } virtual void do_connect() =0; diff --git a/cdk/foundation/socket_detail.cc b/cdk/foundation/socket_detail.cc index ffea5d61c..6663dc5c8 100644 --- a/cdk/foundation/socket_detail.cc +++ b/cdk/foundation/socket_detail.cc @@ -643,7 +643,7 @@ Socket connect(const char *host_name, unsigned short port, struct AddrInfoGuard { addrinfo* list; - ~AddrInfoGuard() { freeaddrinfo(list); } + ~AddrInfoGuard() NOEXCEPT { freeaddrinfo(list); } } guard = { host_list }; @@ -916,6 +916,13 @@ void recv(Socket socket, byte *buffer, size_t buffer_size) size_t bytes_received = 0; + /* + Note: In presence of timeouts recv_some() can return 0 which would lead + to an infinite loop here! See also bug#37278716. + + A solution would be to throw error if timeout was hit? + */ + while (bytes_received != buffer_size) bytes_received += recv_some(socket, buffer + bytes_received, buffer_size - bytes_received, true); } diff --git a/cdk/include/mysql/cdk/api/document.h b/cdk/include/mysql/cdk/api/document.h index ed76ff758..0fb456fa4 100644 --- a/cdk/include/mysql/cdk/api/document.h +++ b/cdk/include/mysql/cdk/api/document.h @@ -107,7 +107,7 @@ class Any_processor virtual Doc_prc* doc() =0; - virtual ~Any_processor() {} + virtual ~Any_processor() NOEXCEPT {} }; @@ -156,7 +156,7 @@ class Doc_processor */ virtual Any_prc* key_val(const string &key) =0; - virtual ~Doc_processor() {} + virtual ~Doc_processor() NOEXCEPT {} }; diff --git a/cdk/include/mysql/cdk/api/obj_ref.h b/cdk/include/mysql/cdk/api/obj_ref.h index 9f0ce2eaf..8c4747c44 100644 --- a/cdk/include/mysql/cdk/api/obj_ref.h +++ b/cdk/include/mysql/cdk/api/obj_ref.h @@ -47,7 +47,7 @@ class Ref_base { public: - virtual ~Ref_base() {} + virtual ~Ref_base() NOEXCEPT {} virtual const string name() const =0; virtual const string orig_name() const { return name(); } diff --git a/cdk/include/mysql/cdk/api/session.h b/cdk/include/mysql/cdk/api/session.h index 40dd4b9df..0460ef44b 100644 --- a/cdk/include/mysql/cdk/api/session.h +++ b/cdk/include/mysql/cdk/api/session.h @@ -44,7 +44,7 @@ class Session { public: - virtual ~Session() {} + virtual ~Session() NOEXCEPT {} // Check if given session is valid. Function is_valid() performs a lightweight, local check while // check_valid() might communicate with the data store to perform this check. diff --git a/cdk/include/mysql/cdk/codec.h b/cdk/include/mysql/cdk/codec.h index 2a37b0097..d960ee5b4 100644 --- a/cdk/include/mysql/cdk/codec.h +++ b/cdk/include/mysql/cdk/codec.h @@ -371,7 +371,7 @@ class Codec Codec(const Format_info &fi) : Codec_base(fi) {} - virtual ~Codec() {} + virtual ~Codec() NOEXCEPT {} virtual size_t from_bytes(bytes buf, float &val); virtual size_t from_bytes(bytes buf, double &val); diff --git a/cdk/include/mysql/cdk/common.h b/cdk/include/mysql/cdk/common.h index d0da13e60..1620175c4 100644 --- a/cdk/include/mysql/cdk/common.h +++ b/cdk/include/mysql/cdk/common.h @@ -414,7 +414,7 @@ class JSON_processor virtual void num(double) =0; virtual void yesno(bool) =0; - virtual ~JSON_processor() {} + virtual ~JSON_processor() NOEXCEPT {} }; typedef api::Doc_base JSON; diff --git a/cdk/include/mysql/cdk/data_source.h b/cdk/include/mysql/cdk/data_source.h index 99ae17eb3..420cefda6 100644 --- a/cdk/include/mysql/cdk/data_source.h +++ b/cdk/include/mysql/cdk/data_source.h @@ -52,7 +52,7 @@ namespace ds { struct Attr_processor { - virtual ~Attr_processor() {} + virtual ~Attr_processor() NOEXCEPT {} virtual void attr(const string &key, const string &val)=0; }; @@ -90,7 +90,7 @@ class Options } } - virtual ~Options() {} + virtual ~Options() NOEXCEPT {} virtual const string& user() const { return m_usr; } virtual const std::string* password() const @@ -171,7 +171,7 @@ class TCPIP throw_error("invalid empty host name"); } - virtual ~TCPIP() {} + virtual ~TCPIP() NOEXCEPT {} virtual unsigned short port() const { return m_port; } virtual const std::string& host() const { return m_host; } @@ -346,7 +346,7 @@ class Unix_socket throw_error("invalid empty socket path"); } - virtual ~Unix_socket() {} + virtual ~Unix_socket() NOEXCEPT {} virtual const std::string& path() const { return m_path; } }; @@ -386,7 +386,7 @@ class TCPIP : public cdk::ds::mysqlx::TCPIP : cdk::ds::mysqlx::TCPIP(_host, _port) {} - virtual ~TCPIP() {} + virtual ~TCPIP() NOEXCEPT {} typedef ds::Options Options; }; diff --git a/cdk/include/mysql/cdk/foundation/async.h b/cdk/include/mysql/cdk/foundation/async.h index 482cbdf2b..1bad184b4 100644 --- a/cdk/include/mysql/cdk/foundation/async.h +++ b/cdk/include/mysql/cdk/foundation/async.h @@ -50,7 +50,7 @@ class Async_op_base : nocopy { public: - virtual ~Async_op_base() {} + virtual ~Async_op_base() NOEXCEPT {} virtual bool is_completed() const =0; diff --git a/cdk/include/mysql/cdk/foundation/codec.h b/cdk/include/mysql/cdk/foundation/codec.h index 8310bb6ae..40314c0f9 100644 --- a/cdk/include/mysql/cdk/foundation/codec.h +++ b/cdk/include/mysql/cdk/foundation/codec.h @@ -71,7 +71,7 @@ class String_codec { public: - virtual ~String_codec() {} + virtual ~String_codec() NOEXCEPT {} //virtual size_t measure(const string&) =0; virtual size_t from_bytes(bytes, string&) =0; @@ -165,7 +165,7 @@ class Number_codec { public: - virtual ~Number_codec() {} + virtual ~Number_codec() NOEXCEPT {} virtual size_t from_bytes(bytes buf, int8_t &val) =0; virtual size_t from_bytes(bytes buf, int16_t &val) =0; @@ -220,8 +220,14 @@ static size_t convert(bytes buf, T &val) /* If buf size is smaller than sizeof(T), convert 1,2,4 or 8 initial bytes from the buffer: as much as fits into T. + + Note: We check here that buffer size is big enough to store given amount + of bytes but compilers still complain under -Warray-bounds (seen on + Solaris with gcc 11.4). */ +PUSH_ARRAY_BOUNDS_WARNING_CDK + if (buf.size() >= sizeof(T)) { val= *(T*)buf.begin(); @@ -252,6 +258,8 @@ static size_t convert(bytes buf, T &val) return 1; } +POP_ARRAY_BOUNDS_WARNING_CDK + // TODO: better error description throw_error(cdkerrc::conversion_error, "Number_codec: no data for conversion"); diff --git a/cdk/include/mysql/cdk/foundation/common.h b/cdk/include/mysql/cdk/foundation/common.h index c13abca42..0ec552799 100644 --- a/cdk/include/mysql/cdk/foundation/common.h +++ b/cdk/include/mysql/cdk/foundation/common.h @@ -42,7 +42,7 @@ #define DIAGNOSTIC_PUSH_CDK PRAGMA_CDK(warning (push)) #define DIAGNOSTIC_POP_CDK PRAGMA_CDK(warning (pop)) -#elif defined __GNUC__ || defined __clang__ +#elif defined __GNUC__ || defined __clang__ #define PRAGMA_CDK(X) _Pragma(#X) #define DISABLE_WARNING_CDK(W) PRAGMA_CDK(GCC diagnostic ignored #W) @@ -113,6 +113,25 @@ #define POP_SYS_WARNINGS_CDK DIAGNOSTIC_POP_CDK +/* + Macros to disable false positives from -Warray-bounds checks for lines + of code that were manually verified to be correct. +*/ + +#ifdef _MSC_VER + +#define PUSH_ARRAY_BOUNDS_WARNING_CDK DIAGNOSTIC_PUSH_CDK +#define POP_ARRAY_BOUNDS_WARNING_CDK DIAGNOSTIC_POP_CDK + +#else + +#define PUSH_ARRAY_BOUNDS_WARNING_CDK \ + DIAGNOSTIC_PUSH_CDK DISABLE_WARNING_CDK(-Warray-bounds) +#define POP_ARRAY_BOUNDS_WARNING_CDK DIAGNOSTIC_POP_CDK + +#endif + + // Avoid warnings from Protobuf includes #if defined _MSC_VER diff --git a/cdk/include/mysql/cdk/foundation/connection_tcpip.h b/cdk/include/mysql/cdk/foundation/connection_tcpip.h index 927c900c4..00a996719 100644 --- a/cdk/include/mysql/cdk/foundation/connection_tcpip.h +++ b/cdk/include/mysql/cdk/foundation/connection_tcpip.h @@ -107,7 +107,7 @@ class IO_error : public Error_class : Error_base(NULL, io_error(num)) {} - virtual ~IO_error() throw() {} + virtual ~IO_error() NOEXCEPT {} }; diff --git a/cdk/include/mysql/cdk/foundation/diagnostics.h b/cdk/include/mysql/cdk/foundation/diagnostics.h index 37ce41427..76abd671d 100644 --- a/cdk/include/mysql/cdk/foundation/diagnostics.h +++ b/cdk/include/mysql/cdk/foundation/diagnostics.h @@ -223,7 +223,7 @@ class Diagnostic_iterator : public api::Diagnostics::Iterator : m_entries(NULL), m_level(Severity::ERROR) {} - virtual ~Diagnostic_iterator() {} + virtual ~Diagnostic_iterator() NOEXCEPT {} const Entry& entry() { @@ -265,8 +265,10 @@ class Diagnostic_arena : m_it(m_entries, Severity::ERROR) {} - virtual ~Diagnostic_arena() - { clear(); } + virtual ~Diagnostic_arena() NOEXCEPT + { + try { clear(); } catch (...) {} + } /* diff --git a/cdk/include/mysql/cdk/foundation/error_category.h b/cdk/include/mysql/cdk/foundation/error_category.h index b38128c39..0d23c5c1c 100644 --- a/cdk/include/mysql/cdk/foundation/error_category.h +++ b/cdk/include/mysql/cdk/foundation/error_category.h @@ -144,7 +144,7 @@ const error_category& posix_error_category(); struct error_category_##EC : public cdk::foundation::error_category_base \ { \ error_category_##EC() {} \ - const char* name() const throw() { return "cdk-" #EC; } \ + const char* name() const NOEXCEPT { return "cdk-" #EC; } \ std::string message(int code) const \ { CDK_ERROR_SWITCH(NS, EC, code); } \ cdk::foundation::error_condition do_default_error_condition(int) const; \ diff --git a/cdk/include/mysql/cdk/foundation/opaque_impl.h b/cdk/include/mysql/cdk/foundation/opaque_impl.h index d074856c9..0f5d6fbc6 100644 --- a/cdk/include/mysql/cdk/foundation/opaque_impl.h +++ b/cdk/include/mysql/cdk/foundation/opaque_impl.h @@ -171,7 +171,7 @@ class opaque_impl protected: - virtual ~opaque_impl(); + virtual ~opaque_impl() NOEXCEPT; // Default constructor: uses default constructor of internal implementation type. diff --git a/cdk/include/mysql/cdk/foundation/opaque_impl.i b/cdk/include/mysql/cdk/foundation/opaque_impl.i index e62fda1c6..0ab2ffd40 100644 --- a/cdk/include/mysql/cdk/foundation/opaque_impl.i +++ b/cdk/include/mysql/cdk/foundation/opaque_impl.i @@ -129,7 +129,7 @@ namespace foundation { namespace cdk { \ namespace foundation { \ template<> \ - opaque_impl::~opaque_impl() { delete m_impl; } \ + opaque_impl::~opaque_impl() NOEXCEPT { delete m_impl; } \ }} // cdk::foundation #define IMPL_DEFAULT(X) \ diff --git a/cdk/include/mysql/cdk/foundation/stream.h b/cdk/include/mysql/cdk/foundation/stream.h index 1d2a6c037..f0533e22c 100644 --- a/cdk/include/mysql/cdk/foundation/stream.h +++ b/cdk/include/mysql/cdk/foundation/stream.h @@ -75,7 +75,7 @@ class Connection , public Output_stream { public: - virtual ~Connection() {} + virtual ~Connection() NOEXCEPT {} virtual void connect() =0; virtual void close() =0; virtual bool is_closed() const =0; diff --git a/cdk/include/mysql/cdk/foundation/variant.h b/cdk/include/mysql/cdk/foundation/variant.h index 03a105963..b7dcaa993 100644 --- a/cdk/include/mysql/cdk/foundation/variant.h +++ b/cdk/include/mysql/cdk/foundation/variant.h @@ -356,9 +356,9 @@ class variant return *this; } - ~variant() + ~variant() NOEXCEPT { - Base::destroy(); + try { Base::destroy(); } catch (...) {} } operator bool() diff --git a/cdk/include/mysql/cdk/mysqlx/common.h b/cdk/include/mysql/cdk/mysqlx/common.h index a1fd64e8b..9d7aa1f54 100644 --- a/cdk/include/mysql/cdk/mysqlx/common.h +++ b/cdk/include/mysql/cdk/mysqlx/common.h @@ -95,13 +95,13 @@ class Server_error typedef protocol::mysqlx::sql_state_t sql_state_t; - Server_error(unsigned num, sql_state_t, const string& desc = string()) throw() + Server_error(unsigned num, sql_state_t, const string& desc = string()) NOEXCEPT : Error_base(NULL, server_error(static_cast(num)), desc) { assert(num < (unsigned)std::numeric_limits::max()); } - virtual ~Server_error() throw() {} + virtual ~Server_error() NOEXCEPT {} }; @@ -115,7 +115,7 @@ class Server_prepare_error Server_prepare_error( unsigned num, sql_state_t sql_state, const string& desc = string() - ) throw() + ) NOEXCEPT : Error_base(NULL, num, sql_state , desc) {} }; @@ -128,7 +128,7 @@ class Server_expectation_error typedef protocol::mysqlx::sql_state_t sql_state_t; - Server_expectation_error(const string& desc) throw() + Server_expectation_error(const string& desc) NOEXCEPT : Error_base(NULL, 5168, sql_state_t("HY000") , desc) {} }; diff --git a/cdk/include/mysql/cdk/mysqlx/result.h b/cdk/include/mysql/cdk/mysqlx/result.h index ad4c5ebfe..0ffbaf016 100644 --- a/cdk/include/mysql/cdk/mysqlx/result.h +++ b/cdk/include/mysql/cdk/mysqlx/result.h @@ -446,12 +446,21 @@ class Stmt_op assert(m_session); } - virtual ~Stmt_op() + virtual ~Stmt_op() NOEXCEPT { - discard(); - wait(); - if (m_session) - m_session->deregister_stmt(this); + try + { + discard(); + wait(); + } + catch (...) {} + + try + { + if (m_session) + m_session->deregister_stmt(this); + } + catch (...) {} } Session& get_session() @@ -812,7 +821,7 @@ class Cursor public: Cursor(const std::shared_ptr &reply); - ~Cursor(); + ~Cursor() NOEXCEPT; void get_rows(mysqlx::Row_processor& rp); void get_rows(mysqlx::Row_processor& rp, row_count_t limit); diff --git a/cdk/include/mysql/cdk/mysqlx/session.h b/cdk/include/mysql/cdk/mysqlx/session.h index 6f9b5752d..85b8d962d 100755 --- a/cdk/include/mysql/cdk/mysqlx/session.h +++ b/cdk/include/mysql/cdk/mysqlx/session.h @@ -148,7 +148,7 @@ class SessionAuth public: SessionAuth(Session&, const char *method); - virtual ~SessionAuth() {} + virtual ~SessionAuth() NOEXCEPT {} /* Authentication data to be sent in the AuthenticateStart message, @@ -294,7 +294,7 @@ class Session */ Compression_type::value negotiate_compression(const std::vector& algorithms); - virtual ~Session(); + virtual ~Session() NOEXCEPT; /* Check if given session is valid. Function is_valid() performs diff --git a/cdk/include/mysql/cdk/protocol/mysqlx.h b/cdk/include/mysql/cdk/protocol/mysqlx.h index 18f345538..f10da5ca6 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx.h @@ -799,7 +799,7 @@ class Protocol::Stream Stream() {} - virtual ~Stream() + virtual ~Stream() NOEXCEPT {} virtual Op* read(const buffers&) =0; @@ -919,7 +919,7 @@ class Processor_base { public: - virtual ~Processor_base(){} + virtual ~Processor_base() NOEXCEPT {} typedef protocol::mysqlx::byte byte; typedef protocol::mysqlx::string string; @@ -1214,7 +1214,7 @@ class Update_processor virtual void target_path(const api::Doc_path&) = 0; virtual Expr_prc* update_op(update_op::value ) = 0; - virtual ~Update_processor() {} + virtual ~Update_processor() NOEXCEPT {} }; class Update_spec @@ -1282,7 +1282,7 @@ class Db_obj : public api::Db_obj return *this; } - virtual ~Db_obj() {} + virtual ~Db_obj() NOEXCEPT {} virtual const string& get_name() const { return m_name; }; diff --git a/cdk/include/mysql/cdk/protocol/mysqlx/expr.h b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h index cda39ee10..43c8cbdfa 100644 --- a/cdk/include/mysql/cdk/protocol/mysqlx/expr.h +++ b/cdk/include/mysql/cdk/protocol/mysqlx/expr.h @@ -244,7 +244,7 @@ class Doc_path DOUBLE_ASTERISK = 5, }; - virtual ~Doc_path() {} + virtual ~Doc_path() NOEXCEPT {} // The "$" path which denotes the whole document. virtual bool is_whole_document() const = 0; diff --git a/cdk/include/mysql/cdk/session.h b/cdk/include/mysql/cdk/session.h index 6bd5e237c..bde0c3f2e 100644 --- a/cdk/include/mysql/cdk/session.h +++ b/cdk/include/mysql/cdk/session.h @@ -78,7 +78,7 @@ class Session const ds::Unix_socket::Options &options = ds::Unix_socket::Options()); #endif //_WIN32 - ~Session(); + ~Session() NOEXCEPT; // Core Session operations. diff --git a/cdk/mysqlx/CMakeLists.txt b/cdk/mysqlx/CMakeLists.txt index aa358f039..871740b82 100644 --- a/cdk/mysqlx/CMakeLists.txt +++ b/cdk/mysqlx/CMakeLists.txt @@ -31,14 +31,6 @@ ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN -DNOGDI) ADD_DEFINITIONS(-DNOMINMAX) ADD_DEFINITIONS(-DSIZEOF_LONG=${SIZEOF_LONG} -DSIZEOF_LONG_LONG=${SIZEOF_LONG_LONG}) -# TODO: Fix compile warnings in auth_mysql41.cc - -if(MSVC) - set_property(SOURCE auth_hash.cc - PROPERTY COMPILE_FLAGS "/W3" - ) -endif() - file(GLOB HEADERS *.h) ADD_LIBRARY(cdk_mysqlx STATIC diff --git a/cdk/mysqlx/converters.h b/cdk/mysqlx/converters.h index 3d378aa40..0e61c1a99 100644 --- a/cdk/mysqlx/converters.h +++ b/cdk/mysqlx/converters.h @@ -243,7 +243,7 @@ struct Expr_prc_converter_base //using Base::reset; //using Base::m_proc; - virtual ~Expr_prc_converter_base() {} + virtual ~Expr_prc_converter_base() NOEXCEPT {} Scalar_prc_converter m_scalar_conv; Args_prc* get_args_converter(Args_prc_to*); diff --git a/cdk/mysqlx/result.cc b/cdk/mysqlx/result.cc index 474e0c0e7..11bab8468 100644 --- a/cdk/mysqlx/result.cc +++ b/cdk/mysqlx/result.cc @@ -552,9 +552,9 @@ Cursor::Cursor(const std::shared_ptr &reply) } -Cursor::~Cursor() +Cursor::~Cursor() NOEXCEPT { - close(); + try { close(); } catch (...) {} } diff --git a/cdk/mysqlx/session.cc b/cdk/mysqlx/session.cc index 414d01ea2..fd97f7a89 100644 --- a/cdk/mysqlx/session.cc +++ b/cdk/mysqlx/session.cc @@ -660,7 +660,7 @@ void Session::authenticate(const Options &options, bool secure_conn) } -Session::~Session() +Session::~Session() NOEXCEPT { //TODO: add timeout to close session! try @@ -668,10 +668,7 @@ Session::~Session() close(); } catch (...) - { - // Something went wrong - do not try to use this session again. - m_isvalid = false; - } + {} } diff --git a/cdk/mysqlx/stmt.h b/cdk/mysqlx/stmt.h index c4f7176a7..4b265ff12 100644 --- a/cdk/mysqlx/stmt.h +++ b/cdk/mysqlx/stmt.h @@ -125,10 +125,15 @@ class Expectation } - ~Expectation() + ~Expectation() NOEXCEPT { - Base::discard(); - Base::wait(); + try + { + Base::discard(); + Base::wait(); + } + catch (...) + {} } @@ -791,7 +796,7 @@ class Order_prc_converter public: - virtual ~Order_prc_converter() {} + virtual ~Order_prc_converter() NOEXCEPT {} Expr_prc* sort_key(Sort_direction::value dir) { @@ -855,7 +860,7 @@ class Cmd_Select {} - virtual ~Cmd_Select() + virtual ~Cmd_Select() NOEXCEPT {} @@ -989,7 +994,7 @@ class Table_proj_prc_converter public: - virtual ~Table_proj_prc_converter() {} + virtual ~Table_proj_prc_converter() NOEXCEPT {} }; @@ -1125,7 +1130,7 @@ struct String_to_col_prc_converter m_proc->name(col); } - virtual ~String_to_col_prc_converter() + virtual ~String_to_col_prc_converter() NOEXCEPT {} }; @@ -1290,7 +1295,7 @@ class Cmd_ViewCrud view.process(*this); } - ~Cmd_ViewCrud() + ~Cmd_ViewCrud() NOEXCEPT { delete m_find; } @@ -1379,7 +1384,7 @@ class Update_prc_converter bool m_has_schema; string m_schema_name; - virtual ~Table() {} + virtual ~Table() NOEXCEPT {} //DB_OBJ const string& get_name() const @@ -1396,7 +1401,7 @@ class Update_prc_converter public: - virtual ~Update_prc_converter() {} + virtual ~Update_prc_converter() NOEXCEPT {} void set_data_model(cdk::protocol::mysqlx::Data_model dm) { diff --git a/cdk/protocol/mysqlx/builders.h b/cdk/protocol/mysqlx/builders.h index 36f7b3b20..d6f303a9e 100644 --- a/cdk/protocol/mysqlx/builders.h +++ b/cdk/protocol/mysqlx/builders.h @@ -285,7 +285,7 @@ struct Builder_base m_args_conv = conv; } - virtual ~Builder_base() {} + virtual ~Builder_base() NOEXCEPT {} }; @@ -1148,7 +1148,7 @@ class Placeholder_conv_imp unsigned m_offset = 0; public: - virtual ~Placeholder_conv_imp() {} + virtual ~Placeholder_conv_imp() NOEXCEPT {} void clear() { diff --git a/cdk/protocol/mysqlx/crud.cc b/cdk/protocol/mysqlx/crud.cc index 30bb27103..b3171d97b 100644 --- a/cdk/protocol/mysqlx/crud.cc +++ b/cdk/protocol/mysqlx/crud.cc @@ -708,9 +708,8 @@ class Update_builder , m_conv(conv) {} - ~Update_builder() - { - } + ~Update_builder() NOEXCEPT + {} virtual void target_name(const string &name) { diff --git a/cdk/protocol/mysqlx/protocol.cc b/cdk/protocol/mysqlx/protocol.cc index e09e416cc..6c5994305 100644 --- a/cdk/protocol/mysqlx/protocol.cc +++ b/cdk/protocol/mysqlx/protocol.cc @@ -163,7 +163,7 @@ Protocol_impl::Protocol_impl(Protocol::Stream *str, Protocol_side side) } -Protocol_impl::~Protocol_impl() +Protocol_impl::~Protocol_impl() NOEXCEPT { free(m_rd_buf); free(m_wr_buf); diff --git a/cdk/protocol/mysqlx/protocol.h b/cdk/protocol/mysqlx/protocol.h index b22939946..cfdf9d653 100644 --- a/cdk/protocol/mysqlx/protocol.h +++ b/cdk/protocol/mysqlx/protocol.h @@ -162,7 +162,7 @@ class Protocol_impl : public Processor_base protected: Protocol_impl(Protocol::Stream*, Protocol_side); - virtual ~Protocol_impl(); + virtual ~Protocol_impl() NOEXCEPT; public: @@ -973,12 +973,14 @@ class Msg_builder } } - ~Msg_builder() + ~Msg_builder() NOEXCEPT { if (m_stmt_id != 0) + try { Prepare_traits::release(m_prepare); } + catch (...) {} } diff --git a/cdk/protocol/mysqlx/protocol_compression.cc b/cdk/protocol/mysqlx/protocol_compression.cc index 95f38a1f2..ae3f18df6 100644 --- a/cdk/protocol/mysqlx/protocol_compression.cc +++ b/cdk/protocol/mysqlx/protocol_compression.cc @@ -137,7 +137,7 @@ size_t Compression_zlib::uncompress(byte *dst, } -Compression_zlib::~Compression_zlib() +Compression_zlib::~Compression_zlib() NOEXCEPT { if (m_zlib_inited) { @@ -256,7 +256,7 @@ size_t Compression_lz4::uncompress(byte *dst, } -Compression_lz4::~Compression_lz4() +Compression_lz4::~Compression_lz4() NOEXCEPT { if (m_dctx) LZ4F_freeDecompressionContext(m_dctx); @@ -338,7 +338,7 @@ size_t Compression_zstd::uncompress(byte *dst, } -Compression_zstd::~Compression_zstd() +Compression_zstd::~Compression_zstd() NOEXCEPT { if (m_u_zstd) ZSTD_freeDStream(m_u_zstd); @@ -456,7 +456,7 @@ void Protocol_compression::set_compression_type } -Protocol_compression::~Protocol_compression() +Protocol_compression::~Protocol_compression() NOEXCEPT { if (m_c_out_buf) free(m_c_out_buf); diff --git a/cdk/protocol/mysqlx/protocol_compression.h b/cdk/protocol/mysqlx/protocol_compression.h index a61b0f005..3a0f03047 100644 --- a/cdk/protocol/mysqlx/protocol_compression.h +++ b/cdk/protocol/mysqlx/protocol_compression.h @@ -67,7 +67,7 @@ class Compression_algorithm size_t compressed_size, size_t &bytes_consumed) = 0; - virtual ~Compression_algorithm() {} + virtual ~Compression_algorithm() NOEXCEPT {} }; @@ -88,7 +88,7 @@ class Compression_zlib : public Compression_algorithm size_t compress(byte *src, size_t len) override; size_t uncompress(byte *dst, size_t dest_size, size_t compressed_size, size_t &bytes_consumed) override; - ~Compression_zlib(); + ~Compression_zlib() NOEXCEPT; }; @@ -109,7 +109,7 @@ class Compression_lz4 : public Compression_algorithm size_t compress(byte *src, size_t len) override; size_t uncompress(byte *dst, size_t dest_size, size_t compressed_size, size_t &bytes_consumed) override; - ~Compression_lz4(); + ~Compression_lz4() NOEXCEPT; }; @@ -129,7 +129,7 @@ class Compression_zstd : public Compression_algorithm size_t compress(byte *src, size_t len) override; size_t uncompress(byte *dst, size_t dest_size, size_t compressed_size, size_t &bytes_consumed) override; - ~Compression_zstd(); + ~Compression_zstd() NOEXCEPT; }; @@ -159,7 +159,7 @@ class Protocol_compression Protocol_compression(); - ~Protocol_compression(); + ~Protocol_compression() NOEXCEPT; /* Returns pointer to internal buffer for compressed input diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 587340e3e..2114b6ede 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -29,6 +29,26 @@ file(GLOB HEADERS *.h) +#TODO: Remove -Wno-delete-non-abstract-non-virtual-dtor when bumping ABI and +# adding virtual destructor for DbDoc, Value and Column_detail + +if(CLANG) + +set_compiler_flag(-Wno-delete-non-abstract-non-virtual-dtor) + + # Note: GCC/clang and MSVC compilers have different rules for resolving + # relative paths in #include "..." directives [1]. The clang-cl compiler + # understands both conventions but gives warning when using MSVC rules. Since + # headers included by this code trigger the warning we disable it here (this + # is about version_info.h included from nysqlx/common_constants.h) + # + # [1] https://stackoverflow.com/questions/48538707/include-search-paths-from-included-header-varies-for-different-compilers + + set_compiler_flag(-Wno-microsoft-include) + +endif() + + add_library(common STATIC session.cc result.cc collection.cc value.cc ${HEADERS} @@ -36,13 +56,6 @@ add_library(common STATIC target_link_libraries(common cdk) -#TODO: Remove -Wno-delete-non-abstract-non-virtual-dtor when bumping ABI and - # adding virtual destructor for DbDoc, Value and Column_detail -if(CLANG) - target_compile_options(common PRIVATE - -Wno-delete-non-abstract-non-virtual-dtor - ) -endif() # # Note: generated version_info.h is placed in the build location diff --git a/common/op_impl.h b/common/op_impl.h index 86a0bf281..0c1d0d66b 100644 --- a/common/op_impl.h +++ b/common/op_impl.h @@ -141,11 +141,15 @@ class Op_base virtual ~Op_base() override { - // Let's aquire lock so that any remaingin replies are consumed on ~Reply - // and this way avoid race conditions with Client::close() - auto lock = m_sess->lock(); - release_stmt_id(); - m_reply.reset(); + try { + // Let's aquire lock so that any remaingin replies are consumed on ~Reply + // and this way avoid race conditions with Client::close() + auto lock = m_sess->lock(); + release_stmt_id(); + m_reply.reset(); + } + catch (...) + {} } cdk::Session& get_cdk_session() diff --git a/common/tests/CMakeLists.txt b/common/tests/CMakeLists.txt index a70e13164..aac020043 100644 --- a/common/tests/CMakeLists.txt +++ b/common/tests/CMakeLists.txt @@ -36,14 +36,6 @@ set_property( PROPERTY COMPILE_DEFINITIONS "" ) -if(WIN32) - add_definitions( - -D_CRT_SECURE_NO_WARNINGS - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - ) - -endif() - #Add cdk includes because we are using their source tests add_test_includes(${PROJECT_SOURCE_DIR}/cdk/include) add_test_includes(${PROJECT_SOURCE_DIR}/cdk/extra/rapidjson/include) diff --git a/devapi/impl.h b/devapi/impl.h index e1056fa25..351e6a55a 100644 --- a/devapi/impl.h +++ b/devapi/impl.h @@ -369,7 +369,7 @@ class DbDoc::Impl friend Value::Access; public: - virtual ~Impl(){} + virtual ~Impl() NOEXCEPT {} }; diff --git a/devapi/result.cc b/devapi/result.cc index 9bd8d0f26..ca940490c 100644 --- a/devapi/result.cc +++ b/devapi/result.cc @@ -488,7 +488,7 @@ Result_detail::Result_detail(Result_init &init) } -Result_detail::~Result_detail() +Result_detail::~Result_detail() NOEXCEPT { try { if (m_owns_impl) diff --git a/devapi/session.cc b/devapi/session.cc index 7e8bc75af..6bf853836 100644 --- a/devapi/session.cc +++ b/devapi/session.cc @@ -370,7 +370,7 @@ mysqlx::string Session_detail::get_default_schema_name() */ -Query_src::~Query_src() +Query_src::~Query_src() NOEXCEPT { delete m_res; } diff --git a/devapi/tests/CMakeLists.txt b/devapi/tests/CMakeLists.txt index 6c71501d4..d1201867f 100644 --- a/devapi/tests/CMakeLists.txt +++ b/devapi/tests/CMakeLists.txt @@ -38,13 +38,6 @@ set_property( PROPERTY COMPILE_DEFINITIONS "" ) -if(WIN32) - add_definitions( - -D_CRT_SECURE_NO_WARNINGS - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - ) - -endif() # # If linking with connector statically, define macro that indicates this diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg index 63094ffb6..495d48568 100644 --- a/doc/doxygen.cfg +++ b/doc/doxygen.cfg @@ -75,7 +75,7 @@ PROJECT_NAME = "MySQL Connector/C++" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 9.1.0 +PROJECT_NUMBER = 9.3.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/usage.txt b/doc/usage.txt index 2f6d9cb58..cc331857b 100644 --- a/doc/usage.txt +++ b/doc/usage.txt @@ -6,7 +6,7 @@ uses Connector/C++ it is enough to link that target with the `mysql::concpp` target defined after loading the `mysql-concpp` module into the project, as in this example: ~~~~~~ - find_module(mysql-concpp REQUIRED) + find_package(mysql-concpp REQUIRED) add_executable(my-target ...) target_link_libraries(my-target mysql::concpp) @@ -14,14 +14,14 @@ in this example: This ensures correct compiler and linker flags when building `my-target` so that connector public headers, the libraries and their dependencies are found when compiling and linking the target. See the CMake documentation -for more information on `find_module()` command and on using CMake modules. +for more information on `find_package()` command and on using CMake modules. We focus here on the scenario where Connector/C++ is installed from a package published by MySQL. There are two variants of this scenario. Either the connector is installed system-wide via package manager such as RPM or DEB, or it is installed locally from TGZ or ZIP package. In case of system-wide installation connector components are installed to default locations and things -are expected to work out-of-the-box. In this case `find_module(mysql-concpp)` +are expected to work out-of-the-box. In this case `find_package(mysql-concpp)` command should work without any further configuration. In case of local installation you need to tell CMake where to look for @@ -29,7 +29,7 @@ the `mysql-concpp` module. This can be done by setting the `mysql-concpp_DIR` variable to the top-level Connector/C++ install location: ~~~~~~ set(mysql-concpp_DIR "/path/to/concpp/install") - find_module(mysql-concpp) + find_package(mysql-concpp) ~~~~~~ (Alternatively the variable can be set when invoking `cmake` using `-Dmysql-concpp_DIR=/path/to/concpp/install` option). @@ -193,7 +193,7 @@ When loading the `mysql-concpp` module a "debug" component can be required so that cmake will report error if debug variants of connector libraries are not found: ~~~~~~ - find_module(mysql-concpp REQUIRE debug) + find_package(mysql-concpp REQUIRE debug) ~~~~~~ Regardless of whether the "debug" component was required or not, the module will set variable `MYSQL_CONCPP_DEBUG_FOUND` to true if debug libraries were @@ -218,7 +218,7 @@ For example: find_package(mysql-concpp) ~~~~ Note that `mysql::openssl` target must be defined before invoking -`find_module(mysql-concpp)` in order to replace the default OpenSSL instance +`find_package(mysql-concpp)` in order to replace the default OpenSSL instance used by the module. diff --git a/include/mysqlx/common.h b/include/mysqlx/common.h index a52429d45..ac97ea710 100644 --- a/include/mysqlx/common.h +++ b/include/mysqlx/common.h @@ -44,6 +44,8 @@ kept in the common/ folder, either as headers or source files. */ +#define NOEXCEPT noexcept + #include "common_constants.h" #include "common/api.h" #include "common/error.h" diff --git a/include/mysqlx/common/op_if.h b/include/mysqlx/common/op_if.h index b17cb7bad..685a43342 100644 --- a/include/mysqlx/common/op_if.h +++ b/include/mysqlx/common/op_if.h @@ -100,7 +100,7 @@ struct Executable_if virtual Executable_if *clone() const = 0; - virtual ~Executable_if() {} + virtual ~Executable_if() NOEXCEPT {} }; diff --git a/include/mysqlx/devapi/detail/result.h b/include/mysqlx/devapi/detail/result.h index ad64dc7b7..83be19583 100644 --- a/include/mysqlx/devapi/detail/result.h +++ b/include/mysqlx/devapi/detail/result.h @@ -94,7 +94,7 @@ class PUBLIC_API Result_detail Result_detail& operator=(Result_detail&&); Result_detail() = default; - virtual ~Result_detail(); + virtual ~Result_detail() NOEXCEPT; Impl& get_impl(); diff --git a/include/mysqlx/devapi/detail/session.h b/include/mysqlx/devapi/detail/session.h index cf4f6d426..b15087062 100644 --- a/include/mysqlx/devapi/detail/session.h +++ b/include/mysqlx/devapi/detail/session.h @@ -85,7 +85,7 @@ class PUBLIC_API Db_obj_base : m_sess(sess), m_name(name) {} - virtual ~Db_obj_base() + virtual ~Db_obj_base() NOEXCEPT {} }; @@ -144,7 +144,7 @@ struct PUBLIC_API Query_src Query_src(const Query_src&) = delete; - virtual ~Query_src(); + virtual ~Query_src() NOEXCEPT; virtual void iterator_start() { @@ -247,6 +247,9 @@ using SQL_statement_cmd = Executable; struct SQL_statement : public Bind_placeholders< SQL_statement_cmd > { + ~SQL_statement() NOEXCEPT + {} + SQL_statement(Session *sess, const string &query) { assert(sess); @@ -372,7 +375,7 @@ struct PUBLIC_API Session_detail Session_detail(common::Settings_impl&); Session_detail(common::Shared_session_pool&); - virtual ~Session_detail() + virtual ~Session_detail() NOEXCEPT { try { if (m_impl) diff --git a/include/mysqlx/devapi/document.h b/include/mysqlx/devapi/document.h index 442dab71c..95c29358f 100644 --- a/include/mysqlx/devapi/document.h +++ b/include/mysqlx/devapi/document.h @@ -360,6 +360,7 @@ class Value CATCH_AND_WRAP } + virtual ~Value() {} public: diff --git a/include/mysqlx/devapi/executable.h b/include/mysqlx/devapi/executable.h index 22f7e763a..2d0fb0536 100644 --- a/include/mysqlx/devapi/executable.h +++ b/include/mysqlx/devapi/executable.h @@ -121,7 +121,7 @@ class Executable operator=(std::move(other)); } - virtual ~Executable() {} + virtual ~Executable() NOEXCEPT {} Executable& operator=(const Executable &other) diff --git a/include/mysqlx/devapi/result.h b/include/mysqlx/devapi/result.h index 3c9e4f971..904636e74 100644 --- a/include/mysqlx/devapi/result.h +++ b/include/mysqlx/devapi/result.h @@ -484,6 +484,9 @@ class Column public: + virtual ~Column() + {} + friend RowResult; struct INTERNAL Access; friend Access; diff --git a/jdbc/CMakeLists.txt b/jdbc/CMakeLists.txt index 60e36e42d..11fc3e4e1 100644 --- a/jdbc/CMakeLists.txt +++ b/jdbc/CMakeLists.txt @@ -215,10 +215,8 @@ if(NOT SHOW_JDBC_WARNINGS) else() - add_compile_options( - -Wno-unused-parameter - -Wno-deprecated-declarations - ) + set_compiler_flag(-Wno-unused-parameter) + set_compiler_flag(-Wno-deprecated-declarations) endif() @@ -266,25 +264,12 @@ add_version_info(connector-jdbc "Implements MySQL Connector/C++ legacy JDBC API." ) +# Note: The MySQL::client target works (and is needed) both when linking +# to the MySQL client library dynamically and statically. In the latter case +# it brings additional linker options that are required (e.g. to resolve +# dependencies of the client library code). - -# Note: When connector links statically to the client library, targets using -# the connector must be able to find dependencies of the client library, such -# as openssl libs. The MYSQL_EXTERNAL_SEARCHPATH variable set by DepFindMySQL. -# cmake stores detected locations where client library dependencies that -# are bundled with it can be found. We add it here as interface property -# so that other targets that link with the connector will have library search -# path correctly set in the compile line. -# -# TODO: Modify merge_libraries() logic to autmatically detect transitive link -# directory path properties of merged targets and then set them on the merged -# library target. - -if(MYSQLCLIENT_STATIC_LINKING) - target_link_directories(connector-jdbc INTERFACE - ${MYSQL_EXTERNAL_SEARCHPATH} - ) -endif() +target_link_libraries(connector-jdbc PUBLIC MySQL::client) # @@ -573,6 +558,18 @@ function(bundle_lib lib) DESTINATION "${INSTALL_LIB_DIR}" COMPONENT JDBCDll ) + # Symlinks need to be created to allow authenticating + # plugins to load dependencies in MacOS + # + # NOTE: in Linux the dependencies are adressed in + # a different way + install(CODE " + execute_process( + COMMAND ${CMAKE_COMMAND} -E create_symlink ../${lib_name} ${lib_name} + WORKING_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/plugin\" + ) + ") + else() install(FILES ${lib} DESTINATION "${INSTALL_LIB_DIR}/private" @@ -663,6 +660,26 @@ macro(bundle_libs to_bundle ignored) endforeach() + if(APPLE) + # Create symlinks for OpenSSL dependencies in MacOS. + # The actual OpenSSL libraries should already be + # installed with XDevAPI connector. + # Other dependencies such as fido2 already have symlinks + # created at this stage. + install(CODE " + foreach(openssl_lib ssl crypto) + file(GLOB found_libs \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/lib\${openssl_lib}.*dylib\") + foreach(lib_file \${found_libs}) + get_filename_component(openssl_lib_name \${lib_file} NAME) + execute_process( + COMMAND ${CMAKE_COMMAND} -E create_symlink ../\${openssl_lib_name} \${openssl_lib_name} + WORKING_DIRECTORY \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${INSTALL_LIB_DIR}/plugin\" + ) + endforeach(lib_file) + endforeach(openssl_lib) + ") + endif() + endmacro(bundle_libs) diff --git a/jdbc/cmake/DepFindMySQL.cmake b/jdbc/cmake/DepFindMySQL.cmake index 971bfd58c..c94b770cd 100644 --- a/jdbc/cmake/DepFindMySQL.cmake +++ b/jdbc/cmake/DepFindMySQL.cmake @@ -297,7 +297,6 @@ function(main) if(MYSQL_LIB_STATIC) target_link_libraries(mysql-client-if INTERFACE MySQL::client-static) - target_link_libraries(mysql-client-if INTERFACE OpenSSL::SSL) else() target_link_libraries(mysql-client-if INTERFACE MySQL::client-shared) endif() @@ -379,7 +378,7 @@ function(main) # # If external dependencies were found, add them to the static target - # as any code that liks to static library should also link with the + # as any code that links to static library should also link with the # external dependencies. # @@ -531,7 +530,8 @@ function(use_mysql_config) # option. if(NOT lib MATCHES - "(mysqlclient|libmysql|^stdc|^gcc|^CrunG3|^c$|^statomic|^ssl|^crypto)" + "(mysqlclient|libmysql|^stdc|^gcc|^CrunG3|^c$|^statomic)" + #|^ssl|^crypto)" ) list(APPEND MYSQL_EXTERNAL_DEPENDENCIES ${lib}) diff --git a/jdbc/cppconn/callback.h b/jdbc/cppconn/callback.h index af555326b..0ff7f3aa1 100644 --- a/jdbc/cppconn/callback.h +++ b/jdbc/cppconn/callback.h @@ -133,6 +133,8 @@ class WebAuthn_Callback ActionRequested(msg); } + virtual ~WebAuthn_Callback() {} + }; @@ -188,6 +190,8 @@ class Fido_Callback FidoActionRequested(msg); } + virtual ~Fido_Callback() {} + friend class mysql::MySQL_Connection; friend class mysql::MySQL_Driver; }; diff --git a/jdbc/cppconn/connection.h b/jdbc/cppconn/connection.h index 12ae59b97..7c4db2e3e 100644 --- a/jdbc/cppconn/connection.h +++ b/jdbc/cppconn/connection.h @@ -139,6 +139,7 @@ "OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE" #define OPT_OCI_CLIENT_CONFIG_PROFILE "OPT_OCI_CLIENT_CONFIG_PROFILE" #define OPT_OPENID_TOKEN_FILE "OPT_OPENID_TOKEN_FILE" +#define OPT_WEBAUTHN_DEVICE_NUMBER "OPT_WEBAUTHN_DEVICE_NUMBER" /* Telemetry options diff --git a/jdbc/driver/CMakeLists.txt b/jdbc/driver/CMakeLists.txt index 271077073..f9ffa2cc3 100755 --- a/jdbc/driver/CMakeLists.txt +++ b/jdbc/driver/CMakeLists.txt @@ -204,8 +204,11 @@ add_library(jdbc STATIC ${MYSQLCPPCONN_SOURCES}) IF(WIN32) target_link_libraries(jdbc PRIVATE Dnsapi) -ELSEIF(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - target_link_libraries(jdbc PRIVATE resolv) +ELSE() + target_link_libraries(jdbc PRIVATE pthread) + IF(NOT CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + target_link_libraries(jdbc PRIVATE resolv) + ENDIF() ENDIF() if (MYSQLCLIENT_STATIC_BINDING) diff --git a/jdbc/driver/mysql_connection.cpp b/jdbc/driver/mysql_connection.cpp index e233698fd..5b933d139 100644 --- a/jdbc/driver/mysql_connection.cpp +++ b/jdbc/driver/mysql_connection.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef HAVE_STDINT_H #include #endif @@ -96,10 +97,6 @@ #endif -bool oci_plugin_is_loaded = false; -bool openid_plugin_is_loaded = false; - - #ifdef DEFAULT_PLUGIN_DIR std::string default_plugin_dir(DEFAULT_PLUGIN_DIR); #else @@ -322,6 +319,16 @@ static const String2IntMap stringOptions[]= {OPT_LOAD_DATA_LOCAL_DIR, MYSQL_OPT_LOAD_DATA_LOCAL_DIR, false} }; +static const std::unordered_set stringPluginOptions = { + OPT_OCI_CONFIG_FILE, + OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE, + OPT_OCI_CLIENT_CONFIG_PROFILE, + OPT_OPENID_TOKEN_FILE +}; + +static const std::unordered_set intPluginOptions = { + OPT_WEBAUTHN_DEVICE_NUMBER +}; //Option conversion for libmysqlclient < 80011 @@ -429,130 +436,182 @@ struct Prio }; -/* - A callback setter object arranges for WebAuthn/Fido authentication - callbacks to be used by the WebAuthn clientlib authentication plugin. +sql::mysql::MySQL_Driver *MySQL_Connection::PluginGuard::callback_drv + = nullptr; + +MySQL_Connection::PluginGuard::state +MySQL_Connection::PluginGuard::webauthn_plugin_state + = state::NONE; + +MySQL_Connection::PluginGuard::PluginGuard(MySQL_Connection *c) +: prx{c->proxy} +{ + //assert(c); + if (!prx.expired()) + prx.lock()->lock_plugin(true); +} - If a user has registered a callback with a driver that creates a connection - then a callback function is registered with authentication plugin which will - call the callback stored in the driver. - The callback function registered with authentication plugin must be changed - depending on which driver is used to create a connection. A callback setter - object makes necessary changes when it detects that the current driver passed - to its ctor is different from the one used last time. +/* + This method arranges for the WebAuthN authentication plugin callback to be + set in agreement with the webauthn callback function specified by the given + driver: + + 1. If driver's callback is set then that callback should be called by + the plugin (if the plugin is used during authentication). - While exists, callback setter also prevents modification of authentication - plugin callbacks by concurrent threads. + 2. Otherwise, if there is no driver specific callback, the plugin should + use its default callback. */ -struct MySQL_Driver::WebAuthn_Callback_Setter +void MySQL_Connection::PluginGuard::register_webauthn_callback(MySQL_Driver &drv) { - using Proxy = NativeAPI::NativeConnectionWrapper; + std::string plugin = "authentication_webauthn_client"; + std::string opt = "plugin_authentication_webauthn_client_messages_callback"; + + if (prx.expired()) + return; + + auto proxy = prx.lock(); + + /* + Compute desired plugin state based on its current state nad driver settings. - WebAuthn_Callback_Setter(MySQL_Driver &drv, Proxy *prx) - : lock{mutex} + Returns NONE if plugin is already in correct state, DEFAULT if plugin's + default callback should be restored or CALLER if plugin should + be configured to call driver's callback. + */ + + auto target_state = [&]() -> state { /* - Note: Meaning of callback type value: + If no WebAuthN callback is registered in the driver but + the plugin was configured to call driver's callback + ( webauthn_plugin_state == CALLER ) we must reset plugin to use its + default callback. + + Note that nothing needs to be done if plugin is not loaded at the moment + ( webauthn_plugin_state == NONE ) because in that case if the plugin + is loaded during authentication it will use its default callback as + required. + */ - 0 or 3 = no callback - 1 or 4 = webauthn only callback - 2 or 5 = webauthn and fido callback + if (!drv.webauthn_callback && webauthn_plugin_state == state::CALLER) + return state::DEFAULT; - Values 3,4,5 indicate that the callback function has been already - (de-)registered with the plugin(s). + /* + If driver has a WebAuthN callback but the plugin is not configured + to call it ( webauthn_plugin_state != CALLER ) or the driver whose + callback would be called is not correct ( callback_drv != &drv ) we must + configure the plugin accordingly. */ - auto callback_type = reinterpret_cast(drv.fido_callback); + if ( + drv.webauthn_callback + && (webauthn_plugin_state != state::CALLER || callback_drv != &drv) + ) + return state::CALLER; + + // If neither of the above then the plugin is already in the correct state. + return state::NONE; + }; + + + try + { /* - Do nothing if we use the same driver as last time nad (de-)registration - was already done. + There is nothing to be done if the plugin is already correctly + configured. We also know that no concurrent thread that makes + a connection can change plugin configuration because to do so it would + need to first grab an exclusive plugin lock (see below) and that is + not possible while this thread holds a shared lock. */ - if ((2 < callback_type) && (driver == &drv)) + if (state::NONE == target_state()) return; - driver = &drv; // Set current driver. - /* - Note: A webauthn callback (callback_type 2 or 5) is registered with - "webauthn" plugin as well as fido callback (callback_type 1 or 4). - If user did not register any callback (callback_type 0 or 3) then - plugin callback is re-set to null. + Current plugin configuration is not as needed nad we must change it + accordingly. To do so we first grab an exclusive plugin lock to ensure + that we don't change the current plugin configuration while another + thread is making connection and relying on it. */ - register_callback(prx, (callback_type % 3) > 0); + proxy->lock_plugin_exclusive(); /* - Note: This will be reset to value 0-2 when user deregisters - the callback or registers a new one. + Note that while upgrading the lock to an exclusive one other threads can + get it before this thread and can change the plugin configuration that + was present during first `target_state()` call above. For that reason we + call `target_state()` again to re-evaluate the required changes and act + accordingly. */ - drv.fido_callback = reinterpret_cast(callback_type + 3); - } - - private: + switch (target_state()) + { + case state::DEFAULT: + { + /* + Note: setting callback option to nullptr restores plugin's default + callback. + */ + proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + plugin, opt, nullptr); + webauthn_plugin_state = state::DEFAULT; + } + break; - // The driver whose callback will be called by authentication plugins. + case state::CALLER: + { + proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + plugin, opt, (const void*)callback_caller); + callback_drv = &drv; + webauthn_plugin_state = state::CALLER; + } + break; - static sql::mysql::MySQL_Driver * driver; - /* - Callback function to be registered with authentication plugins. - If the current driver has a stored callback then it is being called. - */ + default: break; + } - static void callback_func(const char* msg) + /* + At this point we have plugin configured as required by the diver callback + settings and we know this will not change as long as we hold the plugin + lock. + */ + } + catch (sql::MethodNotImplementedException &) { - if (!driver || !driver->fido_callback) + // Note: Ignore errors when re-setting the callback + if(!drv.webauthn_callback) return; - driver->webauthn_callback(msg); - } - - static std::mutex mutex; - std::lock_guard lock; - static - void register_callback(Proxy *proxy, bool set_or_reset) + } + catch (sql::InvalidArgumentException &e) { - std::string plugin = "authentication_webauthn_client"; - std::string opt = "plugin_authentication_webauthn_client"; - - try - { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - plugin.c_str(), opt.c_str(), - set_or_reset ? (const void*)callback_func : nullptr - ); - } - catch (sql::MethodNotImplementedException &) - { - // Note: Ignore errors when re-setting the callback - - if(!set_or_reset) - return; - - } - catch (sql::InvalidArgumentException &e) - { - if(!set_or_reset) - return; - - throw ::sql::SQLException( - "Failed to set fido message callback for " - + plugin + " plugin"); - } - }; + if(!drv.webauthn_callback) + return; -}; + throw ::sql::SQLException( + "Failed to set fido message callback for " + + plugin + " plugin"); + } +} -std::mutex MySQL_Driver::WebAuthn_Callback_Setter::mutex; -sql::mysql::MySQL_Driver *MySQL_Driver::WebAuthn_Callback_Setter::driver - = nullptr; +void MySQL_Connection::PluginGuard::callback_caller(const char* msg) +{ + if (!callback_drv || !callback_drv->webauthn_callback) + return; + callback_drv->webauthn_callback(msg); +} +MySQL_Connection::PluginGuard::~PluginGuard() +{ + if (!prx.expired()) + prx.lock()->lock_plugin(false); +} /* We support : @@ -1253,86 +1312,6 @@ void MySQL_Connection::init(ConnectOptionsMap & properties) proxy->options(MYSQL_OPT_SSL_MODE, &ssl_mode_val); #endif - } else if (!it->first.compare(OPT_OCI_CONFIG_FILE)) { - try { - p_s= (it->second).get(); - } catch (sql::InvalidArgumentException&) { - throw sql::InvalidArgumentException("Wrong type passed for OPT_OCI_CONFIG_FILE. Expected sql::SQLString."); - } - - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_oci_client", - "oci-config-file", - *p_s); - oci_plugin_is_loaded = true; - } catch (sql::InvalidArgumentException &e) { - throw ::sql::SQLUnsupportedOptionException( - "Failed to set config file for authentication_oci_client plugin", - OPT_OCI_CONFIG_FILE - ); - } - } else if (!it->first.compare(OPT_OCI_CLIENT_CONFIG_PROFILE)) { - try { - p_s = (it->second).get(); - } catch (sql::InvalidArgumentException &) { - throw sql::InvalidArgumentException( - "Wrong type passed for OPT_OCI_CLIENT_CONFIG_PROFILE. Expected " - "sql::SQLString."); - } - - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_oci_client", - "authentication-oci-client-config-profile", *p_s); - oci_plugin_is_loaded = true; - } catch (sql::InvalidArgumentException &e) { - throw ::sql::SQLUnsupportedOptionException( - "Failed to set config profile for authentication_oci_client plugin", - OPT_OCI_CLIENT_CONFIG_PROFILE); - } - - } else if (!it->first.compare(OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE)) { -#if defined(_WIN32) - try { - p_s = (it->second).get(); - } catch (sql::InvalidArgumentException &) { - throw sql::InvalidArgumentException( - "Wrong type passed for OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE. " - "Expected sql::SQLString."); - } - - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_kerberos_client", - "plugin_authentication_kerberos_client_mode", - *p_s); - } catch (sql::InvalidArgumentException &e) { - throw ::sql::SQLUnsupportedOptionException( - "Failed to set config file for authentication_kerberos_client " - "plugin", - OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE); - } -#endif // defined(_WIN32) - } else if (!it->first.compare(OPT_OPENID_TOKEN_FILE)) { - try { - p_s= (it->second).get(); - } catch (sql::InvalidArgumentException&) { - throw sql::InvalidArgumentException("Wrong type passed for OPT_OPENID_TOKEN_FILE. Expected sql::SQLString."); - } - - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_openid_connect_client", - "id-token-file", - *p_s); - openid_plugin_is_loaded = true; - } catch (sql::InvalidArgumentException &e) { - throw ::sql::SQLUnsupportedOptionException( - "Failed to set token file for authentication_openid_connect_client plugin", - OPT_OPENID_TOKEN_FILE - ); - } } else if (!it->first.compare(OPT_PLUGIN_DIR)) { // Nothing to do here: this option was handeld before the loop @@ -1358,49 +1337,188 @@ void MySQL_Connection::init(ConnectOptionsMap & properties) } /* End of cycle on connection options map */ - if (oci_plugin_is_loaded) { - if (properties.find(OPT_OCI_CONFIG_FILE) == properties.end()) { - // If OCI plugin is loaded, but oci-config-file is not explicitly set - // the option value needs resetting. - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_oci_client", - "oci-config-file", - nullptr); - } catch (sql::InvalidArgumentException &) { - // Do nothing, the exception is expected. - } - } - if (properties.find(OPT_OCI_CLIENT_CONFIG_PROFILE) == properties.end()) { - // If OCI plugin is loaded, but oci-config-profile is not explicitly set - // the option value needs resetting. - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_oci_client", - "authentication-oci-client-config-profile", - nullptr); - } catch (sql::InvalidArgumentException &) { - // Do nothing, the exception is expected. + /* + Setting plugin options. + + Note that plugins are shared between different drivers but each driver and + each connection can have its own plugin settings. For that reason plugin + options are set here, before making a connection, to the values specified + by this connection and driver. + + The guard is needed to prevent overwriting plugin options by another + connection while this connection is being established. + + Note: If connection options do not specify a value for a plugin option that + plugin option is set to null which resets it to its default value (which + could be overwritten by other connections). + + TODO: Move setting of plugin options later in the connection process, after + any other options which can take long time to set (e.g. OpenSSL options or + options involving DNS resolution). This is because setting plugin options + can potentially block other connection and this blocking should be as short + as possible. + */ + + MySQL_Connection::PluginGuard guard{this}; + + /* + Set option `option` of plugin `plugin_name` of type `plugin_type` to + the value given by connection option `con_opt_name` if it is specified. + Otherwise (if the connection option is not specified) reset plugin option + value to the default value given by `default_val`. + + If plugin option value could not be set throw error with description given + by `err_msg` (not if the plugin option is set to its default value). + + Note that for most plugin options the default value is restored when + the option is set to null. + */ + + auto set_plugin_option = [this, &properties] ( + const ::sql::SQLString con_opt_name, + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const char * err_msg, + const void* default_val = nullptr + ) + { + sql::SQLString *p_s = nullptr; + const void* val = nullptr; + + auto opt = properties.find(con_opt_name); + if (opt != properties.end()) + { + if (stringPluginOptions.count(con_opt_name)) + { + try + { + p_s = (opt->second).get(); + if (!p_s) + throw sql::InvalidArgumentException{ + "No string value passed for " + con_opt_name + }; + val = p_s->c_str(); + } + catch (sql::InvalidArgumentException&) + { + throw sql::InvalidArgumentException( + "Wrong type passed for " + con_opt_name + + ". Expected sql::SQLString."); + } + } + else if (intPluginOptions.count(con_opt_name)) + { + try + { + val = (opt->second).get(); + if (!val) + throw sql::InvalidArgumentException{ + "No int value passed for " + con_opt_name + }; + } + catch (sql::InvalidArgumentException&) + { + throw sql::InvalidArgumentException( + "Wrong type passed for " + con_opt_name + + ". Expected int."); + } + } + else + { + /* + We end up here only if below this lambda is called with connection + option that is not a plugin option (not listed in + `stringPluginOptions` or `intPluginOptions` -- that should never + happen. + */ + assert(false); } } - } + try + { + /* + Note: `val` is null if the connection option was not set. In that case + we reset plugin option to the default value as given by `default_val` + parameter. The last argument of `plugin_option()` informs that the + option set is the default one which is the case when `val` is null. + */ - if (openid_plugin_is_loaded) { - if (properties.find(OPT_OPENID_TOKEN_FILE) == properties.end()) { - // If OpenID plugin is loaded, but OPT_OPENID_TOKEN_FILE is not explicitly set - // the option value needs resetting. - try { - proxy->plugin_option(MYSQL_CLIENT_AUTHENTICATION_PLUGIN, - "authentication_openid_connect_client", - "id-token-file", - nullptr); - } catch (sql::InvalidArgumentException &) { - // Do nothing, the exception is expected. - } + proxy->plugin_option( + plugin_type, plugin_name, option, + val ? val : default_val, val == nullptr + ); } - } + catch (sql::InvalidArgumentException &e) + { + if (val) + // Throw only when setting to a non-default value + throw ::sql::SQLUnsupportedOptionException(err_msg, + con_opt_name.asStdString()); + } + }; + + + set_plugin_option(OPT_OCI_CONFIG_FILE, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + "authentication_oci_client", + "oci-config-file", + "Failed to set config file for authentication_oci_client plugin" + ); + + set_plugin_option(OPT_OCI_CLIENT_CONFIG_PROFILE, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + "authentication_oci_client", + "authentication-oci-client-config-profile", + "Failed to set config profile for authentication_oci_client plugin" + ); + +#if defined(_WIN32) + set_plugin_option(OPT_AUTHENTICATION_KERBEROS_CLIENT_MODE, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + "authentication_kerberos_client", + "plugin_authentication_kerberos_client_mode", + "Failed to set config file for authentication_kerberos_client plugin" + ); +#endif + + set_plugin_option(OPT_OPENID_TOKEN_FILE, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + "authentication_openid_connect_client", + "id-token-file", + "Failed to set token file for authentication_openid_connect_client plugin" + ); + + // Note: The default value for WebAuthN "device" option is 0. + + const int webauthn_device_default_val = 0; + + set_plugin_option(OPT_WEBAUTHN_DEVICE_NUMBER, + MYSQL_CLIENT_AUTHENTICATION_PLUGIN, + "authentication_webauthn_client", + "device", + "Failed to set a WebAuthn authentication device", + &webauthn_device_default_val + ); + + /* + Setting webauthn callback functions. + + The callback is an option of the webauthn authentication plugin that + is configured on the driver level (as opposed to plugin options above, + which are configured on per-connection basis). Correctly setting the option + based on driver configuration is handled by register_webauthn_callback() + function of PluginGuard class. The option will be set only if needed. + + Note: If register_webauthn_callback() sets a callback then the plugin + options guard ensures that this callback function is not modified by other + connections while being used. + */ + + guard.register_webauthn_callback(*static_cast(driver)); + #undef PROCESS_CONNSTR_OPTION @@ -1573,16 +1691,6 @@ void MySQL_Connection::init(ConnectOptionsMap & properties) } - /* - Note: If needed the setter will update callback functions registered with - webauthn/fido authentication plugins to call the callback stored - in the driver. It also protects the callbacks from being modified while - connection is being made. - */ - - MySQL_Driver::WebAuthn_Callback_Setter - setter{*static_cast(driver), proxy.get()}; - //Connect loop { bool connected = false; diff --git a/jdbc/driver/mysql_connection.h b/jdbc/driver/mysql_connection.h index 5d38fd45f..dd4aa23bf 100644 --- a/jdbc/driver/mysql_connection.h +++ b/jdbc/driver/mysql_connection.h @@ -73,6 +73,8 @@ class MySQL_Prepared_Statement; namespace NativeAPI { class NativeConnectionWrapper; +struct st_mysql_client_plugin; +extern std::map <::sql::SQLString, st_mysql_client_plugin*> plugins_cache; } class CPPCONN_PUBLIC_FUNC MySQL_Connection : public sql::Connection @@ -83,13 +85,15 @@ class CPPCONN_PUBLIC_FUNC MySQL_Connection : public sql::Connection MySQL_Statement * createServiceStmt(); public: - MySQL_Connection(Driver * _driver, - ::sql::mysql::NativeAPI::NativeConnectionWrapper & _proxy, + + using Proxy = ::sql::mysql::NativeAPI::NativeConnectionWrapper; + + MySQL_Connection(Driver * _driver, Proxy& _proxy, const sql::SQLString& hostName, const sql::SQLString& userName, const sql::SQLString& password); - MySQL_Connection(Driver * _driver, ::sql::mysql::NativeAPI::NativeConnectionWrapper & _proxy, + MySQL_Connection(Driver * _driver, Proxy & _proxy, std::map< sql::SQLString, sql::ConnectPropertyVal > & options); virtual ~MySQL_Connection(); @@ -193,7 +197,7 @@ class CPPCONN_PUBLIC_FUNC MySQL_Connection : public sql::Connection #pragma warning(push) #pragma warning(disable: 4251) #endif - std::shared_ptr< NativeAPI::NativeConnectionWrapper > proxy; + std::shared_ptr proxy; #ifdef _WIN32 #pragma warning(pop) #endif @@ -217,6 +221,57 @@ class CPPCONN_PUBLIC_FUNC MySQL_Connection : public sql::Connection /* Prevent use of these */ MySQL_Connection(const MySQL_Connection &); void operator=(MySQL_Connection &); + + struct PluginGuard; +}; + +class MySQL_Driver; + +/* + A PluginGuard instance is used to lock plugin options so that no other + connections can set them while the guard exists. + + It also manages the callback setting of the WebAuthN authentication + plugin -- see register_webauthn_callback() method. +*/ + +struct MySQL_Connection::PluginGuard +{ + std::weak_ptr prx; + + PluginGuard(MySQL_Connection *c); + ~PluginGuard(); + + /* + Depending on whether user has set the WebAuthN callback + for the driver or not, this method arranges for either + the driver's callback or the default callback be called + in case WebAuthN authentication is used while making + a connection. + */ + void register_webauthn_callback(MySQL_Driver &drv); + + private: + + /* + State of the WebAuthN plugin: + + NONE -- plugin is not loaded; + DEFAULT -- plugin is loaded and uses default callback; + CALLER -- plugin is loaded and its callback is set to + the `callback_caller()` function. + */ + static + enum class state { NONE, DEFAULT, CALLER } webauthn_plugin_state; + + // The driver whose callback is called by `callback_caller()` + static sql::mysql::MySQL_Driver * callback_drv; + + /* + Callback function to be registered with WebAuthN authentication plugin. + It calls the callback function of `callback_drv` if that is present. + */ + static void callback_caller(const char* msg); }; } /* namespace mysql */ diff --git a/jdbc/driver/mysql_driver.cpp b/jdbc/driver/mysql_driver.cpp index 1783b9111..b2c1b57fb 100644 --- a/jdbc/driver/mysql_driver.cpp +++ b/jdbc/driver/mysql_driver.cpp @@ -207,15 +207,15 @@ void MySQL_Driver::setCallBack(sql::WebAuthn_Callback& cb) /* - Note: Values 1 and 4 of `fido_callback` mean that user has set a WebAuthn + Note: Value 1 of `fido_callback` means that user has set a WebAuthn callback before and it can not be overwritten by Fido one. If later user - de-registers a WebAuthn callaback then `fido_callback` becomes 0 or 4 and + de-registers a WebAuthn callaback then `fido_callback` becomes 0 and error will not be thrown -- user can set a new Fido callback in this situation. */ #define CHECK_FIDO_ERROR \ - if (1 == (reinterpret_cast(fido_callback) % 3)) \ + if (1 == reinterpret_cast(fido_callback)) \ throw sql::SQLException{ \ "You are trying to overwrithe WebAuthn callback with FIDO one. " \ "FIDO authentication plugin and the corresponding callback type " \ diff --git a/jdbc/driver/mysql_driver.h b/jdbc/driver/mysql_driver.h index f764304fc..3e25db3ea 100644 --- a/jdbc/driver/mysql_driver.h +++ b/jdbc/driver/mysql_driver.h @@ -52,7 +52,6 @@ namespace NativeAPI class NativeDriverWrapper; } -//class sql::mysql::NativeAPI::NativeDriverWrapper; class CPPCONN_PUBLIC_FUNC MySQL_Driver : public sql::Driver { @@ -66,9 +65,10 @@ class CPPCONN_PUBLIC_FUNC MySQL_Driver : public sql::Driver #endif /* - Note: With current implementation `fido_callback` and `fido_callback_store` - are not really used and should be removed after deprecation of Fido - authentication plugin and when ABI can be changed. + Note: Currently we do not have a separate FIDO authentication plugin and + a callback for it. However, we keep `fido_callback` and + `fido_callback_store` members to not break ABI. The `fido_callback` is also + re-used as a flag in the logic of `setCallback()` methods (see there). */ ::sql::Fido_Callback* fido_callback = nullptr; @@ -77,9 +77,6 @@ class CPPCONN_PUBLIC_FUNC MySQL_Driver : public sql::Driver /* Callback function to be called by WebAuthn authentication plugin to notify the user. - - Note: The `fido_callback` pointer is re-used as a flag to indicate if - the callback was set by a user and its type (WebAuthn vs. Fido). */ std::function webauthn_callback; @@ -102,6 +99,20 @@ class CPPCONN_PUBLIC_FUNC MySQL_Driver : public sql::Driver const sql::SQLString & getName() override; + /* + We do not have a FIDO authentication plugin any more but for backward + compatibility user can still set a Fido_Callback and it will be used with + the WebAuthN plugin instead. + + New code should use only WebAuthn_Callback -- there is no need to use + the deprecated Fido_Callback other than in old code that was not yet aware + of WebAuthN authentication. + + An attempt to use both types of callbacks and overwrite earlier + WebAuthn_Callback with Fido_Callback will throw an error (it is still OK + to overwrite earlier Fido_Callback with WebAuthn_Callback though). + */ + void setCallBack(sql::Fido_Callback &cb) override; void setCallBack(sql::Fido_Callback &&cb) override; diff --git a/jdbc/driver/nativeapi/mysql_native_connection_wrapper.cpp b/jdbc/driver/nativeapi/mysql_native_connection_wrapper.cpp index 2e5e73e40..b86c0aec4 100644 --- a/jdbc/driver/nativeapi/mysql_native_connection_wrapper.cpp +++ b/jdbc/driver/nativeapi/mysql_native_connection_wrapper.cpp @@ -34,6 +34,7 @@ #include #include +#include #include "../mysql_util.h" #include "../mysql_connection_options.h" @@ -52,6 +53,9 @@ namespace mysql namespace NativeAPI { +std::shared_mutex plugins_cache_mutex; +std::map <::sql::SQLString, st_mysql_client_plugin*> plugins_cache; + /* Function to convert sql::mysql::MySQL_Connection_Options to libmysqlclient mysql_option @@ -452,21 +456,143 @@ MySQL_NativeConnectionWrapper::get_option(::sql::mysql::MySQL_Connection_Options } /* }}} */ + +/* + Accessing plugin options. +*/ + +void MySQL_NativeConnectionWrapper::lock_plugin_impl(lock_type type) +{ + switch (type) + { + case lock_type::GUARD: + case lock_type::SHARED: + // Note: We don't take shared lock if exclusive lock is in place + if (!plugins_ex_lock.owns_lock() && !plugins_sh_lock.owns_lock()) + plugins_sh_lock.lock(); + + if (!plugin_guard) + plugin_guard = (lock_type::GUARD == type); + break; + + case lock_type::EXCLUSIVE: + // Nothing to do if we already hold an exclusive lock + if (plugins_ex_lock.owns_lock()) + break; + // Before taking exclusive lock we need to release the shared lock + if (plugins_sh_lock.owns_lock()) + plugins_sh_lock.unlock(); + // This will wait until no other connection holds a lock + plugins_ex_lock.lock(); + break; + + case lock_type::UNLOCK: + // UNLOCK has no effect if GUARD lock was taken + if (plugin_guard) + break; + // Otherwise UNLOCK and UNGUARD are the same + // FALLTHROUGH + case lock_type::UNGUARD: + if (plugins_sh_lock.owns_lock()) + plugins_sh_lock.unlock(); + if (plugins_ex_lock.owns_lock()) + plugins_ex_lock.unlock(); + break; + } +} + +struct MySQL_NativeConnectionWrapper::PluginGuard +{ + using ConWrapper = MySQL_NativeConnectionWrapper; + + ConWrapper *conn; + + PluginGuard(ConWrapper *c) + : conn{c} + { + conn->lock_plugin_impl(lock_type::SHARED); + } + + ~PluginGuard() + { + // Note: This will do nothing if external guard was created + conn->lock_plugin_impl(lock_type::UNLOCK); + } + + // Upgrade initial shared lock to exclusive one + + void lock() + { + conn->lock_plugin_impl(lock_type::EXCLUSIVE); + } + + /* + Find a plugin in the plugin cache. If `load` is true then loads the plugin + into cache if not already there; otherwise null is returned if the plugin + was not found. + + Throws error if loading of the plugin failed. + */ + + st_mysql_client_plugin* + get_plugin(int plugin_type, SQLString const &name, bool load) + { + /* + Note: Shared plugin lock is held when this method is called (taken in + the constructor). + */ + + if (plugins_cache.count(name) > 0) + return plugins_cache.at(name); + else if (load) + { + /* load client authentication plugin if required */ + auto *plugin = conn->api->client_find_plugin(conn->mysql, name.c_str(), plugin_type); + + lock(); // Upgrade to exclusive lock before writing to cache + + plugins_cache.emplace(name, plugin); + + return plugin; + } + else + return nullptr; + } +}; + + int MySQL_NativeConnectionWrapper::plugin_option( - int plugin_type, - const ::sql::SQLString & plugin_name, - const ::sql::SQLString & option, - const void * value) -try{ - - /* load client authentication plugin if required */ - struct st_mysql_client_plugin *plugin = - api->client_find_plugin(mysql, plugin_name.c_str(), plugin_type); + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const void * value, + bool default_value +) +try +{ + PluginGuard guard{this}; + + /* + Note: Try to load plugin into cache only if the option is set to + a non-default value. + */ + + struct st_mysql_client_plugin *plugin + = guard.get_plugin(plugin_type, plugin_name, !default_value); + + /* + Note: `plugin` can be null here only if we are setting option to + the default value and the plugin was not found in the cache. Otherwise + an attempt to load the plugin will be made and error will be thrown if + it could not be done. + */ + + if (!plugin) + return 0; - /* set option value in plugin */ + guard.lock(); // Note: Only now an exclusive lock is required return api->plugin_options(plugin, option.c_str(), value); - } catch(sql::InvalidArgumentException &e) { @@ -475,41 +601,32 @@ catch(sql::InvalidArgumentException &e) throw sql::InvalidArgumentException(err); } + int MySQL_NativeConnectionWrapper::plugin_option( - int plugin_type, - const ::sql::SQLString & plugin_name, - const ::sql::SQLString & option, - const ::sql::SQLString & value) -try{ - - /* load client authentication plugin if required */ - struct st_mysql_client_plugin *plugin = - api->client_find_plugin(mysql, plugin_name.c_str(), plugin_type); - - /* set option value in plugin */ - return api->plugin_options(plugin, option.c_str(), value.c_str()); - -} -catch(sql::InvalidArgumentException &e) + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const ::sql::SQLString & value, + bool default_value +) { - std::string err(e.what()); - err+= " for plugin " + plugin_name; - throw sql::InvalidArgumentException(err); + return plugin_option( + plugin_type, plugin_name, option, value.c_str(), default_value + ); } + int MySQL_NativeConnectionWrapper::get_plugin_option( int plugin_type, const ::sql::SQLString & plugin_name, const ::sql::SQLString & option, const ::sql::SQLString & value) { - + PluginGuard guard{this}; /* load client authentication plugin if required */ - struct st_mysql_client_plugin *plugin = - api->client_find_plugin(mysql, plugin_name.c_str(), - plugin_type); + struct st_mysql_client_plugin *plugin = guard.get_plugin(plugin_type, plugin_name, true); /* get option value from plugin */ return api->plugin_get_option(plugin, option.c_str(), (void*)value.c_str()); diff --git a/jdbc/driver/nativeapi/mysql_native_connection_wrapper.h b/jdbc/driver/nativeapi/mysql_native_connection_wrapper.h index 865302ae1..04f63e2fe 100644 --- a/jdbc/driver/nativeapi/mysql_native_connection_wrapper.h +++ b/jdbc/driver/nativeapi/mysql_native_connection_wrapper.h @@ -37,7 +37,8 @@ #include #include - +#include +#include namespace sql { @@ -53,12 +54,12 @@ inline const char * nullIfEmpty(const ::sql::SQLString & str) return str.length() > 0 ? str.c_str() : NULL; } +extern std::shared_mutex plugins_cache_mutex; class MySQL_NativeConnectionWrapper : public NativeConnectionWrapper { /* api should be declared before mysql here */ std::shared_ptr api; - bool reconnect = false; ::sql::SQLString m_host; ::sql::SQLString m_user; @@ -140,12 +141,15 @@ struct st_mysql* mysql; int get_option(::sql::mysql::MySQL_Connection_Options, const bool &) override; int get_option(::sql::mysql::MySQL_Connection_Options, const int &) override; - int plugin_option(int plugin_type, const ::sql::SQLString &plugin_name, - const ::sql::SQLString &option, const void *) override; + int plugin_option( + int plugin_type, const ::sql::SQLString &plugin_name, + const ::sql::SQLString &option, const void *, bool + ) override; - int plugin_option(int plugin_type, const ::sql::SQLString &plugin_name, - const ::sql::SQLString &option, - const ::sql::SQLString &value) override; + int plugin_option( + int plugin_type, const ::sql::SQLString &plugin_name, + const ::sql::SQLString &option, const ::sql::SQLString &value, bool + ) override; int get_plugin_option(int plugin_type, const ::sql::SQLString &plugin_name, const ::sql::SQLString &option, @@ -176,6 +180,65 @@ struct st_mysql* mysql; NativeStatementWrapper &stmt_init() override; unsigned int warning_count() override; + + void lock_plugin(bool lock_or_unlock) override + { + lock_plugin_impl(lock_or_unlock ? lock_type::GUARD : lock_type::UNGUARD); + } + + void lock_plugin_exclusive() override + { + lock_plugin_impl(lock_type::EXCLUSIVE); + } + + /* + Implementation of plugin locking. + + There are the following lock request that can be made with + lock_plugin_impl() method: + + - SHARED lock can be taken if there are no EXCLUSIVE locks present (when + requested it watis until this is the case), existence of other SHARED + (or GUARD) locks does not prevent SHARED lock to be taken; + + - GUARD lock is like a SHARED lock but it prevents locks to be released + by UNLOCK request (see below). + + - EXCLUSIVE lock can be taken only when no other connection holds any type + of lock (when requested it waits until this is the case). EXCLUSIVE lock + can be requested while holding SHARED or GUARD lock. + + The UNLOCK request is used to remove SHARED or EXCLUSIVE locks provided + that no GUARD lock was taken. If GUARD lock was taken then an UNLOCK + request has no effect -- any locks taken remain in place. Only UNGUARD + request can be used to remove locks after GUARD request -- either + the original GUARD lock or an EXCLUSIVE lock to which it was upgraded. + + If connection already holds a plugin lock then another request to get + a lock has the following effect depending on the requested lock type: + + - EXCLUSIVE - upgrade shared lock to exclusive one + - GUARD - keep existing locks until UNGUARD request is made + - SHARED - no effect + */ + + enum class lock_type {GUARD, SHARED, EXCLUSIVE, UNLOCK, UNGUARD}; + + void lock_plugin_impl(lock_type); + + // These are used by lock_plugin_impl() + + std::shared_lock plugins_sh_lock{plugins_cache_mutex, std::defer_lock}; + std::unique_lock plugins_ex_lock{plugins_cache_mutex, std::defer_lock}; + bool plugin_guard = false; + + /* + This class handles locking of plugin when plugin options are set + (in plugin_option() methods) as well as implements access to the plugin + cache. + */ + + struct PluginGuard; }; } /* namespace NativeAPI */ diff --git a/jdbc/driver/nativeapi/native_connection_wrapper.h b/jdbc/driver/nativeapi/native_connection_wrapper.h index e1d517265..6efb8b425 100644 --- a/jdbc/driver/nativeapi/native_connection_wrapper.h +++ b/jdbc/driver/nativeapi/native_connection_wrapper.h @@ -69,6 +69,7 @@ enum Protocol_Type PROTOCOL_COUNT }; + class NativeConnectionWrapper : public util::nocopy { public: @@ -139,20 +140,34 @@ class NativeConnectionWrapper : public util::nocopy virtual int get_option(::sql::mysql::MySQL_Connection_Options, const int &) = 0; - virtual int plugin_option(int plugin_type, - const ::sql::SQLString & plugin_name, - const ::sql::SQLString & option, - const void * value) = 0; - - virtual int plugin_option(int plugin_type, - const ::sql::SQLString & plugin_name, - const ::sql::SQLString & option, - const ::sql::SQLString & value) = 0; - - virtual int get_plugin_option(int plugin_type, - const ::sql::SQLString & plugin_name, - const ::sql::SQLString & option, - const ::sql::SQLString & value) = 0; + /* + Note: The `default_value` flag informs whether the value to which option + is set is its default value. This can be used to avoid unnecessary loading + of the plugin. + */ + + virtual int plugin_option( + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const void * value, + bool default_value = false + ) = 0; + + virtual int plugin_option( + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const ::sql::SQLString & value, + bool default_value = false + ) = 0; + + virtual int get_plugin_option( + int plugin_type, + const ::sql::SQLString & plugin_name, + const ::sql::SQLString & option, + const ::sql::SQLString & value + ) = 0; virtual bool has_query_attributes() = 0; @@ -180,6 +195,43 @@ class NativeConnectionWrapper : public util::nocopy virtual unsigned int warning_count() = 0; + /* + This method is used to lock plugin options. + + After lock_plugin(true) call other connections that try to set plugin + options using plugin_option() methods will wait until lock_plugin(false) + is called on this connection. + */ + + virtual void lock_plugin(bool) = 0; + + /* + This method is used to lock plugin options exclusively before making any + plugin_option() call. + + Normally a thread takes an exclusive lock on plugin options only when it + calls `plugin_option()` method to modify one. This might however lead to + a race condition in a situation like this: + + lock_plugin(true); // lock plugin options + val = get_plugin_option(...); // read some option <1> + plugin_option(...); // write other option <2> + + If in <2> we want to set option X based on the value `val` of another + option Y that was read in step <1> there is no guarantee that at the time + of setting option X option Y has still the same value `val` that we saw + before. This is because while plugin_option() waits for exclusive access + to the options another thread can get that exclusive access first and + modify the value of Y. To avoid such race condition the code should grab + an exclusive lock on plugin options up-front rather than during + `plugin_option()` call: + + lock_plugin_exclusive(); + val = get_plugin_option(...); + plugin_option(...); + */ + + virtual void lock_plugin_exclusive() = 0; }; } /* namespace NativeAPI */ diff --git a/jdbc/extra/otel/CMakeLists.txt b/jdbc/extra/otel/CMakeLists.txt index bbed9bdf4..0d3708fa7 100644 --- a/jdbc/extra/otel/CMakeLists.txt +++ b/jdbc/extra/otel/CMakeLists.txt @@ -19,6 +19,14 @@ if(NOT (WIN32 OR APPLE OR CMAKE_SYSTEM_NAME MATCHES "SunOS")) if(WIN32) # Note: warning C4996 is triggered by OTel headers (as of version 1.10.0) target_compile_definitions(otel_api INTERFACE _SILENCE_CXX17_RESULT_OF_DEPRECATION_WARNING) + + else() + + # Note: warning triggered by OTel headers reported by clang 18: + # builtin __has_trivial_copy is deprecated; use __is_trivially_copyable instead + + target_compile_options(otel_api INTERFACE -Wno-deprecated-builtins) + endif() endif() diff --git a/jdbc/test/CMakeLists.txt b/jdbc/test/CMakeLists.txt index a8ee26532..c8259b973 100644 --- a/jdbc/test/CMakeLists.txt +++ b/jdbc/test/CMakeLists.txt @@ -41,6 +41,33 @@ INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}/include") INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}/include/jdbc") INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}/include/jdbc/cppconn") +set(MY_TARGET_LINK_LIBRARIES connector-jdbc) + + +# Note: Some unit tests use std::filesystem part of the standard C++ library +# and for some versions of the standard library its implementation is in +# additional library stdc++fs. + +if(NOT WIN32) + + set(check_src "${CMAKE_CURRENT_BINARY_DIR}/filesystem_chk.cc") + file(WRITE "${check_src}" + "#include \n" + "int main() { (void)std::filesystem::current_path(); }" + ) + + try_compile(COMPILE_RESULT + ${CMAKE_CURRENT_BINARY_DIR} "${check_src}" + # OUTPUT_VARIABLE build_log + ) + + if(NOT COMPILE_RESULT) + list(APPEND MY_TARGET_LINK_LIBRARIES -lstdc++fs) + endif() + +endif() + + IF(MSBUILD) IF(CMAKE_BUILD_TYPE STREQUAL "Debug") LINK_DIRECTORIES(${MYSQL_DIR}/lib/debug) @@ -50,15 +77,8 @@ IF(MSBUILD) ADD_DEFINITIONS("-D_SCL_SECURE_NO_WARNINGS") ADD_DEFINITIONS("-D_CRT_SECURE_NO_WARNINGS") - - SET(MY_TARGET_LINK_LIBRARIES connector-jdbc) -ELSEIF(NOT MSBUILD) - SET(MY_TARGET_LINK_LIBRARIES connector-jdbc) ENDIF() -if(NOT MYSQLCLIENT_STATIC_LINKING) - list(APPEND MY_TARGET_LINK_LIBRARIES MySQL::client) -endif() IF(CMAKE_COMPILER_IS_GNUCC AND MYSQLCPPCONN_GCOV_ENABLE) SET(MY_GCOV_LINK_LIBRARIES gcov) diff --git a/jdbc/test/unit/CMakeLists.txt b/jdbc/test/unit/CMakeLists.txt index 0fa38be18..29b7f7be8 100644 --- a/jdbc/test/unit/CMakeLists.txt +++ b/jdbc/test/unit/CMakeLists.txt @@ -26,12 +26,13 @@ # along with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +list(APPEND MY_TARGET_LINK_LIBRARIES test_framework) + IF(WIN32) if(MSBUILD) LINK_DIRECTORIES(${MYSQL_DIR}/lib/$(ConfigurationName)) LINK_DIRECTORIES(../framework/$(ConfigurationName)) endif() - SET(MY_TARGET_LINK_LIBRARIES connector-jdbc test_framework) SET(MY_TARGET_LINK_LIBRARIES_STATIC_CPPLIB connector-jdbc-static test_framework) # ADD_DEFINITIONS("-D_SECURE_SCL") ADD_DEFINITIONS("-D_SCL_SECURE_NO_WARNINGS") @@ -64,7 +65,6 @@ IF(WIN32) ) ELSEIF(NOT WIN32) - SET(MY_TARGET_LINK_LIBRARIES connector-jdbc test_framework) FIND_LIBRARY(MYSQLCPPCONN_DYNLOAD_MYSQL_LIB NAMES libmysqlclient_r.so @@ -95,9 +95,6 @@ ELSEIF(NOT WIN32) ) ENDIF(WIN32) -if(NOT MYSQLCLIENT_STATIC_LINKING) - list(APPEND MY_TARGET_LINK_LIBRARIES MySQL::client) -endif() IF(CMAKE_COMPILER_IS_GNUCC AND MYSQLCPPCONN_GCOV_ENABLE) SET(MY_GCOV_LINK_LIBRARIES gcov) diff --git a/jdbc/test/unit/classes/CMakeLists.txt b/jdbc/test/unit/classes/CMakeLists.txt index 80d23482f..a3e1477e5 100644 --- a/jdbc/test/unit/classes/CMakeLists.txt +++ b/jdbc/test/unit/classes/CMakeLists.txt @@ -221,7 +221,7 @@ foreach (token # Install tokens install( - FILES ${token} + FILES tokens/${token} DESTINATION tests/jdbc COMPONENT JDBCTests EXCLUDE_FROM_ALL diff --git a/jdbc/test/unit/classes/connection.cpp b/jdbc/test/unit/classes/connection.cpp index f42ad2017..182cec77f 100644 --- a/jdbc/test/unit/classes/connection.cpp +++ b/jdbc/test/unit/classes/connection.cpp @@ -3986,8 +3986,18 @@ void connection::tls_deprecation() 4. Set env variable MYSQL_WEBAUTHN to non-empty value */ -/* Variable value will be changed by callbacks */ -int callback_variable = -1; +/* + Variable value will be changed by callbacks. + We want to use thread local variable to avoid theoretical race condition + when after a connection is made and before the check is done another + thread might modify the variable value. + + The aim of the test is to make sure the correct callback is called inside + each thread. If the wrong callback is called the local thread variable + will have unexpected value. Hence we can detect if the driver incorrectly + handles setting of callbacks. +*/ +thread_local int callback_variable = -1; void my_callback(sql::SQLString s) { @@ -4035,14 +4045,30 @@ void connection::test_fido_webauthn(sql::ConnectOptionsMap &opt, bool callback_i if (getenv("PLUGIN_DIR")) opt[OPT_PLUGIN_DIR] = getenv("PLUGIN_DIR"); + /* + This is for extra testing of WEBAUTHN_DEVICE_NUMBER option in various + scenarios of Webauthn authentication. + */ + + { + char *opt_val = getenv("WEBAUTHN_DEVICE_NUMBER"); + if (opt_val) + opt[OPT_WEBAUTHN_DEVICE_NUMBER] = std::atoi(opt_val); + } + sql::Driver * driver = sql::mysql::get_driver_instance(); auto test_connection_drv = [&opt](int expected, sql::Driver *drv) { callback_variable = 0; - cout << "Before connect: " << callback_variable << endl; - Connection fido_connection(drv->connect(opt)); - cout << "After connect: " << callback_variable << endl; + cout << "Before connect: " << callback_variable << + " Expected: " << expected << + " DRIVER=" << drv << " THREAD=" << std::this_thread::get_id() << endl; + auto cn = drv->connect(opt); + Connection fido_connection(cn); + cout << "After connect: " << callback_variable << + " Expected: " << expected << + " DRIVER=" << drv << " THREAD=" << std::this_thread::get_id() << endl; ASSERT_EQUALS(expected, callback_variable); }; @@ -4053,7 +4079,6 @@ void connection::test_fido_webauthn(sql::ConnectOptionsMap &opt, bool callback_i try { - cout << endl << "Default callback (0)" << endl; test_connection(0); @@ -4086,46 +4111,66 @@ void connection::test_fido_webauthn(sql::ConnectOptionsMap &opt, bool callback_i cout << endl << "Multi driver tests: " << endl; - auto multi_drv_test = [test_connection_drv]() + /* + The driver instances should be created before they are + used inside the multi-thread test. + */ + sql::Driver *driver1 = sql::mysql::get_driver_instance_by_name("drv1"); + sql::Driver *driver2 = sql::mysql::get_driver_instance_by_name("drv2"); + + auto multi_drv_test = [test_connection_drv, driver1, driver2]() { - sql::Driver * driver1 = sql::mysql::get_driver_instance_by_name("drv1"); - driver1->setCallBack(CB{[](sql::SQLString msg) { - cout << "Driver 1 Callback : " << msg << endl; + driver1->setCallBack(CB{[driver1](sql::SQLString msg) { + cout << "Driver 1 Callback : " << msg << " DRIVER=" << + driver1 << " THREAD=" << std::this_thread::get_id() << endl; callback_variable = 111; }}); - sql::Driver * driver2 = sql::mysql::get_driver_instance_by_name("drv2"); - driver2->setCallBack(CB{[](sql::SQLString msg) { - cout << "Driver 2 Callback : " << msg << endl; + driver2->setCallBack(CB{[driver2](sql::SQLString msg) { + cout << "Driver 2 Callback : " << msg << " DRIVER=" << + driver2 << " THREAD=" << std::this_thread::get_id() << endl; callback_variable = 222; }}); test_connection_drv(111, driver1); test_connection_drv(222, driver2); - // Multi-driver callbacks have to be reset too. - // Otherwise they will remain set in the next test. - driver1->setCallBack(CB{nullptr}); - driver2->setCallBack(CB{nullptr}); }; multi_drv_test(); + /* + Multi-driver callbacks have to be reset too. + Otherwise they will remain set in the next test. + */ + + driver1->setCallBack(CB{nullptr}); + driver2->setCallBack(CB{nullptr}); + cout << endl << "Multithread driver tests: " << endl; { std::vector workers; - for (int i = 0; i < 3; ++i) - { + for (int i = 0; i < 3; ++i) { workers.push_back(std::thread{multi_drv_test}); } - for (auto &w : workers) - { + for (auto &w : workers) { w.join(); } } + + /* + Multi-driver callbacks have to be reset after all threads finish. + Otherwise, resetting a callback for a driver after one thread + is finished, but another one is still running will result in + premature disabling of the callbacks. + */ + + driver1->setCallBack(CB{nullptr}); + driver2->setCallBack(CB{nullptr}); + } catch (sql::SQLException &e) { @@ -4387,7 +4432,7 @@ void connection::openid_token() sql::ConnectOptionsMap opts = map; opts[OPT_USERNAME] = "MySQLUser"; opts["hostName"] = url; - + if (getenv("PLUGIN_DIR")) opts[OPT_PLUGIN_DIR] = getenv("PLUGIN_DIR"); diff --git a/mysql-concpp-config.cmake.in b/mysql-concpp-config.cmake.in index e1469eefb..a6cbf3b8f 100644 --- a/mysql-concpp-config.cmake.in +++ b/mysql-concpp-config.cmake.in @@ -46,16 +46,24 @@ # Also, the following variables are set: # # - Xxx_FOUND -# - Xxx_DEBUG_FOUND, Xxx_debug_FOUND -- (1) +# - Xxx_JDBC_FOUND, Xxx_jdbc_FOUND -- (1a) +# - Xxx_DEBUG_FOUND, Xxx_debug_FOUND -- (1b) +# - Xxx_RELEASE_FOUND, Xxx_release_FOUND -- (1b) # - Xxx_VERSION, Xxx_VERSION_CC # - Xxx_ROOT_DIR -- (2) # - Xxx_RUNTIME_LIBRARY_DIRS, Xxx_RUNTIME_LIBRARY_DIR -- (2,3) -# - Xxx_PLUGIN_DIR -- (4) +# - Xxx_RUNTIME_LIBRARY_DIRS_DEBUG, Xxx_RUNTIME_LIBRARY_DIR_DEBUG -- (4a) +# - Xxx_RUNTIME_LIBRARY_DIRS_RELEASE, Xxx_RUNTIME_LIBRARY_DIR_RELEASE -- (4b) +# - Xxx_PLUGIN_DIR -- (5a,5b) # # In these variable names Xxx is either `MYSQL_CONCPP` or `mysql-concpp`, # CC is version component: one of `MAJOR`, `MINOR` or `PATCH`. # -# Note (1): These are set to true if debug libraries are available +# Note (1a): Set to true if the classic JDBC connector libraries were found and +# the -jdbc targets are defined. It must be the case if `REQUIRE jdbc` clause +# was used in the cmake `find_package()` command. +# +# Note (1b): These are set to true if debug/release libraries are available # (see below). # # Note (2): Set only in case of a monolithic install (TGZ, ZIP, MSI). @@ -67,13 +75,28 @@ # case the _RUNTIME_LIBRARY_DIR(S) variable gives the location where shared # connector libraries can be found. # -# Note (4): The JDBC connector might require loading of authentication plugins -# at connection time (depending on authentication mechaism being used). These +# Note (4a): If debug variants of connector libraries were found these +# variables are set to their location. +# +# Note (4b): For consistency, these variables are set if release variants +# of connector libraries were found and in that case they are equal +# to _RUNTIME_LIBRARY_DIR(S) ones. +# +# Note (5a): The JDBC connector might require loading of authentication plugins +# at connection time (depending on authentication mechanism being used). These # plugins are in the location given by _PLUGIN_DIR variable. Depending on # the installation type it might be necessary to specify this location # with connection configuration options for plugins to be correctly found # at runtime (see: https://dev.mysql.com/doc/connector-cpp/8.2/en/connector-cpp-authentication.html) # +# Note (5b): Authentication plugins are bundled with the connector and +# the _PLUGIN_DIR variable is set only when the JDBC connector links the MySQL +# client library statically (which is the typical case). It is also possible +# to build JDBC connector with dynamic linking to the MySQL client library. +# In that case plugins are not bundled with the connector and _PLUGIN_DIR +# variable is not set -- if needed the plugins that come with the MySQL client +# library should be used in that case. +# # Note: The variables are put in the cache but if Xxx_FOUND is not set or # is false then the module will be re-loaded and the other variables in # the cache will be overwritten with newly detected values. @@ -81,14 +104,15 @@ # Note: If mysql-concpp_FIND_VERBOSE is true when loading package diagnostic # messages will be printed by this script. # +# # OpenSSL dependency # ------------------ # -# Connector/C++ requires OpenSSL libraires. Depending on the platform and +# Connector/C++ requires OpenSSL libraries. Depending on the platform and # the installation type it is either expected that OpenSSL will be installed # on the system or these libraries are bundled in the connector package. # Connector library targets are configured to use OpenSSL from appropriate -# locations. This can be overriden by user -- if `mysql::openssl` target +# locations. This can be overridden by user -- if `mysql::openssl` target # is defined prior to loading `mysql-concpp` package then this target is used # to resolve dependency on the OpenSSL library. # @@ -119,11 +143,26 @@ # clause of `find_package()` command. If this is done then `find_package()` # will fail if debug libraries were not found. # +# When using custom builds of Connector/C++ it is possible to have +# an installation with only debug libraries. On Windows, in such situation, +# the connector targets created here will work only for debug builds. +# On non-Windows platforms debug libraries can and will be used for building +# in any mode. Presence of release libraries is indicated by _RELEASE_FOUND +# variable. One can use `REQUIRE release` clause of `find_package()` command +# to ensure that release variants of the libraries are present. +# # Note: Debug libraries are needed and used only on Windows. For Linux # separate packages with debug symbols are available that can be used -# to debug connector libraries but only release builds of these libararies +# to debug connector libraries but only release builds of these libraries # are distributed. # +# Note: When only debug libraries are available the _RUNTIME_LIBRARY_DIR(S) +# variables point at the location of these debug libraries on non-Windows +# platforms (because they are used by other build types). However, on Windows +# the _RUNTIME_LIBRARY_DIR(S) variables still point to the location where +# release variants of the libraries should be installed (but are not present). +# The libraries can be located using _RUNTIME_LIBRARY_DIR(S)_DEBUG variables +# in such scenario. # message(STATUS "mysql-concpp module config (${MYSQL_CONCPP_FOUND}, ${mysql-concpp_FOUND})") @@ -138,62 +177,65 @@ function(message_info) message(STATUS "mysql-concpp: " ${ARGV}) endfunction() +function(set_warning) + set(warning_message ${ARGV} CACHE INTERNAL "warning message") +endfunction() + # -# If WITH_MYSQL is not false then it is assumed that the `concpp-jdbc-static` -# target depends on the MySQL client library. Additionally, if WITH_MYSQL is a -# path pointing at MySQL install location, the library path will be extended so -# that linker looks for the client library at that location. -# -# Note: The default value is set based on whether the JDBC connector was -# statically linked with the client library or not. +# JDBC_MYSQL_DEP tells whether JDBC connector library depends on the MySQL +# client library. This is not the case when the connector library links +# the client library statically. However, if WITH_MYSQL option is defined +# and not false then JDBC targets are always configured to depend on the client +# library. Additionally, if WITH_MYSQL is a path pointing at MySQL install +# location, the library path will be extended so that linker looks for the +# client library at that location. # -if(NOT @MYSQLCLIENT_STATIC_LINKING@) +set(JDBC_MYSQL_DEP OFF) +if(WITH_MYSQL OR NOT @MYSQLCLIENT_STATIC_LINKING@) set(JDBC_MYSQL_DEP ON) -else() - set(JDBC_MYSQL_DEP OFF) endif() -set(WITH_MYSQL ${JDBC_MYSQL_DEP} - CACHE INTERNAL - "MySQL install location (to find the client library)" -) - macro(main) - # Set paths to look for headers and libraries either relative to this file - # or in system-wide locations. - # - # FIXME: lib64/ or lib/ as appropriate for the platform - + # We can have two types of installations -- in case of RPM/DEB install + # connector files are installed to system-wide locations (system-wide + # install), in other cases all connector files are installed into a single + # root directory (monolithic install). if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/include/mysqlx/xdevapi.h") # Case of monolithic install + set(monolithic 1) + set(MYSQL_CONCPP_ROOT_DIR "${CMAKE_CURRENT_LIST_DIR}") - set(LIB_PATH "${MYSQL_CONCPP_ROOT_DIR}/@INSTALL_LIB_DIR@") message_info("Module installed at: ${MYSQL_CONCPP_ROOT_DIR}") - set(INCLUDE_PATH "${MYSQL_CONCPP_ROOT_DIR}/include") + + set(INCLUDE_DIR "${MYSQL_CONCPP_ROOT_DIR}/include") + set(LIBRARY_DIR "${MYSQL_CONCPP_ROOT_DIR}/@INSTALL_LIB_DIR@") + + set(fail_message "Could NOT find MySQL Connector/C++ libraries at ${MYSQL_CONCPP_ROOT_DIR}.") else() # System-wide install, DEB or RPM layout. - set(INCLUDE_PATH "/usr/include/mysql-cppconn") - get_filename_component(LIB_PATH "${CMAKE_CURRENT_LIST_DIR}/../.." ABSOLUTE) + set(monolithic 0) - file(GLOB found "${LIB_PATH}/*libmysqlcppconn*") + set(INCLUDE_DIR "/usr/include/mysql-cppconn") - if(NOT found) - # Note: Use RPM layout as fallback - set(LIB_PATH "/usr/@INSTALL_LIB_DIR@") - endif() + # We do not set LIBRARY_DIR because in this case we will search for the libraries in system-wide locations. + + set(fail_message + "Could NOT find MySQL Connector/C++ libraries at system-wide locations." + ) endif() + # Headers must always be found first. find_includes() @@ -208,25 +250,109 @@ macro(main) message_info("Include path: ${MYSQL_CONCPP_INCLUDE_DIR}") - # Note: On windows we look for the import library, not the DLL. This import - # library normally is in a ./vsNN subfolder of the library path. + # This suffix is used to locate static and import libraries on Windows - unset(vs_suffix) + set(vs_suffix) if(WIN32) set(vs_suffix vs14) endif() - # Find required dependencies. Currtently this looks for OpenSSL and defines + # Find required dependencies. Currently this looks for OpenSSL and defines # `mysql::openssl` interface library for it if found. find_deps() # Find connector libraries and define interface targets for the ones that - # were found. + # were found. This will set/update LIBRARY_DIR to the location where + # libraries were found and will also set RELEASE/DEBUG_FOUND flags + # if the corresponding variant of the libraries was found. + + set(DEBUG_FOUND 0) + set(RELEASE_FOUND 0) find_connector(XDevAPI) find_connector(JDBC) + + set(MYSQL_CONCPP_DEBUG_FOUND ${DEBUG_FOUND}) + set(MYSQL_CONCPP_RELEASE_FOUND ${RELEASE_FOUND}) + + if(monolithic) + + # Set MYSQL_CONCPP_RUNTIME_LIBRARY_DIR_*. Variables based on LIBRARY_DIR + # determined above. + + if(DEBUG_FOUND) + + set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR_DEBUG "${LIBRARY_DIR}/debug") + + elseif(WIN32) + + set_warning( + "Debug variants of connector libraries were not found" + "at the install location -- building in debug mode will not work" + ) + + endif() + + + if(RELEASE_FOUND) + + set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR_RELEASE "${LIBRARY_DIR}") + set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR "${LIBRARY_DIR}") + + elseif(NOT WIN32) + + # If release libraries were not found and we are on non-Win platform we + # will use debug libraries also for release builds. + + message_info( + "Using debug variants of connector libraries for release builds because" + " release variants are not found at the install location" + ) + + set( + MYSQL_CONCPP_RUNTIME_LIBRARY_DIR + "${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR_DEBUG}" + ) + + else() + + # On Windows one can not mix release and debug code. The targets created + # above have only debug-mode paths defined. We set + # MYSQL_CONCPP_RUNTIME_LIBRARY_DIR to the path where release libraries + # would be expected even if they were not found there. + + set_warning( + "Release variants of connector libraries were not found" + "at the install location -- building in release mode will not work" + ) + + set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR "${LIBRARY_DIR}") + + endif() + + # Note: Set plugin dir location only if connector has client library + # statically linked in (does not depend on external one). + + if(NOT JDBC_MYSQL_DEP) + set(MYSQL_CONCPP_PLUGIN_DIR "${LIBRARY_DIR}/plugin") + endif() + + else() + + # Note: In system-wide install case we do not set _RUNTIME_LIBRARY_DIR_* + # variables as libraries are installed at system-wide locations. + + if(NOT JDBC_MYSQL_DEP) + set(MYSQL_CONCPP_PLUGIN_DIR + "${LIBRARY_DIR}/mysql/libmysqlcppconn@JDBC_ABI_VERSION_MAJOR@/plugin" + ) + endif() + + endif() + + # Aliases for -xdevapi* targets. foreach(suffix "" "-static" "-debug" "-static-debug") @@ -236,15 +362,17 @@ macro(main) add_library(mysql::concpp${suffix} ALIAS mysql::concpp-xdevapi${suffix}) endif() - endforeach() + if(TARGET mysql::concpp-jdbc${suffix}) + set(MYSQL_CONCPP_JDBC_FOUND 1) + endif() + +endforeach() # Build the NOT_FOUND message. # Note: The different find_xxx() functions set the specific part # of the message, such as ${fail_message_devapi}, in case of failure. - set(fail_message "Could NOT find MySQL Connector/C++ at ${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}.") - if(fail_message_devapi) # AND MYSQL_CONCPP_FIND_REQUIRED_devapi) list(APPEND fail_message ${fail_message_devapi}) elseif(fail_message_jdbc) # AND MYSQL_CONCPP_FIND_REQUIRED_jdbc) @@ -253,37 +381,73 @@ macro(main) set_not_found(${fail_message}) + # Build the success message which can optionally contain warnings + # TODO: Warnings about missing debug/release library variants + + set(MYSQL_CONCPP_FOUND_MSG ${MYSQL_CONCPP_INCLUDE_DIR}) + if(warning_message) + string(JOIN " " warning_message ${warning_message}) + set(MYSQL_CONCPP_FOUND_MSG + "${MYSQL_CONCPP_FOUND_MSG} WARNING: ${warning_message}" + ) + endif() + include(FindPackageHandleStandardArgs) + # Note: The _FOUND variable name expected by FPHSA for component CCC + # is mysql-concpp_CCC_FOUND + + set(mysql-concpp_jdbc_FOUND ${MYSQL_CONCPP_JDBC_FOUND}) + set(mysql-concpp_debug_FOUND ${MYSQL_CONCPP_DEBUG_FOUND}) + set(mysql-concpp_release_FOUND ${MYSQL_CONCPP_RELEASE_FOUND}) + find_package_handle_standard_args(mysql-concpp REQUIRED_VARS - mysql-concpp_VERSION - MYSQL_CONCPP_FOUND + MYSQL_CONCPP_FOUND_MSG MYSQL_CONCPP_INCLUDE_DIR + MYSQL_CONCPP_FOUND VERSION_VAR mysql-concpp_VERSION - # HANDLE_COMPONENTS + HANDLE_COMPONENTS FAIL_MESSAGE "${mysql-concpp_NOT_FOUND_MESSAGE}" ) # Set alternative variables + set(MYSQL_CONCPP_jdbc_FOUND ${MYSQL_CONCPP_JDBC_FOUND}) + set(MYSQL_CONCPP_debug_FOUND ${MYSQL_CONCPP_DEBUG_FOUND}) + set(MYSQL_CONCPP_release_FOUND ${MYSQL_CONCPP_RELEASE_FOUND}) + foreach(var - ROOT_DIR PLUGIN_DIR RUNTIME_LIBRARY_DIR RUNTIME_LIBRARY_DIRS DEBUG_FOUND + ROOT_DIR PLUGIN_DIR + RUNTIME_LIBRARY_DIR RUNTIME_LIBRARY_DIRS + RUNTIME_LIBRARY_DIR_DEBUG RUNTIME_LIBRARY_DIRS_DEBUG + RUNTIME_LIBRARY_DIR_RELEASE RUNTIME_LIBRARY_DIRS_RELEASE + DEBUG_FOUND debug_FOUND RELEASE_FOUND release_FOUND + JDBC_FOUND jdbc_FOUND ) if(NOT DEFINED MYSQL_CONCPP_${var}) continue() endif() - set(mysql-concpp_${var} ${MYSQL_CONCPP_${var}} CACHE INTERNAL "mysql-concpp module config variable" FORCE) - set(MYSQL_CONCPP_${var} ${MYSQL_CONCPP_${var}} CACHE INTERNAL "mysql-concpp module config variable" FORCE) + # handle _DIR_ and _DIRS_ variants if(var STREQUAL "RUNTIME_LIBRARY_DIR") - set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIRS - "${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}" - ) + foreach(suffix "" "_RELEASE" "_DEBUG") + if(NOT DEFINED MYSQL_CONCPP_RUNTIME_LIBRARY_DIR${suffix}) + continue() + endif() + set( + MYSQL_CONCPP_RUNTIME_LIBRARY_DIRS${suffix} + "${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR${suffix}}" + ) + endforeach() endif() + set(mysql-concpp_${var} ${MYSQL_CONCPP_${var}} CACHE INTERNAL "mysql-concpp module config variable" FORCE) + set(MYSQL_CONCPP_${var} ${MYSQL_CONCPP_${var}} CACHE INTERNAL "mysql-concpp module config variable" FORCE) + + endforeach(var) foreach(ver "" _MAJOR _MINOR _PATCH _TWEAK _COUNT) @@ -313,23 +477,24 @@ endfunction() function(find_includes) - #message(STATUS "Looking for headers at: ${INCLUDE_PATH}") + #message(STATUS "Looking for headers at: ${INCLUDE_DIR}") + unset(MYSQL_CONCPP_INCLUDE_DIR CACHE) find_path(MYSQL_CONCPP_INCLUDE_DIR NAMES mysqlx/xdevapi.h - PATHS ${INCLUDE_PATH} + PATHS ${INCLUDE_DIR} NO_DEFAULT_PATH - NO_CACHE + # NO_CACHE # Note: requires cmake 3.21 ) if(NOT MYSQL_CONCPP_INCLUDE_DIR) if(MYSQL_CONCPP_ROOT_DIR) set(fail_message_includes - "at MYSQL_CONCPP_ROOT_DIR: ${INCLUDE_PATH}" + "at MYSQL_CONCPP_ROOT_DIR: ${INCLUDE_DIR}" ) else() - set(fail_message_includes "at ${INCLUDE_PATH}") + set(fail_message_includes "at ${INCLUDE_DIR}") endif() set_parent(fail_message_includes) @@ -344,47 +509,31 @@ endfunction() # Find XDevAPI or JDBC connector libraries, as specified by parameter `which` # and create interface library targets for them. Both shared and static -# variants are searched for. +# variants are searched for. If some libraries are not found the corresponding +# targets are not created. +# +# If LIBRARY_DIR is set the libraries are searched in that location, otherwise +# they are searched in system-wide locations. In either case LIBRARY_DIR is +# set/updated to the location where libraries were found. # -# TODO: Currently this will fail if release libraries are not found, even -# if debug ones are present. Should this be changed? +# Flags RELEASE_FOUND and DEBUG_FOUND are set if the corresponding variants +# of the libraries were found. function(find_connector which) if(which STREQUAL "JDBC") set(base_name "mysqlcppconn") - set(target_name "concpp-jdbc") + set(target_name "jdbc") else() set(base_name "mysqlcppconnx") - set(target_name "concpp-xdevapi") + set(target_name "xdevapi") endif() - # Set location of shared libraries or DLLs in case of Win (if not already - # done). - - if(NOT MYSQL_CONCPP_RUNTIME_LIBRARY_DIR) - - set(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR "${LIB_PATH}") - - # Note: set MYSQL_CONCPP_RUNTIME_LIBRARY_DIR as output variable only - # in case of monolithic install. - - if(MYSQL_CONCPP_ROOT_DIR) - - message_info( - "Runtime library folder: ${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}" - ) - set_parent(MYSQL_CONCPP_RUNTIME_LIBRARY_DIR) - - endif() - - set( - MYSQL_CONCPP_PLUGIN_DIR "${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}/plugin" - PARENT_SCOPE - ) - - endif() + # Look for the connector library and if found create the import target for + # it. Sets ${target_name}_RELEASE and ${target_name}_DEBUG to indicate + # whether release/debug variant of the library was found. Also sets + # or updates LIBRARY_DIR to the location where the library was found. add_connector_target(${which} ${target_name} ${base_name}) @@ -396,27 +545,48 @@ function(find_connector which) add_connector_target(${which} ${target_name}-static ${base_name}-static) endif() - set_parent(MYSQL_CONCPP_DEBUG_FOUND) + # Process targets created above to do consistency checks and declare required + # dependencies. Also sets DEBUG/RELEASE_FOUND flags as needed. foreach(tgt ${target_name} ${target_name}-static) - if(NOT TARGET mysql::${tgt}) + if(${tgt}_RELEASE) + set_parent(RELEASE_FOUND 1) + endif() + + if(${tgt}_DEBUG) + set_parent(DEBUG_FOUND 1) + endif() + + if(NOT TARGET mysql::concpp-${tgt}) continue() endif() + if(DEBUG_FOUND AND NOT ${tgt}_DEBUG) + list(APPEND DEBUG_MISSING ${tgt}) + endif() + set_parent(DEBUG_MISSING) + + if(RELEASE_FOUND AND NOT ${tgt}_RELEASE) + list(APPEND RELEASE_MISSING ${tgt}) + endif() + set_parent(RELEASE_MISSING) + unset(libs) - # JDBC dependency on the client library if specified via WITH_MYSQL + # JDBC dependency on the client library - if(target_name MATCHES "-jdbc" AND WITH_MYSQL) + if(tgt MATCHES "jdbc" AND JDBC_MYSQL_DEP) - list(APPEND libs mysqlclient) + if(NOT WIN32) + list(APPEND libs mysqlclient) + endif() - if(EXISTS "${WITH_MYSQL}/lib") + if(DEFINED WITH_MYSQL AND EXISTS "${WITH_MYSQL}/lib") message_info("Client library path: ${WITH_MYSQL}/lib") - target_link_directories(mysql::${tgt} + target_link_directories(mysql::concpp-${tgt} INTERFACE "${WITH_MYSQL}/lib" ) @@ -426,7 +596,7 @@ function(find_connector which) # OpenSSL dependency (target `mysql::openssl` is defined by find_deps()) # - # Note: Even though legacy connector does not use OpenSSL directly it migth + # Note: Even though JDBC connector does not use OpenSSL directly it might # have the client library statically linked in and get dependency # on OpenSSL that way. @@ -436,7 +606,7 @@ function(find_connector which) if(tgt MATCHES "-static") - set_target_properties(mysql::${tgt} PROPERTIES + set_target_properties(mysql::concpp-${tgt} PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES CXX INTERFACE_COMPILE_DEFINITIONS STATIC_CONCPP ) @@ -467,98 +637,218 @@ function(find_connector which) endif() - target_link_libraries(mysql::${tgt} INTERFACE ${libs}) + target_link_libraries(mysql::concpp-${tgt} INTERFACE ${libs}) - string(JOIN " " libs ${libs}) - message_info("Link libraries for target ${tgt}: ${libs}") + if(libs) + string(JOIN " " libs ${libs}) + message_info("Link libraries for target ${tgt}: ${libs}") + endif() endforeach(tgt) endfunction(find_connector) -# Create connector library import target named ${tgt} and pointing at library -# with base name ${base_name}. Target is not created if the library could -# not be found. If debug variant of library is found then it is used -# for IMPORT_LOCATION_DEBUG. In this case _DEBUG_FOUND variable is set to 1. +# Create connector library import target named ${tgt} pointing at library +# with base name ${base_name} if it was found. +# +# If LIBRARY_DIR is set the library is searched in that location, otherwise it +# is searched in system-wide locations. If the library is found, LIBRARY_DIR +# is set/updated to the location where it was found. +# +# Both release and debug variants of the library are searched for. Flags +# ${tgt}_RELEASE and ${tgt}_DEBUG are set to tell which variant was found. +# +# Note: The which parameter, either "XDevAPI" or "JDBC", is used for +# diagnostics only. function(add_connector_target which tgt base_name) + set(lib_name "${base_name}") set(type "SHARED") + set(static 0) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + if(tgt MATCHES "-static") set(type "STATIC") + set(static 1) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + + set(XDevAPI_abi @ABI_VERSION_MAJOR@) + set(JDBC_abi @JDBC_ABI_VERSION_MAJOR@) + set(find_lib_paths) + set(win_opts) + + if(LIBRARY_DIR) + set(find_lib_paths PATHS "${LIBRARY_DIR}" NO_DEFAULT_PATH) endif() + if(WIN32) + if(static) + set(win_opts PATH_SUFFIXES ${vs_suffix}) + else() + set(lib_name "${base_name}-${${which}_abi}-vs14") + endif() + endif() + + #message("!!! looking for ${lib_name} with options: ${find_lib_opts}") + unset(lib_path CACHE) find_library(lib_path - NAMES ${base_name} - PATHS ${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}/${vs_suffix} - NO_DEFAULT_PATH - NO_CACHE + NAMES ${lib_name} + ${find_lib_paths} ${win_opts} + # NO_CACHE ) - if(NOT lib_path) - message_info("Did not find ${which} ${type} library") - return() - endif() + if(lib_path) - message_info("${which} ${type} library at: ${lib_path}") - #message(STATUS "Creating target: mysql::${tgt}") + message_info( + "Found ${which} ${type} library at: ${lib_path}" + ) - add_library(mysql::${tgt} ${type} IMPORTED GLOBAL) + set_parent(${tgt}_RELEASE 1) - target_compile_features(mysql::${tgt} INTERFACE cxx_std_11) + # Note: LIBRARY_DIR is not yet set here if we were looking for the library + # in system-wide locations. In any case we set/update LIBRARY_DIR to + # the actual location of the library that was found. - set_target_properties(mysql::${tgt} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_CONCPP_INCLUDE_DIR}" - ) + get_filename_component(LIBRARY_DIR "${lib_path}" DIRECTORY) + set_parent(LIBRARY_DIR) - # TODO: On Win set IMPORTED_LOCATION to the DLL path rather than the import library... + if(WIN32 AND NOT static) + find_imp_lib(imp_lib_path ${base_name} "${lib_path}") + endif() - set_target_properties(mysql::${tgt} PROPERTIES - IMPORTED_LOCATION "${lib_path}" - ) + endif() - if(WIN32) - set_target_properties(mysql::${tgt} PROPERTIES - IMPORTED_IMPLIB "${lib_path}" + # Look for debug variant of the library if LIBRARY_DIR is set. This is + # the case in one of these situations: + # + # a) the release library was found at LIBRARY_DIR above; + # + # b) we have monolithic connector install and LIBRARY_DIR is the library + # location inside that monolithic install. + # + # Case (b) is if we have not found the release library inside a monolithic + # connector installation but we still can find a debug library there. + + if(LIBRARY_DIR) + + unset(lib_path_debug CACHE) + find_library(lib_path_debug + NAMES ${lib_name} + PATHS "${LIBRARY_DIR}/debug" + ${win_opts} + NO_DEFAULT_PATH + # NO_CACHE ) - endif() - # Look for debug variant of the library. + if(lib_path_debug) - unset(lib_path_debug CACHE) - find_library(lib_path_debug - NAMES ${base_name} - PATHS ${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}/debug/${vs_suffix} - NO_DEFAULT_PATH - NO_CACHE - ) + message_info( + "Found debug variant of ${which} ${type} library at: ${lib_path_debug}" + ) - if(lib_path_debug) + set_parent(${tgt}_DEBUG 1) + + if(WIN32 AND NOT static) + find_imp_lib(imp_lib_path_debug ${base_name} "${lib_path_debug}") + endif() + + endif() + + endif() - message_info( - "Found debug variant of ${which} ${type} library at: ${lib_path_debug}" - ) - set(MYSQL_CONCPP_DEBUG_FOUND 1 PARENT_SCOPE) + if(NOT lib_path AND NOT lib_path_debug) + + message_info("Did not find ${which} ${type} library") + return() endif() - # Note: On non-Windows platforms we set the debug location of the connector - # target only if the debug library variant was found so that if it was - # not found then the release variant will be used. # - # However, on Windows it is not possible to mix debug and release code. - # Therefore we always set the debug location of the connector target - # on Windows so that if it is used in debug builds and the debug library - # variant is not present a linker error will be reported. + # Note: At this point we know that either the release or the debug connector + # was found. + # + # On non-Windows platforms the release connector can be used for debug + # builds if the debug connector was not found and vice-versa, the debug + # connector can be used for release builds if the release connector was + # not found. + # + # However, on Windows it is not possible to mix debug and release code which + # is reflected in the logic below. + # - if(WIN32) + if(WIN32 AND NOT lib_path_debug) + + # If debug connector was not found on Windows we still set debug path to its + # expected location so that: + # + # 1. If debug connector is added later it will be used in debug builds. + # + # 2. If debug connector is not present then debug builds will fail which + # is what we want in that case (rather than incorrectly using the release + # variant of the library). + # + # Note: LIBRARY_DIR must be defined because the release library must have + # been found above. set(lib_path_debug - "${MYSQL_CONCPP_RUNTIME_LIBRARY_DIR}/debug/${vs_suffix}/${base_name}.lib" + "${LIBRARY_DIR}/debug/${lib_name}.dll" ) + set(imp_lib_path_debug + "${LIBRARY_DIR}/debug/${vs_suffix}/${base_name}.lib" + ) + + # Note: If debug connector was not found on non-Windows platform then + # lib_path_debug remains undefined which means that the import target will + # not have a _DEBUG location defined. Therefore the main (release) location + # will be used also in debug builds as we want in that case. + + elseif(WIN32 AND NOT lib_path) + + # If release connector was not found on Windows we still set the release + # path to its expected location so that release builds will fail (because + # the release library will be not found at the location) or, if release + # connector is added later release builds will start working. + + set(lib_path "${LIBRARY_DIR}/${lib_name}.dll") + set(imp_lib_path "${LIBRARY_DIR}/${vs_suffix}/${base_name}.lib") + + elseif(NOT WIN32 AND NOT lib_path) + + # If we are on non-Windows platform and the release connector was not found + # then use the debug connector as a replacement. + + set(lib_path "${lib_path_debug}") + + endif() + + + set(tgt "concpp-${tgt}") + #message(STATUS "Creating target: mysql::${tgt}") + + add_library(mysql::${tgt} ${type} IMPORTED GLOBAL) + target_compile_features(mysql::${tgt} INTERFACE cxx_std_11) + + set_target_properties(mysql::${tgt} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MYSQL_CONCPP_INCLUDE_DIR}" + ) + + + if(lib_path) + + set_target_properties(mysql::${tgt} PROPERTIES + IMPORTED_LOCATION "${lib_path}" + ) + + if(WIN32 AND imp_lib_path) + set_target_properties(mysql::${tgt} PROPERTIES + IMPORTED_IMPLIB "${imp_lib_path}" + ) + endif() endif() @@ -568,9 +858,9 @@ function(add_connector_target which tgt base_name) IMPORTED_LOCATION_DEBUG "${lib_path_debug}" ) - if(WIN32) + if(WIN32 AND imp_lib_path_debug) set_target_properties(mysql::${tgt} PROPERTIES - IMPORTED_IMPLIB_DEBUG "${lib_path_debug}" + IMPORTED_IMPLIB_DEBUG "${imp_lib_path_debug}" ) endif() @@ -579,6 +869,36 @@ function(add_connector_target which tgt base_name) endfunction(add_connector_target) +# On Windows find import library for the DLL library at the given `path` with +# given `base_name`. The location of the import library is stored in variable +# named by `var`. +# +# Note: Not finding an import library for a DLL is a fatal error. + +function(find_imp_lib var base_name path) + + get_filename_component(base_path ${path} DIRECTORY) + set(CMAKE_FIND_LIBRARY_SUFFIXES .lib) + + #message("!!! Looking for import library for: ${path}") + unset(${var} CACHE) + find_library(${var} + NAMES ${base_name} + PATHS ${base_path} + PATH_SUFFIXES ${vs_suffix} + NO_DEFAULT_PATH + # NO_CACHE + ) + + if(NOT ${var}) + message(FATAL_ERROR "Could not find import library for ${path}") + endif() + + set_parent(${var}) + +endfunction(find_imp_lib) + + function(find_deps) if(TARGET mysql::openssl) @@ -600,19 +920,19 @@ function(find_deps) unset(ssl_lib CACHE) find_library(ssl_lib NAMES ssl libssl - PATHS ${LIB_PATH} + PATHS ${LIBRARY_DIR} PATH_SUFFIXES private ${vs_suffix} NO_DEFAULT_PATH - NO_CACHE + # NO_CACHE ) unset(ssl_crypto CACHE) find_library(ssl_crypto NAMES crypto libcrypto - PATHS ${LIB_PATH} + PATHS ${LIBRARY_DIR} PATH_SUFFIXES private ${vs_suffix} NO_DEFAULT_PATH - NO_CACHE + # NO_CACHE ) if(NOT ssl_lib OR NOT ssl_crypto) diff --git a/packaging/CMakeLists.txt b/packaging/CMakeLists.txt index 55223d834..7a86eed8e 100644 --- a/packaging/CMakeLists.txt +++ b/packaging/CMakeLists.txt @@ -190,6 +190,7 @@ cpack_add_component_group(main) cpack_add_component_group(tests) cpack_add_component_group(debug) +cpack_add_component(DevCommon GROUP main) cpack_add_component(XDevAPIDev GROUP main) cpack_add_component(XDevAPIDll GROUP main) cpack_add_component(JDBCDev GROUP main) diff --git a/packaging/WiX/CMakeLists.txt b/packaging/WiX/CMakeLists.txt index 16e0b7ba6..ee7517a3d 100644 --- a/packaging/WiX/CMakeLists.txt +++ b/packaging/WiX/CMakeLists.txt @@ -514,33 +514,21 @@ function(make_wix_identifier STR VAR) set(${VAR} "${STR}.${out}" PARENT_SCOPE) endfunction() + # # Generate UUIDs # -find_program(UUIDGEN_COMMAND uuidgen) - -if(NOT UUIDGEN_COMMAND) - message(FATAL_ERROR "Could not find uuidgen executable") -endif() - function(generate_guid VAR) - EXECUTE_PROCESS( - COMMAND ${UUIDGEN_COMMAND} -c - RESULT_VARIABLE res - OUTPUT_VARIABLE guid - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - - if(res) - message(FATAL_ERROR "Could not generate UUID: ${res}") - endif() - + string(RANDOM x) + string(UUID guid NAMESPACE "96122528-4F58-40F8-AB22-96F9853460F8" NAME "${x}" TYPE MD5 UPPER) + # message(STATUS "generated guid: ${guid}") set(${VAR} ${guid} PARENT_SCOPE) endfunction() + # # Convert path into a list # diff --git a/packaging/WiX/connector-cpp.wxs.in b/packaging/WiX/connector-cpp.wxs.in index fbb9fbaf4..9aa4ec2fc 100644 --- a/packaging/WiX/connector-cpp.wxs.in +++ b/packaging/WiX/connector-cpp.wxs.in @@ -115,8 +115,26 @@ - + + + + + + @@ -125,8 +143,10 @@ + + @@ -136,8 +156,10 @@ + + @@ -147,27 +169,6 @@ - - - - - - - - diff --git a/packaging/compat.patch b/packaging/compat.patch index 03583b884..5b4befee7 100644 --- a/packaging/compat.patch +++ b/packaging/compat.patch @@ -32,8 +32,21 @@ index 8b960402..37fac11d 100644 # # Set higher warning level for the main connector code. +diff --git a/doc/doxygen.cfg b/doc/doxygen.cfg +index 7bf32bcf..b3f2bee6 100644 +--- a/doc/doxygen.cfg ++++ b/doc/doxygen.cfg +@@ -66,7 +66,7 @@ PROJECT_NAME = "MySQL Connector/C++" + # could be handy for archiving the generated documentation or if some version + # control system is used. + +-PROJECT_NUMBER = 8.0.23 ++PROJECT_NUMBER = 9.3.0 + + # Using the PROJECT_BRIEF tag one can provide an optional one line description + # for a project that appears at the top of each page and should give viewer a diff --git a/version.cmake b/version.cmake -index 53f8f540..4d32f5ee 100644 +index 53f8f540..7e589341 100644 --- a/version.cmake +++ b/version.cmake @@ -34,8 +34,8 @@ set(COPYRIGHT_YEAR "2024" CACHE INTERNAL "version info") @@ -43,7 +56,7 @@ index 53f8f540..4d32f5ee 100644 -set(CONCPP_VERSION_MAJOR 8 CACHE INTERNAL "version info") -set(CONCPP_VERSION_MINOR 4 CACHE INTERNAL "version info") +set(CONCPP_VERSION_MAJOR 9 CACHE INTERNAL "version info") -+set(CONCPP_VERSION_MINOR 1 CACHE INTERNAL "version info") ++set(CONCPP_VERSION_MINOR 3 CACHE INTERNAL "version info") set(CONCPP_VERSION_MICRO 0 CACHE INTERNAL "version info") # Level is "-alpha", "-beta", empty if GA set(CONCPP_VERSION_LEVEL "" CACHE INTERNAL "version info") diff --git a/packaging/deb-in/copyright.in b/packaging/deb-in/copyright.in index 3977c6f7a..b6ef630aa 100644 --- a/packaging/deb-in/copyright.in +++ b/packaging/deb-in/copyright.in @@ -4,7 +4,7 @@ Upstream-Contact: MySQL Release Engineering Source: https://dev.mysql.com/doc/connector-cpp/en/ Files: * -Copyright: 2008, 2024, Oracle and/or its affiliates. +Copyright: 2008, 2025, Oracle and/or its affiliates. License: @DEB_LICENSENAME@ This is a release of MySQL Connector/C++, the C++ interface for communicating with MySQL servers. diff --git a/packaging/mysql-connector-c++.spec.in b/packaging/mysql-connector-c++.spec.in index 96065d19a..c2bffc469 100644 --- a/packaging/mysql-connector-c++.spec.in +++ b/packaging/mysql-connector-c++.spec.in @@ -214,14 +214,20 @@ mkdir -p %{buildroot}%{plugin_dir} mv -v %{buildroot}%{_libdir}/plugin/* %{buildroot}%{plugin_dir} rm -rf %{buildroot}%{_libdir}/{plugin,private} +%pretrans devel +test -L /usr/include/mysql-cppconn && rm -f /usr/include/mysql-cppconn || true -%post -p /sbin/ldconfig +%post +/sbin/ldconfig -%postun -p /sbin/ldconfig +%postun +/sbin/ldconfig -%post jdbc -p /sbin/ldconfig +%post jdbc +/sbin/ldconfig -%postun jdbc -p /sbin/ldconfig +%postun jdbc +/sbin/ldconfig ############################################### @@ -280,7 +286,7 @@ rm -rf %{buildroot}%{_libdir}/{plugin,private} - Fixed provides/obsoletes information - Updates to configure/build/install logic -* Mon May 12 2024 Gipson Pulla - 9.0.0-1 +* Sun May 12 2024 Gipson Pulla - 9.0.0-1 - Bumped the version to 9.0.0 series. * Fri Nov 03 2023 Sreedhar Sreedhargadda - 8.2.0-1 diff --git a/testapp/CMakeLists.txt b/testapp/CMakeLists.txt index 6eb221018..2942c7693 100644 --- a/testapp/CMakeLists.txt +++ b/testapp/CMakeLists.txt @@ -60,12 +60,42 @@ PROJECT(MySQL_CONCPP_TEST) # ======================================================================== # Dependencies +function(find_openssl where) + + if(where STREQUAL "bundled") + if(mysql-concpp_DIR) + set(WITH_SSL "${mysql-concpp_DIR}") + else() + message(WARNING + "A request to use bundled OpenSSL libraries was made but" + " Connector/C++ install location was not explicitly given" + " via mysql-concpp_DIR or WITH_CONCPP setting." + ) + return() + endif() + endif() -if(WITH_SSL) + unset(openssl CACHE) + find_library(openssl + NAMES ssl + PATHS "${WITH_SSL}" + PATH_SUFFIXES "" "lib" "lib64" + NO_DEFAULT_PATH + # NO_CACHE # Note: requires cmake 3.21 + ) + + if(NOT openssl) + message(WARNING + "OpenSSL libraries not found at specified location: ${WITH_SSL}" + ) + return() + endif() + get_filename_component(WITH_SSL "${openssl}" DIRECTORY CACHE) message(STATUS "Using custom OpenSSL libraries at: ${WITH_SSL}") add_library(openssl INTERFACE) + # TODO: Is this path correct also on non-Win platforms? target_link_directories(openssl INTERFACE "${WITH_SSL}") if(WIN32) @@ -77,12 +107,16 @@ if(WITH_SSL) target_link_libraries(openssl INTERFACE ${ssl_libs}) add_library(mysql::openssl ALIAS openssl) -endif() +endfunction() + if(NOT DEFINED mysql-concpp_DIR AND DEFINED WITH_CONCPP) set(mysql-concpp_DIR "${WITH_CONCPP}") endif() +if(WITH_SSL) + find_openssl("${WITH_SSL}") +endif() find_package(mysql-concpp REQUIRED ${REQUIRED_COMPONENTS}) diff --git a/testing/CMakeLists.txt b/testing/CMakeLists.txt index 73c901b69..b8d76e616 100644 --- a/testing/CMakeLists.txt +++ b/testing/CMakeLists.txt @@ -49,25 +49,13 @@ endif() add_library(test_harness STATIC test_harness.cc) set_target_properties(test_harness PROPERTIES FOLDER "Tests") +target_link_libraries(test_harness PUBLIC gtest) + add_test_libraries(test_harness connector) add_test_includes(${CMAKE_CURRENT_SOURCE_DIR}) -if(MSVC) - - set(TEST_COMPILE_FLAGS - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - -D_CRT_SECURE_NO_WARNINGS - -D_SCL_SECURE_NO_WARNINGS - ) - - target_compile_definitions(test_harness PUBLIC - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - ) - - target_compile_options(test_harness PUBLIC /std:c++14) - -else() +if(NOT MSVC) set(TEST_COMPILE_FLAGS -Wno-sign-compare diff --git a/testing/find_package/CMakeLists.txt b/testing/find_package/CMakeLists.txt index e92ea2127..7135f04d3 100644 --- a/testing/find_package/CMakeLists.txt +++ b/testing/find_package/CMakeLists.txt @@ -124,11 +124,12 @@ macro(add_version_tests) if(WITH_CONCPP) - find_file(INFO_SRC + unset(INFO_SRC CACHE) + find_file(INFO_SRC NAME INFO_SRC PATHS ${WITH_CONCPP} NO_DEFAULT_PATH - NO_CACHE + #NO_CACHE # Note: requires cmake 3.21 ) else() @@ -210,7 +211,7 @@ macro(add_version_tests) # Prepare options for run_test.cmake - set(test_opts + set(test_opts "-DVERSION=${VERSION_${A}}" "-DWITH_DEBUG=${WITH_DEBUG}" ) @@ -256,12 +257,13 @@ macro(add_tests) if(WITH_SSL) + unset(openssl_lib CACHE) find_library(openssl_lib NAMES ssl libssl PATHS ${WITH_SSL} PATH_SUFFIXES lib NO_DEFAULT_PATH - NO_CACHE + # NO_CACHE ) endif() @@ -287,8 +289,8 @@ macro(add_tests) # Note: On Windows scenarios which build in Debug mode with static # connector library are added only if debug package is available. - if(WIN32 - AND A STREQUAL "static" + if(WIN32 + AND A STREQUAL "static" AND B STREQUAL "Debug" AND NOT WITH_DEBUG ) @@ -332,7 +334,7 @@ macro(add_tests) # # They are implemented by run_test.cmake -- see there. - add_test("config_${name_suffix}" + add_test("config_${name_suffix}" ${CMAKE_COMMAND} "-DCDK_DIR=${CDK_DIR}" "-DCONCPP_SRC_DIR=${HOME_DIR}/../.." @@ -347,7 +349,7 @@ macro(add_tests) FIXTURES_SETUP "${name_suffix}_configured" ) - add_test("build_${name_suffix}" + add_test("build_${name_suffix}" ${CMAKE_COMMAND} "-DCDK_DIR=${CDK_DIR}" "-DCONCPP_SRC_DIR=${HOME_DIR}/../.." @@ -365,7 +367,7 @@ macro(add_tests) message(STATUS "# added test: build_${name_suffix}") - add_test("check_${name_suffix}" + add_test("check_${name_suffix}" ${CMAKE_COMMAND} "-DCDK_DIR=${CDK_DIR}" "-DCONCPP_SRC_DIR=${HOME_DIR}/../.." diff --git a/testing/find_package/run_test.cmake b/testing/find_package/run_test.cmake index d4a2e0550..f3ca4b7bf 100644 --- a/testing/find_package/run_test.cmake +++ b/testing/find_package/run_test.cmake @@ -182,11 +182,11 @@ function(action_check) foreach(exec devapi_test xapi_test jdbc_test) set(exec_path) - find_program(exec_path + find_program(exec_path NAMES ${exec} PATHS "config_test/${out_dir}" NO_DEFAULT_PATH - NO_CACHE + # NO_CACHE # note: requires cmake 3.21 ) if(NOT EXISTS "${exec_path}") diff --git a/testing/tests.cmake b/testing/tests.cmake index 5258ce48a..edd8b7e3e 100644 --- a/testing/tests.cmake +++ b/testing/tests.cmake @@ -191,7 +191,12 @@ if(NOT DEFINED ABI_CHECK AND MSVC AND MAINTAINER_MODE) set(ABI_CHECK 1) endif() -if(ABI_CHECK) +# Note: The machinery we use to perform ABI checks works only +# with the original MSVC compiler which can produce required +# export map file, not with clang-cl (for which MSVC is also +# defined) + +if(ABI_CHECK AND MSVC AND NOT CLANG) add_abi_check() endif() diff --git a/version.cmake b/version.cmake index 7598398df..11a196aad 100644 --- a/version.cmake +++ b/version.cmake @@ -28,14 +28,14 @@ # Note: To be used in copyright notes of generated files -set(COPYRIGHT_YEAR "2024" CACHE INTERNAL "version info") +set(COPYRIGHT_YEAR "2025" CACHE INTERNAL "version info") # # Connector/C++ version # set(CONCPP_VERSION_MAJOR 9 CACHE INTERNAL "version info") -set(CONCPP_VERSION_MINOR 1 CACHE INTERNAL "version info") +set(CONCPP_VERSION_MINOR 3 CACHE INTERNAL "version info") set(CONCPP_VERSION_MICRO 0 CACHE INTERNAL "version info") # Level is "-alpha", "-beta", empty if GA set(CONCPP_VERSION_LEVEL "" CACHE INTERNAL "version info") diff --git a/xapi/tests/CMakeLists.txt b/xapi/tests/CMakeLists.txt index 1beda2812..5b1220455 100644 --- a/xapi/tests/CMakeLists.txt +++ b/xapi/tests/CMakeLists.txt @@ -36,12 +36,6 @@ set_property( PROPERTY COMPILE_DEFINITIONS "" ) -IF(WIN32) - add_definitions( - -D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING - ) -ENDIF() - if(BUILD_STATIC) add_definitions(-DSTATIC_CONCPP) endif() diff --git a/xapi/tests/xapi-t.cc b/xapi/tests/xapi-t.cc index 11d22dcb4..95b2ec206 100644 --- a/xapi/tests/xapi-t.cc +++ b/xapi/tests/xapi-t.cc @@ -67,13 +67,15 @@ void check_compress(mysqlx_session_t *sess) buf_len = 65536; memset(buf, 0, buf_len); - EXPECT_NE(nullptr, row = mysqlx_row_fetch_one(res)); + row = mysqlx_row_fetch_one(res); + EXPECT_FALSE(nullptr == row); EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, buf, &buf_len)); test_row("Test ", buf); buf_len = 65536; memset(buf, 0, buf_len); - EXPECT_NE(nullptr, row = mysqlx_row_fetch_one(res)); + row = mysqlx_row_fetch_one(res); + EXPECT_FALSE(nullptr == row); EXPECT_EQ(RESULT_OK, mysqlx_get_bytes(row, 0, 0, buf, &buf_len)); test_row("0123 ", buf); @@ -2552,7 +2554,6 @@ TEST_F(xapi, dns_srv) //Specifying a port number with DNS SRV lookup is not allowed. { - EXPECT_EQ(nullptr, mysqlx_get_client_from_url("mysqlx+srv://root@_mysqlx._tcp.localhost:33060", nullptr, &error)); std::cout << "Expected Error: " << mysqlx_error_message(error) << std::endl; @@ -2949,7 +2950,7 @@ TEST_F(xapi, tls_ver_ciphers) error = NULL; sess = mysqlx_get_session_from_options(opt, &error); mysqlx_free(error); - EXPECT_NE(NULL, sess); + EXPECT_FALSE(NULL == sess); mysqlx_session_close(sess); diff --git a/xapi/tests/xapi_crud-t.cc b/xapi/tests/xapi_crud-t.cc index 211ab8e50..82809858f 100644 --- a/xapi/tests/xapi_crud-t.cc +++ b/xapi/tests/xapi_crud-t.cc @@ -754,7 +754,7 @@ TEST_F(xapi, basic) const char *col_schema = mysqlx_column_get_schema(res, i); const char *col_cat = mysqlx_column_get_catalog(res, i); - EXPECT_NE(nullptr, col_cat); + EXPECT_FALSE(nullptr == col_cat); printf("\n Column # %d", i + 1); printf("\n * name: %s, orig name: %s, table: %s, orig table: %s, schema: %s, catalog: %s",