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

kou 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 0e37230b6d GH-47876: [C++][FlightRPC] ODBC: macOS `.PKG` installer for 
Intel and ARM (#49766)
0e37230b6d is described below

commit 0e37230b6d1ba09e1d3bf6002027dc7df7e8f17b
Author: Alina (Xi) Li <[email protected]>
AuthorDate: Wed May 20 18:43:32 2026 -0700

    GH-47876: [C++][FlightRPC] ODBC: macOS `.PKG` installer for Intel and ARM 
(#49766)
    
    ### Rationale for this change
    
    Generate and upload macOS .pkg installer in CI. The installer is unsigned.
    
    ### What changes are included in this PR?
    Adds in support for macOS `.PKG` Installer for Intel and ARM. It will 
install:
    ```
    /Library/ODBC/arrow-odbc
    ├── doc
    │   ├── Connection-Options.md
    │   └── LICENSE.txt
    └── lib
        ├── libarrow_flight_sql_odbc.2400.0.0.dylib
        ├── libarrow_flight_sql_odbc.2400.dylib -> 
libarrow_flight_sql_odbc.2400.0.0.dylib
        └── libarrow_flight_sql_odbc.dylib -> 
libarrow_flight_sql_odbc.2400.dylib
    
    3 directories, 5 files
    ```
    If Apache Arrow Flight SQL ODBC is already registered in the system DSN on 
the user machine, the installer will not overwrite the registration.
    
    ### Are these changes tested?
    Tested on Intel macOS. Team will test ARM installer using ARM machine later.
    ### Are there any user-facing changes?
    Developers can download the `.pkg` installers for usage.
    * GitHub Issue: #47876
    
    Lead-authored-by: justing-bq <[email protected]>
    Co-authored-by: Alina (Xi) Li <[email protected]>
    Co-authored-by: vic-tsang <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 .github/workflows/cpp_extra.yml                    | 14 ++++
 .pre-commit-config.yaml                            |  2 +
 cpp/src/arrow/flight/sql/odbc/CMakeLists.txt       | 77 ++++++++++++++++++--
 .../arrow/flight/sql/odbc/install/mac/README.txt   |  9 +++
 .../arrow/flight/sql/odbc/install/mac/postinstall  | 48 +++++++++++++
 .../arrow/flight/sql/odbc/install/mac/welcome.txt  |  1 +
 .../flight/sql/odbc/install/unix/install_odbc.sh   | 33 +++++----
 .../sql/odbc/install/unix/install_odbc_ini.sh      | 84 ++++++++++++++++++++++
 dev/release/rat_exclude_files.txt                  |  2 +
 9 files changed, 250 insertions(+), 20 deletions(-)

diff --git a/.github/workflows/cpp_extra.yml b/.github/workflows/cpp_extra.yml
index c762b7cfcd..73b06f9dee 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 2b7e3ce763..e7cf88b16c 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 4227873706..446dac9527 100644
--- a/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
+++ b/cpp/src/arrow/flight/sql/odbc/CMakeLists.txt
@@ -132,13 +132,11 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER)
   set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Apache Arrow Flight SQL ODBC Driver")
   set(CPACK_PACKAGE_CONTACT "[email protected]")
 
-  # 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)
+            COMPONENT ArrowFlightSQLODBC)
     install(TARGETS arrow_shared
                     arrow_compute_shared
                     arrow_flight_shared
@@ -150,7 +148,7 @@ if(ARROW_FLIGHT_SQL_ODBC_INSTALLER)
                     "ext-ms-.*"
                     POST_EXCLUDE_REGEXES
                     ".*system32/.*\\.dll"
-            RUNTIME DESTINATION bin COMPONENT arrow_flight_sql_odbc)
+            RUNTIME DESTINATION bin COMPONENT ArrowFlightSQLODBC)
 
     set(CPACK_WIX_EXTRA_SOURCES
         
"${CMAKE_CURRENT_SOURCE_DIR}/install/windows/arrow-flight-sql-odbc.wxs")
@@ -159,10 +157,69 @@ 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_ARROWFLIGHTSQLODBC_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 ArrowFlightSQLODBC)
+
+    # 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 ArrowFlightSQLODBC
+            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 ArrowFlightSQLODBC
+            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"
+                  "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../NOTICE.txt"
+                  "${CMAKE_CURRENT_SOURCE_DIR}/connection-options.md"
+            DESTINATION "${ODBC_DOC_INSTALL_DIR}"
+            COMPONENT Docs)
   endif()
 
   get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
-  set(CPACK_COMPONENTS_ALL "arrow_flight_sql_odbc")
+  set(CPACK_COMPONENTS_ALL "ArrowFlightSQLODBC" "Docs")
 
   if(WIN32)
     # WiX msi installer on Windows
@@ -173,14 +230,20 @@ 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")
+  elseif(APPLE)
+    # macOS and Linux
+    set(CPACK_GENERATOR "productbuild")
   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
   include(CPack)
-  cpack_add_component(arrow_flight_sql_odbc
+  cpack_add_component(ArrowFlightSQLODBC
                       DISPLAY_NAME "ODBC library"
                       DESCRIPTION "Apache Arrow Flight SQL ODBC library bin, 
required to install"
                       REQUIRED)
+  cpack_add_component(Docs
+                      DISPLAY_NAME "Documentation"
+                      DESCRIPTION "Documentation for Apache Arrow Flight SQL 
ODBC Driver"
+                      REQUIRED)
 endif()
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 0000000000..f83af5eb4a
--- /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 0000000000..e4f2018143
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/odbc/install/mac/postinstall
@@ -0,0 +1,48 @@
+#!/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.
+
+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"
+
+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
+}
+
+# clean temporary script
+rm -f "$odbc_install_script" "$dsn_install_script"
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 0000000000..5898db428f
--- /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 5ddcc8a4cb..97899923f5 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 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"
+    SYSTEM_ODBCINST_FILE="/etc/odbcinst.ini"
     ;;
   *)
     # macOS
-    USER_ODBCINST_FILE="$HOME/Library/ODBC/odbcinst.ini"
-    mkdir -p "$HOME"/Library/ODBC
+    SYSTEM_ODBCINST_FILE="/Library/ODBC/odbcinst.ini"
+    mkdir -p /Library/ODBC
     ;;
 esac
 
 DRIVER_NAME="Apache Arrow Flight SQL ODBC Driver"
 
-touch "$USER_ODBCINST_FILE"
+touch "$SYSTEM_ODBCINST_FILE"
 
-if grep -q "^\[$DRIVER_NAME\]" "$USER_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
-" >>"$USER_ODBCINST_FILE"
+" >>"$SYSTEM_ODBCINST_FILE"
 fi
 
 # Check if [ODBC Drivers] section exists
-if grep -q '^\[ODBC Drivers\]' "$USER_ODBCINST_FILE"; then
+if grep -q '^\[ODBC Drivers\]' "$SYSTEM_ODBCINST_FILE"; then
   # Section exists: check if driver entry exists
-  if ! grep -q "^${DRIVER_NAME}=" "$USER_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
-" "$USER_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"
-  } >>"$USER_ODBCINST_FILE"
+  } >>"$SYSTEM_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 0000000000..4fa7a31901
--- /dev/null
+++ b/cpp/src/arrow/flight/sql/odbc/install/unix/install_odbc_ini.sh
@@ -0,0 +1,84 @@
+#!/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.
+
+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 <abs_path_to_odbc_dsn_ini>" >&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" <<EOF
+
+[$DSN_NAME]
+Description = An ODBC Driver DSN for Apache Arrow Flight SQL
+Driver      = $DRIVER_NAME
+Host        =
+Port        =
+UID         =
+PWD         =
+EOF
+fi
+
+# Check if [ODBC Data Sources] section exists
+if grep -q '^\[ODBC Data Sources\]' "$SYSTEM_ODBC_FILE"; then
+  # Section exists: check if DSN entry exists
+  if ! grep -Eq "^${DSN_NAME}[[:space:]]*=" "$SYSTEM_ODBC_FILE"; then
+    # Add DSN entry under [ODBC Data Sources] section
+    tmp_file="$(mktemp "${SYSTEM_ODBC_FILE}.XXXX")"
+
+    # Use awk to insert the line immediately after [ODBC Data Sources]
+    awk -v dsn="$DSN_NAME" -v driver="$DRIVER_NAME" '
+      $0 ~ /^\[ODBC Data Sources\]/ && !inserted {
+        print
+        print dsn "=" driver
+        inserted=1
+        next
+      }
+      { print }
+    ' "$SYSTEM_ODBC_FILE" > "$tmp_file"
+
+    mv "$tmp_file" "$SYSTEM_ODBC_FILE"
+
+    # Restore expected permissions/ownership for system ODBC config
+    chmod 644 "$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 bd685845bc..f9e1cebcd7 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

Reply via email to