This is an automated email from the ASF dual-hosted git repository.

raulcd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/main by this push:
     new 8fa322c3e24 GH-49538: [C++][FlightRPC][ODBC] Use static linkage in 
Windows FlightSQL ODBC driver (#49585)
8fa322c3e24 is described below

commit 8fa322c3e24b326859f947b2b699e95feb0303f7
Author: Bryce Mecum <[email protected]>
AuthorDate: Tue Sep 29 00:44:27 2026 -0700

    GH-49538: [C++][FlightRPC][ODBC] Use static linkage in Windows FlightSQL 
ODBC driver (#49585)
    
    ### Rationale for this change
    
    The FlightSQL ODBC driver was previously using dynamic linkage for the 
Arrow deps it relies on. This worked but prevented a challenge for code signing 
because (I think) we'd have to sign each DLL and signing costs money. We can 
use static linkage with a dynamically linked MSVC runtime so we only have one 
DLL to sign.
    
    Ref: https://github.com/apache/arrow/issues/49404
    
    ### What changes are included in this PR?
    
    Updates to CMake and CI for the build to allow static linkage with dynamic 
MSVC runtime (`x64-windows-static-md`).
    
    ### Are these changes tested?
    
    Yes.
    
    ### Are there any user-facing changes?
    
    No.
    * GitHub Issue: #49538
    
    Authored-by: Bryce Mecum <[email protected]>
    Signed-off-by: Raúl Cumplido <[email protected]>
---
 .github/workflows/cpp_extra.yml                    |  8 ++-
 .github/workflows/package_odbc.yml                 | 11 ++--
 ci/vcpkg/amd64-windows-no-absl-sync-release.cmake  |  4 +-
 cpp/cmake_modules/FindGTestAlt.cmake               |  6 ++
 cpp/src/arrow/flight/CMakeLists.txt                |  4 +-
 cpp/src/arrow/flight/sql/CMakeLists.txt            |  5 ++
 cpp/src/arrow/flight/sql/odbc/CMakeLists.txt       | 44 ++++++++------
 .../arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt | 42 +++++++++----
 cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt | 69 +++++++++++-----------
 .../arrow/flight/sql/odbc/tests/odbc_test_suite.cc | 24 ++++++++
 .../arrow/flight/transport/grpc/customize_grpc.h   | 38 ++++++++++--
 11 files changed, 175 insertions(+), 80 deletions(-)

diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml
index 046e95292b0..6c12048050f 100644
--- a/.github/workflows/cpp_extra.yml
+++ b/.github/workflows/cpp_extra.yml
@@ -689,8 +689,8 @@ jobs:
       contents: read
       packages: write
     env:
-      ARROW_BUILD_SHARED: ON
-      ARROW_BUILD_STATIC: OFF
+      ARROW_BUILD_SHARED: OFF
+      ARROW_BUILD_STATIC: ON
       ARROW_BUILD_TESTS: ON
       ARROW_BUILD_TYPE: release
       # Turn Arrow CSV off to disable `find_package(Arrow)` check on MSVC CI.
@@ -706,6 +706,10 @@ jobs:
       # Build Arrow with GPR_DISABLE_ABSEIL_SYNC so grpcpp's Mutex ABI
       # matches the gRPC rebuilt by the overlay triplet. Remove once fixed 
upstream.
       ARROW_CXXFLAGS: -DGPR_DISABLE_ABSEIL_SYNC
+      ARROW_DEPENDENCY_USE_SHARED: OFF
+      ARROW_MIMALLOC: OFF
+      ARROW_TEST_LINKAGE: static
+      ARROW_USE_STATIC_CRT: OFF
       CMAKE_GENERATOR: Ninja
       CMAKE_INSTALL_PREFIX: /usr
       VCPKG_BINARY_SOURCES: 'clear;nugettimeout,600;nuget,GitHub,readwrite'
diff --git a/.github/workflows/package_odbc.yml 
b/.github/workflows/package_odbc.yml
index cc2aad00aca..8bab30e5b4c 100644
--- a/.github/workflows/package_odbc.yml
+++ b/.github/workflows/package_odbc.yml
@@ -50,21 +50,24 @@ jobs:
     permissions:
       packages: write
     env: &odbc_msvc_env
-      ARROW_BUILD_SHARED: ON
-      ARROW_BUILD_STATIC: OFF
+      ARROW_BUILD_SHARED: OFF
+      ARROW_BUILD_STATIC: ON
       ARROW_BUILD_TESTS: OFF
       ARROW_BUILD_TYPE: release
-      # Turn Arrow CSV off to disable `find_package(Arrow)` check on MSVC CI. 
+      # Turn Arrow CSV off to disable `find_package(Arrow)` check on MSVC CI.
       # GH-49050 TODO: enable `find_package(Arrow)` check on MSVC CI.
       ARROW_CSV: OFF
       ARROW_DEPENDENCY_SOURCE: VCPKG
+      ARROW_DEPENDENCY_USE_SHARED: OFF
       ARROW_FLIGHT_SQL_ODBC: ON
       ARROW_FLIGHT_SQL_ODBC_INSTALLER: ON
       ARROW_HOME: /usr
+      ARROW_MIMALLOC: OFF
+      ARROW_USE_STATIC_CRT: OFF
       CMAKE_GENERATOR: Ninja
       CMAKE_INSTALL_PREFIX: /usr
       VCPKG_BINARY_SOURCES: 'clear;nugettimeout,600;nuget,GitHub,readwrite'
-      VCPKG_DEFAULT_TRIPLET: x64-windows
+      VCPKG_DEFAULT_TRIPLET: x64-windows-static-md
     steps:
       - name: Checkout Arrow
         uses: actions/checkout@v7
diff --git a/ci/vcpkg/amd64-windows-no-absl-sync-release.cmake 
b/ci/vcpkg/amd64-windows-no-absl-sync-release.cmake
index 97c73e31464..436650842ad 100644
--- a/ci/vcpkg/amd64-windows-no-absl-sync-release.cmake
+++ b/ci/vcpkg/amd64-windows-no-absl-sync-release.cmake
@@ -17,10 +17,10 @@
 
 # GH-49465: rebuild gRPC with native sync instead of absl::Mutex to avoid the
 # Windows exit hang. See the ODBC Windows job in cpp_extra.yml
-# Dynamic CRT/linkage and release-only to match that job.
+# Static library linkage, dynamic CRT (/MD), release-only to match that job.
 set(VCPKG_TARGET_ARCHITECTURE x64)
 set(VCPKG_CRT_LINKAGE dynamic)
-set(VCPKG_LIBRARY_LINKAGE dynamic)
+set(VCPKG_LIBRARY_LINKAGE static)
 set(VCPKG_BUILD_TYPE release)
 
 set(VCPKG_C_FLAGS "/DGPR_DISABLE_ABSEIL_SYNC")
diff --git a/cpp/cmake_modules/FindGTestAlt.cmake 
b/cpp/cmake_modules/FindGTestAlt.cmake
index d1873d138e6..766fbfc9422 100644
--- a/cpp/cmake_modules/FindGTestAlt.cmake
+++ b/cpp/cmake_modules/FindGTestAlt.cmake
@@ -38,7 +38,12 @@ find_package(GTest ${find_package_args})
 set(GTestAlt_FOUND ${GTest_FOUND})
 if(GTestAlt_FOUND AND GTestAlt_NEED_CXX_STANDARD_CHECK)
   set(KEEP_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE})
+  set(KEEP_CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_TRY_COMPILE_CONFIGURATION})
   set(CMAKE_TRY_COMPILE_TARGET_TYPE EXECUTABLE)
+  # Match the parent build when dependencies are available for only one 
configuration.
+  if(NOT CMAKE_TRY_COMPILE_CONFIGURATION)
+    set(CMAKE_TRY_COMPILE_CONFIGURATION ${CMAKE_BUILD_TYPE})
+  endif()
   set(GTestAlt_CXX_STANDARD_TEST_SOURCE
       "${CMAKE_CURRENT_BINARY_DIR}/gtest_cxx_standard_test.cc")
   file(WRITE ${GTestAlt_CXX_STANDARD_TEST_SOURCE}
@@ -56,6 +61,7 @@ TEST(CXX_STANDARD, MatcherStringView) {
               LINK_LIBRARIES GTest::gtest_main
               OUTPUT_VARIABLE GTestAlt_CXX_STANDARD_OUTPUT)
   set(CMAKE_TRY_COMPILE_TARGET_TYPE ${KEEP_CMAKE_TRY_COMPILE_TARGET_TYPE})
+  set(CMAKE_TRY_COMPILE_CONFIGURATION ${KEEP_CMAKE_TRY_COMPILE_CONFIGURATION})
   if(NOT GTestAlt_CXX_STANDARD_AVAILABLE)
     message(STATUS "GTest can't be used with C++${CMAKE_CXX_STANDARD}.")
     message(STATUS "Use -DGTest_SOURCE=BUNDLED.")
diff --git a/cpp/src/arrow/flight/CMakeLists.txt 
b/cpp/src/arrow/flight/CMakeLists.txt
index 8974c9581f7..91afab15702 100644
--- a/cpp/src/arrow/flight/CMakeLists.txt
+++ b/cpp/src/arrow/flight/CMakeLists.txt
@@ -123,9 +123,9 @@ function(arrow_set_generated_proto_files_properties)
   set(GENERATED_FILES ${ARGN})
   set_source_files_properties(${GENERATED_FILES} PROPERTIES GENERATED TRUE)
   if(MSVC)
-    # Suppress missing dll-interface warning
+    # Suppress warnings caused by Protobuf (dll-interface)
     set_source_files_properties(${GENERATED_FILES}
-                                PROPERTIES COMPILE_OPTIONS "/wd4251"
+                                PROPERTIES COMPILE_OPTIONS "/wd4251;/wd4275"
                                            SKIP_UNITY_BUILD_INCLUSION TRUE)
   elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
     # Disable -Wmissing-declarations
diff --git a/cpp/src/arrow/flight/sql/CMakeLists.txt 
b/cpp/src/arrow/flight/sql/CMakeLists.txt
index 2299bdfe0a3..6e01672248d 100644
--- a/cpp/src/arrow/flight/sql/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/CMakeLists.txt
@@ -99,6 +99,10 @@ if(MSVC)
 endif()
 foreach(LIB_TARGET ${ARROW_FLIGHT_SQL_LIBRARIES})
   target_compile_definitions(${LIB_TARGET} PRIVATE ARROW_FLIGHT_SQL_EXPORTING)
+  if(MSVC)
+    # Suppress warnings caused by Protobuf (dll-interface)
+    target_compile_options(${LIB_TARGET} PRIVATE "/wd4275")
+  endif()
 endforeach()
 
 if(ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static" AND ARROW_BUILD_STATIC)
@@ -177,6 +181,7 @@ if(ARROW_BUILD_TESTS OR ARROW_BUILD_EXAMPLES)
                                                        ARROW_FLIGHT_SQL_STATIC)
     endforeach()
   endif()
+
 endif()
 
 if(ARROW_FLIGHT_SQL_ODBC)
diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt 
b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
index 181d855fde4..178d144bac3 100644
--- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
@@ -59,28 +59,41 @@ if(WIN32)
   list(APPEND ARROW_FLIGHT_SQL_ODBC_SRCS odbc.def install/versioninfo.rc)
 endif()
 
-# On Windows, dynmaic build for ODBC is supported.
-# On unix systems, static build for ODBC is supported, all libraries are 
linked statically on unix.
-set(ARROW_FLIGHT_SQL_ODBC_DEPENDENCIES "")
+# Initialize install interface libs (only set in Windows static build)
 set(ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS "")
 set(ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS "")
 set(ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS "")
+
 if(WIN32)
-  set(ARROW_FLIGHT_SQL_ODBC_DEPENDENCIES arrow_flight_sql)
-  set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_shared 
arrow_odbc_spi_impl)
-  set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static)
-  list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS
-       ArrowFlight::arrow_flight_sql_shared)
-  list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS
-       ArrowFlight::arrow_flight_sql_static)
+  if(ARROW_BUILD_STATIC)
+    # Static Arrow deps on Windows — self-contained ODBC DLL
+    set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_static
+                                               arrow_odbc_spi_impl)
+    set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static)
+    list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS
+         ArrowFlight::arrow_flight_sql_static)
+    list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS
+         ArrowFlight::arrow_flight_sql_static)
+  else()
+    set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_flight_sql_shared
+                                               arrow_odbc_spi_impl)
+    set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static)
+    list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_INSTALL_INTERFACE_LIBS
+         ArrowFlight::arrow_flight_sql_shared)
+    list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS
+         ArrowFlight::arrow_flight_sql_static)
+  endif()
   list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS ODBC::ODBC 
${ODBCINST})
 else()
-  # Unix
+  # Unix/macOS: driver dynamically links arrow_flight_sql so the driver and 
test
+  # binary share the same grpc/arrow_flight runtime.
   set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_odbc_spi_impl)
   set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS ODBC::ODBC ${ODBCINST})
 endif()
 
 add_arrow_lib(arrow_flight_sql_odbc
+              BUILD_SHARED
+              ON
               CMAKE_PACKAGE_NAME
               ArrowFlightSqlOdbc
               PKG_CONFIG_NAME
@@ -91,8 +104,6 @@ add_arrow_lib(arrow_flight_sql_odbc
               ${ARROW_FLIGHT_SQL_ODBC_SRCS}
               DEFINITIONS
               UNICODE
-              DEPENDENCIES
-              ${ARROW_FLIGHT_SQL_ODBC_DEPENDENCIES}
               SHARED_LINK_FLAGS
               ${ARROW_VERSION_SCRIPT_FLAGS} # Defined in 
cpp/arrow/CMakeLists.txt
               SHARED_LINK_LIBS
@@ -149,15 +160,10 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER)
   set(CPACK_PACKAGE_CONTACT "[email protected]")
 
   if(WIN32)
-    # Install ODBC and its Arrow dependencies
     install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
             DESTINATION bin
             COMPONENT ArrowFlightSQLODBC)
-    install(TARGETS arrow_shared
-                    arrow_compute_shared
-                    arrow_flight_shared
-                    arrow_flight_sql_shared
-                    arrow_flight_sql_odbc_shared
+    install(TARGETS arrow_flight_sql_odbc_shared
                     RUNTIME_DEPENDENCIES
                     PRE_EXCLUDE_REGEXES
                     "api-ms-.*"
diff --git a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt 
b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt
index a455ddadd23..4d990b3e89a 100644
--- a/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt
@@ -133,12 +133,21 @@ endif()
 if(WIN32)
   find_package(ODBC REQUIRED)
   target_include_directories(arrow_odbc_spi_impl PUBLIC ${ODBC_INCLUDE_DIR})
-  target_link_libraries(arrow_odbc_spi_impl
-                        PUBLIC arrow_flight_sql_shared
-                               arrow_compute_shared
-                               Boost::locale
-                               arrow::simdjson
-                               ${ODBCINST})
+  if(ARROW_BUILD_STATIC)
+    target_link_libraries(arrow_odbc_spi_impl
+                          PUBLIC arrow_flight_sql_static
+                                 arrow_compute_static
+                                 Boost::locale
+                                 arrow::simdjson
+                                 ${ODBCINST})
+  else()
+    target_link_libraries(arrow_odbc_spi_impl
+                          PUBLIC arrow_flight_sql_shared
+                                 arrow_compute_shared
+                                 Boost::locale
+                                 arrow::simdjson
+                                 ${ODBCINST})
+  endif()
 else()
   # Unix
   target_include_directories(arrow_odbc_spi_impl SYSTEM BEFORE PUBLIC 
${ODBC_INCLUDE_DIR})
@@ -166,11 +175,19 @@ target_link_libraries(arrow_odbc_spi_impl_cli 
arrow_odbc_spi_impl)
 
 # On Windows, dynamic linking ODBC is supported.
 # On unix systems, static linking ODBC is supported, thus the library linking 
is static.
-if(WIN32)
-  set(ODBC_SPI_IMPL_TEST_LINK_LIBS arrow_flight_testing_shared)
+# Use STATIC_LINK_LIBS when Flight tests require static linkage to avoid 
mixing static/shared Arrow
+if(WIN32 AND ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
+  set(ODBC_SPI_IMPL_TEST_STATIC_LIBS arrow_odbc_spi_impl 
arrow_flight_testing_static
+                                     ${ARROW_TEST_STATIC_LINK_LIBS})
+  set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS "")
+elseif(WIN32)
+  set(ODBC_SPI_IMPL_TEST_STATIC_LIBS "")
+  set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS arrow_odbc_spi_impl 
arrow_flight_testing_shared)
 else()
-  # unix
-  set(ODBC_SPI_IMPL_TEST_LINK_LIBS arrow_flight_testing_static)
+  # Unix - always static
+  set(ODBC_SPI_IMPL_TEST_STATIC_LIBS arrow_odbc_spi_impl 
arrow_flight_testing_static
+                                     ${ARROW_TEST_STATIC_LINK_LIBS})
+  set(ODBC_SPI_IMPL_TEST_EXTRA_LIBS "")
 endif()
 
 add_arrow_test(odbc_spi_impl_test
@@ -190,5 +207,6 @@ add_arrow_test(odbc_spi_impl_test
                record_batch_transformer_test.cc
                util_test.cc
                EXTRA_LINK_LIBS
-               arrow_odbc_spi_impl
-               ${ODBC_SPI_IMPL_TEST_LINK_LIBS})
+               ${ODBC_SPI_IMPL_TEST_EXTRA_LIBS}
+               STATIC_LINK_LIBS
+               ${ODBC_SPI_IMPL_TEST_STATIC_LIBS})
diff --git a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt 
b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
index 0f45bfd0c81..81f8ec891be 100644
--- a/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
@@ -42,38 +42,35 @@ set(ARROW_FLIGHT_SQL_ODBC_TEST_SRCS
     # GH-46889: move protobuf_test_util to a more common location
     ../../../../engine/substrait/protobuf_test_util.cc)
 
-# GH-49651 Link ODBC tests statically on Linux and dynamically on macOS/Windows
-if(WIN32 OR APPLE)
-  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_flight_sql_odbc_shared
-                                           ${ARROW_TEST_SHARED_LINK_LIBS})
-else()
-  # GH-49651 Link ODBC tests statically on Linux to fix segfault
-  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_flight_sql_odbc_static
-                                           ${ARROW_TEST_STATIC_LINK_LIBS})
-endif()
-
-# On macOS, link `ODBCINST` first to ensure iodbc take precedence over unixodbc
+# On macOS, link `ODBCINST` first to ensure iodbc takes precedence over 
unixodbc.
 set(ARROW_FLIGHT_SQL_ODBC_TEST_LIBS ${ODBCINST} ${ODBC_LIBRARIES} 
${SQLite3_LIBRARIES})
 
-# On Windows, dynamic linking ODBC is supported, tests link libraries 
dynamically.
-# On unix systems, static linking ODBC is supported, thus tests link libraries 
statically.
-set(ARROW_FLIGHT_SQL_ODBC_TEST_EXTRA_LINK_LIBS "")
-set(ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS "")
-if(WIN32)
-  # arrow_odbc_spi_impl is required on Windows due to dynamic linking
-  list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_EXTRA_LINK_LIBS arrow_odbc_spi_impl
-       ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS})
+# STATIC_LINK_LIBS replaces add_arrow_test's default Arrow test libraries, 
while
+# EXTRA_LINK_LIBS supplements them.
+if(WIN32 AND ARROW_FLIGHT_TEST_LINKAGE STREQUAL "shared")
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE EXTRA_LINK_LIBS)
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_odbc_spi_impl
+                                           ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS})
+elseif(WIN32)
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE STATIC_LINK_LIBS)
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS
+      arrow_odbc_spi_impl ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} 
arrow_flight_sql_odbc_static
+      ${ARROW_TEST_STATIC_LINK_LIBS})
+elseif(APPLE)
+  # GH-49651: Link the ODBC driver dynamically on macOS.
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE STATIC_LINK_LIBS)
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS
+      ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} arrow_flight_sql_odbc_shared
+      ${ARROW_TEST_SHARED_LINK_LIBS})
 else()
-  # Unix
-  list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS
-       ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} 
${ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS})
-
-  if(NOT APPLE)
-    # Links static dependencies on Linux to support ARROW_TEST_LINKAGE=static
-    list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS arrow_odbc_spi_impl
-         ${ARROW_PROTOBUF_LIBPROTOBUF})
-  endif()
-
+  # GH-49651: Link the ODBC driver statically on Linux to avoid a segfault.
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE STATIC_LINK_LIBS)
+  set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS
+      ${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS}
+      arrow_flight_sql_odbc_static
+      ${ARROW_TEST_STATIC_LINK_LIBS}
+      arrow_odbc_spi_impl
+      ${ARROW_PROTOBUF_LIBPROTOBUF})
 endif()
 
 add_arrow_test(flight_sql_odbc_test
@@ -82,13 +79,19 @@ add_arrow_test(flight_sql_odbc_test
                ${ARROW_FLIGHT_SQL_MOCK_SERVER_SRCS}
                DEFINITIONS
                UNICODE
-               EXTRA_LINK_LIBS
-               ${ARROW_FLIGHT_SQL_ODBC_TEST_EXTRA_LINK_LIBS}
-               STATIC_LINK_LIBS
-               ${ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS})
+               ${ARROW_FLIGHT_SQL_ODBC_TEST_LINK_MODE}
+               ${ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS})
 
 find_package(ODBC REQUIRED)
 target_link_libraries(arrow-flight-sql-odbc-test PRIVATE ODBC::ODBC)
 
+if(WIN32)
+  # GH-49538: Dynamically pass the filename of the driver DLL so 
PinDriverModule
+  # in odbc_test_suite.cc can hold a handle to it.
+  target_compile_definitions(arrow-flight-sql-odbc-test
+                             PRIVATE 
"ARROW_FLIGHT_SQL_ODBC_DLL_FILE_NAME=L\"$<TARGET_FILE_NAME:arrow_flight_sql_odbc_shared>\""
+  )
+endif()
+
 # Disable unity build due to sqlite_sql_info.cc conflict with sql.h and 
sqlext.h headers.
 set_target_properties(arrow-flight-sql-odbc-test PROPERTIES UNITY_BUILD OFF)
diff --git a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc 
b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc
index 3125c18b92a..79a8ed9f88c 100644
--- a/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc
+++ b/cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc
@@ -29,6 +29,22 @@
 
 namespace arrow::flight::sql::odbc {
 
+#ifdef _WIN32
+namespace {
+
+// GH-49538: Hold a handle to the driver for the entire duration of the test
+// suite to avoid a segfault on teardown. This most likely due to having two
+// statically linked copies of gRPC in the test program (one from the driver 
and
+// one from the mock server).
+void PinDriverModule() {
+  HMODULE unused = nullptr;
+  GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, 
ARROW_FLIGHT_SQL_ODBC_DLL_FILE_NAME,
+                     &unused);
+}
+
+}  // namespace
+#endif  // _WIN32
+
 class MockServerEnvironment : public ::testing::Environment {
  public:
   void SetUp() override {
@@ -137,6 +153,14 @@ void ODBCTestBase::ConnectWithString(std::string 
connect_str, SQLHDBC& conn_hand
                              static_cast<SQLSMALLINT>(connect_str0.size()), 
out_str,
                              kOdbcBufferSize, &out_str_len, 
SQL_DRIVER_NOPROMPT))
       << GetOdbcErrorMessage(SQL_HANDLE_DBC, conn_handle);
+
+// GH-49538: Hold a handle to the driver for the entire duration of the test
+// suite to avoid a segfault on teardown. This most likely due to having two
+// statically linked copies of gRPC in the test program (one from the driver 
and
+// one from the mock server).
+#ifdef _WIN32
+  PinDriverModule();
+#endif
 }
 
 void ODBCTestBase::Disconnect(SQLHENV& env_handle, SQLHDBC& conn_handle) {
diff --git a/cpp/src/arrow/flight/transport/grpc/customize_grpc.h 
b/cpp/src/arrow/flight/transport/grpc/customize_grpc.h
index 7836f7c161d..4a64e4e0721 100644
--- a/cpp/src/arrow/flight/transport/grpc/customize_grpc.h
+++ b/cpp/src/arrow/flight/transport/grpc/customize_grpc.h
@@ -20,16 +20,42 @@
 #include <limits>
 #include <memory>
 
+#if __has_include(<absl/synchronization/mutex.h>)
+
 // HACK: Workaround absl::Mutex ABI incompatibility by making sure the
 // non-debug version of Abseil is included
 // (https://github.com/conda-forge/abseil-cpp-feedstock/issues/104,
 //  https://github.com/abseil/abseil-cpp/issues/1624)
-
-#if __has_include(<absl/synchronization/mutex.h>)
-
-#  ifndef NDEBUG
-#    define ARROW_NO_NDEBUG
-#    define NDEBUG
+//
+// Abseil picks where Mutex::Dtor lives based on NDEBUG:
+//
+//   mutex.h:  #if defined(NDEBUG) && !ABSL_HAVE_THREAD_SANITIZER &&
+//                 !ABSL_BUILD_DLL   -> inline, emitted into this TU
+//   mutex.cc: #if !defined(NDEBUG) || ABSL_HAVE_THREAD_SANITIZER ||
+//                 ABSL_BUILD_DLL    -> strong, out-of-line
+//
+// Defining NDEBUG here makes this TU emit its own inline Mutex::Dtor. Whether
+// that helps or hurts depends on how the Abseil we link against was built:
+//
+//  - Abseil built *with* NDEBUG (the conda case above): it inlined Dtor away
+//    and never exported it, so a debug TU that expects the out-of-line symbol
+//    gets an undefined reference. Emitting our own copy fixes that.
+//
+//  - Abseil built *without* NDEBUG (a Debug vcpkg/system build): it has the
+//    strong out-of-line Dtor. Emitting our own copy is then a duplicate
+//    definition, which a *static* Abseil turns into LNK2005 (GH-49585). With a
+//    shared Abseil it is harmless, since the definitions live in separate
+//    images.
+//
+// So restrict the hack to the cases where it cannot produce a duplicate:
+// anything that is not MSVC-linking-static-Abseil. On MSVC, Abseil's CMake 
puts
+// ABSL_CONSUME_DLL in the INTERFACE compile definitions of its targets, so its
+// presence tells us we are consuming the DLL rather than the static library.
+#  if !defined(_MSC_VER) || defined(ABSL_CONSUME_DLL)
+#    ifndef NDEBUG
+#      define ARROW_NO_NDEBUG
+#      define NDEBUG
+#    endif
 #  endif
 
 #  include <absl/synchronization/mutex.h>

Reply via email to