暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【DuckDB】一条 SQL 同时连接 Oracle 和 GaussDB

原创 DarkAthena 2026-05-23
239

【DuckDB】一条 SQL 同时连接 Oracle 和 GaussDB

前言

在数据迁移、数据比对、异构数据库运维等场景中,经常需要同时查询多个不同类型的数据库。DuckDB 作为一款嵌入式分析型数据库,支持通过扩展连接多种外部数据源。本文将演示如何在一条 SQL 中同时连接 OracleGaussDB,并实现跨库联合查询。

同时,由于连接 Oracle 数据库需要通过 ODBC 驱动,而生产环境通常不允许随意安装系统级 ODBC 包,本文提供了一套完全自包含的部署方案——所有依赖(DuckDB CLI、扩展、Oracle Instant Client、unixODBC 运行库)全部打包在项目目录内,无需修改系统任何配置。

环境说明

已验证环境

环境一: Ubuntu 22.04 x86_64

项目
操作系统 Ubuntu 22.04 x86_64
DuckDB 版本 v1.5.3
Oracle 数据库 Oracle 19c Enterprise Edition
GaussDB 版本 506.0.0.SPC0500
Oracle 连接 system/oraclepassword@192.168.163.227:1527/pdb1
GaussDB 连接 admin/gaussdbpassword@192.168.163.227:15432/postgres

环境二: Kylin V10 x86_64

项目
操作系统 Kylin Linux Advanced Server V10 (Lance) x86_64
内核版本 4.19.90-52.22.v2207.ky10.x86_64
DuckDB 版本 v1.5.3
Oracle 数据库 Oracle 19c Enterprise Edition
GaussDB 版本 506.0.0.SPC0500
Oracle 连接 system/oraclepassword@192.168.163.227:1527/pdb1
GaussDB 连接 admin/gaussdbpassword@192.168.163.227:15432/postgres

兼容性声明

本方案设计时考虑了以下兼容性:

  • 操作系统: Debian/Ubuntu 系列 + Fedora/RHEL 系列(含 Kylin、openEuler、Anolis 等国产系统)
  • CPU 架构: x86_64 (amd64) + ARM64 (aarch64)
  • 前提条件: 目标机器需要有网络访问权限(下载依赖),root 权限(安装系统包)

核心原理

DuckDB 连接两种数据库的方式不同:

数据库 连接方式 DuckDB 扩展 依赖
Oracle ODBC odbc_scanner Oracle Instant Client + unixODBC
GaussDB PostgreSQL 协议 postgres_scanner 无额外依赖

关键技术点:

  1. Oracle 通过 ODBC 连接:使用 DuckDB 的 odbc_connect() + odbc_query() 函数
  2. GaussDB 通过 PostgreSQL 协议连接:使用 DuckDB 的 ATTACH ... AS gaussdb (TYPE postgres) 语法
  3. GaussDB 需要 text 协议:执行 SET pg_use_text_protocol=true; 避免二进制协议兼容问题
  4. 自包含部署:通过环境变量将所有路径指向项目目录

项目结构

duckdb-oracle-gaussdb/ ├── install.sh # 在线安装脚本(需要外网) ├── install_offline.sh # 离线安装脚本(使用 offline_packages/) ├── prepare.sh # 离线准备脚本 - Linux/Mac bash 版 ├── prepare.ps1 # 离线准备脚本 - Windows PowerShell 版 ├── run.sh # 运行跨库查询(在线/离线通用) ├── env.sh # 环境变量(install.sh 生成,勿手动编辑) ├── offline_packages/ # 离线依赖包(prepare.sh 生成) │ ├── VERSION # 版本信息 │ └── amd64/ # 或 arm64/,按目标架构 │ ├── duckdb/ # DuckDB CLI 压缩包 │ ├── extensions/ # DuckDB 扩展文件 │ └── oracle/ # Oracle Instant Client 压缩包 ├── bin/ │ └── duckdb # DuckDB CLI ├── runtime/ │ ├── extensions/ │ │ ├── odbc_scanner.duckdb_extension # DuckDB ODBC 扩展 │ │ └── postgres_scanner.duckdb_extension # DuckDB PostgreSQL 扩展 │ ├── oracle/ │ │ └── instantclient_23_26/ # Oracle Instant Client │ │ ├── libsqora.so.23.1 # ODBC 驱动 │ │ ├── libclntsh.so.23.1 # Oracle 客户端库 │ │ └── ... │ └── unixodbc/ │ └── lib/ │ ├── libodbc.so.2 # unixODBC 运行库 │ ├── libodbcinst.so.2 # unixODBC 驱动管理 │ ├── libltdl.so.7 # libtool (unixODBC 依赖) │ └── libaio.so.1 # libaio (Oracle 依赖) └── var/ ├── odbc/ │ ├── odbcinst.ini # ODBC 驱动配置 │ └── odbc.ini # ODBC 数据源配置 ├── home/ # DuckDB HOME 目录 └── tmp/ # 临时文件目录

一、安装部署

步骤 1: 创建项目目录

mkdir -p /data/duckdb-oracle-gaussdb cd /data/duckdb-oracle-gaussdb

步骤 2: 创建安装脚本

创建 install.sh 文件:

#!/usr/bin/env bash set -euo pipefail # ============================================================ # DuckDB + Oracle + GaussDB 自包含安装脚本 # 支持: Debian/Ubuntu + Fedora/RHEL, amd64 + arm64 # ============================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$SCRIPT_DIR" DOWNLOAD_DIR="$PROJECT_DIR/.downloads" RUNTIME_DIR="$PROJECT_DIR/runtime" BIN_DIR="$PROJECT_DIR/bin" VAR_DIR="$PROJECT_DIR/var" EXT_DIR="$RUNTIME_DIR/extensions" ORACLE_DIR="$RUNTIME_DIR/oracle" UNIXODBC_DIR="$RUNTIME_DIR/unixodbc/lib" DUCKDB_VERSION="1.5.3" # ---------- 颜色输出 ---------- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } # ---------- 检测 OS 和架构 ---------- detect_env() { if [[ -f /etc/os-release ]]; then . /etc/os-release case "$ID" in ubuntu|debian|linuxmint|pop) OS_FAMILY="debian" ;; fedora) OS_FAMILY="fedora" ;; rhel|rocky|almalinux|centos|kylin|openeuler|anolis) OS_FAMILY="rhel" ;; *) error "不支持的发行版: $ID";; esac else error "无法检测操作系统" fi ARCH="$(uname -m)" case "$ARCH" in x86_64) ARCH_SUFFIX="amd64"; ORACLE_ARCH="linuxx64" ;; aarch64) ARCH_SUFFIX="arm64"; ORACLE_ARCH="linuxarm64" ;; *) error "不支持的架构: $ARCH";; esac info "检测到: OS=$OS_FAMILY ($ID $VERSION_ID), 架构=$ARCH ($ARCH_SUFFIX)" } # ---------- 安装系统依赖 ---------- install_sys_deps() { info "安装系统依赖..." if [[ "$OS_FAMILY" == "debian" ]]; then export DEBIAN_FRONTEND=noninteractive apt-get update -qq # Debian 12+ 用 libaio1t64, 旧版用 libaio1 apt-get install -y -qq curl unzip libaio1t64 unixodbc 2>/dev/null || \ apt-get install -y -qq curl unzip libaio1 unixodbc 2>/dev/null || \ apt-get install -y -qq curl unzip libaio unixodbc elif [[ "$OS_FAMILY" == "fedora" || "$OS_FAMILY" == "rhel" ]]; then dnf install -y -q curl unzip libaio unixODBC 2>/dev/null || \ yum install -y -q curl unzip libaio unixODBC fi info "系统依赖安装完成" } # ---------- 下载文件 (带代理备选) ---------- download() { local url="$1" dest="$2" if [[ -f "$dest" ]]; then info "已存在,跳过: $(basename "$dest")" return fi info "下载: $(basename "$dest")" if curl -L --fail --connect-timeout 30 --max-time 300 --retry 2 \ -o "$dest" "$url" 2>/dev/null; then return fi warn "直连失败, 尝试通过代理下载..." local proxy_url="https://ghfast.top/${url}" if curl -L --fail --connect-timeout 30 --max-time 300 \ -o "$dest" "$proxy_url" 2>/dev/null; then return fi error "下载失败: $url" } # ---------- 下载 DuckDB CLI ---------- install_duckdb() { info "安装 DuckDB CLI v${DUCKDB_VERSION} ($ARCH_SUFFIX)..." mkdir -p "$BIN_DIR" local zip_url zip_url="https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/duckdb_cli-linux-${ARCH_SUFFIX}.zip" local zip_file="$DOWNLOAD_DIR/duckdb_cli-linux-${ARCH_SUFFIX}.zip" download "$zip_url" "$zip_file" unzip -o "$zip_file" -d "$DOWNLOAD_DIR/duckdb-tmp" > /dev/null cp -f "$DOWNLOAD_DIR/duckdb-tmp/duckdb" "$BIN_DIR/duckdb" chmod +x "$BIN_DIR/duckdb" rm -rf "$DOWNLOAD_DIR/duckdb-tmp" info "DuckDB CLI: $($BIN_DIR/duckdb --version 2>/dev/null | head -1)" } # ---------- 下载 DuckDB 扩展 ---------- install_extensions() { info "下载 DuckDB 扩展 ($ARCH_SUFFIX)..." mkdir -p "$EXT_DIR" mkdir -p "$VAR_DIR/home" for ext_name in odbc postgres; do local ext_file="$EXT_DIR/${ext_name}_scanner.duckdb_extension" if [[ -f "$ext_file" ]]; then info "已存在,跳过: ${ext_name}_scanner" continue fi # 先尝试直接从扩展 CDN 下载 local ext_base ext_base="https://extensions.duckdb.org/v${DUCKDB_VERSION}/linux_${ARCH_SUFFIX}" if curl -sL --fail --connect-timeout 30 \ -o "$ext_file" \ "${ext_base}/${ext_name}_scanner.duckdb_extension" 2>/dev/null; then info "直接下载成功: ${ext_name}_scanner" continue fi # 通过 DuckDB 内置 INSTALL 下载 info "通过 DuckDB INSTALL 下载: ${ext_name}" HOME="$VAR_DIR/home" "$BIN_DIR/duckdb" -unsigned \ -c "INSTALL ${ext_name};" 2>/dev/null || true local cached cached="$(find "$VAR_DIR/home/.duckdb/extensions/" \ -name "${ext_name}_scanner.duckdb_extension" 2>/dev/null | head -1)" if [[ -n "$cached" ]]; then cp -f "$cached" "$ext_file" info "下载成功: ${ext_name}_scanner" else error "无法下载 ${ext_name}_scanner 扩展" fi done info "扩展文件:" ls -lh "$EXT_DIR/" } # ---------- 安装 Oracle Instant Client ---------- install_oracle_client() { info "安装 Oracle Instant Client ($ORACLE_ARCH)..." mkdir -p "$ORACLE_DIR" local base_url base_url="https://download.oracle.com/otn_software/linux/instantclient" download "${base_url}/instantclient-basiclite-${ORACLE_ARCH}.zip" \ "$DOWNLOAD_DIR/ic-basiclite.zip" download "${base_url}/instantclient-odbc-${ORACLE_ARCH}.zip" \ "$DOWNLOAD_DIR/ic-odbc.zip" unzip -o "$DOWNLOAD_DIR/ic-basiclite.zip" -d "$ORACLE_DIR" > /dev/null unzip -o "$DOWNLOAD_DIR/ic-odbc.zip" -d "$ORACLE_DIR" > /dev/null ORACLE_IC_DIR="$(find "$ORACLE_DIR" -maxdepth 1 -type d \ -name 'instantclient_*' | head -1)" if [[ -z "$ORACLE_IC_DIR" ]]; then error "Oracle Instant Client 解压后未找到 instantclient_* 目录" fi local sqora sqora="$(find "$ORACLE_IC_DIR" -name 'libsqora.so.*' | head -1)" if [[ -n "$sqora" ]]; then info "找到 Oracle ODBC 驱动: $(basename "$sqora")" else error "未找到 libsqora.so (Oracle ODBC 驱动)" fi info "Oracle Instant Client: $ORACLE_IC_DIR" } # ---------- 提取 unixODBC 运行时库 ---------- extract_unixodbc() { info "提取 unixODBC 运行时库到项目目录..." mkdir -p "$UNIXODBC_DIR" local lib_search_paths=() if [[ "$OS_FAMILY" == "debian" ]]; then lib_search_paths=( /usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu /usr/lib ) elif [[ "$OS_FAMILY" == "fedora" || "$OS_FAMILY" == "rhel" ]]; then lib_search_paths=(/usr/lib64 /usr/lib) fi for lib in libodbc.so.2 libodbcinst.so.2 libodbc.so.2.0.0 \ libodbcinst.so.2.0.0; do for sp in "${lib_search_paths[@]}"; do if [[ -f "$sp/$lib" ]]; then cp -a "$sp/$lib" "$UNIXODBC_DIR/" 2>/dev/null || true break fi done done # libaio + libltdl (含符号链接) for lib_pattern in "libaio.so.1*" "libltdl.so.7*"; do for sp in "${lib_search_paths[@]}"; do local found found="$(find "$sp" -maxdepth 1 -name "$lib_pattern" 2>/dev/null | head -1)" if [[ -n "$found" ]]; then cp -a "$sp/$lib_pattern" "$UNIXODBC_DIR/" 2>/dev/null || true break fi done done info "unixODBC 运行时库:" ls -lh "$UNIXODBC_DIR/" } # ---------- 生成 ODBC 配置 ---------- generate_odbc_config() { info "生成 ODBC 配置..." mkdir -p "$VAR_DIR/odbc" "$VAR_DIR/home" "$VAR_DIR/tmp" local sqora_file sqora_file="$(find "$ORACLE_IC_DIR" -name 'libsqora.so.*' \ ! -name '*.so' | sort -V | tail -1)" if [[ -z "$sqora_file" ]]; then error "未找到 Oracle ODBC 驱动库" fi cat >"$VAR_DIR/odbc/odbcinst.ini" <<EOF [Oracle ODBC driver] Description=Oracle ODBC driver (self-contained) Driver=${sqora_file} Setup= FileUsage=1 CPTimeout= CPReuse= EOF cat >"$VAR_DIR/odbc/odbc.ini" <<EOF [OraclePDB1] Driver=Oracle ODBC driver Description=Oracle PDB1 Self-Contained DBQ=//192.168.163.227:1527/pdb1 UserID=system [ODBC Data Sources] OraclePDB1=Oracle ODBC driver EOF info "ODBC 配置文件已生成" } # ---------- 写入 env.sh ---------- write_env_file() { cat >"$PROJECT_DIR/env.sh" <<EOF # 此文件由 install.sh 自动生成,请勿手动编辑 export PROJECT_DIR="$PROJECT_DIR" export DUCKDB_BIN="$PROJECT_DIR/bin/duckdb" export ODBC_EXT="$PROJECT_DIR/runtime/extensions/odbc_scanner.duckdb_extension" export POSTGRES_EXT="$PROJECT_DIR/runtime/extensions/postgres_scanner.duckdb_extension" export ORACLE_IC_DIR="$ORACLE_IC_DIR" export UNIXODBC_LIB_DIR="$UNIXODBC_DIR" export ODBC_CONF_DIR="$PROJECT_DIR/var/odbc" export TEMP_DIR="$PROJECT_DIR/var/tmp" export HOME_DIR="$PROJECT_DIR/var/home" export ORACLE_DRIVER_NAME="Oracle ODBC driver" EOF info "env.sh 已生成" } # ---------- 验证安装 ---------- verify_installation() { echo "" info "========== 安装验证 ==========" local errors=0 if [[ -x "$BIN_DIR/duckdb" ]]; then info "[OK] DuckDB CLI: $($BIN_DIR/duckdb --version 2>/dev/null | head -1)" else error "[FAIL] DuckDB CLI"; errors=$((errors+1)); fi if [[ -f "$EXT_DIR/odbc_scanner.duckdb_extension" ]]; then info "[OK] ODBC 扩展" else error "[FAIL] ODBC 扩展"; errors=$((errors+1)); fi if [[ -f "$EXT_DIR/postgres_scanner.duckdb_extension" ]]; then info "[OK] PostgreSQL 扩展" else error "[FAIL] PostgreSQL 扩展"; errors=$((errors+1)); fi if [[ -d "$ORACLE_IC_DIR" ]]; then info "[OK] Oracle Instant Client: $ORACLE_IC_DIR" else error "[FAIL] Oracle Instant Client"; errors=$((errors+1)); fi if ls "$UNIXODBC_DIR"/libodbc.so* 1>/dev/null 2>&1; then info "[OK] unixODBC 库文件" else error "[FAIL] unixODBC 库"; errors=$((errors+1)); fi if [[ $errors -gt 0 ]]; then error "安装失败: $errors 项错误"; fi info "========== 安装完成 ==========" echo "" info "下一步: cd $PROJECT_DIR && ./run.sh" } # ========== 主流程 ========== main() { echo "============================================================" echo " DuckDB + Oracle + GaussDB 自包含安装" echo " OS: $(. /etc/os-release 2>/dev/null && echo "$ID $VERSION_ID") 架构: $(uname -m)" echo "============================================================" echo "" mkdir -p "$DOWNLOAD_DIR" "$RUNTIME_DIR" "$VAR_DIR" detect_env install_sys_deps install_duckdb install_extensions install_oracle_client extract_unixodbc generate_odbc_config write_env_file verify_installation } main "$@"

赋予执行权限并运行:

chmod +x install.sh ./install.sh

安装过程会自动:

  1. 检测操作系统和 CPU 架构
  2. 安装系统依赖(curl、unzip、libaio、unixODBC)
  3. 下载 DuckDB CLI v1.5.3
  4. 下载 DuckDB 的 ODBC 和 PostgreSQL 扩展
  5. 下载 Oracle Instant Client(Basic Lite + ODBC)
  6. 提取 unixODBC 运行时库到项目目录
  7. 生成 ODBC 配置文件
  8. 验证所有组件

预期安装输出:

============================================================ DuckDB + Oracle + GaussDB 自包含安装 OS: ubuntu 22.04 架构: x86_64 ============================================================ [INFO] 检测到: OS=debian (ubuntu 22.04), 架构=x86_64 (amd64) [INFO] 安装系统依赖... [INFO] 系统依赖安装完成 [INFO] 安装 DuckDB CLI v1.5.3 (amd64)... [INFO] DuckDB CLI: v1.5.3 (Variegata) 14eca11bd9 [INFO] 下载 DuckDB 扩展 (amd64)... ... [INFO] ========== 安装完成 ========== [INFO] 下一步: cd /data/duckdb-oracle-gaussdb && ./run.sh

二、运行跨库查询

步骤 3: 创建运行脚本

创建 run.sh 文件:

#!/usr/bin/env bash set -euo pipefail # ============================================================ # DuckDB 跨库查询: Oracle + GaussDB # 通过一条 SQL 同时查询两个异构数据库 # ============================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [[ ! -f "$SCRIPT_DIR/env.sh" ]]; then echo "[ERROR] env.sh 未找到,请先执行: $SCRIPT_DIR/install.sh" >&2 exit 1 fi source "$SCRIPT_DIR/env.sh" # ---------- 默认连接参数 (可通过环境变量覆盖) ---------- ORACLE_HOST="${ORACLE_HOST:-192.168.163.227}" ORACLE_PORT="${ORACLE_PORT:-1527}" ORACLE_SERVICE="${ORACLE_SERVICE:-pdb1}" ORACLE_USER="${ORACLE_USER:-system}" ORACLE_PASSWORD="${ORACLE_PASSWORD:-oraclepassword}" GAUSSDB_HOST="${GAUSSDB_HOST:-192.168.163.227}" GAUSSDB_PORT="${GAUSSDB_PORT:-15432}" GAUSSDB_DB="${GAUSSDB_DB:-postgres}" GAUSSDB_USER="${GAUSSDB_USER:-admin}" GAUSSDB_PASSWORD="${GAUSSDB_PASSWORD:-gaussdbpassword}" # ---------- 校验 ---------- for f in "$DUCKDB_BIN" "$ODBC_EXT" "$POSTGRES_EXT"; do if [[ ! -f "$f" ]]; then echo "[ERROR] 文件未找到: $f" >&2 exit 1 fi done # ---------- 设置运行环境 ---------- export HOME="$HOME_DIR" export ODBCSYSINI="$ODBC_CONF_DIR" export ODBCINI="$ODBC_CONF_DIR/odbc.ini" export LD_LIBRARY_PATH="$ORACLE_IC_DIR:$UNIXODBC_LIB_DIR:${LD_LIBRARY_PATH:-}" # ---------- 转义函数 ---------- escape_sql() { printf "%s" "$1" | sed "s/'/''/g" } ORACLE_CONN_STR="Driver={$ORACLE_DRIVER_NAME};DBQ=//$ORACLE_HOST:$ORACLE_PORT/$ORACLE_SERVICE" ORACLE_CONN_ESC="$(escape_sql "$ORACLE_CONN_STR")" ORACLE_USER_ESC="$(escape_sql "$ORACLE_USER")" ORACLE_PASS_ESC="$(escape_sql "$ORACLE_PASSWORD")" GAUSSDB_CONN_STR="host=$GAUSSDB_HOST port=$GAUSSDB_PORT dbname=$GAUSSDB_DB user=$GAUSSDB_USER password=$GAUSSDB_PASSWORD sslmode=disable" GAUSSDB_CONN_ESC="$(escape_sql "$GAUSSDB_CONN_STR")" # ---------- DuckDB SQL ---------- cat <<'SQL_EOF' > "$TEMP_DIR/query.sql" -- ============================================================= -- DuckDB 跨库联合查询: Oracle + GaussDB -- ============================================================= -- 加载扩展 LOAD '__ODBC_EXT__'; LOAD '__POSTGRES_EXT__'; -- GaussDB 必须设置 text 协议 SET pg_use_text_protocol=true; SET threads=1; -- 连接 Oracle (通过 ODBC) SET VARIABLE oracle_conn = odbc_connect( '__ORACLE_CONN__', '__ORACLE_USER__', '__ORACLE_PASS__' ); -- 连接 GaussDB (通过 PostgreSQL Scanner) ATTACH '__GAUSSDB_CONN__' AS gaussdb (TYPE postgres); -- ============================================================= -- 测试 1: 分别验证两个数据库连通性 -- ============================================================= SELECT '===== [1] 测试 Oracle 连通性 =====' AS info; SELECT * FROM odbc_query(getvariable('oracle_conn'), 'SELECT ''Oracle_OK'' AS status, SYSDATE AS oracle_time FROM dual'); SELECT '===== [2] 测试 GaussDB 连通性 =====' AS info; SELECT 'GaussDB_OK' AS status, current_timestamp AS gaussdb_time FROM postgres_query('gaussdb', 'SELECT current_database()'); -- ============================================================= -- 测试 2: 一条 SQL 同时查询 Oracle 和 GaussDB -- ============================================================= SELECT '===== [3] 跨库联合查询 =====' AS info; SELECT o.status AS oracle_result, o.oracle_time AS oracle_sysdate, g.status AS gaussdb_result, g.gaussdb_time AS gaussdb_timestamp FROM (SELECT status, oracle_time FROM odbc_query(getvariable('oracle_conn'), 'SELECT ''Oracle_OK'' AS status, TO_CHAR(SYSDATE, ''YYYY-MM-DD HH24:MI:SS'') AS oracle_time FROM dual') ) o CROSS JOIN (SELECT 'GaussDB_OK' AS status, current_timestamp AS gaussdb_time FROM postgres_query('gaussdb', 'SELECT current_timestamp AS ts') ) g; -- ============================================================= -- 测试 3: 获取两个数据库的版本信息 -- ============================================================= SELECT '===== [4] 数据库版本信息 =====' AS info; SELECT 'Oracle' AS db_source, version_str AS version FROM odbc_query(getvariable('oracle_conn'), 'SELECT banner AS version_str FROM v$version WHERE rownum = 1') UNION ALL SELECT 'GaussDB' AS db_source, setting AS version FROM gaussdb.pg_catalog.pg_settings WHERE name = 'server_version'; -- ============================================================= -- 清理 -- ============================================================= SELECT odbc_close(getvariable('oracle_conn')); DETACH gaussdb; SELECT '===== 跨库查询完成 =====' AS info; SQL_EOF # 替换 SQL 中的占位符 sed -i "s|__ODBC_EXT__|${ODBC_EXT}|g" "$TEMP_DIR/query.sql" sed -i "s|__POSTGRES_EXT__|${POSTGRES_EXT}|g" "$TEMP_DIR/query.sql" sed -i "s|__ORACLE_CONN__|${ORACLE_CONN_ESC}|g" "$TEMP_DIR/query.sql" sed -i "s|__ORACLE_USER__|${ORACLE_USER_ESC}|g" "$TEMP_DIR/query.sql" sed -i "s|__ORACLE_PASS__|${ORACLE_PASS_ESC}|g" "$TEMP_DIR/query.sql" sed -i "s|__GAUSSDB_CONN__|${GAUSSDB_CONN_ESC}|g" "$TEMP_DIR/query.sql" # ---------- 执行 ---------- echo "============================================================" echo " DuckDB 跨库查询: Oracle + GaussDB" echo " Oracle: ${ORACLE_USER}@${ORACLE_HOST}:${ORACLE_PORT}/${ORACLE_SERVICE}" echo " GaussDB: ${GAUSSDB_USER}@${GAUSSDB_HOST}:${GAUSSDB_PORT}/${GAUSSDB_DB}" echo "============================================================" echo "" "$DUCKDB_BIN" -batch -unsigned < "$TEMP_DIR/query.sql"

赋予执行权限并运行:

chmod +x run.sh ./run.sh

实际运行结果

============================================================ DuckDB 跨库查询: Oracle + GaussDB Oracle: system@192.168.163.227:1527/pdb1 GaussDB: admin@192.168.163.227:15432/postgres ============================================================ ┌────────────────────────────────────┐ │ info │ │ varchar │ ├────────────────────────────────────┤ │ ===== [1] 测试 Oracle 连通性 ===== │ └────────────────────────────────────┘ ┌───────────┬─────────────┐ │ STATUS │ ORACLE_TIME │ │ varchar │ date │ ├───────────┼─────────────┤ │ Oracle_OK │ 2026-05-22 │ └───────────┴─────────────┘ ┌─────────────────────────────────────┐ │ info │ │ varchar │ ├─────────────────────────────────────┤ │ ===== [2] 测试 GaussDB 连通性 ===== │ └─────────────────────────────────────┘ ┌────────────┬───────────────────────────────┐ │ status │ gaussdb_time │ │ varchar │ timestamp with time zone │ ├────────────┼───────────────────────────────┤ │ GaussDB_OK │ 2026-05-22 16:26:36.448552+08 │ └────────────┴───────────────────────────────┘ ┌──────────────────────────────┐ │ info │ │ varchar │ ├──────────────────────────────┤ │ ===== [3] 跨库联合查询 ===== │ └──────────────────────────────┘ ┌───────────────┬─────────────────────┬────────────────┬───────────────────────────────┐ │ oracle_result │ oracle_sysdate │ gaussdb_result │ gaussdb_timestamp │ │ varchar │ varchar │ varchar │ timestamp with time zone │ ├───────────────┼─────────────────────┼────────────────┼───────────────────────────────┤ │ Oracle_OK │ 2026-05-22 07:09:31 │ GaussDB_OK │ 2026-05-22 07:09:34.067699+00 │ └───────────────┴─────────────────────┴────────────────┴───────────────────────────────┘ ┌────────────────────────────────┐ │ info │ │ varchar │ ├────────────────────────────────┤ │ ===== [4] 数据库版本信息 ===== │ └────────────────────────────────┘ ┌───────────┬────────────────────────────────────────────────────────────────────────┐ │ db_source │ version │ │ varchar │ varchar │ ├───────────┼────────────────────────────────────────────────────────────────────────┤ │ Oracle │ Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production │ │ GaussDB │ gaussdb (GaussDB Kernel 506.0.0.SPC0500 build d474632c) compiled at... │ └───────────┴────────────────────────────────────────────────────────────────────────┘ ┌──────────────────────────┐ │ info │ │ varchar │ ├──────────────────────────┤ │ ===== 跨库查询完成 ===== │ └──────────────────────────┘

可以看到:

  • 测试 1: Oracle 单独查询 DUAL 表成功
  • 测试 2: GaussDB 单独查询成功
  • 测试 3: 一条 SQL 同时从 Oracle 和 GaussDB 获取数据并做 CROSS JOIN 联合展示
  • 测试 4: 分别获取了 Oracle 19c 和 GaussDB 的版本信息

三、关键代码解析

3.1 DuckDB 连接 Oracle 的方式

LOAD 'runtime/extensions/odbc_scanner.duckdb_extension'; SET VARIABLE oracle_conn = odbc_connect( 'Driver={Oracle ODBC driver};DBQ=//192.168.163.227:1527/pdb1', 'system', 'oraclepassword' );

使用 DuckDB 的 odbc_connect() 建立连接,返回一个连接句柄存入变量。之后通过 odbc_query(连接句柄, SQL) 执行任意 Oracle SQL。

3.2 DuckDB 连接 GaussDB 的方式

LOAD 'runtime/extensions/postgres_scanner.duckdb_extension'; SET pg_use_text_protocol=true; -- 关键! GaussDB 需要此设置 ATTACH 'host=192.168.163.227 port=15432 dbname=postgres user=admin password=gaussdbpassword sslmode=disable' AS gaussdb (TYPE postgres);

使用 ATTACH 语法将 GaussDB 作为外部数据库挂载到 DuckDB 中,之后可以直接用 gaussdb.schema.table 的方式查询。

重要: SET pg_use_text_protocol=true; 是连接 GaussDB 的关键设置。

此外,DuckDB 还提供了 postgres_query() 函数,可以在 GaussDB 服务端直接执行 SQL 并返回结果。这在需要调用 GaussDB 特有函数(如 version())时非常有用,因为 DuckDB 的 ATTACH 模式下同名函数会被 DuckDB 自身拦截:

-- 错误: version() 被 DuckDB 拦截,返回的是 DuckDB 版本 SELECT version() FROM gaussdb.pg_catalog.pg_settings LIMIT 1; -- 结果: v1.5.3 (错误!) -- 正确: 用 postgres_query 在 GaussDB 端执行,返回真实版本 SELECT * FROM postgres_query('gaussdb', 'SELECT version()'); -- 结果: gaussdb (GaussDB Kernel 506.0.0.SPC0500 build d474632c) compiled at 2025-08-28 13:06:27 last mr 24872 release ```GaussDB 虽然兼容 PostgreSQL 协议,但在二进制协议传输上可能存在兼容性问题,使用 text 协议可以避免这类问题。 ### 3.3 跨库联合查询的核心 SQL ```sql SELECT o.status AS oracle_result, o.oracle_time AS oracle_sysdate, g.status AS gaussdb_result, g.gaussdb_time AS gaussdb_timestamp FROM (SELECT status, oracle_time FROM odbc_query(getvariable('oracle_conn'), 'SELECT ''Oracle_OK'' AS status, TO_CHAR(SYSDATE, ''YYYY-MM-DD HH24:MI:SS'') AS oracle_time FROM dual') ) o CROSS JOIN (SELECT 'GaussDB_OK' AS status, current_timestamp AS gaussdb_time FROM postgres_query('gaussdb', 'SELECT current_timestamp AS ts') ) g;

这条 SQL 的核心逻辑:

  1. 通过 odbc_query() 从 Oracle 查询 DUAL 表获取 SYSDATE
  2. 通过 DuckDB 本地查询获取 GaussDB 的时间戳
  3. 使用 CROSS JOIN 将两个结果合并到一行输出

3.4 自包含部署的关键环境变量

export HOME="$HOME_DIR" # 隔离 DuckDB 扩展缓存目录 export ODBCSYSINI="$ODBC_CONF_DIR" # 指定 ODBC 驱动配置位置 export ODBCINI="$ODBC_CONF_DIR/odbc.ini" # 指定 ODBC 数据源配置位置 export LD_LIBRARY_PATH="$ORACLE_IC_DIR:$UNIXODBC_LIB_DIR:${LD_LIBRARY_PATH:-}"

这些环境变量确保:

  • DuckDB 不会去 ~/.duckdb/extensions 寻找扩展
  • ODBC 驱动管理器使用项目内的配置文件,而非 /etc/odbc*.ini
  • 动态链接器能找到 Oracle 客户端库和 unixODBC 运行库

四、自定义使用

修改数据库连接参数

可以通过环境变量覆盖默认连接参数:

ORACLE_HOST=10.0.0.1 \ ORACLE_PORT=1521 \ ORACLE_SERVICE=orcl \ ORACLE_USER=scott \ ORACLE_PASSWORD=tiger \ GAUSSDB_HOST=10.0.0.2 \ GAUSSDB_PORT=5432 \ GAUSSDB_DB=mydb \ GAUSSDB_USER=myuser \ GAUSSDB_PASSWORD=mypass \ ./run.sh

自定义查询 SQL

编辑 run.sh 中的 SQL 模板(cat <<'SQL_EOF'SQL_EOF 之间的部分),替换为你自己的查询语句。

例如,同时从 Oracle 的 EMP 表和 GaussDB 的 employee 表查询数据:

-- Oracle 中的数据 SELECT * FROM odbc_query(getvariable('oracle_conn'), 'SELECT empno, ename, sal FROM emp WHERE deptno = 10'); -- GaussDB 中的数据 (通过 ATTACH 挂载后, 使用 gaussdb.schema.table 查询) SELECT * FROM gaussdb.public.employee WHERE department_id = 10; -- 跨库联合 SELECT 'oracle' AS source, empno AS id, ename AS name, sal AS salary FROM odbc_query(getvariable('oracle_conn'), 'SELECT empno, ename, sal FROM emp') UNION ALL SELECT 'gaussdb' AS source, id, name, salary FROM gaussdb.public.employee;

五、常见问题排查

Q1: odbc_connect 报错 Could not locate or load driver

原因: Oracle ODBC 驱动库(libsqora.so)未找到。

排查:

# 检查驱动文件是否存在 find runtime/oracle -name 'libsqora.so*' # 检查 ODBC 配置中的 Driver 路径是否正确 cat var/odbc/odbcinst.ini # 检查 LD_LIBRARY_PATH echo $LD_LIBRARY_PATH

Q2: odbc_connect 报错 ORA-12154: TNS:could not resolve the connect identifier

原因: 连接字符串格式错误,或数据库地址/端口/服务名不正确。

排查: 确认 DBQ 参数格式为 //host:port/service_name

Q3: GaussDB 连接报错 FATAL: ...

原因: GaussDB 连接参数不正确,或网络不通。

排查:

# 测试网络连通性 nc -zv 192.168.163.227 15432 # 确认密码中的特殊字符已正确转义

注意: 如果密码中包含 @ 等特殊字符,在 PostgreSQL 连接字符串中需要正确处理。在 run.sh 的连接字符串中,密码通过 escape_sql 函数处理了单引号转义,但如果密码中包含其他特殊字符可能需要额外处理。

Q4: INSTALL 扩展失败

原因: 网络问题导致 DuckDB 无法从官方 CDN 下载扩展。

解决: 可以手动下载扩展文件放到 runtime/extensions/ 目录:

  1. 访问 https://extensions.duckdb.org/v1.5.3/linux_amd64/ 查看可用扩展
  2. 下载 odbc_scanner.duckdb_extensionpostgres_scanner.duckdb_extension
  3. 放到 runtime/extensions/ 目录

或者使用代理:

curl -L -o runtime/extensions/postgres_scanner.duckdb_extension \ "https://ghfast.top/https://extensions.duckdb.org/v1.5.3/linux_amd64/postgres_scanner.duckdb_extension"

Q5: libaio.so.1: cannot open shared object file

原因: 缺少 libaio 库。Oracle Instant Client 依赖此库。

解决:

# Debian/Ubuntu apt-get install libaio1t64 # Debian 12+ # 或 apt-get install libaio1 # 旧版 # Fedora/RHEL dnf install libaio

六、离线部署方案

生产环境通常处于内网,无法直接访问外网下载 DuckDB、扩展和 Oracle 客户端。本方案提供完整的离线部署流程:在有网络的机器上预下载所有依赖,打包后拷贝到内网目标机器安装

离线部署流程概览

┌──────────────────────┐ ┌──────────────────────┐ │ 有网络的机器 │ │ 内网目标机器 │ │ │ │ │ │ 1. ./prepare.sh │ scp/ │ 3. 解压离线包 │ │ (下载所有依赖) │ U盘/ │ 4. ./install_offline.sh│ │ 2. 打包离线包 │ 其他 │ (从离线包安装) │ │ tar czf ... ───────→ │ 5. ./run.sh │ └──────────────────────┘ └──────────────────────┘

前提条件

  • 有网络机器: 能访问 GitHub、DuckDB 扩展 CDN、Oracle 官网
  • 内网目标机器: 有 yum 或 apt 软件源(用于安装 curl、unzip、libaio、unixODBC 这四个基础系统包),有 root 权限
  • 两台机器 CPU 架构一致(amd64 打包的不能在 arm64 上用,反之亦然)

步骤 1: 在有网络的机器上准备离线包

准备脚本提供两个版本:Linux 版prepare.sh,bash)和 Windows 版prepare.ps1,PowerShell)。两者功能完全相同,根据你手上有的网络机器选择即可。

方式 A: 在 Linux 上准备

prepare.sh 脚本放到项目目录下:

mkdir -p /data/duckdb-oracle-gaussdb cd /data/duckdb-oracle-gaussdb

创建 prepare.sh 文件:

#!/usr/bin/env bash set -euo pipefail # ============================================================ # 离线部署 - 准备脚本 # 在有网络的机器上运行,下载所有离线依赖到 offline_packages/ 目录 # # 用法: # ./prepare.sh # 下载当前架构的包 # ./prepare.sh --all-arch # 下载 amd64 + arm64 全部包 # ARCH=arm64 ./prepare.sh # 指定下载 arm64 的包 # ============================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" OFFLINE_DIR="$SCRIPT_DIR/offline_packages" DUCKDB_VERSION="1.5.3" # ---------- 颜色输出 ---------- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } # ---------- 下载函数 ---------- download() { local url="$1" dest="$2" desc="$3" if [[ -f "$dest" ]]; then info "已存在,跳过: $desc" return fi info "下载: $desc" if curl -L --fail --connect-timeout 30 --max-time 600 --retry 3 \ -o "$dest" "$url" 2>/dev/null; then return fi warn "直连失败, 尝试代理: $desc" local proxy_url="https://ghfast.top/${url}" if curl -L --fail --connect-timeout 30 --max-time 600 \ -o "$dest" "$proxy_url" 2>/dev/null; then return fi error "下载失败: $desc ($url)" } # ---------- 下载单个架构 ---------- prepare_single_arch() { local arch="$1" local arch_suffix="$2" local oracle_arch="$3" local arch_dir="$OFFLINE_DIR/$arch_suffix" mkdir -p "$arch_dir/duckdb" "$arch_dir/extensions" "$arch_dir/oracle" # 1. DuckDB CLI info "===== 下载 DuckDB CLI ($arch_suffix) =====" local duckdb_zip="duckdb_cli-linux-${arch_suffix}.zip" download \ "https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/${duckdb_zip}" \ "$arch_dir/duckdb/${duckdb_zip}" \ "DuckDB CLI v${DUCKDB_VERSION} ($arch_suffix)" # 2. DuckDB 扩展 info "===== 下载 DuckDB 扩展 ($arch_suffix) =====" local ext_base="https://extensions.duckdb.org/v${DUCKDB_VERSION}/linux_${arch_suffix}" for ext_name in odbc postgres; do local ext_file="${ext_name}_scanner.duckdb_extension" download \ "${ext_base}/${ext_file}" \ "$arch_dir/extensions/${ext_file}" \ "DuckDB ${ext_name}_scanner 扩展 ($arch_suffix)" done # 3. Oracle Instant Client info "===== 下载 Oracle Instant Client ($oracle_arch) =====" local oracle_base="https://download.oracle.com/otn_software/linux/instantclient" download \ "${oracle_base}/instantclient-basiclite-${oracle_arch}.zip" \ "$arch_dir/oracle/instantclient-basiclite-${oracle_arch}.zip" \ "Oracle Instant Client Basic Lite ($oracle_arch)" download \ "${oracle_base}/instantclient-odbc-${oracle_arch}.zip" \ "$arch_dir/oracle/instantclient-odbc-${oracle_arch}.zip" \ "Oracle Instant Client ODBC ($oracle_arch)" echo "" info "$arch_suffix 包准备完成:" echo " DuckDB CLI: $(du -h "$arch_dir/duckdb/${duckdb_zip}" | cut -f1)" echo " ODBC 扩展: $(du -h "$arch_dir/extensions/odbc_scanner.duckdb_extension" | cut -f1)" echo " PG 扩展: $(du -h "$arch_dir/extensions/postgres_scanner.duckdb_extension" | cut -f1)" echo " Oracle Basic: $(du -h "$arch_dir/oracle/instantclient-basiclite-${oracle_arch}.zip" | cut -f1)" echo " Oracle ODBC: $(du -h "$arch_dir/oracle/instantclient-odbc-${oracle_arch}.zip" | cut -f1)" } # ========== 主流程 ========== main() { echo "============================================================" echo " 离线部署准备 - 下载所有依赖包" echo " DuckDB v${DUCKDB_VERSION}" echo "============================================================" echo "" mkdir -p "$OFFLINE_DIR" if [[ "${1:-}" == "--all-arch" ]]; then info "下载全部架构 (amd64 + arm64)" echo "" prepare_single_arch "amd64" "amd64" "linuxx64" echo "" prepare_single_arch "arm64" "arm64" "linuxarm64" else local target_arch="${ARCH:-}" if [[ -z "$target_arch" ]]; then local current_arch current_arch="$(uname -m)" case "$current_arch" in x86_64) target_arch="amd64" ;; aarch64) target_arch="arm64" ;; *) error "不支持的架构: $current_arch" ;; esac fi case "$target_arch" in amd64) prepare_single_arch "amd64" "amd64" "linuxx64" ;; arm64) prepare_single_arch "arm64" "arm64" "linuxarm64" ;; *) error "不支持的架构: $target_arch" ;; esac fi cat >"$OFFLINE_DIR/VERSION" <<EOF DUCKDB_VERSION=${DUCKDB_VERSION} PREPARE_DATE=$(date '+%Y-%m-%d %H:%M:%S') PREPARE_HOST=$(hostname 2>/dev/null || echo unknown) EOF echo "" info "============================================================" info " 离线包准备完成!" info " 目录: $OFFLINE_DIR" info "" info " 下一步:" info " 1. tar czf duckdb-offline-packages.tar.gz offline_packages/" info " 2. scp 到目标机器并解压" info " 3. 在目标机器执行: ./install_offline.sh" info "============================================================" } main "$@"

赋予执行权限并运行:

chmod +x prepare.sh # 下载当前架构的包(根据机器自动判断 amd64/arm64) ./prepare.sh # 如果需要同时准备两种架构的包(可在一台机器上为不同架构的目标机准备) # ./prepare.sh --all-arch

方式 B: 在 Windows 上准备

如果你的网络机器是 Windows,使用 PowerShell 脚本。将以下内容保存为 prepare.ps1

param( [ValidateSet("amd64", "arm64")] [string]$Arch = "", [switch]$AllArch ) $ErrorActionPreference = "Stop" $DUCKDB_VERSION = "1.5.3" $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $OfflineDir = Join-Path $ScriptDir "offline_packages" # ---------- 下载函数 ---------- function Download-File { param( [string]$Url, [string]$Dest, [string]$Desc ) if (Test-Path $Dest) { Write-Host "[INFO] 已存在,跳过: $Desc" -ForegroundColor Green return } Write-Host "[INFO] 下载: $Desc" -ForegroundColor Green # 先尝试直连 try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri $Url -OutFile $Dest -UseBasicParsing ` -TimeoutSec 600 -ErrorAction Stop return } catch { Write-Host "[WARN] 直连失败, 尝试代理..." -ForegroundColor Yellow } # 通过代理下载 $proxyUrl = "https://ghfast.top/$Url" try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 Invoke-WebRequest -Uri $proxyUrl -OutFile $Dest -UseBasicParsing ` -TimeoutSec 600 -ErrorAction Stop return } catch { Write-Host "[ERROR] 下载失败: $Desc ($Url)" -ForegroundColor Red Write-Host "[ERROR] $($_.Exception.Message)" -ForegroundColor Red exit 1 } } # ---------- 下载单个架构 ---------- function Prepare-SingleArch { param( [string]$ArchSuffix, [string]$OracleArch ) $archDir = Join-Path $OfflineDir $ArchSuffix $duckdbDir = Join-Path $archDir "duckdb" $extDir = Join-Path $archDir "extensions" $oracleDir = Join-Path $archDir "oracle" New-Item -ItemType Directory -Force -Path $duckdbDir | Out-Null New-Item -ItemType Directory -Force -Path $extDir | Out-Null New-Item -ItemType Directory -Force -Path $oracleDir | Out-Null # 1. DuckDB CLI Write-Host "" Write-Host "===== 下载 DuckDB CLI ($ArchSuffix) =====" $duckdbZip = "duckdb_cli-linux-${ArchSuffix}.zip" $duckdbUrl = "https://github.com/duckdb/duckdb/releases/download/v${DUCKDB_VERSION}/${duckdbZip}" $duckdbDest = Join-Path $duckdbDir $duckdbZip Download-File -Url $duckdbUrl -Dest $duckdbDest ` -Desc "DuckDB CLI v${DUCKDB_VERSION} ($ArchSuffix)" # 2. DuckDB 扩展 Write-Host "" Write-Host "===== 下载 DuckDB 扩展 ($ArchSuffix) =====" $extBase = "https://extensions.duckdb.org/v${DUCKDB_VERSION}/linux_${ArchSuffix}" foreach ($extName in @("odbc", "postgres")) { $extFile = "${extName}_scanner.duckdb_extension" $extUrl = "${extBase}/${extFile}" $extDest = Join-Path $extDir $extFile Download-File -Url $extUrl -Dest $extDest ` -Desc "DuckDB ${extName}_scanner 扩展 ($ArchSuffix)" } # 3. Oracle Instant Client Write-Host "" Write-Host "===== 下载 Oracle Instant Client ($OracleArch) =====" $oracleBase = "https://download.oracle.com/otn_software/linux/instantclient" $icBasicUrl = "${oracleBase}/instantclient-basiclite-${OracleArch}.zip" $icBasicDest = Join-Path $oracleDir "instantclient-basiclite-${OracleArch}.zip" Download-File -Url $icBasicUrl -Dest $icBasicDest ` -Desc "Oracle Instant Client Basic Lite ($OracleArch)" $icOdbcUrl = "${oracleBase}/instantclient-odbc-${OracleArch}.zip" $icOdbcDest = Join-Path $oracleDir "instantclient-odbc-${OracleArch}.zip" Download-File -Url $icOdbcUrl -Dest $icOdbcDest ` -Desc "Oracle Instant Client ODBC ($OracleArch)" Write-Host "" Write-Host "[INFO] $ArchSuffix 包准备完成:" -ForegroundColor Green Write-Host " DuckDB CLI: $([math]::Round((Get-Item $duckdbDest).Length / 1MB, 1)) MB" Write-Host " ODBC 扩展: $([math]::Round((Get-Item (Join-Path $extDir 'odbc_scanner.duckdb_extension')).Length / 1MB, 1)) MB" Write-Host " PG 扩展: $([math]::Round((Get-Item (Join-Path $extDir 'postgres_scanner.duckdb_extension')).Length / 1MB, 1)) MB" Write-Host " Oracle Basic: $([math]::Round((Get-Item $icBasicDest).Length / 1MB, 1)) MB" Write-Host " Oracle ODBC: $([math]::Round((Get-Item $icOdbcDest).Length / 1MB, 1)) MB" } # ========== 主流程 ========== Write-Host "============================================================" Write-Host " 离线部署准备 - 下载所有依赖包 (Windows)" Write-Host " DuckDB v${DUCKDB_VERSION}" Write-Host "============================================================" Write-Host "" New-Item -ItemType Directory -Force -Path $OfflineDir | Out-Null if ($AllArch) { Write-Host "[INFO] 下载全部架构 (amd64 + arm64)" Prepare-SingleArch -ArchSuffix "amd64" -OracleArch "linuxx64" Prepare-SingleArch -ArchSuffix "arm64" -OracleArch "linuxarm64" } else { if ($Arch -eq "") { Write-Host "请选择目标 Linux 机器的 CPU 架构:" Write-Host " [1] amd64 (x86_64) -- 大多数服务器" Write-Host " [2] arm64 (aarch64) -- 鲲鹏/飞腾等 ARM 服务器" $choice = Read-Host "输入选择 (1 或 2)" switch ($choice) { "1" { $Arch = "amd64" } "2" { $Arch = "arm64" } default { Write-Host "[ERROR] 无效选择" -ForegroundColor Red; exit 1 } } } switch ($Arch) { "amd64" { Prepare-SingleArch -ArchSuffix "amd64" -OracleArch "linuxx64" } "arm64" { Prepare-SingleArch -ArchSuffix "arm64" -OracleArch "linuxarm64" } } } # 写入版本信息 $versionContent = "DUCKDB_VERSION=$DUCKDB_VERSION`nPREPARE_OS=Windows`nPREPARE_DATE=$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" Set-Content -Path (Join-Path $OfflineDir "VERSION") -Value $versionContent -Encoding UTF8 Write-Host "" Write-Host "============================================================" -ForegroundColor Green Write-Host " 离线包准备完成!" -ForegroundColor Green Write-Host " 目录: $OfflineDir" -ForegroundColor Green Write-Host "" Write-Host " 下一步:" -ForegroundColor Green Write-Host " 1. 将 offline_packages 目录压缩为 zip" -ForegroundColor Green Write-Host " 2. 拷贝到内网 Linux 目标机器 (scp/U盘/共享文件夹)" -ForegroundColor Green Write-Host " 3. 在目标机器上解压并执行:" -ForegroundColor Green Write-Host " tar xzf duckdb-offline-packages.tar.gz" -ForegroundColor Green Write-Host " ./install_offline.sh" -ForegroundColor Green Write-Host "============================================================" -ForegroundColor Green

在 PowerShell 中运行:

# 打开 PowerShell,进入 prepare.ps1 所在目录 cd C:\your\path o # 下载指定架构(交互式选择) .\prepare.ps1 # 或直接指定架构 .\prepare.ps1 -Arch amd64 .\prepare.ps1 -Arch arm64 # 同时下载两种架构 .\prepare.ps1 -AllArch

注意: 下载的文件都是 Linux 版本的(DuckDB Linux CLI、Linux 扩展、Linux Oracle Client),Windows 只是作为"下载中转站",最终目标运行环境仍然是 Linux。下载完成后将 offline_packages 目录压缩拷贝到 Linux 目标机器即可。

下载完成后,offline_packages/ 目录结构如下:

offline_packages/ ├── VERSION # 版本信息 └── amd64/ # 或 arm64/,取决于目标架构 ├── duckdb/ │ └── duckdb_cli-linux-amd64.zip # DuckDB CLI ├── extensions/ │ ├── odbc_scanner.duckdb_extension # ODBC 扩展 │ └── postgres_scanner.duckdb_extension # PostgreSQL 扩展 └── oracle/ ├── instantclient-basiclite-linuxx64.zip # Oracle Basic Lite └── instantclient-odbc-linuxx64.zip # Oracle ODBC

步骤 2: 打包并拷贝到内网

在 Linux 上打包

tar czf duckdb-offline-packages.tar.gz offline_packages/ scp duckdb-offline-packages.tar.gz root@192.168.x.x:/data/duckdb-oracle-gaussdb/

在 Windows 上打包

# 用 PowerShell 压缩 Compress-Archive -Path offline_packages -DestinationPath duckdb-offline-packages.tar.gz # 注意: Linux 端解压 tar.gz 更方便,建议在 Windows 上用 7-Zip 等工具压缩为 .tar.gz # 或直接拷贝 offline_packages 整个目录(U盘、共享文件夹等)

Windows 上压缩为 .tar.gz 可以用 7-Zip:先右键 offline_packages7-Zip → 添加到压缩包 (格式选 tar),再对生成的 .tar 文件同样操作选 gzip。也可以直接拷贝 offline_packages 文件夹到目标 Linux 机器上跳过压缩步骤。

步骤 3: 在内网目标机器上安装

在目标机器上:

cd /data/duckdb-oracle-gaussdb # 解压离线包 tar xzf duckdb-offline-packages.tar.gz # 将 prepare.sh、install_offline.sh、run.sh 放到项目目录 # (如果还没有的话,从代码仓库获取或手动创建)

创建 install_offline.sh 文件:

#!/usr/bin/env bash set -euo pipefail # ============================================================ # 离线部署 - 安装脚本 # 在内网目标机器上运行,使用 offline_packages/ 中的预下载包 # # 前提条件: # 1. offline_packages/ 目录已存在于项目目录下 # 2. 目标机器有 yum/apt 软件源(安装 curl, unzip, libaio, unixODBC) # 3. root 权限 # ============================================================ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="$SCRIPT_DIR" OFFLINE_DIR="$PROJECT_DIR/offline_packages" RUNTIME_DIR="$PROJECT_DIR/runtime" BIN_DIR="$PROJECT_DIR/bin" VAR_DIR="$PROJECT_DIR/var" EXT_DIR="$RUNTIME_DIR/extensions" ORACLE_DIR="$PROJECT_DIR/runtime/oracle" UNIXODBC_DIR="$PROJECT_DIR/runtime/unixodbc/lib" # ---------- 颜色输出 ---------- RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m' info() { echo -e "${GREEN}[INFO]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } # ---------- 检测 OS 和架构 ---------- detect_env() { if [[ -f /etc/os-release ]]; then . /etc/os-release case "$ID" in ubuntu|debian|linuxmint|pop) OS_FAMILY="debian" ;; fedora) OS_FAMILY="fedora" ;; rhel|rocky|almalinux|centos|kylin|openeuler|anolis) OS_FAMILY="rhel" ;; *) error "不支持的发行版: $ID";; esac else error "无法检测操作系统" fi ARCH="$(uname -m)" case "$ARCH" in x86_64) ARCH_SUFFIX="amd64"; ;; aarch64) ARCH_SUFFIX="arm64"; ;; *) error "不支持的架构: $ARCH";; esac info "检测到: OS=$OS_FAMILY ($ID $VERSION_ID), 架构=$ARCH ($ARCH_SUFFIX)" } # ---------- 检查离线包 ---------- check_offline_packages() { if [[ ! -d "$OFFLINE_DIR/$ARCH_SUFFIX" ]]; then error "未找到当前架构($ARCH_SUFFIX)的离线包: $OFFLINE_DIR/$ARCH_SUFFIX" fi local pkg_dir="$OFFLINE_DIR/$ARCH_SUFFIX" local oracle_arch case "$ARCH_SUFFIX" in amd64) oracle_arch="linuxx64" ;; arm64) oracle_arch="linuxarm64" ;; esac for f in \ "duckdb/duckdb_cli-linux-${ARCH_SUFFIX}.zip" \ "extensions/odbc_scanner.duckdb_extension" \ "extensions/postgres_scanner.duckdb_extension" \ "oracle/instantclient-basiclite-${oracle_arch}.zip" \ "oracle/instantclient-odbc-${oracle_arch}.zip" do if [[ ! -f "$pkg_dir/$f" ]]; then error "缺少离线包: $pkg_dir/$f" fi done info "离线包检查通过" } # ---------- 安装系统依赖 ---------- install_sys_deps() { info "安装系统依赖 (通过 yum/apt)..." if [[ "$OS_FAMILY" == "debian" ]]; then export DEBIAN_FRONTEND=noninteractive apt-get update -qq apt-get install -y -qq curl unzip libaio1t64 unixodbc 2>/dev/null || \ apt-get install -y -qq curl unzip libaio1 unixodbc 2>/dev/null || \ apt-get install -y -qq curl unzip libaio unixodbc elif [[ "$OS_FAMILY" == "fedora" || "$OS_FAMILY" == "rhel" ]]; then dnf install -y -q curl unzip libaio unixODBC 2>/dev/null || \ yum install -y -q curl unzip libaio unixODBC fi info "系统依赖安装完成" } # ---------- 从离线包安装 DuckDB CLI ---------- install_duckdb() { info "安装 DuckDB CLI ($ARCH_SUFFIX)..." mkdir -p "$BIN_DIR" local zip_file="$OFFLINE_DIR/$ARCH_SUFFIX/duckdb/duckdb_cli-linux-${ARCH_SUFFIX}.zip" unzip -o "$zip_file" -d "$PROJECT_DIR/.tmp-duckdb" > /dev/null cp -f "$PROJECT_DIR/.tmp-duckdb/duckdb" "$BIN_DIR/duckdb" chmod +x "$BIN_DIR/duckdb" rm -rf "$PROJECT_DIR/.tmp-duckdb" info "DuckDB CLI: $($BIN_DIR/duckdb --version 2>/dev/null | head -1)" } # ---------- 从离线包复制扩展 ---------- install_extensions() { info "安装 DuckDB 扩展 ($ARCH_SUFFIX)..." mkdir -p "$EXT_DIR" cp -f "$OFFLINE_DIR/$ARCH_SUFFIX/extensions/odbc_scanner.duckdb_extension" \ "$EXT_DIR/" cp -f "$OFFLINE_DIR/$ARCH_SUFFIX/extensions/postgres_scanner.duckdb_extension" \ "$EXT_DIR/" info "扩展文件:" ls -lh "$EXT_DIR/" } # ---------- 从离线包安装 Oracle Instant Client ---------- install_oracle_client() { info "安装 Oracle Instant Client ($ARCH_SUFFIX)..." mkdir -p "$ORACLE_DIR" local oracle_arch case "$ARCH_SUFFIX" in amd64) oracle_arch="linuxx64" ;; arm64) oracle_arch="linuxarm64" ;; esac unzip -o "$OFFLINE_DIR/$ARCH_SUFFIX/oracle/instantclient-basiclite-${oracle_arch}.zip" \ -d "$ORACLE_DIR" > /dev/null unzip -o "$OFFLINE_DIR/$ARCH_SUFFIX/oracle/instantclient-odbc-${oracle_arch}.zip" \ -d "$ORACLE_DIR" > /dev/null ORACLE_IC_DIR="$(find "$ORACLE_DIR" -maxdepth 1 -type d -name 'instantclient_*' | head -1)" if [[ -z "$ORACLE_IC_DIR" ]]; then error "Oracle Instant Client 解压后未找到 instantclient_* 目录" fi local sqora sqora="$(find "$ORACLE_IC_DIR" -name 'libsqora.so.*' | head -1)" if [[ -n "$sqora" ]]; then info "找到 Oracle ODBC 驱动: $(basename "$sqora")" else error "未找到 libsqora.so (Oracle ODBC 驱动)" fi info "Oracle Instant Client: $ORACLE_IC_DIR" } # ---------- 提取 unixODBC 运行时库 ---------- extract_unixodbc() { info "提取 unixODBC 运行时库到项目目录..." mkdir -p "$UNIXODBC_DIR" local lib_search_paths=() if [[ "$OS_FAMILY" == "debian" ]]; then lib_search_paths=(/usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu /usr/lib) elif [[ "$OS_FAMILY" == "fedora" || "$OS_FAMILY" == "rhel" ]]; then lib_search_paths=(/usr/lib64 /usr/lib) fi for lib in libodbc.so.2 libodbcinst.so.2 libodbc.so.2.0.0 libodbcinst.so.2.0.0; do for sp in "${lib_search_paths[@]}"; do if [[ -f "$sp/$lib" ]]; then cp -a "$sp/$lib" "$UNIXODBC_DIR/" 2>/dev/null || true break fi done done for lib_pattern in "libaio.so.1*" "libltdl.so.7*"; do for sp in "${lib_search_paths[@]}"; do if find "$sp" -maxdepth 1 -name "$lib_pattern" -print -quit 2>/dev/null | grep -q .; then cp -a "$sp"/$lib_pattern "$UNIXODBC_DIR/" 2>/dev/null || true break fi done done info "unixODBC 运行时库:" ls -lh "$UNIXODBC_DIR/" } # ---------- 生成 ODBC 配置 ---------- generate_odbc_config() { info "生成 ODBC 配置..." mkdir -p "$VAR_DIR/odbc" "$VAR_DIR/home" "$VAR_DIR/tmp" local sqora_file sqora_file="$(find "$ORACLE_IC_DIR" -name 'libsqora.so.*' \ __import__("subprocess").run('-name '*.so' | sort -V | tail -1)"', shell=True) if [[ -z "$sqora_file" ]]; then error "未找到 Oracle ODBC 驱动库" fi cat >"$VAR_DIR/odbc/odbcinst.ini" <<EOF [Oracle ODBC driver] Description=Oracle ODBC driver (self-contained) Driver=${sqora_file} Setup= FileUsage=1 CPTimeout= CPReuse= EOF cat >"$VAR_DIR/odbc/odbc.ini" <<EOF [OraclePDB1] Driver=Oracle ODBC driver Description=Oracle PDB1 Self-Contained DBQ=//192.168.163.227:1527/pdb1 UserID=system [ODBC Data Sources] OraclePDB1=Oracle ODBC driver EOF info "ODBC 配置文件已生成" } # ---------- 写入 env.sh ---------- write_env_file() { cat >"$PROJECT_DIR/env.sh" <<EOF # 此文件由 install_offline.sh 自动生成,请勿手动编辑 export PROJECT_DIR="$PROJECT_DIR" export DUCKDB_BIN="$PROJECT_DIR/bin/duckdb" export ODBC_EXT="$PROJECT_DIR/runtime/extensions/odbc_scanner.duckdb_extension" export POSTGRES_EXT="$PROJECT_DIR/runtime/extensions/postgres_scanner.duckdb_extension" export ORACLE_IC_DIR="$ORACLE_IC_DIR" export UNIXODBC_LIB_DIR="$UNIXODBC_DIR" export ODBC_CONF_DIR="$PROJECT_DIR/var/odbc" export TEMP_DIR="$PROJECT_DIR/var/tmp" export HOME_DIR="$PROJECT_DIR/var/home" export ORACLE_DRIVER_NAME="Oracle ODBC driver" EOF info "env.sh 已生成" } # ---------- 验证安装 ---------- verify_installation() { echo "" info "========== 安装验证 ==========" local errors=0 if [[ -x "$BIN_DIR/duckdb" ]]; then info "[OK] DuckDB CLI: $($BIN_DIR/duckdb --version 2>/dev/null | head -1)" else error "[FAIL] DuckDB CLI"; errors=$((errors+1)); fi if [[ -f "$EXT_DIR/odbc_scanner.duckdb_extension" ]]; then info "[OK] ODBC 扩展" else error "[FAIL] ODBC 扩展"; errors=$((errors+1)); fi if [[ -f "$EXT_DIR/postgres_scanner.duckdb_extension" ]]; then info "[OK] PostgreSQL 扩展" else error "[FAIL] PostgreSQL 扩展"; errors=$((errors+1)); fi if [[ -d "$ORACLE_IC_DIR" ]]; then info "[OK] Oracle Instant Client" else error "[FAIL] Oracle Instant Client"; errors=$((errors+1)); fi if ls "$UNIXODBC_DIR"/libodbc.so* 1>/dev/null 2>&1; then info "[OK] unixODBC 库文件" else error "[FAIL] unixODBC 库"; errors=$((errors+1)); fi if [[ $errors -gt 0 ]]; then error "安装失败: $errors 项错误"; fi info "========== 离线安装完成 ==========" echo "" info "下一步: cd $PROJECT_DIR && ./run.sh" } # ========== 主流程 ========== main() { echo "============================================================" echo " DuckDB + Oracle + GaussDB 离线安装" echo " OS: $(. /etc/os-release 2>/dev/null && echo "$ID $VERSION_ID") 架构: $(uname -m)" echo "============================================================" echo "" mkdir -p "$RUNTIME_DIR" "$VAR_DIR" detect_env check_offline_packages install_sys_deps install_duckdb install_extensions install_oracle_client extract_unixodbc generate_odbc_config write_env_file verify_installation } main "$@"

赋予执行权限并运行:

chmod +x install_offline.sh ./install_offline.sh

离线安装过程与在线安装基本一致,唯一区别是不执行任何网络下载——DuckDB CLI、扩展、Oracle 客户端全部从 offline_packages/ 目录读取。只有四个基础系统包(curl、unzip、libaio、unixODBC)通过 yum/apt 从本地软件源安装。

安装完成后,运行脚本 run.sh 与在线部署完全相同,无需任何修改。

离线部署 vs 在线部署对比

对比项 在线部署 (install.sh) 离线部署 (install_offline.sh)
网络要求 需要外网访问 仅需内网 yum/apt 源
DuckDB CLI 从 GitHub 下载 offline_packages/ 解压
DuckDB 扩展 从 CDN/DuckDB INSTALL 下载 offline_packages/ 复制
Oracle 客户端 从 Oracle 官网下载 offline_packages/ 解压
系统依赖 同(curl, unzip, libaio, unixODBC)
unixODBC 库 从系统提取 从系统提取
运行时 完全相同 完全相同
准备工作 需要先在有网机器运行 prepare.sh

关于 run.sh 的说明

离线部署和在线部署共用同一个 run.shrun.sh 只使用项目目录内的文件(DuckDB CLI、扩展、配置),不依赖网络。因此无论用哪种方式安装,run.sh 的行为完全一致。

七、方案优势与局限

优势

  1. 完全自包含: 所有依赖打包在项目目录内,不污染系统环境
  2. 多平台支持: 同时兼容 Debian/Ubuntu 和 Fedora/RHEL,amd64 和 arm64
  3. 零配置运行: 安装脚本自动处理所有配置,运行脚本自动设置环境变量
  4. 灵活扩展: 支持通过环境变量覆盖连接参数,SQL 模板可自定义
  5. 无 root 运行时需求: 安装后,运行 run.sh 不需要 root 权限

局限

  1. 网络依赖: 安装时需要网络下载 DuckDB、扩展和 Oracle Client
  2. 架构绑定: 打包后的目录只能在相同 CPU 架构上运行(amd64 不能在 arm64 上用,反之亦然)
  3. glibc 兼容性: 目标机器的 glibc 版本不能比构建环境明显更老
  4. Oracle ODBC 性能: ODBC 连接有额外的序列化/反序列化开销,不适合大批量数据传输
  5. DuckDB 版本绑定: 扩展版本必须与 DuckDB CLI 版本严格匹配

八、多平台验证

为了验证方案的通用性,在两台不同操作系统的服务器上进行了测试。

Ubuntu 22.04 x86_64 — 首次验证

============================================================ DuckDB + Oracle + GaussDB 自包含安装 OS: ubuntu 22.04 架构: x86_64 ============================================================ [INFO] 检测到: OS=debian (ubuntu 22.04), 架构=x86_64 (amd64) ... [INFO] ========== 安装完成 ==========

运行结果:

┌───────────────┬─────────────────────┬────────────────┬───────────────────────────────┐ │ oracle_result │ oracle_sysdate │ gaussdb_result │ gaussdb_timestamp │ │ varchar │ varchar │ varchar │ timestamp with time zone │ ├───────────────┼─────────────────────┼────────────────┼───────────────────────────────┤ │ Oracle_OK │ 2026-05-22 07:09:31 │ GaussDB_OK │ 2026-05-22 07:09:34.067699+00 │ └───────────────┴─────────────────────┴────────────────┴───────────────────────────────┘ ┌───────────┬────────────────────────────────────────────────────────────────────────┐ │ db_source │ version │ │ varchar │ varchar │ ├───────────┼────────────────────────────────────────────────────────────────────────┤ │ Oracle │ Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production │ │ GaussDB │ gaussdb (GaussDB Kernel 506.0.0.SPC0500 build d474632c) compiled at... │ └───────────┴────────────────────────────────────────────────────────────────────────┘

Kylin V10 x86_64 — 国产系统验证

Kylin V10 是基于 RHEL 的国产操作系统,其 /etc/os-releaseID=kylin,不在标准 RHEL 识别列表中。因此需要在 install.shdetect_env() 函数中将 kylin 加入 rhel 分支:

# 修改前 rhel|rocky|almalinux|centos) OS_FAMILY="rhel" ;; # 修改后 rhel|rocky|almalinux|centos|kylin|openeuler|anolis) OS_FAMILY="rhel" ;;

安装过程输出:

============================================================ DuckDB + Oracle + GaussDB 自包含安装 OS: kylin V10 架构: x86_64 ============================================================ [INFO] 检测到: OS=rhel (kylin V10), 架构=x86_64 (amd64) [INFO] 安装系统依赖... [INFO] 系统依赖安装完成 [INFO] 安装 DuckDB CLI v1.5.3 (amd64)... [WARN] 直连失败, 尝试通过代理下载... [INFO] DuckDB CLI: v1.5.3 (Variegata) 14eca11bd9 [INFO] 下载 DuckDB 扩展 (amd64)... [INFO] 通过 DuckDB INSTALL 下载: odbc [INFO] 下载成功: odbc_scanner [INFO] 通过 DuckDB INSTALL 下载: postgres [INFO] 下载成功: postgres_scanner [INFO] 安装 Oracle Instant Client (linuxx64)... [INFO] 找到 Oracle ODBC 驱动: libsqora.so.23.1 [INFO] 提取 unixODBC 运行时库到项目目录... [INFO] ========== 安装完成 ==========

注意: GitHub 直连不通时,脚本自动通过 ghfast.top 代理下载了 DuckDB CLI;扩展则通过 DuckDB 内置的 INSTALL 命令成功下载。

运行结果:

============================================================ DuckDB 跨库查询: Oracle + GaussDB Oracle: system@192.168.163.227:1527/pdb1 GaussDB: admin@192.168.163.227:15432/postgres ============================================================ ┌───────────┬─────────────┐ │ STATUS │ ORACLE_TIME │ │ varchar │ date │ ├───────────┼─────────────┤ │ Oracle_OK │ 2026-05-22 │ └───────────┴─────────────┘ ┌────────────┬───────────────────────────────┐ │ status │ gaussdb_time │ │ varchar │ timestamp with time zone │ ├────────────┼───────────────────────────────┤ │ GaussDB_OK │ 2026-05-22 16:26:36.448552+08 │ └────────────┴───────────────────────────────┘ ┌───────────────┬─────────────────────┬────────────────┬───────────────────────────────┐ │ oracle_result │ oracle_sysdate │ gaussdb_result │ gaussdb_timestamp │ │ varchar │ varchar │ varchar │ timestamp with time zone │ ├───────────────┼─────────────────────┼────────────────┼───────────────────────────────┤ │ Oracle_OK │ 2026-05-22 08:03:14 │ GaussDB_OK │ 2026-05-22 16:03:17.636536+08 │ └───────────────┴─────────────────────┴────────────────┴───────────────────────────────┘ ┌───────────┬────────────────────────────────────────────────────────────────────────┐ │ db_source │ version │ │ varchar │ varchar │ ├───────────┼────────────────────────────────────────────────────────────────────────┤ │ Oracle │ Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production │ │ GaussDB │ gaussdb (GaussDB Kernel 506.0.0.SPC0500 build d474632c) compiled at... │ └───────────┴────────────────────────────────────────────────────────────────────────┘

验证结论

验证项 Ubuntu 22.04 Kylin V10
OS 识别 debian rhel (自动)
系统依赖安装 apt-get 已预装
DuckDB CLI 下载 直连 代理 (自动回退)
扩展下载 DuckDB INSTALL DuckDB INSTALL
Oracle 连接 通过 通过
GaussDB 连接 通过 通过
跨库联合查询 通过 通过
版本查询 Oracle 19c + GaussDB 506 Oracle 19c + GaussDB 506

两台服务器均一次安装成功,无需任何手动干预,证明该方案的跨平台兼容性良好。

总结

本文实现了一个完全自包含的 DuckDB 跨库查询方案,核心要点:

  • DuckDB 通过 ODBC scanner 扩展连接 Oracle
  • DuckDB 通过 PostgreSQL scanner 扩展连接 GaussDB
  • 连接 GaussDB 必须设置 SET pg_use_text_protocol=true;
  • 所有运行时依赖打包在项目目录内,通过环境变量隔离
  • 安装脚本自动检测 OS 发行版和 CPU 架构,适配多种 Linux 环境

整个方案只需两个脚本(install.sh + run.sh),即可在任意 Linux 服务器上快速部署并实现 Oracle + GaussDB 的跨库联合查询。

参考链接

本文完全由wps灵犀claw生成,最终article.md文件我一字没改
image-WzQD.png
image-sRAo.png


最后修改时间:2026-05-25 15:22:38
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论