Skip to content
Draft
58 changes: 54 additions & 4 deletions .github/workflows/cpp_extra.yml
Original file line number Diff line number Diff line change
Expand Up @@ -526,29 +526,49 @@ jobs:
packages: write
env:
ARROW_BUILD_SHARED: ON
ARROW_BUILD_STATIC: 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.
ARROW_TEST_LINKAGE: shared
ARROW_CMAKE_ARGS: -DVCPKG_TARGET_TRIPLET=x64-windows-static-md
# 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
steps:
- name: Disable Crash Dialogs
- name: Configure Crash Dumps
run: |
# Disable crash dialog UI but enable dump collection
reg add `
"HKCU\SOFTWARE\Microsoft\Windows\Windows Error Reporting" `
/v DontShowUI `
/t REG_DWORD `
/d 1 `
/f
# Enable local crash dumps
reg add `
"HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" `
/v DumpFolder `
/t REG_EXPAND_SZ `
/d "%LOCALAPPDATA%\CrashDumps" `
/f
reg add `
"HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps" `
/v DumpType `
/t REG_DWORD `
/d 2 `
/f
# Create dumps directory
New-Item -ItemType Directory -Force -Path "$env:LOCALAPPDATA\CrashDumps" | Out-Null
- name: Checkout Arrow
uses: actions/checkout@v6
with:
Expand Down Expand Up @@ -610,10 +630,24 @@ jobs:
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
set VCPKG_ROOT=%VCPKG_ROOT_KEEP%
bash -c "ci/scripts/cpp_build.sh $(pwd) $(pwd)/build"
- name: List vcpkg packages for debugging
shell: bash
run: |
echo "=== Installed vcpkg packages (protobuf, grpc, abseil) ==="
vcpkg list | grep -E 'protobuf|grpc|abseil' || echo "No matching packages found"
- name: Register Flight SQL ODBC Driver
shell: cmd
run: |
call "cpp\src\arrow\flight\sql\odbc\tests\install_odbc.cmd" ${{ github.workspace }}\build\cpp\%ARROW_BUILD_TYPE%\arrow_flight_sql_odbc.dll
- name: Upload test executable and dependencies for debugging
if: always()
uses: actions/upload-artifact@v7
with:
name: arrow-flight-sql-odbc-test-debug
path: |
build/cpp/${{ env.ARROW_BUILD_TYPE }}/arrow-flight-sql-odbc-test.exe
build/cpp/${{ env.ARROW_BUILD_TYPE }}/*.dll
if-no-files-found: warn
- name: Test
shell: cmd
run: |
Expand All @@ -623,6 +657,22 @@ jobs:
# Convert VCPKG Windows path to MSYS path
for /f "usebackq delims=" %%I in (`bash -c "cygpath -u \"$VCPKG_ROOT_KEEP\""` ) do set VCPKG_ROOT=%%I
bash -c "ci/scripts/cpp_test.sh $(pwd) $(pwd)/build"
- name: Collect crash dumps
if: failure()
shell: bash
run: |
echo "=== Collecting crash dumps from Windows Error Reporting ==="
mkdir -p crash-dumps
# Windows dumps go to %LOCALAPPDATA%\CrashDumps
cp "$LOCALAPPDATA/CrashDumps/"*.dmp crash-dumps/ 2>/dev/null || echo "No crash dumps found"
ls -lh crash-dumps/ || echo "Crash dumps directory is empty"
- name: Upload crash dumps
if: failure()
uses: actions/upload-artifact@v7
with:
name: arrow-flight-sql-odbc-crash-dumps
path: crash-dumps/
if-no-files-found: warn
- name: Install WiX Toolset
shell: pwsh
run: |
Expand Down
8 changes: 8 additions & 0 deletions cpp/src/arrow/compute/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ if(ARROW_TESTING)
# Even though this is still just an object library we still need to "link" our
# dependencies so that include paths are configured correctly
target_link_libraries(arrow_compute_core_testing PUBLIC ${ARROW_GTEST_GMOCK})
# When using static test linkage, define ARROW_STATIC so test_util_internal.cc doesn't expect DLL imports
if(ARROW_TEST_LINKAGE STREQUAL "static")
target_compile_definitions(arrow_compute_core_testing PRIVATE ARROW_STATIC ARROW_COMPUTE_STATIC)
endif()
endif()

# Define arrow_compute_testing object library for test files requiring extra kernels.
Expand All @@ -46,6 +50,10 @@ if(ARROW_TESTING AND ARROW_COMPUTE)
target_link_libraries(arrow_compute_testing
PUBLIC $<TARGET_OBJECTS:arrow_compute_core_testing>
PUBLIC ${ARROW_GTEST_GTEST})
# When using static test linkage, define ARROW_STATIC so test_env.cc doesn't expect DLL imports
if(ARROW_TEST_LINKAGE STREQUAL "static")
target_compile_definitions(arrow_compute_testing PRIVATE ARROW_STATIC ARROW_COMPUTE_STATIC)
endif()
endif()

set(ARROW_COMPUTE_TEST_PREFIX "arrow-compute")
Expand Down
4 changes: 4 additions & 0 deletions cpp/src/arrow/compute/kernels/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ if(ARROW_TESTING)
# Even though this is still just an object library we still need to "link" our
# dependencies so that include paths are configured correctly
target_link_libraries(arrow_compute_kernels_testing PUBLIC ${ARROW_GTEST_GMOCK})
# When using static test linkage, define ARROW_STATIC so test_util_internal.cc doesn't expect DLL imports
if(ARROW_TEST_LINKAGE STREQUAL "static")
target_compile_definitions(arrow_compute_kernels_testing PRIVATE ARROW_STATIC)
endif()
endif()

add_arrow_test(scalar_cast_test
Expand Down
54 changes: 37 additions & 17 deletions cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,20 @@ set(ARROW_FLIGHT_SQL_ODBC_DEPENDENCIES "")
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)
if(WIN32 AND 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_shared)
ArrowFlight::arrow_flight_sql_static)
list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS
ArrowFlight::arrow_flight_sql_static)
list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS ODBC::ODBC ${ODBCINST})
elseif(WIN32)
# Dynamic Arrow deps on Windows (current behavior)
set(ARROW_FLIGHT_SQL_ODBC_DEPENDENCIES arrow_flight_sql)
set(ARROW_FLIGHT_SQL_ODBC_SHARED_LINK_LIBS arrow_odbc_spi_impl)
set(ARROW_FLIGHT_SQL_ODBC_STATIC_LINK_LIBS arrow_flight_sql_static)
list(APPEND ARROW_FLIGHT_SQL_ODBC_STATIC_INSTALL_INTERFACE_LIBS
ArrowFlight::arrow_flight_sql_static)
list(APPEND ARROW_FLIGHT_SQL_ODBC_SHARED_PRIVATE_LINK_LIBS ODBC::ODBC ${ODBCINST})
Expand Down Expand Up @@ -135,22 +143,34 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER)
# GH-47876 TODO: set up `arrow_flight_sql_odbc` component for macOS Installer
# GH-47877 TODO: set up `arrow_flight_sql_odbc` component for Linux Installer
if(WIN32)
# Install ODBC and its Arrow dependencies
install(PROGRAMS ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS}
DESTINATION bin
COMPONENT arrow_flight_sql_odbc)
install(TARGETS arrow_shared
arrow_compute_shared
arrow_flight_shared
arrow_flight_sql_shared
arrow_flight_sql_odbc_shared
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES
"api-ms-.*"
"ext-ms-.*"
POST_EXCLUDE_REGEXES
".*system32/.*\\.dll"
RUNTIME DESTINATION bin COMPONENT arrow_flight_sql_odbc)
if(ARROW_BUILD_STATIC)
# Static build: only install the self-contained ODBC DLL
install(TARGETS arrow_flight_sql_odbc_shared
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES
"api-ms-.*"
"ext-ms-.*"
POST_EXCLUDE_REGEXES
".*system32/.*\\.dll"
RUNTIME DESTINATION bin COMPONENT arrow_flight_sql_odbc)
else()
# Dynamic build: install ODBC DLL + Arrow dependency DLLs
install(TARGETS arrow_shared
arrow_compute_shared
arrow_flight_shared
arrow_flight_sql_shared
arrow_flight_sql_odbc_shared
RUNTIME_DEPENDENCIES
PRE_EXCLUDE_REGEXES
"api-ms-.*"
"ext-ms-.*"
POST_EXCLUDE_REGEXES
".*system32/.*\\.dll"
RUNTIME DESTINATION bin COMPONENT arrow_flight_sql_odbc)
endif()

set(CPACK_WIX_EXTRA_SOURCES
"${CMAKE_CURRENT_SOURCE_DIR}/install/windows/arrow-flight-sql-odbc.wxs")
Expand Down
40 changes: 31 additions & 9 deletions cpp/src/arrow/flight/sql/odbc/odbc_impl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,17 @@ 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
${ODBCINST})
if(ARROW_BUILD_STATIC)
target_link_libraries(arrow_odbc_spi_impl
PUBLIC arrow_flight_sql_static
arrow_compute_static
Boost::locale
${ODBCINST})
else()
target_link_libraries(arrow_odbc_spi_impl
PUBLIC arrow_flight_sql_shared arrow_compute_shared Boost::locale
${ODBCINST})
endif()
else()
# Unix
target_include_directories(arrow_odbc_spi_impl SYSTEM BEFORE PUBLIC ${ODBC_INCLUDE_DIR})
Expand Down Expand Up @@ -163,11 +171,24 @@ 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")
# Static linkage required - pass everything via STATIC_LINK_LIBS
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)
# Shared linkage - use EXTRA_LINK_LIBS
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
Expand All @@ -187,5 +208,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})
23 changes: 19 additions & 4 deletions cpp/src/arrow/flight/sql/odbc/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,12 @@ set(ARROW_FLIGHT_SQL_ODBC_TEST_SRCS
type_info_test.cc
# Enable Protobuf cleanup after test execution
# GH-46889: move protobuf_test_util to a more common location
../../../../engine/substrait/protobuf_test_util.cc)
#../../../../engine/substrait/protobuf_test_util.cc)
)

if(ARROW_TEST_LINKAGE STREQUAL "static")
# ODBC tests must respect ARROW_FLIGHT_TEST_LINKAGE since they depend on Flight libraries
# which may be forced to static linkage due to static gRPC/Protobuf
if(ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
set(ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS arrow_flight_sql_odbc_static
${ARROW_TEST_STATIC_LINK_LIBS})
else()
Expand All @@ -57,8 +60,14 @@ set(ARROW_FLIGHT_SQL_ODBC_TEST_LIBS ${ODBCINST} ${ODBC_LIBRARIES} ${SQLite3_LIBR
# 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
if(WIN32 AND ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
# Static Windows tests
list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS
arrow_odbc_spi_impl
${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS}
${ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS})
elseif(WIN32)
# Dynamic Windows tests (current behavior)
list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_EXTRA_LINK_LIBS arrow_odbc_spi_impl
${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS})
else()
Expand All @@ -67,6 +76,12 @@ else()
${ARROW_FLIGHT_SQL_ODBC_TEST_LIBS} ${ARROW_FLIGHT_SQL_ODBC_TEST_LINK_LIBS})
endif()

# When Flight tests require static linkage, we must also add Arrow test libs to STATIC_LINK_LIBS
# to avoid add_arrow_test from adding shared Arrow test libs
if(ARROW_FLIGHT_TEST_LINKAGE STREQUAL "static")
list(APPEND ARROW_FLIGHT_SQL_ODBC_TEST_STATIC_LINK_LIBS ${ARROW_TEST_STATIC_LINK_LIBS})
endif()

add_arrow_test(flight_sql_odbc_test
SOURCES
${ARROW_FLIGHT_SQL_ODBC_TEST_SRCS}
Expand Down
17 changes: 16 additions & 1 deletion cpp/src/arrow/flight/sql/odbc/tests/odbc_test_suite.cc
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,22 @@ void ODBCTestBase::TearDown() {

void ODBCTestBase::TearDownTestSuite() {
if (connected) {
Disconnect();
// WORKAROUND GH-49585: Skip Disconnect() to avoid segfault when run through CTest
//
// When tests are run through CTest (but NOT when run directly from cmd.exe),
// SQLFreeHandle(SQL_HANDLE_ENV) crashes during cleanup. The crash occurs only with
// static linkage (ARROW_TEST_LINKAGE=static) and happens while freeing the ODBC
// environment handle, which triggers cleanup of statically-linked gRPC/Flight resources.
//
// Root cause appears to be CTest's process management (signal handling, I/O redirection,
// or environment differences) interfering with gRPC cleanup during static destruction.
//
// This workaround leaks the ODBC handles but allows tests to complete successfully.
// A proper fix would require ensuring gRPC is kept alive until all ODBC handles are freed,
// or switching to dynamic linkage for tests.
//
// Disconnect();
std::cerr << "[TEARDOWN] Skipping Disconnect() to avoid CTest-specific crash" << std::endl;
connected = false;
}
}
Expand Down
Loading