From 1b8f118a2eb436ec6264486d9da696bd97115c74 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Wed, 15 Apr 2026 10:47:31 -0700 Subject: [PATCH 1/2] macOS `.PKG` installer for Intel and ARM Co-authored-by: vic-tsang cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh is originally authored by vic-tsang --------------------------------------- * Initial draft for macOS .pkg installer * in-progress for `install_odbc` * Remove `$HOME` from registration script * Generate .pkg installer and attempts to fix installer * Attempt to fix doc not seen * Attempt to fix ODBC registration script * Fix installer script and doc * Rename `install_odbc_ini.sh` to `postinstall` * Reuse `install_odbc.sh` script inside `postinstall` * Fix to generate macOS installer - Check $(pwd)/build/cpp * Clean up PR and todos * Update format to re-use code * Use `install_odbc_ini.sh` script to install DSN Keep a lightweight `postinstall` file for macOS * Update install_odbc_ini.sh execution access * Address Justin's comment --- .github/workflows/cpp_extra.yml | 14 ++++ .pre-commit-config.yaml | 2 + cpp/src/arrow/flight/sql/odbc/CMakeLists.txt | 75 ++++++++++++++++++- .../flight/sql/odbc/Connection-Options.md | 20 +++++ .../flight/sql/odbc/install/mac/README.txt | 9 +++ .../flight/sql/odbc/install/mac/Welcome.txt | 1 + .../flight/sql/odbc/install/mac/postinstall | 30 ++++++++ .../sql/odbc/install/unix/install_odbc.sh | 6 +- .../sql/odbc/install/unix/install_odbc_ini.sh | 72 ++++++++++++++++++ dev/release/rat_exclude_files.txt | 2 + 10 files changed, 226 insertions(+), 5 deletions(-) create mode 100644 cpp/src/arrow/flight/sql/odbc/Connection-Options.md create mode 100644 cpp/src/arrow/flight/sql/odbc/install/mac/README.txt create mode 100644 cpp/src/arrow/flight/sql/odbc/install/mac/Welcome.txt create mode 100755 cpp/src/arrow/flight/sql/odbc/install/mac/postinstall create mode 100755 cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 5aaad7f39332..70964c65c159 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -429,6 +429,7 @@ jobs: ARROW_DEPENDENCY_SOURCE: BUNDLED ARROW_DEPENDENCY_USE_SHARED: OFF ARROW_FLIGHT_SQL_ODBC: ON + ARROW_FLIGHT_SQL_ODBC_INSTALLER: ON ARROW_HOME: /tmp/local ARROW_MIMALLOC: OFF steps: @@ -504,6 +505,19 @@ jobs: --allow libresolv \ --allow libz \ "$(pwd)/build/cpp/${{ matrix.build-type }}/libarrow_flight_sql_odbc.dylib" + - name: Generate macOS Installer + if: matrix.build-type == 'release' + shell: bash + run: | + cd $(pwd)/build/cpp + cpack + - name: Upload ODBC PKG to the job + if: matrix.build-type == 'release' + uses: actions/upload-artifact@v7 + with: + name: flight-sql-odbc-pkg-installer-${{ matrix.architecture }} + path: build/cpp/ArrowFlightSqlOdbcODBC-*.pkg + if-no-files-found: error - name: Register Flight SQL ODBC Driver run: | sudo cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh $(pwd)/build/cpp/${{ matrix.build-type }}/libarrow_flight_sql_odbc.dylib diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0544ff11bf88..26d31ffecc1c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -347,7 +347,9 @@ repos: ?^cpp/build-support/update-thrift\.sh$| ?^cpp/examples/minimal_build/run\.sh$| ?^cpp/examples/tutorial_examples/run\.sh$| + ?^cpp/src/arrow/flight/sql/odbc/install/mac/postinstall$| ?^cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc\.sh$| + ?^cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini\.sh$| ?^dev/release/05-binary-upload\.sh$| ?^dev/release/08-binary-verify\.sh$| ?^dev/release/binary-recover\.sh$| diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 4227873706ff..0f9757c2c80d 100644 --- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt @@ -132,7 +132,6 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Arrow Flight SQL ODBC Driver") set(CPACK_PACKAGE_CONTACT "dev@arrow.apache.org") - # 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 @@ -159,6 +158,66 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/install/windows/arrow-wix-banner.bmp") + else() + if(APPLE) + set(CPACK_PACKAGE_FILE_NAME + "ArrowFlightSqlOdbcODBC-${CPACK_PACKAGE_VERSION_MAJOR}.${ODBC_PACKAGE_VERSION_MINOR}.${ODBC_PACKAGE_VERSION_PATCH}" + ) + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") + + set(CPACK_SET_DESTDIR ON) + set(CPACK_INSTALL_PREFIX "/Library/ODBC") + # Register ODBC after install + set(CPACK_POSTFLIGHT_ARROW_FLIGHT_SQL_ODBC_SCRIPT + "${CMAKE_CURRENT_SOURCE_DIR}/install/mac/postinstall") + set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/install/mac/README.txt") + set(CPACK_RESOURCE_FILE_WELCOME + "${CMAKE_CURRENT_SOURCE_DIR}/install/mac/Welcome.txt") + + set(ODBC_INSTALL_DIR "arrow-odbc/lib") + set(DOC_INSTALL_DIR "arrow-odbc/doc") + else() + # Linux + # GH-49595: TODO implement DEB installer + # GH-47977: TODO implement RPM installer + message(STATUS "ODBC_PACKAGE_FORMAT DEB not implemented, see GH-49595") + message(STATUS "ODBC_PACKAGE_FORMAT RPM not implemented, see GH-47977") + endif() + + # Install ODBC + install(TARGETS arrow_flight_sql_odbc_shared + DESTINATION "${ODBC_INSTALL_DIR}" + COMPONENT arrow_flight_sql_odbc) + + # Install temporary driver registration scripts, they will be removed after driver registration is complete + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/install/unix/install_odbc.sh" + DESTINATION "${ODBC_INSTALL_DIR}" + COMPONENT arrow_flight_sql_odbc + PERMISSIONS OWNER_EXECUTE + OWNER_WRITE + OWNER_READ + GROUP_EXECUTE + GROUP_READ + WORLD_EXECUTE + WORLD_READ) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/install/unix/install_odbc_ini.sh" + DESTINATION "${ODBC_INSTALL_DIR}" + COMPONENT arrow_flight_sql_odbc + PERMISSIONS OWNER_EXECUTE + OWNER_WRITE + OWNER_READ + GROUP_EXECUTE + GROUP_READ + WORLD_EXECUTE + WORLD_READ) + + # Install documentation files + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../LICENSE.txt" + DESTINATION "${DOC_INSTALL_DIR}" + COMPONENT Docs) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/Connection-Options.md" + DESTINATION "${DOC_INSTALL_DIR}" + COMPONENT Docs) endif() get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS) @@ -173,8 +232,13 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) # Upgrade GUID is required to be unchanged for ODBC installer to upgrade set(CPACK_WIX_UPGRADE_GUID "DBF27A18-F8BF-423F-9E3A-957414D52C4B") set(CPACK_WIX_PRODUCT_GUID "279D087B-93B5-4DC3-BA69-BCF485022A26") + else() + # macOS and Linux + list(APPEND CPACK_COMPONENTS_ALL Docs) + if(APPLE) + set(CPACK_GENERATOR "productbuild") + endif() endif() - # GH-47876 TODO: create macOS Installer using cpack # GH-47877 TODO: create Linux Installer using cpack # Load CPack after all CPACK* variables are set @@ -183,4 +247,11 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) DISPLAY_NAME "ODBC library" DESCRIPTION "Apache Arrow Flight SQL ODBC library bin, required to install" REQUIRED) + if(UNIX) + # On macOS and Linux, provide connection string documentation since users need to manually enter DSN keys. + cpack_add_component(Docs + DISPLAY_NAME "Documentation" + DESCRIPTION "Documentation for Apache Arrow Flight SQL ODBC Driver" + ) + endif() endif() diff --git a/cpp/src/arrow/flight/sql/odbc/Connection-Options.md b/cpp/src/arrow/flight/sql/odbc/Connection-Options.md new file mode 100644 index 000000000000..61ca1eac6e4d --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/Connection-Options.md @@ -0,0 +1,20 @@ + + +GH-49723 TODO: enter ODBC connection options for unix DSN diff --git a/cpp/src/arrow/flight/sql/odbc/install/mac/README.txt b/cpp/src/arrow/flight/sql/odbc/install/mac/README.txt new file mode 100644 index 000000000000..8624470eb8bb --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/mac/README.txt @@ -0,0 +1,9 @@ +Files are available in '/Library/ODBC/arrow-odbc' after installation. + +To setup a connection, you can use DSN to store your data source connection information. +1. Open 'iODBC Data Source Administrator'. +2. To create a user DSN, go to 'User DSN' tab and click 'Add'. +3. Select 'Apache Arrow Flight SQL ODBC Driver' and click 'Finish'. +4. Enter DSN name and connection string values. +For the list of all supported options, check '/Library/ODBC/arrow-odbc/doc/Connection-Options.md'. +5. Click 'Ok' to save the DSN. diff --git a/cpp/src/arrow/flight/sql/odbc/install/mac/Welcome.txt b/cpp/src/arrow/flight/sql/odbc/install/mac/Welcome.txt new file mode 100644 index 000000000000..5898db428f6f --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/mac/Welcome.txt @@ -0,0 +1 @@ +Apache Arrow Flight SQL ODBC Driver is a read-only ODBC driver for connecting to data sources that support Arrow Flight SQL. diff --git a/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall b/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall new file mode 100755 index 000000000000..9499c2fe0e92 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. + +# Use temporary driver registration script to register ODBC driver in system DSN +odbc_install_script="/Library/ODBC/arrow-odbc/lib/install_odbc.sh" +"$odbc_install_script" /Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc.dylib + +# Use temporary DSN registration script to register sample system DSN +dsn_install_script="/Library/ODBC/arrow-odbc/lib/install_odbc_ini.sh" +"$dsn_install_script" /Library/ODBC/odbc.ini + +# clean temporary script +rm -f "$odbc_install_script" +rm -f "$dsn_install_script" diff --git a/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh index 5ddcc8a4cbda..b97fabfbadac 100755 --- a/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh +++ b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh @@ -17,7 +17,7 @@ # specific language governing permissions and limitations # under the License. -# Used by macOS ODBC installer script `install_odbc_ini.sh` and macOS ODBC testing +# Used by arrow/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall set -euo pipefail @@ -46,8 +46,8 @@ case "$(uname)" in ;; *) # macOS - USER_ODBCINST_FILE="$HOME/Library/ODBC/odbcinst.ini" - mkdir -p "$HOME"/Library/ODBC + USER_ODBCINST_FILE="/Library/ODBC/odbcinst.ini" + mkdir -p /Library/ODBC ;; esac diff --git a/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh new file mode 100755 index 000000000000..b86d4047b12c --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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 +# +# http://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. + +SYSTEM_ODBC_FILE="$1" + +if [[ -z "$SYSTEM_ODBC_FILE" ]]; then + echo "error: path to system ODBC DSN is not specified. Call format: install_odbc_ini abs_path_to_odbc_dsn_ini" + exit 1 +fi + +DRIVER_NAME="Apache Arrow Flight SQL ODBC Driver" +DSN_NAME="Apache Arrow Flight SQL ODBC DSN" + +touch "$SYSTEM_ODBC_FILE" + +if grep -q "^\[$DSN_NAME\]" "$SYSTEM_ODBC_FILE"; then + echo "DSN [$DSN_NAME] already exists in $SYSTEM_ODBC_FILE" +else + echo "Adding [$DSN_NAME] to $SYSTEM_ODBC_FILE..." + cat >> "$SYSTEM_ODBC_FILE" < "${SYSTEM_ODBC_FILE}.tmp" && mv "${SYSTEM_ODBC_FILE}.tmp" "$SYSTEM_ODBC_FILE" + fi +else + # Section doesn't exist, append section and DSN entry at end + { + echo "" + echo "[ODBC Data Sources]" + echo "${DSN_NAME}=${DRIVER_NAME}" + } >> "$SYSTEM_ODBC_FILE" +fi diff --git a/dev/release/rat_exclude_files.txt b/dev/release/rat_exclude_files.txt index bd685845bc7c..6dea092feacf 100644 --- a/dev/release/rat_exclude_files.txt +++ b/dev/release/rat_exclude_files.txt @@ -13,6 +13,8 @@ ci/vcpkg/*.patch CHANGELOG.md cpp/CHANGELOG_PARQUET.md cpp/src/arrow/c/dlpack_abi.h +cpp/src/arrow/flight/sql/odbc/install/mac/README.txt +cpp/src/arrow/flight/sql/odbc/install/mac/Welcome.txt cpp/src/arrow/io/mman.h cpp/src/arrow/util/random.h cpp/src/arrow/status.cc From fdd2ef2cf888186a25234725ad5201c7e95317d2 Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" Date: Wed, 15 Apr 2026 15:07:51 -0700 Subject: [PATCH 2/2] Add timeout limit for macOS --- .github/workflows/cpp_extra.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 70964c65c159..0c6f069e3c20 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -414,7 +414,7 @@ jobs: needs.check-labels.outputs.force == 'true' || contains(fromJSON(needs.check-labels.outputs.ci-extra-labels || '[]'), 'CI: Extra') || contains(fromJSON(needs.check-labels.outputs.ci-extra-labels || '[]'), 'CI: Extra: C++') - timeout-minutes: 75 + timeout-minutes: 120 strategy: fail-fast: false matrix: