From b4b6d70245860fc39d7751e6453a79ca3e764b4d 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 Co-authored-by: justing-bq for addressing feedback --------------------------------------- * 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 Add timeout limit for macOS Address feedback --- .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/postinstall | 51 ++++++++++++ .../flight/sql/odbc/install/mac/welcome.txt | 1 + .../sql/odbc/install/unix/install_odbc.sh | 22 ++--- .../sql/odbc/install/unix/install_odbc_ini.sh | 82 +++++++++++++++++++ dev/release/rat_exclude_files.txt | 2 + 10 files changed, 265 insertions(+), 13 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 100755 cpp/src/arrow/flight/sql/odbc/install/mac/postinstall create mode 100644 cpp/src/arrow/flight/sql/odbc/install/mac/welcome.txt 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 c762b7cfcdb4..2a0348a905a5 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -428,6 +428,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: @@ -503,6 +504,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/ArrowFlightSqlOdbc-*.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 2b7e3ce7633d..e7cf88b16c1f 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/07-flightsqlodbc-upload\.sh$| ?^dev/release/09-binary-verify\.sh$| diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 4227873706ff..632303f127f4 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 + "ArrowFlightSqlOdbc-${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(ODBC_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 "${ODBC_DOC_INSTALL_DIR}" + COMPONENT Docs) + install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/connection-options.md" + DESTINATION "${ODBC_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..72e2abcb875c --- /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 set up 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/postinstall b/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall new file mode 100755 index 000000000000..67235ee00813 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall @@ -0,0 +1,51 @@ +#!/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. + +#!/usr/bin/env bash +set -euo pipefail + +odbc_install_script="/Library/ODBC/arrow-odbc/lib/install_odbc.sh" +dsn_install_script="/Library/ODBC/arrow-odbc/lib/install_odbc_ini.sh" +driver_lib="/Library/ODBC/arrow-odbc/lib/libarrow_flight_sql_odbc.dylib" +dsn_file="/Library/ODBC/odbc.ini" + +cleanup() { + rm -f "$odbc_install_script" "$dsn_install_script" +} +trap cleanup EXIT + +if [[ ! -x "$odbc_install_script" ]]; then + echo "ERROR: ODBC install script $odbc_install_script not found" >&2 + exit 1 +fi + +"$odbc_install_script" "$driver_lib" || { + echo "ERROR: Failed to register ODBC driver ($driver_lib)" >&2 + exit 1 +} + +if [[ ! -x "$dsn_install_script" ]]; then + echo "ERROR: DSN install script $dsn_install_script not found" >&2 + exit 1 +fi + +"$dsn_install_script" "$dsn_file" || { + echo "ERROR: Failed to register DSN to ($dsn_file)" >&2 + exit 1 +} 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/unix/install_odbc.sh b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh index 5ddcc8a4cbda..c0de301b6d8b 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 @@ -42,20 +42,20 @@ fi case "$(uname)" in Linux) - USER_ODBCINST_FILE="/etc/odbcinst.ini" + ODBCINST_FILE="/etc/odbcinst.ini" ;; *) # macOS - USER_ODBCINST_FILE="$HOME/Library/ODBC/odbcinst.ini" - mkdir -p "$HOME"/Library/ODBC + ODBCINST_FILE="/Library/ODBC/odbcinst.ini" + mkdir -p /Library/ODBC ;; esac DRIVER_NAME="Apache Arrow Flight SQL ODBC Driver" -touch "$USER_ODBCINST_FILE" +touch "$ODBCINST_FILE" -if grep -q "^\[$DRIVER_NAME\]" "$USER_ODBCINST_FILE"; then +if grep -q "^\[$DRIVER_NAME\]" "$ODBCINST_FILE"; then echo "Driver [$DRIVER_NAME] already exists in odbcinst.ini" else echo "Adding [$DRIVER_NAME] to odbcinst.ini..." @@ -63,17 +63,17 @@ else [$DRIVER_NAME] Description=An ODBC Driver for Apache Arrow Flight SQL Driver=$ODBC_64BIT -" >>"$USER_ODBCINST_FILE" +" >>"$ODBCINST_FILE" fi # Check if [ODBC Drivers] section exists -if grep -q '^\[ODBC Drivers\]' "$USER_ODBCINST_FILE"; then +if grep -q '^\[ODBC Drivers\]' "$ODBCINST_FILE"; then # Section exists: check if driver entry exists - if ! grep -q "^${DRIVER_NAME}=" "$USER_ODBCINST_FILE"; then + if ! grep -q "^${DRIVER_NAME}=" "$ODBCINST_FILE"; then # Driver entry does not exist, add under [ODBC Drivers] sed -i '' "/^\[ODBC Drivers\]/a\\ ${DRIVER_NAME}=Installed -" "$USER_ODBCINST_FILE" +" "$ODBCINST_FILE" fi else # Section doesn't exist, append both section and driver entry at end @@ -81,5 +81,5 @@ else echo "" echo "[ODBC Drivers]" echo "${DRIVER_NAME}=Installed" - } >>"$USER_ODBCINST_FILE" + } >>"$ODBCINST_FILE" fi 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..9597b48340a6 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh @@ -0,0 +1,82 @@ +#!/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. + +#!/usr/bin/env bash +set -euo pipefail + +SYSTEM_ODBC_FILE="${1:-}" + +if [[ -z "$SYSTEM_ODBC_FILE" ]]; then + echo "ERROR: path to system ODBC DSN is not specified." >&2 + echo "Usage: install_odbc_ini.sh " >&2 + exit 1 +fi + +DRIVER_NAME="Apache Arrow Flight SQL ODBC Driver" +DSN_NAME="Apache Arrow Flight SQL ODBC DSN" + +if ! touch "$SYSTEM_ODBC_FILE"; then + echo "ERROR: Cannot access or create $SYSTEM_ODBC_FILE" >&2 + exit 1 +fi + +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" < "$tmp_file" + + mv "$tmp_file" "$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..f9e1cebcd74a 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 a5484a2abadaf7c08ea4820dfcd8edcb34723f6d Mon Sep 17 00:00:00 2001 From: "Alina (Xi) Li" <96995091+alinaliBQ@users.noreply.github.com> Date: Fri, 17 Apr 2026 15:48:09 -0700 Subject: [PATCH 2/2] ODBC Linux rpm installer support * Implement RPM installer fix formatting Remove todos ODBC rpm Installer wrap up * installing `rpm` package fixed the `cpack` command issue * Fix cpack command on CI (merge into last commit when ready) Change to use `awk` so script works on both platforms Comment out `find` and `tree` steps Change build path to be under /arrow Since docker is mounted, changing build path to be in `/arrow` will allow host machine to access docker build contents TEMP - Disable non-ODBC items Add commands to find build folder Attempt to build RPM installer * not sure if `/build/cpp` can be accessed outside of docker. Hopefully it should. * add `rpm` dependency install Indicate RPM in workflow run Add rpm `postinstall` (not tested) Remove merge conflict code * Enable ODBC installer build in CI instead of `compose.yaml` Update workflow matrix Update cpp_extra.yml Fix package name --- .github/workflows/cpp_extra.yml | 26 ++++++++++++--- .pre-commit-config.yaml | 1 + ci/docker/ubuntu-24.04-cpp.dockerfile | 1 + ci/scripts/cpp_build.sh | 1 + compose.yaml | 7 ++-- cpp/cmake_modules/DefineOptions.cmake | 6 ++++ cpp/src/arrow/flight/sql/odbc/CMakeLists.txt | 33 +++++++++++++++---- cpp/src/arrow/flight/sql/odbc/README.md | 16 +++++++++ .../flight/sql/odbc/install/linux/postinst | 30 +++++++++++++++++ .../sql/odbc/install/unix/install_odbc.sh | 29 +++++++++------- 10 files changed, 125 insertions(+), 25 deletions(-) create mode 100755 cpp/src/arrow/flight/sql/odbc/install/linux/postinst diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml index 2a0348a905a5..c4a938f3ec60 100644 --- a/.github/workflows/cpp_extra.yml +++ b/.github/workflows/cpp_extra.yml @@ -350,7 +350,7 @@ jobs: odbc-linux: needs: check-labels - name: ODBC Linux + name: ODBC ${{ matrix.build-type }} ${{ matrix.title }} runs-on: ubuntu-latest if: >- needs.check-labels.outputs.force == 'true' || @@ -359,6 +359,15 @@ jobs: timeout-minutes: 75 strategy: fail-fast: false + matrix: + include: + - image: ubuntu-cpp-odbc + title: AMD64 Ubuntu RPM + build-type: release + format: rpm + run-options: >- + -e ARROW_FLIGHT_SQL_ODBC_INSTALLER=ON + -e ODBC_PACKAGE_FORMAT=RPM env: ARCH: amd64 ARCHERY_DEBUG: 1 @@ -376,8 +385,8 @@ jobs: uses: actions/cache@v5 with: path: .docker - key: ubuntu-cpp-odbc-${{ hashFiles('cpp/**') }} - restore-keys: ubuntu-cpp-odbc- + key: ${{ matrix.image }}-${{ matrix.format }}-${{ hashFiles('cpp/**') }} + restore-keys: ${{ matrix.image }}-${{ matrix.format }}- - name: Setup Python on hosted runner uses: actions/setup-python@v6 with: @@ -392,7 +401,14 @@ jobs: # GH-40558: reduce ASLR to avoid ASAN/LSAN crashes sudo sysctl -w vm.mmap_rnd_bits=28 source ci/scripts/util_enable_core_dumps.sh - archery docker run ubuntu-cpp-odbc + archery docker run ${{ matrix.run-options || '' }} ${{ matrix.image }} + - name: Upload ODBC ${{ matrix.format }} to the job + if: matrix.build-type == 'release' + uses: actions/upload-artifact@v7 + with: + name: flight-sql-odbc-${{ matrix.format }}-installer + path: build/cpp/ArrowFlightSqlOdbc-*.${{ matrix.format }} + if-no-files-found: error - name: Docker Push if: >- success() && @@ -403,7 +419,7 @@ jobs: ARCHERY_DOCKER_USER: ${{ secrets.DOCKERHUB_USER }} ARCHERY_DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_TOKEN }} continue-on-error: true - run: archery docker push ubuntu-cpp-odbc + run: archery docker push ${{ matrix.image }} odbc-macos: needs: check-labels diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7cf88b16c1f..2fe29be6087f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -348,6 +348,7 @@ repos: ?^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/linux/rpm/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$| diff --git a/ci/docker/ubuntu-24.04-cpp.dockerfile b/ci/docker/ubuntu-24.04-cpp.dockerfile index 074301b472dc..eca5495b12f0 100644 --- a/ci/docker/ubuntu-24.04-cpp.dockerfile +++ b/ci/docker/ubuntu-24.04-cpp.dockerfile @@ -118,6 +118,7 @@ RUN apt-get update -y -q && \ python3-venv \ rados-objclass-dev \ rapidjson-dev \ + rpm \ rsync \ tzdata \ tzdata-legacy \ diff --git a/ci/scripts/cpp_build.sh b/ci/scripts/cpp_build.sh index 1e2f3e8f8f1a..5023c30a5df4 100755 --- a/ci/scripts/cpp_build.sh +++ b/ci/scripts/cpp_build.sh @@ -274,6 +274,7 @@ else -Dlz4_SOURCE=${lz4_SOURCE:-} \ -Dnlohmann_json_SOURCE=${nlohmann_json_SOURCE:-} \ -Dopentelemetry-cpp_SOURCE=${opentelemetry_cpp_SOURCE:-} \ + -DODBC_PACKAGE_FORMAT=${ODBC_PACKAGE_FORMAT:-} \ -DORC_SOURCE=${ORC_SOURCE:-} \ -DPARQUET_BUILD_EXAMPLES=${PARQUET_BUILD_EXAMPLES:-OFF} \ -DPARQUET_BUILD_EXECUTABLES=${PARQUET_BUILD_EXECUTABLES:-OFF} \ diff --git a/compose.yaml b/compose.yaml index be32a95dd945..e903fed82c7c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -516,12 +516,15 @@ services: ARROW_PARQUET: "OFF" ARROW_S3: "OFF" ARROW_SUBSTRAIT: "OFF" + # Use `/arrow/build` so build artifacts are visible on the CI host + # Generate ODBC installer before testing # Register ODBC before running tests command: > /bin/bash -c " - /arrow/ci/scripts/cpp_build.sh /arrow /build && + /arrow/ci/scripts/cpp_build.sh /arrow /arrow/build && + (cd /arrow/build/cpp && cpack) && sudo /arrow/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc.sh /usr/local/lib/libarrow_flight_sql_odbc.so && - /arrow/ci/scripts/cpp_test.sh /arrow /build" + /arrow/ci/scripts/cpp_test.sh /arrow /arrow/build" ubuntu-cpp-minimal: # Arrow build with minimal components/dependencies diff --git a/cpp/cmake_modules/DefineOptions.cmake b/cpp/cmake_modules/DefineOptions.cmake index 017a5a6efb26..260dc4e9da65 100644 --- a/cpp/cmake_modules/DefineOptions.cmake +++ b/cpp/cmake_modules/DefineOptions.cmake @@ -343,6 +343,12 @@ takes precedence over ccache if a storage backend is configured" ON) ARROW_FLIGHT_SQL ARROW_COMPUTE) + define_option(ARROW_FLIGHT_SQL_ODBC_INSTALLER + "Build the installer Arrow Flight SQL ODBC extension" + OFF + DEPENDS + ARROW_FLIGHT_SQL_ODBC) + define_option(ARROW_GANDIVA "Build the Gandiva libraries" OFF diff --git a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt index 632303f127f4..a4a07d00d43b 100644 --- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt +++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt @@ -159,10 +159,11 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) set(CPACK_WIX_UI_BANNER "${CMAKE_CURRENT_SOURCE_DIR}/install/windows/arrow-wix-banner.bmp") else() + set(ODBC_UNIX_FILE_NAME + "ArrowFlightSqlOdbc-${CPACK_PACKAGE_VERSION_MAJOR}.${ODBC_PACKAGE_VERSION_MINOR}.${ODBC_PACKAGE_VERSION_PATCH}" + ) if(APPLE) - set(CPACK_PACKAGE_FILE_NAME - "ArrowFlightSqlOdbc-${CPACK_PACKAGE_VERSION_MAJOR}.${ODBC_PACKAGE_VERSION_MINOR}.${ODBC_PACKAGE_VERSION_PATCH}" - ) + set(CPACK_PACKAGE_FILE_NAME "${ODBC_UNIX_FILE_NAME}") set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") set(CPACK_SET_DESTDIR ON) @@ -178,10 +179,28 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER) set(ODBC_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") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "${CPACK_PACKAGE_NAME}") + if(${ODBC_PACKAGE_FORMAT} STREQUAL "DEB") + # GH-49595 TODO: implement DEB installer + message(STATUS "ODBC_PACKAGE_FORMAT DEB not implemented, see GH-49595") + elseif(${ODBC_PACKAGE_FORMAT} STREQUAL "RPM") + set(CPACK_RPM_PACKAGE_ARCHITECTURE x86_64) + set(CPACK_GENERATOR RPM) + set(CPACK_RPM_POST_INSTALL_SCRIPT_FILE + "${CMAKE_CURRENT_SOURCE_DIR}/install/linux/postinst") + set(CPACK_RPM_FILE_NAME "${ODBC_UNIX_FILE_NAME}.rpm") + # Disable dependency check as ODBC embeds all third party dependencies + set(CPACK_RPM_PACKAGE_AUTOREQPROV "no") + set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE 1) + set(CPACK_RPM_COMPONENT_INSTALL ON) + else() + message(FATAL_ERROR "ODBC_PACKAGE_FORMAT '${ODBC_PACKAGE_FORMAT}' must be DEB or RPM for Linux installer." + ) + endif() + + # By default, Linux installs under /usr + set(ODBC_INSTALL_DIR "lib64/arrow-odbc/lib") + set(ODBC_DOC_INSTALL_DIR "lib64/arrow-odbc/doc") endif() # Install ODBC diff --git a/cpp/src/arrow/flight/sql/odbc/README.md b/cpp/src/arrow/flight/sql/odbc/README.md index a2a3fd79041a..ca3b1b3e254e 100644 --- a/cpp/src/arrow/flight/sql/odbc/README.md +++ b/cpp/src/arrow/flight/sql/odbc/README.md @@ -125,6 +125,22 @@ After ODBC has been registered, you can run the ODBC tests. It is recommended to .\cpp\build\< release | debug >\< Release | Debug>\arrow-flight-sql-odbc-test.exe ``` +## Installers + +ODBC installers are uploaded to the CI artifacts. + +| Operating System | Package Format | +|------------------|----------------| +| Windows | MSI | +| macOS | PKG | +| Linux | DEB / RPM | + +### Install `.RPM` on Ubuntu +While installing via `.DEB` installer on Ubuntu is the recommended approach, users may install `.RPM` on Ubuntu using below command +``` +alien -i --scripts ArrowFlightSqlOdbc-.rpm +``` + ## Known Limitations - Conversion from timestamp data type with specified time zone value to strings is not supported at the moment. This doesn't impact driver's usage of retrieving timestamp data from Power BI on Windows, and Excel on macOS and Windows. See GH-47504 for more context. diff --git a/cpp/src/arrow/flight/sql/odbc/install/linux/postinst b/cpp/src/arrow/flight/sql/odbc/install/linux/postinst new file mode 100755 index 000000000000..df20fab84a97 --- /dev/null +++ b/cpp/src/arrow/flight/sql/odbc/install/linux/postinst @@ -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="/usr/lib64/arrow-odbc/lib/install_odbc.sh" +"$odbc_install_script" /usr/lib64/arrow-odbc/lib/libarrow_flight_sql_odbc.so + +# Use temporary DSN registration script to register sample system DSN +dsn_install_script="/usr/lib64/arrow-odbc/lib/install_odbc_ini.sh" +"$dsn_install_script" /etc/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 c0de301b6d8b..8c9423f1218e 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 @@ -42,20 +42,20 @@ fi case "$(uname)" in Linux) - ODBCINST_FILE="/etc/odbcinst.ini" + SYSTEM_ODBCINST_FILE="/etc/odbcinst.ini" ;; *) # macOS - ODBCINST_FILE="/Library/ODBC/odbcinst.ini" + SYSTEM_ODBCINST_FILE="/Library/ODBC/odbcinst.ini" mkdir -p /Library/ODBC ;; esac DRIVER_NAME="Apache Arrow Flight SQL ODBC Driver" -touch "$ODBCINST_FILE" +touch "$SYSTEM_ODBCINST_FILE" -if grep -q "^\[$DRIVER_NAME\]" "$ODBCINST_FILE"; then +if grep -q "^\[$DRIVER_NAME\]" "$SYSTEM_ODBCINST_FILE"; then echo "Driver [$DRIVER_NAME] already exists in odbcinst.ini" else echo "Adding [$DRIVER_NAME] to odbcinst.ini..." @@ -63,17 +63,24 @@ else [$DRIVER_NAME] Description=An ODBC Driver for Apache Arrow Flight SQL Driver=$ODBC_64BIT -" >>"$ODBCINST_FILE" +" >>"$SYSTEM_ODBCINST_FILE" fi # Check if [ODBC Drivers] section exists -if grep -q '^\[ODBC Drivers\]' "$ODBCINST_FILE"; then +if grep -q '^\[ODBC Drivers\]' "$SYSTEM_ODBCINST_FILE"; then # Section exists: check if driver entry exists - if ! grep -q "^${DRIVER_NAME}=" "$ODBCINST_FILE"; then + if ! grep -q "^${DRIVER_NAME}=" "$SYSTEM_ODBCINST_FILE"; then # Driver entry does not exist, add under [ODBC Drivers] - sed -i '' "/^\[ODBC Drivers\]/a\\ -${DRIVER_NAME}=Installed -" "$ODBCINST_FILE" + + awk -v driver="$DRIVER_NAME" ' + $0 ~ /^\[ODBC Drivers\]/ && !inserted { + print + print driver "=Installed" + inserted=1 + next + } + { print } + ' "$SYSTEM_ODBCINST_FILE" > "${SYSTEM_ODBCINST_FILE}.tmp" && mv "${SYSTEM_ODBCINST_FILE}.tmp" "$SYSTEM_ODBCINST_FILE" fi else # Section doesn't exist, append both section and driver entry at end @@ -81,5 +88,5 @@ else echo "" echo "[ODBC Drivers]" echo "${DRIVER_NAME}=Installed" - } >>"$ODBCINST_FILE" + } >>"$SYSTEM_ODBCINST_FILE" fi