From c1b2ced96fdb7017059c1f2f6df773b13fac1ccd Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 22:43:30 -0700 Subject: [PATCH 01/22] Add oracle to CI --- .github/workflows/ci.yml | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7aa121c81..f84897921 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -248,8 +248,46 @@ jobs: if-no-files-found: error include-hidden-files: true + test-oracle: + runs-on: ubuntu-latest + env: + TORTOISE_TEST_MODULES: tests.testmodels + TORTOISE_ORACLE_PASS: 123456 + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@v6 + - uses: gvenzl/setup-oracle-free@v1 + with: + app-user: test_db + app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + - uses: astral-sh/setup-uv@v7 + - uses: actions/cache@v5 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/uv.lock') }} + restore-keys: | + ${{ runner.os }}-pip- + - name: Install dependencies + run: make deps + - name: Test Oracle + run: make test_oracle + env: + PYTHONDEVMODE: 1 + - name: Upload coverage artifact + uses: actions/upload-artifact@v4 + with: + name: coverage-oracle-${{ matrix.python-version }} + path: .coverage + if-no-files-found: error + include-hidden-files: true + coverage: - needs: [test-sqlite, test-postgres, test-mysql, test-mssql] + needs: [test-sqlite, test-postgres, test-mysql, test-mssql, test-oracle] runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 From 0d009bc681353a5110e8f960b4af414169f0af7e Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 23:02:05 -0700 Subject: [PATCH 02/22] Set up oracle client --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f84897921..64b80f1a7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,6 +253,7 @@ jobs: env: TORTOISE_TEST_MODULES: tests.testmodels TORTOISE_ORACLE_PASS: 123456 + TORTOISE_ORACLE_DRIVER: cx_Oracle # Oracle Instant Client strategy: matrix: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] @@ -262,6 +263,15 @@ jobs: with: app-user: test_db app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} + - uses: iamazeem/setup-oracle-instant-client-action@v2 +# id: oracle-client +# - name: Configure Oracle ODBC driver +# run: | +# ORACLE_HOME=$(find /opt -name "instantclient*" -type d 2>/dev/null | head -1) +# echo "[Oracle Instant Client]" | sudo tee /etc/odbcinst.ini +# echo "Description = Oracle ODBC Driver" | sudo tee -a /etc/odbcinst.ini +# echo "Driver = ${ORACLE_HOME}/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini +# cat /etc/odbcinst.ini - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} From fc7942eb39bfcb01ce8f685011db50d9123f4d5b Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 23:20:01 -0700 Subject: [PATCH 03/22] Set up oracle client --- .github/workflows/ci.yml | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64b80f1a7..889521dd0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,25 +253,38 @@ jobs: env: TORTOISE_TEST_MODULES: tests.testmodels TORTOISE_ORACLE_PASS: 123456 - TORTOISE_ORACLE_DRIVER: cx_Oracle # Oracle Instant Client strategy: matrix: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v6 + - name: Install system dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y unixodbc unixodbc-dev libaio1t64 + sudo ln -sf /usr/lib/x86_64-linux-gnu/libaio.so.1t64 \ + /usr/lib/x86_64-linux-gnu/libaio.so.1 - uses: gvenzl/setup-oracle-free@v1 with: app-user: test_db app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} - uses: iamazeem/setup-oracle-instant-client-action@v2 -# id: oracle-client -# - name: Configure Oracle ODBC driver -# run: | -# ORACLE_HOME=$(find /opt -name "instantclient*" -type d 2>/dev/null | head -1) -# echo "[Oracle Instant Client]" | sudo tee /etc/odbcinst.ini -# echo "Description = Oracle ODBC Driver" | sudo tee -a /etc/odbcinst.ini -# echo "Driver = ${ORACLE_HOME}/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini -# cat /etc/odbcinst.ini + - name: Install Oracle Instant Client ODBC and register driver + run: | + # Discover the version installed by the action (e.g. "21" or "23") + IC_VER=$(ls /usr/lib/oracle/ | sort -V | tail -1) + echo "Detected Instant Client version: $IC_VER" + # Install the matching ODBC package from the same Oracle apt repo + sudo apt-get install -y "oracle-instantclient${IC_VER}-odbc" + IC_LIB="/usr/lib/oracle/${IC_VER}/client64/lib" + # Register the driver with unixODBC. + # odbc_update_ini.sh creates an entry like [Oracle c ODBC driver] + # in /etc/odbcinst.ini using the system unixODBC installation. + sudo "${IC_LIB}/odbc_update_ini.sh" /usr + # Confirm registration and capture the exact driver name + DRIVER_NAME=$(odbcinst -q -d | grep -oP '(?<=\[)[^\]]+' | grep -i oracle | head -1) + echo "Registered ODBC driver: $DRIVER_NAME" + echo "TORTOISE_ORACLE_DRIVER=${DRIVER_NAME}" >> "$GITHUB_ENV" - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} From 44eb77e99474f28d75db10c8a45e21cb71b21acc Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 23:24:41 -0700 Subject: [PATCH 04/22] Remove symlink setup --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889521dd0..e5bebc05e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -262,8 +262,6 @@ jobs: run: | sudo apt-get update -qq sudo apt-get install -y unixodbc unixodbc-dev libaio1t64 - sudo ln -sf /usr/lib/x86_64-linux-gnu/libaio.so.1t64 \ - /usr/lib/x86_64-linux-gnu/libaio.so.1 - uses: gvenzl/setup-oracle-free@v1 with: app-user: test_db From 9c42ffb80cf880ce3b73af06355f8c717fee452c Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 23:34:02 -0700 Subject: [PATCH 05/22] Add debug info --- .github/workflows/ci.yml | 52 +++++++++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5bebc05e..4f7222144 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,19 +269,49 @@ jobs: - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Install Oracle Instant Client ODBC and register driver run: | - # Discover the version installed by the action (e.g. "21" or "23") - IC_VER=$(ls /usr/lib/oracle/ | sort -V | tail -1) - echo "Detected Instant Client version: $IC_VER" - # Install the matching ODBC package from the same Oracle apt repo - sudo apt-get install -y "oracle-instantclient${IC_VER}-odbc" - IC_LIB="/usr/lib/oracle/${IC_VER}/client64/lib" - # Register the driver with unixODBC. - # odbc_update_ini.sh creates an entry like [Oracle c ODBC driver] - # in /etc/odbcinst.ini using the system unixODBC installation. + echo "── Locating Instant Client installation ────" + echo "sqlplus path : $(which sqlplus || echo 'not in PATH')" + echo "LD_LIBRARY_PATH : $LD_LIBRARY_PATH" + + # Find libclntsh.so to locate the lib dir regardless of install path. + # This is robust whether the action installs to /usr/lib/oracle/, + # /opt/oracle/, or any other location. + LIBCLNTSH=$(find / -name "libclntsh.so*" -not -path "*/proc/*" 2>/dev/null | head -1) + echo "libclntsh found : $LIBCLNTSH" + IC_LIB=$(dirname "$LIBCLNTSH") + echo "Instant Client lib dir: $IC_LIB" + + echo "── Instant Client lib dir contents ─────────" + ls "$IC_LIB" + + # Derive the numeric major version from the path if it follows the + # standard RPM layout, e.g. /usr/lib/oracle/21/client64/lib → 21 + IC_VER=$(echo "$IC_LIB" | grep -oP '(?<=/oracle/)\d+(?=/)' || true) + echo "Detected version (from path): ${IC_VER:-unknown}" + + echo "── Installing ODBC package ─────────────────" + # Try versioned package name first (RPM-based layout), then unversioned + if [ -n "$IC_VER" ]; then + sudo apt-get install -y "oracle-instantclient${IC_VER}-odbc" \ + || sudo apt-get install -y oracle-instantclient-odbc + else + sudo apt-get install -y oracle-instantclient-odbc + fi + + echo "── Instant Client lib dir after ODBC install" + ls "$IC_LIB" + + echo "── Registering driver with unixODBC ────────" sudo "${IC_LIB}/odbc_update_ini.sh" /usr - # Confirm registration and capture the exact driver name + + echo "── /etc/odbcinst.ini ───────────────────────" + cat /etc/odbcinst.ini + + echo "── Registered ODBC drivers ─────────────────" + odbcinst -q -d + DRIVER_NAME=$(odbcinst -q -d | grep -oP '(?<=\[)[^\]]+' | grep -i oracle | head -1) - echo "Registered ODBC driver: $DRIVER_NAME" + echo "Captured driver name: '$DRIVER_NAME'" echo "TORTOISE_ORACLE_DRIVER=${DRIVER_NAME}" >> "$GITHUB_ENV" - uses: actions/setup-python@v6 with: From 3356ad1ddc86a2f7d1a1093a43a1bb22082fca48 Mon Sep 17 00:00:00 2001 From: seladb Date: Wed, 18 Mar 2026 23:43:51 -0700 Subject: [PATCH 06/22] Try a fix --- .github/workflows/ci.yml | 58 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f7222144..6d1897479 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,40 +269,40 @@ jobs: - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Install Oracle Instant Client ODBC and register driver run: | - echo "── Locating Instant Client installation ────" - echo "sqlplus path : $(which sqlplus || echo 'not in PATH')" - echo "LD_LIBRARY_PATH : $LD_LIBRARY_PATH" - - # Find libclntsh.so to locate the lib dir regardless of install path. - # This is robust whether the action installs to /usr/lib/oracle/, - # /opt/oracle/, or any other location. - LIBCLNTSH=$(find / -name "libclntsh.so*" -not -path "*/proc/*" 2>/dev/null | head -1) + echo "── Locating action-installed Instant Client ─" + # Scope find to $RUNNER_TEMP to avoid hitting the Oracle Free + # container overlay, which also contains libclntsh.so. + LIBCLNTSH=$(find "$RUNNER_TEMP" -name "libclntsh.so*" 2>/dev/null | head -1) echo "libclntsh found : $LIBCLNTSH" IC_LIB=$(dirname "$LIBCLNTSH") - echo "Instant Client lib dir: $IC_LIB" - - echo "── Instant Client lib dir contents ─────────" - ls "$IC_LIB" + echo "IC lib dir : $IC_LIB" - # Derive the numeric major version from the path if it follows the - # standard RPM layout, e.g. /usr/lib/oracle/21/client64/lib → 21 - IC_VER=$(echo "$IC_LIB" | grep -oP '(?<=/oracle/)\d+(?=/)' || true) - echo "Detected version (from path): ${IC_VER:-unknown}" + echo "── Locating libsqora.so from Oracle Free container overlay ──" + # gvenzl/setup-oracle-free pulls a container whose layers are + # unpacked under ~/.local/share/containers/storage/overlay/ + SQORA=$(find /home/runner/.local/share/containers -name "libsqora.so*" \ + 2>/dev/null | head -1) + echo "libsqora found : $SQORA" + ORACLE_FREE_LIB=$(dirname "$SQORA") + echo "Oracle Free lib : $ORACLE_FREE_LIB" - echo "── Installing ODBC package ─────────────────" - # Try versioned package name first (RPM-based layout), then unversioned - if [ -n "$IC_VER" ]; then - sudo apt-get install -y "oracle-instantclient${IC_VER}-odbc" \ - || sudo apt-get install -y oracle-instantclient-odbc - else - sudo apt-get install -y oracle-instantclient-odbc - fi - - echo "── Instant Client lib dir after ODBC install" - ls "$IC_LIB" + echo "── Copying ODBC library into IC lib dir ────" + sudo cp "$ORACLE_FREE_LIB"/libsqora.so* "$IC_LIB/" + ls "$IC_LIB"/libsqora* echo "── Registering driver with unixODBC ────────" - sudo "${IC_LIB}/odbc_update_ini.sh" /usr + # Write the driver entry directly — no odbc_update_ini.sh needed. + IC_VER=$(echo "$LIBCLNTSH" | grep -oP '\d+(?=\.\d+$)' | head -1) + DRIVER_NAME="Oracle ${IC_VER}c ODBC driver" + echo "Driver name: $DRIVER_NAME" + + sudo odbcinst -i -d -r << EOF + [${DRIVER_NAME}] + Description=Oracle ODBC driver for Oracle ${IC_VER}c + Driver=${IC_LIB}/libsqora.so.${IC_VER}.1 + Setup=${IC_LIB}/libsqora.so.${IC_VER}.1 + FileUsage=1 + EOF echo "── /etc/odbcinst.ini ───────────────────────" cat /etc/odbcinst.ini @@ -310,8 +310,6 @@ jobs: echo "── Registered ODBC drivers ─────────────────" odbcinst -q -d - DRIVER_NAME=$(odbcinst -q -d | grep -oP '(?<=\[)[^\]]+' | grep -i oracle | head -1) - echo "Captured driver name: '$DRIVER_NAME'" echo "TORTOISE_ORACLE_DRIVER=${DRIVER_NAME}" >> "$GITHUB_ENV" - uses: actions/setup-python@v6 with: From 47a91c05224a33da73d4e51414e1358d8279a7ea Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:03:16 -0700 Subject: [PATCH 07/22] Try a simpler approach --- .github/workflows/ci.yml | 53 +++++++++------------------------------- 1 file changed, 11 insertions(+), 42 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d1897479..facedf2b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,6 +253,7 @@ jobs: env: TORTOISE_TEST_MODULES: tests.testmodels TORTOISE_ORACLE_PASS: 123456 + TORTOISE_ORACLE_DRIVER: OracleODBC strategy: matrix: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] @@ -269,48 +270,16 @@ jobs: - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Install Oracle Instant Client ODBC and register driver run: | - echo "── Locating action-installed Instant Client ─" - # Scope find to $RUNNER_TEMP to avoid hitting the Oracle Free - # container overlay, which also contains libclntsh.so. - LIBCLNTSH=$(find "$RUNNER_TEMP" -name "libclntsh.so*" 2>/dev/null | head -1) - echo "libclntsh found : $LIBCLNTSH" - IC_LIB=$(dirname "$LIBCLNTSH") - echo "IC lib dir : $IC_LIB" - - echo "── Locating libsqora.so from Oracle Free container overlay ──" - # gvenzl/setup-oracle-free pulls a container whose layers are - # unpacked under ~/.local/share/containers/storage/overlay/ - SQORA=$(find /home/runner/.local/share/containers -name "libsqora.so*" \ - 2>/dev/null | head -1) - echo "libsqora found : $SQORA" - ORACLE_FREE_LIB=$(dirname "$SQORA") - echo "Oracle Free lib : $ORACLE_FREE_LIB" - - echo "── Copying ODBC library into IC lib dir ────" - sudo cp "$ORACLE_FREE_LIB"/libsqora.so* "$IC_LIB/" - ls "$IC_LIB"/libsqora* - - echo "── Registering driver with unixODBC ────────" - # Write the driver entry directly — no odbc_update_ini.sh needed. - IC_VER=$(echo "$LIBCLNTSH" | grep -oP '\d+(?=\.\d+$)' | head -1) - DRIVER_NAME="Oracle ${IC_VER}c ODBC driver" - echo "Driver name: $DRIVER_NAME" - - sudo odbcinst -i -d -r << EOF - [${DRIVER_NAME}] - Description=Oracle ODBC driver for Oracle ${IC_VER}c - Driver=${IC_LIB}/libsqora.so.${IC_VER}.1 - Setup=${IC_LIB}/libsqora.so.${IC_VER}.1 - FileUsage=1 - EOF - - echo "── /etc/odbcinst.ini ───────────────────────" - cat /etc/odbcinst.ini - - echo "── Registered ODBC drivers ─────────────────" - odbcinst -q -d - - echo "TORTOISE_ORACLE_DRIVER=${DRIVER_NAME}" >> "$GITHUB_ENV" + - name: Configure ODBC + run: | + echo "[OracleODBC]" | sudo tee /etc/odbcinst.ini + echo "Driver=/opt/oracle/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini + + echo "[OracleDB]" | sudo tee /etc/odbc.ini + echo "Driver=OracleODBC" | sudo tee -a /etc/odbc.ini + echo "ServerName=localhost:1521/FREEPDB1" | sudo tee -a /etc/odbc.ini + echo "User=system" | sudo tee -a /etc/odbc.ini + echo "Password=oracle" | sudo tee -a /etc/odbc.ini - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} From ae4876a833a1484e796644fd53a2c8829f7f7062 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:14:55 -0700 Subject: [PATCH 08/22] Fix --- .github/workflows/ci.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index facedf2b2..d7473ec0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -272,8 +272,16 @@ jobs: run: | - name: Configure ODBC run: | + # Detect actual folder dynamically + ORACLE_DIR=$(ls -d /opt/oracle/instantclient_*) + echo "Oracle dir: $ORACLE_DIR" + + # Persist for later steps + echo "ORACLE_DIR=$ORACLE_DIR" >> $GITHUB_ENV + echo "LD_LIBRARY_PATH=$ORACLE_DIR" >> $GITHUB_ENV + echo "[OracleODBC]" | sudo tee /etc/odbcinst.ini - echo "Driver=/opt/oracle/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini + echo "Driver=$ORACLE_DIR/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini echo "[OracleDB]" | sudo tee /etc/odbc.ini echo "Driver=OracleODBC" | sudo tee -a /etc/odbc.ini From 1ad0b96504904cad453186c3d8feaef562636f73 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:20:35 -0700 Subject: [PATCH 09/22] Fix --- .github/workflows/ci.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d7473ec0f..24fd7cf66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -268,24 +268,26 @@ jobs: app-user: test_db app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} - uses: iamazeem/setup-oracle-instant-client-action@v2 - - name: Install Oracle Instant Client ODBC and register driver + - name: Locate Oracle ODBC driver run: | - - name: Configure ODBC - run: | - # Detect actual folder dynamically - ORACLE_DIR=$(ls -d /opt/oracle/instantclient_*) - echo "Oracle dir: $ORACLE_DIR" + DRIVER_PATH=$(find $HOME -name "libsqora.so*" | head -n 1) + + echo "Found driver at: $DRIVER_PATH" - # Persist for later steps - echo "ORACLE_DIR=$ORACLE_DIR" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$ORACLE_DIR" >> $GITHUB_ENV + if [ -z "$DRIVER_PATH" ]; then + echo "ERROR: libsqora.so not found" + exit 1 + fi + echo "DRIVER_PATH=$DRIVER_PATH" >> $GITHUB_ENV + - name: Configure ODBC + run: | echo "[OracleODBC]" | sudo tee /etc/odbcinst.ini - echo "Driver=$ORACLE_DIR/libsqora.so.21.1" | sudo tee -a /etc/odbcinst.ini + echo "Driver=$DRIVER_PATH" | sudo tee -a /etc/odbcinst.ini echo "[OracleDB]" | sudo tee /etc/odbc.ini echo "Driver=OracleODBC" | sudo tee -a /etc/odbc.ini - echo "ServerName=localhost:1521/FREEPDB1" | sudo tee -a /etc/odbc.ini + echo "ServerName=127.0.0.1:1521/FREEPDB1" | sudo tee -a /etc/odbc.ini echo "User=system" | sudo tee -a /etc/odbc.ini echo "Password=oracle" | sudo tee -a /etc/odbc.ini - uses: actions/setup-python@v6 From bb154a70d78647a7428ee7373010590953806086 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:28:08 -0700 Subject: [PATCH 10/22] Try a fixed DB name --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 02a99b786..57e239cd3 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ test_mssql: $(py_warn) TORTOISE_TEST_DB="mssql://sa:$(TORTOISE_MSSQL_PASS)@127.0.0.1:1433/test_\{\}?driver=$(TORTOISE_MSSQL_DRIVER)&TrustServerCertificate=YES" uv run --frozen pytest $(pytest_opts) --cov-report= test_oracle: - $(py_warn) TORTOISE_TEST_DB="oracle://SYSTEM:$(TORTOISE_ORACLE_PASS)@127.0.0.1:1521/test_\{\}?driver=$(TORTOISE_ORACLE_DRIVER)" uv run --frozen pytest $(pytest_opts) --cov-report= + $(py_warn) TORTOISE_TEST_DB="oracle://SYSTEM:$(TORTOISE_ORACLE_PASS)@127.0.0.1:1521/FREEPDB1?driver=$(TORTOISE_ORACLE_DRIVER)" uv run --frozen pytest $(pytest_opts) --cov-report= _testall: test_sqlite test_postgres_asyncpg test_postgres_psycopg test_mysql_myisam test_mysql test_mysql_asyncmy test_mssql From 3b7556311fc58d1ca1fd4f239089f5159d66b92d Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:35:31 -0700 Subject: [PATCH 11/22] Add a wait loop --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 24fd7cf66..16cb8dcd1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -290,6 +290,16 @@ jobs: echo "ServerName=127.0.0.1:1521/FREEPDB1" | sudo tee -a /etc/odbc.ini echo "User=system" | sudo tee -a /etc/odbc.ini echo "Password=oracle" | sudo tee -a /etc/odbc.ini + - name: Wait for Oracle + run: | + for i in {1..15}; do + echo "Checking Oracle service..." + if echo "SELECT 1 FROM dual;" | sqlplus system/oracle@127.0.0.1:1521/FREEPDB1 &>/dev/null; then + echo "Oracle ready!" + break + fi + sleep 5 + done - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} From bdd5a9dd49d9c330364fa8e288a385bfac722064 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:42:13 -0700 Subject: [PATCH 12/22] Update the password --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 16cb8dcd1..7d4b18656 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,7 +252,7 @@ jobs: runs-on: ubuntu-latest env: TORTOISE_TEST_MODULES: tests.testmodels - TORTOISE_ORACLE_PASS: 123456 + TORTOISE_ORACLE_PASS: oracle TORTOISE_ORACLE_DRIVER: OracleODBC strategy: matrix: From 2a08857ebf4371dd39c73e5e1e4bee607cb90a29 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:51:20 -0700 Subject: [PATCH 13/22] Update the user --- .github/workflows/ci.yml | 4 +++- Makefile | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d4b18656..faca9add5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -252,6 +252,8 @@ jobs: runs-on: ubuntu-latest env: TORTOISE_TEST_MODULES: tests.testmodels + TORTOISE_ORACLE_DB: FREEPDB1 + TORTOISE_ORACLE_USER: test TORTOISE_ORACLE_PASS: oracle TORTOISE_ORACLE_DRIVER: OracleODBC strategy: @@ -265,7 +267,7 @@ jobs: sudo apt-get install -y unixodbc unixodbc-dev libaio1t64 - uses: gvenzl/setup-oracle-free@v1 with: - app-user: test_db + app-user: ${{ env.TORTOISE_ORACLE_USER }} app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Locate Oracle ODBC driver diff --git a/Makefile b/Makefile index 57e239cd3..cd9b9577f 100644 --- a/Makefile +++ b/Makefile @@ -86,7 +86,7 @@ test_mssql: $(py_warn) TORTOISE_TEST_DB="mssql://sa:$(TORTOISE_MSSQL_PASS)@127.0.0.1:1433/test_\{\}?driver=$(TORTOISE_MSSQL_DRIVER)&TrustServerCertificate=YES" uv run --frozen pytest $(pytest_opts) --cov-report= test_oracle: - $(py_warn) TORTOISE_TEST_DB="oracle://SYSTEM:$(TORTOISE_ORACLE_PASS)@127.0.0.1:1521/FREEPDB1?driver=$(TORTOISE_ORACLE_DRIVER)" uv run --frozen pytest $(pytest_opts) --cov-report= + $(py_warn) TORTOISE_TEST_DB="oracle://$(TORTOISE_ORACLE_USER):$(TORTOISE_ORACLE_PASS)@127.0.0.1:1521/$(TORTOISE_ORACLE_DB)?driver=$(TORTOISE_ORACLE_DRIVER)" uv run --frozen pytest $(pytest_opts) --cov-report= _testall: test_sqlite test_postgres_asyncpg test_postgres_psycopg test_mysql_myisam test_mysql test_mysql_asyncmy test_mssql From a8ffc09a66a38b23ed482a4b4c697609a6201fad Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 00:54:30 -0700 Subject: [PATCH 14/22] Update the user --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index faca9add5..7e3446f11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -290,13 +290,13 @@ jobs: echo "[OracleDB]" | sudo tee /etc/odbc.ini echo "Driver=OracleODBC" | sudo tee -a /etc/odbc.ini echo "ServerName=127.0.0.1:1521/FREEPDB1" | sudo tee -a /etc/odbc.ini - echo "User=system" | sudo tee -a /etc/odbc.ini - echo "Password=oracle" | sudo tee -a /etc/odbc.ini + echo "User=${TORTOISE_ORACLE_USER}" | sudo tee -a /etc/odbc.ini + echo "Password=${TORTOISE_ORACLE_PASS}" | sudo tee -a /etc/odbc.ini - name: Wait for Oracle run: | for i in {1..15}; do echo "Checking Oracle service..." - if echo "SELECT 1 FROM dual;" | sqlplus system/oracle@127.0.0.1:1521/FREEPDB1 &>/dev/null; then + if echo "SELECT 1 FROM dual;" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} &>/dev/null; then echo "Oracle ready!" break fi From 4e54750eec8eeb3a01596cf5b7c6dbf2f60b9453 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 01:04:27 -0700 Subject: [PATCH 15/22] Use SYSTEM user --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7e3446f11..4f982a40d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -253,7 +253,7 @@ jobs: env: TORTOISE_TEST_MODULES: tests.testmodels TORTOISE_ORACLE_DB: FREEPDB1 - TORTOISE_ORACLE_USER: test + TORTOISE_ORACLE_USER: SYSTEM TORTOISE_ORACLE_PASS: oracle TORTOISE_ORACLE_DRIVER: OracleODBC strategy: @@ -267,8 +267,8 @@ jobs: sudo apt-get install -y unixodbc unixodbc-dev libaio1t64 - uses: gvenzl/setup-oracle-free@v1 with: - app-user: ${{ env.TORTOISE_ORACLE_USER }} - app-user-password: ${{ env.TORTOISE_ORACLE_PASS }} + app-user: appuser + app-user-password: 123456 - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Locate Oracle ODBC driver run: | From 03ce794140322906876902aa76ff45a76c3b17d6 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 01:12:56 -0700 Subject: [PATCH 16/22] Trigger CI From d8c6467e737d5d0b9ea7bd4462b372ea55f10c2b Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 01:20:36 -0700 Subject: [PATCH 17/22] Update oracle password --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4f982a40d..3ba1e84fa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -269,6 +269,7 @@ jobs: with: app-user: appuser app-user-password: 123456 + oracle-password: ${{ env.TORTOISE_ORACLE_PASS }} - uses: iamazeem/setup-oracle-instant-client-action@v2 - name: Locate Oracle ODBC driver run: | From 54fb0acdd4bb46782af5348f7bed8bf92d9b809f Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 01:37:33 -0700 Subject: [PATCH 18/22] Delete FREEPDB1 user --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ba1e84fa..8891cb05c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,6 +303,12 @@ jobs: fi sleep 5 done + - name: Delete the user with the DB name + run: | + sqlplus -S ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} as sysdba < Date: Thu, 19 Mar 2026 01:41:43 -0700 Subject: [PATCH 19/22] Delete FREEPDB1 user --- .github/workflows/ci.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8891cb05c..1d1d76f65 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,10 +305,7 @@ jobs: done - name: Delete the user with the DB name run: | - sqlplus -S ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} as sysdba < Date: Thu, 19 Mar 2026 01:42:13 -0700 Subject: [PATCH 20/22] Delete FREEPDB1 user --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d1d76f65..0c64c2784 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,7 +305,7 @@ jobs: done - name: Delete the user with the DB name run: | - echo "DROP USER ${TORTOISE_ORACLE_DB} CASCADE;" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} < Date: Thu, 19 Mar 2026 02:02:30 -0700 Subject: [PATCH 21/22] Delete FREEPDB1 role --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0c64c2784..cab3e66f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -303,9 +303,9 @@ jobs: fi sleep 5 done - - name: Delete the user with the DB name + - name: Delete the role with the DB name run: | - echo "DROP USER ${TORTOISE_ORACLE_DB} CASCADE;" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} + echo "EXECUTE IMMEDIATE 'DROP ROLE ${TORTOISE_ORACLE_DB}';" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} From fc547c2807dbd0525b992bdcdaef2dfcc9a63799 Mon Sep 17 00:00:00 2001 From: seladb Date: Thu, 19 Mar 2026 22:43:03 -0700 Subject: [PATCH 22/22] Fix the delete role command --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cab3e66f6..1bc06f50d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -305,7 +305,7 @@ jobs: done - name: Delete the role with the DB name run: | - echo "EXECUTE IMMEDIATE 'DROP ROLE ${TORTOISE_ORACLE_DB}';" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} + echo -e "WHENEVER SQLERROR EXIT SQL.SQLCODE\nBEGIN EXECUTE IMMEDIATE 'DROP ROLE ${TORTOISE_ORACLE_DB}'; END;\n/" | sqlplus ${TORTOISE_ORACLE_USER}/${TORTOISE_ORACLE_PASS}@127.0.0.1:1521/${TORTOISE_ORACLE_DB} - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }}