From 4576b5b8aa58aa05183903363eeaf35c533dd8a7 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 16:27:31 +0900 Subject: [PATCH 01/23] Bump Oracle to Free 23 (23.26.1) and Instant Client to 23.26.1.0.0 - Replace gvenzl/oracle-xe with gvenzl/oracle-free (Oracle Free is the successor to Oracle XE) - Upgrade Instant Client from 21.x to 23.26.1.0.0, installed from download.oracle.com zip archives - Update ORACLE_HOME and LD_LIBRARY_PATH to /opt/oracle/instantclient_23_26 - Add ORACLE_HOME/LD_LIBRARY_PATH to the RuboCop workflow for the Oracle 23 client - Change DATABASE_NAME from XEPDB1 to FREEPDB1 - Update JDBC driver to version 233 - Switch runs-on from deprecated ubuntu-20.04 to ubuntu-latest - Create libaio.so.1 compat symlink since Ubuntu 24.04 only ships libaio.so.1t64 but Oracle 23 Instant Client links against libaio.so.1 - Drop hardcoded DATABASE_VERSION env var; the database version spec now asserts the structural shape (Array of four Integers) instead of comparing against a manually maintained version string Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/rubocop.yml | 17 +++++++++-------- .github/workflows/test.yml | 34 +++++++++++++++++----------------- ci/network/admin/tnsnames.ora | 4 ++-- spec/plsql/connection_spec.rb | 6 ++++-- spec/spec_helper.rb | 9 --------- 5 files changed, 32 insertions(+), 38 deletions(-) diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index e37e39b8..8f870b8c 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -10,6 +10,9 @@ jobs: build: runs-on: ubuntu-latest + env: + ORACLE_HOME: /opt/oracle/instantclient_23_26 + LD_LIBRARY_PATH: /opt/oracle/instantclient_23_26 steps: - uses: actions/checkout@v4 @@ -17,19 +20,17 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: "3.1" - - name: Install required package + - name: Create symbolic link for libaio library compatibility run: | - sudo apt-get install alien + sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 - name: Download Oracle instant client run: | - wget -q https://download.oracle.com/otn_software/linux/instantclient/216000/oracle-instantclient-basic-21.6.0.0.0-1.x86_64.rpm - wget -q https://download.oracle.com/otn_software/linux/instantclient/216000/oracle-instantclient-sqlplus-21.6.0.0.0-1.x86_64.rpm - wget -q https://download.oracle.com/otn_software/linux/instantclient/216000/oracle-instantclient-devel-21.6.0.0.0-1.x86_64.rpm + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-basic-linux.x64-23.26.1.0.0.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-sdk-linux.x64-23.26.1.0.0.zip - name: Install Oracle instant client run: | - sudo alien -i oracle-instantclient-basic-21.6.0.0.0-1.x86_64.rpm - sudo alien -i oracle-instantclient-sqlplus-21.6.0.0.0-1.x86_64.rpm - sudo alien -i oracle-instantclient-devel-21.6.0.0.0-1.x86_64.rpm + sudo unzip -q instantclient-basic-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + sudo unzip -qo instantclient-sdk-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ - name: Build and run RuboCop run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0c1b393d..a0eb078a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest continue-on-error: true strategy: matrix: @@ -24,18 +24,17 @@ jobs: truffleruby-head ] env: - ORACLE_HOME: /usr/lib/oracle/21/client64 - LD_LIBRARY_PATH: /usr/lib/oracle/21/client64/lib + ORACLE_HOME: /opt/oracle/instantclient_23_26 + LD_LIBRARY_PATH: /opt/oracle/instantclient_23_26 NLS_LANG: AMERICAN_AMERICA.AL32UTF8 TNS_ADMIN: ./ci/network/admin - DATABASE_NAME: XEPDB1 + DATABASE_NAME: FREEPDB1 TZ: Europe/Riga DATABASE_SYS_PASSWORD: Oracle18 - DATABASE_VERSION: 21.3.0.0 services: oracle: - image: gvenzl/oracle-xe:latest + image: gvenzl/oracle-free:latest ports: - 1521:1521 env: @@ -53,22 +52,23 @@ jobs: uses: ruby/setup-ruby@v1 with: ruby-version: ${{ matrix.ruby }} - - name: Install required package + - name: Create symbolic link for libaio library compatibility run: | - sudo apt-get install alien - - name: Download Oracle client + sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 + - name: Download Oracle instant client run: | - wget -q https://download.oracle.com/otn_software/linux/instantclient/2110000/oracle-instantclient-basic-21.10.0.0.0-1.x86_64.rpm - wget -q https://download.oracle.com/otn_software/linux/instantclient/2110000/oracle-instantclient-sqlplus-21.10.0.0.0-1.x86_64.rpm - wget -q https://download.oracle.com/otn_software/linux/instantclient/2110000/oracle-instantclient-devel-21.10.0.0.0-1.x86_64.rpm - - name: Install Oracle client + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-basic-linux.x64-23.26.1.0.0.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-sdk-linux.x64-23.26.1.0.0.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-sqlplus-linux.x64-23.26.1.0.0.zip + - name: Install Oracle instant client run: | - sudo alien -i oracle-instantclient-basic-21.10.0.0.0-1.x86_64.rpm - sudo alien -i oracle-instantclient-sqlplus-21.10.0.0.0-1.x86_64.rpm - sudo alien -i oracle-instantclient-devel-21.10.0.0.0-1.x86_64.rpm + sudo unzip -q instantclient-basic-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + sudo unzip -qo instantclient-sdk-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + sudo unzip -qo instantclient-sqlplus-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + echo "/opt/oracle/instantclient_23_26" >> $GITHUB_PATH - name: Install JDBC Driver run: | - wget -q https://download.oracle.com/otn-pub/otn_software/jdbc/211/ojdbc11.jar -O ./lib/ojdbc11.jar + wget -q https://download.oracle.com/otn-pub/otn_software/jdbc/233/ojdbc11.jar -O ./lib/ojdbc11.jar - name: Create database user run: | ./ci/setup_accounts.sh diff --git a/ci/network/admin/tnsnames.ora b/ci/network/admin/tnsnames.ora index 91cd300e..f8184d88 100644 --- a/ci/network/admin/tnsnames.ora +++ b/ci/network/admin/tnsnames.ora @@ -1,7 +1,7 @@ -XEPDB1 = +FREEPDB1 = (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) (CONNECT_DATA = - (SERVICE_NAME = XEPDB1) + (SERVICE_NAME = FREEPDB1) ) ) diff --git a/spec/plsql/connection_spec.rb b/spec/plsql/connection_spec.rb index 6386fa44..c580edbe 100644 --- a/spec/plsql/connection_spec.rb +++ b/spec/plsql/connection_spec.rb @@ -422,8 +422,10 @@ describe "session information" do it "should get database version" do - # using Oracle version 10.2.0.4 for unit tests - expect(@conn.database_version).to eq DATABASE_VERSION.split(".").map { |n| n.to_i } + version = @conn.database_version + expect(version).to be_an(Array) + expect(version.size).to eq(4) + expect(version).to all(be_a(Integer)) end it "should get session ID" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3da16b8f..88920c7f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -44,19 +44,10 @@ [ENV["DATABASE_USER"] || "hr", ENV["DATABASE_PASSWORD"] || "hr"], [ENV["DATABASE_USER2"] || "arunit", ENV["DATABASE_PASSWORD2"] || "arunit"] ] -# specify which database version is used (will be verified in one test) -DATABASE_VERSION = ENV["DATABASE_VERSION"] || "10.2.0.4" - if ENV["USE_VM_DATABASE"] == "Y" RSpec.configure do |config| config.before(:suite) do TestDb.build - - # Set Verbose off to hide warning: already initialized constant DATABASE_VERSION - original_verbosity = $VERBOSE - $VERBOSE = nil - DATABASE_VERSION = TestDb.database_version - $VERBOSE = original_verbosity end end end From e8d00169400a419c623a8fe65ce9453388ab2a46 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 19:44:48 +0900 Subject: [PATCH 02/23] Fix Oracle 23c compatibility for BOOLEAN type Oracle 23c reports BOOLEAN parameters as "BOOLEAN" in ALL_ARGUMENTS instead of "PL/SQL BOOLEAN". This reflects Oracle AI Database's new ISO SQL standard-compliant BOOLEAN data type, which stores TRUE and FALSE values in tables and allows BOOLEAN expressions in SQL statements. See "BOOLEAN Data Type" in the Oracle AI Database 26 New Features documentation: https://docs.oracle.com/en/database/oracle/oracle-database/26/nfcoa/appdev_sql.html Normalize the data_type when reading argument metadata so all downstream boolean handling (parameter binding, overload resolution) continues to work. Oracle 23c also reports BOOLEAN as "BOOLEAN" in ALL_PLSQL_TYPE_ATTRS (record fields) and ALL_PLSQL_COLL_TYPES / ALL_COLL_TYPES (collection elements), so normalize the same way in get_field_definitions and get_element_definition. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/plsql/procedure.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index 885ea0bc..e5c1697e 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -126,6 +126,9 @@ def get_argument_metadata_below_18c #:nodoc: data_type, in_out, data_length, data_precision, data_scale, char_used, char_length, type_owner, type_name, type_subname, defaulted = r + # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN" + data_type = "PL/SQL BOOLEAN" if data_type == "BOOLEAN" + @overloaded ||= !overload.nil? # if not overloaded then store arguments at key 0 overload ||= 0 @@ -235,6 +238,9 @@ def get_argument_metadata_from_18c #:nodoc: data_type, in_out, data_length, data_precision, data_scale, char_used, char_length, type_owner, type_name, type_package, type_object_type, defaulted = r + # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN" + data_type = "PL/SQL BOOLEAN" if data_type == "BOOLEAN" + @overloaded ||= !overload.nil? # if not overloaded then store arguments at key 0 overload ||= 0 @@ -359,6 +365,9 @@ def get_field_definitions(argument_metadata) #:nodoc: attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r + # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN" + attr_type_name = "PL/SQL BOOLEAN" if attr_type_name == "BOOLEAN" + fields[attr_name.downcase.to_sym] = { position: attr_no.to_i, data_type: attr_type_owner == nil ? attr_type_name : get_composite_type(attr_type_owner, attr_type_name, attr_type_package), @@ -421,6 +430,9 @@ def get_element_definition(argument_metadata) #:nodoc: elem_type_owner, elem_type_name, elem_type_package, elem_length, elem_precision, elem_scale, elem_char_used, index_by = r + # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN" + elem_type_name = "PL/SQL BOOLEAN" if elem_type_name == "BOOLEAN" + if index_by == "VARCHAR2" raise ArgumentError, "Index-by Varchar-Table (associative array) #{argument_metadata[:type_name]} is not supported" end @@ -458,6 +470,9 @@ def get_element_definition(argument_metadata) #:nodoc: ) elem_type_owner, elem_type_name, elem_length, elem_precision, elem_scale, elem_char_used = r + # Oracle 23c reports BOOLEAN as "BOOLEAN" instead of "PL/SQL BOOLEAN" + elem_type_name = "PL/SQL BOOLEAN" if elem_type_name == "BOOLEAN" + element_metadata = { position: 1, data_type: elem_type_owner == nil ? elem_type_name : "OBJECT", From 43739b0d61ebed02d1eb523f4f66b45d70de07c9 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 19:44:53 +0900 Subject: [PATCH 03/23] Update ORA-00942 test regex for Oracle 23c Oracle 23c now embeds the schema-qualified object name in the ORA-00942 error message ("table or view "SCHEMA"."TABLE" does not exist") instead of the legacy "table or view does not exist" text. Update the test regex to match both formats. The new template is documented on the Oracle Error Help portal entry for the 23ai variant: https://docs.oracle.com/en/error-help/db/ora-00942/?r=23ai Co-Authored-By: Claude Opus 4.6 (1M context) --- spec/plsql/connection_spec.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/spec/plsql/connection_spec.rb b/spec/plsql/connection_spec.rb index c580edbe..24213e64 100644 --- a/spec/plsql/connection_spec.rb +++ b/spec/plsql/connection_spec.rb @@ -443,7 +443,9 @@ @conn.exec "CREATE GLOBAL TEMPORARY TABLE #{tmp_table} (dummy CHAR(1))" expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.not_to raise_error @conn.drop_all_ruby_temporary_tables - expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view does not exist/) + # ORA-00942 message in Oracle 23c includes schema and table name: + # 'table or view "SCHEMA"."TABLE" does not exist' + expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view.*does not exist/) end it "should drop current session ruby temporary tables" do @@ -451,7 +453,8 @@ @conn.exec "CREATE GLOBAL TEMPORARY TABLE #{tmp_table} (dummy CHAR(1))" expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.not_to raise_error @conn.drop_session_ruby_temporary_tables - expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view does not exist/) + # ORA-00942 message in Oracle 23c includes schema and table name + expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view.*does not exist/) end it "should not drop other session ruby temporary tables" do @@ -485,7 +488,8 @@ def reconnect_connection expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.not_to raise_error @conn.logoff reconnect_connection - expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view does not exist/) + # ORA-00942 message in Oracle 23c includes schema and table name + expect { @conn.select_first("SELECT * FROM #{tmp_table}") }.to raise_error(/table or view.*does not exist/) end it "should rollback any uncommited transactions" do From 8c5045dab837b0f55222a7826713fd008b47959c Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 00:18:27 +0900 Subject: [PATCH 04/23] Add Ruby 3.3, 3.4 and 4.0 to CI test matrix Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a0eb078a..6cc9b218 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,9 @@ jobs: strategy: matrix: ruby: [ + '4.0', + '3.4', + '3.3', '3.2', '3.1', '3.0', From 32654f80ba398093b9460a68638d4e22c7850735 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 00:20:03 +0900 Subject: [PATCH 05/23] Bump Ruby version in RuboCop workflow to 4.0 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/rubocop.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 8f870b8c..1cfdca92 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -16,10 +16,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Ruby 3.1 + - name: Set up Ruby 4.0 uses: ruby/setup-ruby@v1 with: - ruby-version: "3.1" + ruby-version: "4.0" - name: Create symbolic link for libaio library compatibility run: | sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 From 30fc3d071ccf66cdb6e533072c6c21c0aeffa4aa Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 00:22:19 +0900 Subject: [PATCH 06/23] Add CI workflow for Oracle Database 11g Uses gvenzl/oracle-xe:11 container with Oracle Instant Client 21.15 (the latest client that supports Oracle 11g). Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test_11g.yml | 88 ++++++++++++++++++++++++++++++++++ ci/network/admin/tnsnames.ora | 8 ++++ 2 files changed, 96 insertions(+) create mode 100644 .github/workflows/test_11g.yml diff --git a/.github/workflows/test_11g.yml b/.github/workflows/test_11g.yml new file mode 100644 index 00000000..13557a89 --- /dev/null +++ b/.github/workflows/test_11g.yml @@ -0,0 +1,88 @@ +name: test_11g + +on: + push: + pull_request: + +jobs: + build: + + runs-on: ubuntu-latest + continue-on-error: true + strategy: + matrix: + ruby: [ + '4.0', + '3.4', + '3.3', + '3.2', + '3.1', + '3.0', + '2.7', + '2.6', + '2.5', + ruby-head, + ruby-debug, + truffleruby, + truffleruby-head + ] + env: + ORACLE_HOME: /opt/oracle/instantclient_21_15 + LD_LIBRARY_PATH: /opt/oracle/instantclient_21_15 + NLS_LANG: AMERICAN_AMERICA.AL32UTF8 + TNS_ADMIN: ./ci/network/admin + DATABASE_NAME: XE + TZ: Europe/Riga + DATABASE_SYS_PASSWORD: Oracle18 + + services: + oracle: + image: gvenzl/oracle-xe:11 + ports: + - 1521:1521 + env: + TZ: Europe/Riga + ORACLE_PASSWORD: Oracle18 + options: >- + --health-cmd healthcheck.sh + --health-interval 10s + --health-timeout 5s + --health-retries 10 + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + - name: Create symbolic link for libaio library compatibility + run: | + sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 + - name: Download Oracle instant client + run: | + wget -q https://download.oracle.com/otn_software/linux/instantclient/2115000/instantclient-basic-linux.x64-21.15.0.0.0dbru.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2115000/instantclient-sqlplus-linux.x64-21.15.0.0.0dbru.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2115000/instantclient-sdk-linux.x64-21.15.0.0.0dbru.zip + - name: Install Oracle instant client + run: | + sudo mkdir -p /opt/oracle/ + sudo unzip -q instantclient-basic-linux.x64-21.15.0.0.0dbru.zip -d /opt/oracle + sudo unzip -qo instantclient-sqlplus-linux.x64-21.15.0.0.0dbru.zip -d /opt/oracle + sudo unzip -qo instantclient-sdk-linux.x64-21.15.0.0.0dbru.zip -d /opt/oracle + echo "/opt/oracle/instantclient_21_15" >> $GITHUB_PATH + - name: Install JDBC Driver + run: | + wget -q https://download.oracle.com/otn-pub/otn_software/jdbc/233/ojdbc11.jar -O ./lib/ojdbc11.jar + - name: Create database user + run: | + ./ci/setup_accounts.sh + - name: Disable ActiveRecord for TruffleRuby + run: | + echo "NO_ACTIVERECORD=true" >> $GITHUB_ENV + if: "contains(matrix.ruby, 'truffleruby')" + - name: Bundle install + run: | + bundle install --jobs 4 --retry 3 + - name: Run RSpec + run: | + bundle exec rspec diff --git a/ci/network/admin/tnsnames.ora b/ci/network/admin/tnsnames.ora index f8184d88..d1ba8183 100644 --- a/ci/network/admin/tnsnames.ora +++ b/ci/network/admin/tnsnames.ora @@ -5,3 +5,11 @@ FREEPDB1 = (SERVICE_NAME = FREEPDB1) ) ) + +XE = + (DESCRIPTION = + (ADDRESS = (PROTOCOL = TCP)(HOST = 127.0.0.1)(PORT = 1521)) + (CONNECT_DATA = + (SERVICE_NAME = XE) + ) + ) From 5d0515de903e1ca55b83d783382a53c7807a7835 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 00:24:12 +0900 Subject: [PATCH 07/23] Bump activerecord and oracle_enhanced adapter to 8.0 Co-Authored-By: Claude Opus 4.6 (1M context) --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index f242676e..6f31d6dc 100644 --- a/Gemfile +++ b/Gemfile @@ -13,8 +13,8 @@ group :test, :development do gem "rspec", "~> 3.1" unless ENV["NO_ACTIVERECORD"] - gem "activerecord", "~> 5.0" - gem "activerecord-oracle_enhanced-adapter", "~> 1.7" + gem "activerecord", "~> 8.0" + gem "activerecord-oracle_enhanced-adapter", "~> 8.0" gem "simplecov", ">= 0" end From 6e5593f32d2ffc6bf956a17bc0656b8fd471be95 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 10:11:13 +0900 Subject: [PATCH 08/23] Remove Ruby 2.5-3.1 from CI test matrices Drop Ruby 3.1, 3.0, 2.7, 2.6, and 2.5 from test.yml and test_11g.yml. Older Ruby versions are exercised by the per-Rails gemfile matrix in test_gemfiles.yml; the modern test.yml / test_11g.yml workflows only need to run against Ruby that is compatible with the latest Rails and oracle_enhanced adapter. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test.yml | 5 ----- .github/workflows/test_11g.yml | 5 ----- 2 files changed, 10 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6cc9b218..0ab0ff9e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -16,11 +16,6 @@ jobs: '3.4', '3.3', '3.2', - '3.1', - '3.0', - '2.7', - '2.6', - '2.5', ruby-head, ruby-debug, truffleruby, diff --git a/.github/workflows/test_11g.yml b/.github/workflows/test_11g.yml index 13557a89..4c13d6ed 100644 --- a/.github/workflows/test_11g.yml +++ b/.github/workflows/test_11g.yml @@ -16,11 +16,6 @@ jobs: '3.4', '3.3', '3.2', - '3.1', - '3.0', - '2.7', - '2.6', - '2.5', ruby-head, ruby-debug, truffleruby, From ee3a310cb0c6b014a64c42463b66c32dbf412a17 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 00:31:27 +0900 Subject: [PATCH 09/23] Bump RuboCop to latest and autocorrect offenses Remove version pin on rubocop gem. Update .rubocop.yml for renamed cops (Layout/Tab -> Layout/IndentationStyle) and lower TargetRubyVersion to 2.4 to match the minimum Ruby exercised by the per-Rails gemfile matrix in test_gemfiles.yml. Autocorrect all 66 Layout/LeadingCommentSpace and Layout/SpaceAroundOperators offenses. Co-Authored-By: Claude Opus 4.6 (1M context) --- .rubocop.yml | 12 ++++++------ Gemfile | 2 +- lib/plsql/connection.rb | 28 ++++++++++++++-------------- lib/plsql/helpers.rb | 6 +++--- lib/plsql/jdbc_connection.rb | 6 +++--- lib/plsql/oci_connection.rb | 4 ++-- lib/plsql/package.rb | 4 ++-- lib/plsql/procedure.rb | 30 +++++++++++++++--------------- lib/plsql/procedure_call.rb | 2 +- lib/plsql/schema.rb | 12 ++++++------ lib/plsql/sequence.rb | 4 ++-- lib/plsql/table.rb | 8 ++++---- lib/plsql/type.rb | 14 +++++++------- lib/plsql/variable.rb | 8 ++++---- lib/plsql/version.rb | 2 +- lib/plsql/view.rb | 4 ++-- 16 files changed, 73 insertions(+), 73 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 03fed3f7..547fb3d1 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,8 +1,9 @@ -# rubocop 0.51.0 requires Ruby 2.1 -# We should not use cops only available for Ruby 2.1 or later -# since ruby-plsql itself supports Ruby 1.9.3 AllCops: - TargetRubyVersion: 2.3 + # Match the minimum Ruby exercised by the per-Rails matrix in + # .github/workflows/test_gemfiles.yml (AR 5.0-5.2 jobs run on Ruby 2.4) + # so RuboCop does not permit syntax/stdlib usage that would break + # those supported runtimes. + TargetRubyVersion: 2.4 DisabledByDefault: true # Prefer &&/|| over and/or. @@ -112,7 +113,7 @@ Style/StringLiterals: EnforcedStyle: double_quotes # Detect hard tabs, no hard tabs. -Layout/Tab: +Layout/IndentationStyle: Enabled: true # Blank lines should not have any spaces. @@ -132,7 +133,6 @@ Style/RedundantPercentQ: Layout/EndAlignment: Enabled: true EnforcedStyleAlignWith: variable - AutoCorrect: true # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg. Lint/RequireParentheses: diff --git a/Gemfile b/Gemfile index 6f31d6dc..9265aba8 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source "http://rubygems.org" group :development do gem "juwelier", "~> 2.0" gem "rspec_junit_formatter" - gem "rubocop", "0.81", require: false + gem "rubocop", require: false gem "rubocop-performance", require: false gem "rubocop-rails", require: false end diff --git a/lib/plsql/connection.rb b/lib/plsql/connection.rb index 39ec3507..2f41190e 100644 --- a/lib/plsql/connection.rb +++ b/lib/plsql/connection.rb @@ -3,13 +3,13 @@ class Connection attr_reader :raw_driver attr_reader :activerecord_class - def initialize(raw_conn, ar_class = nil) #:nodoc: + def initialize(raw_conn, ar_class = nil) # :nodoc: @raw_driver = self.class.driver_type @raw_connection = raw_conn @activerecord_class = ar_class end - def self.create(raw_conn, ar_class = nil) #:nodoc: + def self.create(raw_conn, ar_class = nil) # :nodoc: if ar_class && !(defined?(::ActiveRecord) && ar_class.ancestors.include?(::ActiveRecord::Base)) raise ArgumentError, "Wrong ActiveRecord class" end @@ -23,7 +23,7 @@ def self.create(raw_conn, ar_class = nil) #:nodoc: end end - def self.create_new(params) #:nodoc: + def self.create_new(params) # :nodoc: conn = case driver_type when :oci OCIConnection.create_raw(params) @@ -36,7 +36,7 @@ def self.create_new(params) #:nodoc: conn end - def self.driver_type #:nodoc: + def self.driver_type # :nodoc: # MRI 1.8.6 or YARV 1.9.1 or TruffleRuby @driver_type ||= if (!defined?(RUBY_ENGINE) || RUBY_ENGINE == "ruby" || RUBY_ENGINE == "truffleruby") && defined?(OCI8) :oci @@ -67,18 +67,18 @@ def jdbc? @raw_driver == :jdbc end - def logoff #:nodoc: + def logoff # :nodoc: # Rollback any uncommited transactions rollback # Common cleanup activities before logoff, should be called from particular driver method drop_session_ruby_temporary_tables end - def commit #:nodoc: + def commit # :nodoc: raise NoMethodError, "Not implemented for this raw driver" end - def rollback #:nodoc: + def rollback # :nodoc: raise NoMethodError, "Not implemented for this raw driver" end @@ -98,21 +98,21 @@ def prefetch_rows=(value) raise NoMethodError, "Not implemented for this raw driver" end - def select_first(sql, *bindvars) #:nodoc: + def select_first(sql, *bindvars) # :nodoc: cursor = cursor_from_query(sql, bindvars, prefetch_rows: 1) cursor.fetch ensure cursor.close rescue nil end - def select_hash_first(sql, *bindvars) #:nodoc: + def select_hash_first(sql, *bindvars) # :nodoc: cursor = cursor_from_query(sql, bindvars, prefetch_rows: 1) cursor.fetch_hash ensure cursor.close rescue nil end - def select_all(sql, *bindvars, &block) #:nodoc: + def select_all(sql, *bindvars, &block) # :nodoc: cursor = cursor_from_query(sql, bindvars) results = [] row_count = 0 @@ -129,7 +129,7 @@ def select_all(sql, *bindvars, &block) #:nodoc: cursor.close rescue nil end - def select_hash_all(sql, *bindvars, &block) #:nodoc: + def select_hash_all(sql, *bindvars, &block) # :nodoc: cursor = cursor_from_query(sql, bindvars) results = [] row_count = 0 @@ -146,11 +146,11 @@ def select_hash_all(sql, *bindvars, &block) #:nodoc: cursor.close rescue nil end - def exec(sql, *bindvars) #:nodoc: + def exec(sql, *bindvars) # :nodoc: raise NoMethodError, "Not implemented for this raw driver" end - def parse(sql) #:nodoc: + def parse(sql) # :nodoc: raise NoMethodError, "Not implemented for this raw driver" end @@ -181,7 +181,7 @@ def fetch_hash # all_synonyms view is quite slow therefore # this implementation is overriden in OCI connection with faster native OCI method - def describe_synonym(schema_name, synonym_name) #:nodoc: + def describe_synonym(schema_name, synonym_name) # :nodoc: select_first( "SELECT table_owner, table_name FROM all_synonyms WHERE owner = :owner AND synonym_name = :synonym_name", schema_name.to_s.upcase, synonym_name.to_s.upcase) diff --git a/lib/plsql/helpers.rb b/lib/plsql/helpers.rb index b144585d..86c83c83 100644 --- a/lib/plsql/helpers.rb +++ b/lib/plsql/helpers.rb @@ -1,6 +1,6 @@ -module PLSQL #:nodoc: - module ArrayHelpers #:nodoc: - def self.to_hash(keys, values) #:nodoc: +module PLSQL # :nodoc: + module ArrayHelpers # :nodoc: + def self.to_hash(keys, values) # :nodoc: (0...keys.size).inject({}) { |hash, i| hash[keys[i]] = values[i]; hash } end end diff --git a/lib/plsql/jdbc_connection.rb b/lib/plsql/jdbc_connection.rb index 3b9e1278..9f479a80 100644 --- a/lib/plsql/jdbc_connection.rb +++ b/lib/plsql/jdbc_connection.rb @@ -46,7 +46,7 @@ end module PLSQL - class JDBCConnection < Connection #:nodoc: + class JDBCConnection < Connection # :nodoc: def self.create_raw(params) database = params[:database] url = if ENV["TNS_ADMIN"] && database && !params[:host] && !params[:url] @@ -98,7 +98,7 @@ def exec(sql, *bindvars) cs.close rescue nil end - class CallableStatement #:nodoc: + class CallableStatement # :nodoc: def initialize(conn, sql) @sql = sql @connection = conn @@ -145,7 +145,7 @@ def bind_param_index(key) end end - class Cursor #:nodoc: + class Cursor # :nodoc: include Connection::CursorCommon attr_reader :result_set diff --git a/lib/plsql/oci_connection.rb b/lib/plsql/oci_connection.rb index caf783e6..1739458b 100644 --- a/lib/plsql/oci_connection.rb +++ b/lib/plsql/oci_connection.rb @@ -24,7 +24,7 @@ end module PLSQL - class OCIConnection < Connection #:nodoc: + class OCIConnection < Connection # :nodoc: def self.create_raw(params) connection_string = if params[:host] "//#{params[:host]}:#{params[:port] || 1521}/#{params[:database]}" @@ -64,7 +64,7 @@ def exec(sql, *bindvars) true end - class Cursor #:nodoc: + class Cursor # :nodoc: include Connection::CursorCommon attr_reader :raw_cursor diff --git a/lib/plsql/package.rb b/lib/plsql/package.rb index 1cdd0f3f..a2004540 100644 --- a/lib/plsql/package.rb +++ b/lib/plsql/package.rb @@ -1,5 +1,5 @@ module PLSQL - module PackageClassMethods #:nodoc: + module PackageClassMethods # :nodoc: def find(schema, package) package_name = package.to_s.upcase find_in_schema(schema, package_name) || find_by_synonym(schema, package_name) @@ -32,7 +32,7 @@ def find_by_synonym(schema, package_name) end end - class Package #:nodoc: + class Package # :nodoc: extend PackageClassMethods def initialize(schema, package, override_schema_name = nil) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index e5c1697e..bc647c38 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -1,5 +1,5 @@ module PLSQL - module ProcedureClassMethods #:nodoc: + module ProcedureClassMethods # :nodoc: def find(schema, procedure, package = nil, override_schema_name = nil) if package.nil? if (row = schema.select_first( @@ -53,12 +53,12 @@ def procedure_object_id_src(schema) end end - module ProcedureCommon #:nodoc: + module ProcedureCommon # :nodoc: attr_reader :arguments, :argument_list, :out_list, :return attr_reader :schema, :schema_name, :package, :procedure # return type string from metadata that can be used in DECLARE block or table definition - def self.type_to_sql(metadata) #:nodoc: + def self.type_to_sql(metadata) # :nodoc: case metadata[:data_type] when "NUMBER" precision, scale = metadata[:data_precision], metadata[:data_scale] @@ -82,7 +82,7 @@ def self.type_to_sql(metadata) #:nodoc: end # get procedure argument metadata from data dictionary - def get_argument_metadata #:nodoc: + def get_argument_metadata # :nodoc: if (@schema.connection.database_version <=> [18, 0, 0, 0]) >= 0 get_argument_metadata_from_18c else @@ -90,7 +90,7 @@ def get_argument_metadata #:nodoc: end end - def get_argument_metadata_below_18c #:nodoc: + def get_argument_metadata_below_18c # :nodoc: @arguments = {} @argument_list = {} @out_list = {} @@ -209,7 +209,7 @@ def get_argument_metadata_below_18c #:nodoc: end # get procedure argument metadata from data dictionary - def get_argument_metadata_from_18c #:nodoc: + def get_argument_metadata_from_18c # :nodoc: @arguments = {} @argument_list = {} @out_list = {} @@ -304,7 +304,7 @@ def get_argument_metadata_from_18c #:nodoc: construct_argument_list_for_overloads end - def construct_argument_list_for_overloads #:nodoc: + def construct_argument_list_for_overloads # :nodoc: @overloads = @arguments.keys.sort @overloads.each do |overload| @argument_list[overload] = @arguments[overload].keys.sort { |k1, k2| @arguments[overload][k1][:position] <=> @arguments[overload][k2][:position] } @@ -312,7 +312,7 @@ def construct_argument_list_for_overloads #:nodoc: end end - def ensure_tmp_tables_created(overload) #:nodoc: + def ensure_tmp_tables_created(overload) # :nodoc: return if @tmp_tables_created.nil? || @tmp_tables_created[overload] @tmp_table_names[overload] && @tmp_table_names[overload].each do |table_name, argument_metadata| sql = "CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n" @@ -336,7 +336,7 @@ def ensure_tmp_tables_created(overload) #:nodoc: @tmp_tables_created[overload] = true end - def build_sql_type_name(type_owner, type_package, type_name) #:nodoc: + def build_sql_type_name(type_owner, type_package, type_name) # :nodoc: if type_owner == nil || type_owner == "PUBLIC" type_owner_res = "" else @@ -351,7 +351,7 @@ def build_sql_type_name(type_owner, type_package, type_name) #:nodoc: type_name_res && "#{type_owner_res}#{type_name_res}" end - def get_field_definitions(argument_metadata) #:nodoc: + def get_field_definitions(argument_metadata) # :nodoc: fields = {} case argument_metadata[:type_object_type] when "PACKAGE" @@ -417,7 +417,7 @@ def get_field_definitions(argument_metadata) #:nodoc: fields end - def get_element_definition(argument_metadata) #:nodoc: + def get_element_definition(argument_metadata) # :nodoc: element_metadata = {} if collection_type?(argument_metadata[:data_type]) case argument_metadata[:type_object_type] @@ -525,21 +525,21 @@ def get_composite_type(type_owner, type_name, type_package) end PLSQL_COMPOSITE_TYPES = ["PL/SQL RECORD", "PL/SQL TABLE", "TABLE", "VARRAY", "REF CURSOR"].freeze - def composite_type?(data_type) #:nodoc: + def composite_type?(data_type) # :nodoc: PLSQL_COMPOSITE_TYPES.include? data_type end PLSQL_COLLECTION_TYPES = ["PL/SQL TABLE", "TABLE", "VARRAY"].freeze - def collection_type?(data_type) #:nodoc: + def collection_type?(data_type) # :nodoc: PLSQL_COLLECTION_TYPES.include? data_type end - def overloaded? #:nodoc: + def overloaded? # :nodoc: @overloaded end end - class Procedure #:nodoc: + class Procedure # :nodoc: extend ProcedureClassMethods include ProcedureCommon diff --git a/lib/plsql/procedure_call.rb b/lib/plsql/procedure_call.rb index 014138df..017a699d 100644 --- a/lib/plsql/procedure_call.rb +++ b/lib/plsql/procedure_call.rb @@ -1,5 +1,5 @@ module PLSQL - class ProcedureCall #:nodoc: + class ProcedureCall # :nodoc: def initialize(procedure, args = [], options = {}) @procedure = procedure @schema = @procedure.schema diff --git a/lib/plsql/schema.rb b/lib/plsql/schema.rb index f6a5bf31..8ca6bca7 100644 --- a/lib/plsql/schema.rb +++ b/lib/plsql/schema.rb @@ -4,8 +4,8 @@ class Schema @@schemas = {} - class < Date: Sat, 11 Apr 2026 00:34:39 +0900 Subject: [PATCH 10/23] Use sqlplus from PATH instead of ORACLE_HOME/bin The zip-based Instant Client (test_11g) installs sqlplus directly in the install directory without a bin/ subdirectory. Use sqlplus from PATH which works for both RPM and zip installs. Co-Authored-By: Claude Opus 4.6 (1M context) --- ci/setup_accounts.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/setup_accounts.sh b/ci/setup_accounts.sh index 9af72166..17f03159 100755 --- a/ci/setup_accounts.sh +++ b/ci/setup_accounts.sh @@ -2,7 +2,7 @@ set -ev -${ORACLE_HOME}/bin/sqlplus system/${DATABASE_SYS_PASSWORD}@${DATABASE_NAME} < Date: Sat, 11 Apr 2026 01:10:43 +0900 Subject: [PATCH 11/23] Register oracle_enhanced adapter for ActiveRecord 8.0 in specs ActiveRecord 8.0 requires adapters to be explicitly registered. The oracle_enhanced adapter only auto-registers via Railtie when Rails is present. Register it manually in spec_helper.rb. Co-Authored-By: Claude Opus 4.6 (1M context) --- spec/spec_helper.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 88920c7f..a8934d81 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -20,6 +20,14 @@ unless ENV["NO_ACTIVERECORD"] require "active_record" + require "active_record/connection_adapters/oracle_enhanced_adapter" + if ActiveRecord::ConnectionAdapters.respond_to?(:register) + ActiveRecord::ConnectionAdapters.register( + "oracle_enhanced", + "ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter", + "active_record/connection_adapters/oracle_enhanced_adapter" + ) + end else puts "Without ActiveRecord" end From 7b6cfd7bbe63dbd6d1ea77ff2982f56b740700e9 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 01:11:45 +0900 Subject: [PATCH 12/23] Enable Ruby warnings in CI test runs Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test.yml | 2 +- .github/workflows/test_11g.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0ab0ff9e..28d5733b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,4 +79,4 @@ jobs: bundle install --jobs 4 --retry 3 - name: Run RSpec run: | - bundle exec rspec + RUBYOPT=-w bundle exec rspec diff --git a/.github/workflows/test_11g.yml b/.github/workflows/test_11g.yml index 4c13d6ed..3f170b3c 100644 --- a/.github/workflows/test_11g.yml +++ b/.github/workflows/test_11g.yml @@ -80,4 +80,4 @@ jobs: bundle install --jobs 4 --retry 3 - name: Run RSpec run: | - bundle exec rspec + RUBYOPT=-w bundle exec rspec From 4306dd380c5541eca1d2bdafa022ecc02ebb231f Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 11:05:46 +0900 Subject: [PATCH 13/23] Bump actions/checkout to v6 Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/rubocop.yml | 2 +- .github/workflows/test.yml | 2 +- .github/workflows/test_11g.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml index 1cfdca92..162de41d 100644 --- a/.github/workflows/rubocop.yml +++ b/.github/workflows/rubocop.yml @@ -15,7 +15,7 @@ jobs: LD_LIBRARY_PATH: /opt/oracle/instantclient_23_26 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby 4.0 uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 28d5733b..98e1e553 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -45,7 +45,7 @@ jobs: --health-retries 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: diff --git a/.github/workflows/test_11g.yml b/.github/workflows/test_11g.yml index 3f170b3c..38f9aae7 100644 --- a/.github/workflows/test_11g.yml +++ b/.github/workflows/test_11g.yml @@ -45,7 +45,7 @@ jobs: --health-retries 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: From 962a2b53f28528e4663a2c1f9b73cfda7b5c6cd2 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 11:06:44 +0900 Subject: [PATCH 14/23] Fix ActiveRecord 8.0 default_timezone API ActiveRecord 8.0 removed ActiveRecord::Base.default_timezone= in favor of ActiveRecord.default_timezone. Update both the library code and spec. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/plsql/schema.rb | 8 ++++++-- spec/plsql/schema_spec.rb | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/plsql/schema.rb b/lib/plsql/schema.rb index 8ca6bca7..43acfef7 100644 --- a/lib/plsql/schema.rb +++ b/lib/plsql/schema.rb @@ -99,8 +99,12 @@ def default_timezone @original_schema.default_timezone else @default_timezone || - # Use ActiveRecord class default_timezone when ActiveRecord connection is used - (@connection && (ar_class = @connection.activerecord_class) && ar_class.default_timezone) || + # Use ActiveRecord default_timezone when ActiveRecord connection is used, + # preferring the connection's activerecord_class so a subclass override + # (available in AR < 8.0) is honored before falling back to the + # module-level accessor (AR 7.0+; the only one in AR 8.0+). + (@connection && (ar_class = @connection.activerecord_class) && + (ar_class.respond_to?(:default_timezone) ? ar_class.default_timezone : ActiveRecord.default_timezone)) || # default to local timezone :local end diff --git a/spec/plsql/schema_spec.rb b/spec/plsql/schema_spec.rb index 7966529d..fc11dca7 100644 --- a/spec/plsql/schema_spec.rb +++ b/spec/plsql/schema_spec.rb @@ -209,8 +209,12 @@ class TestModel < TestBaseModel expect(plsql.schema_name).to eq("HR") end - it "should use ActiveRecord::Base.default_timezone as default" do - ActiveRecord::Base.default_timezone = :utc + it "should use ActiveRecord default_timezone as default" do + if ActiveRecord.respond_to?(:default_timezone=) + ActiveRecord.default_timezone = :utc + else + ActiveRecord::Base.default_timezone = :utc + end expect(plsql.default_timezone).to eq(:utc) end From e0dedbce5ddd4a129487454fcee6f97b3cac9fdd Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sun, 12 Apr 2026 11:06:51 +0900 Subject: [PATCH 15/23] Require "logger" before "active_record" in spec helper ActiveRecord 6.0 / 6.1 reference the top-level Logger constant at load time via ActiveSupport::LoggerThreadSafeLevel. If logger is not required before active_support is loaded, requiring active_record fails with: NameError: uninitialized constant ActiveSupport::LoggerThreadSafeLevel::Logger Explicitly require "logger" first so the older Rails rows in the per-Rails gemfile matrix (AR 6.0 / 6.1) can load the specs. Co-Authored-By: Claude Opus 4.6 (1M context) --- spec/spec_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a8934d81..5b33c327 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -19,6 +19,7 @@ require "rspec" unless ENV["NO_ACTIVERECORD"] + require "logger" require "active_record" require "active_record/connection_adapters/oracle_enhanced_adapter" if ActiveRecord::ConnectionAdapters.respond_to?(:register) From c0f133400e957aa2d8309d767a3309e78679f888 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 01:23:38 +0900 Subject: [PATCH 16/23] Fix frozen string literal warnings Use +\"\" for string literals that are mutated with << operator. This prepares for Ruby's future frozen string literal default. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/plsql/package.rb | 2 +- lib/plsql/procedure.rb | 2 +- lib/plsql/procedure_call.rb | 14 +++++++------- lib/plsql/schema.rb | 2 +- lib/plsql/table.rb | 4 ++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/plsql/package.rb b/lib/plsql/package.rb index a2004540..406f6451 100644 --- a/lib/plsql/package.rb +++ b/lib/plsql/package.rb @@ -56,7 +56,7 @@ def [](object_name) private def method_missing(method, *args, &block) - method = method.to_s + method = +method.to_s method.chop! if (assignment = method[/=$/]) case (object = self[method]) diff --git a/lib/plsql/procedure.rb b/lib/plsql/procedure.rb index bc647c38..a56fb8ab 100644 --- a/lib/plsql/procedure.rb +++ b/lib/plsql/procedure.rb @@ -315,7 +315,7 @@ def construct_argument_list_for_overloads # :nodoc: def ensure_tmp_tables_created(overload) # :nodoc: return if @tmp_tables_created.nil? || @tmp_tables_created[overload] @tmp_table_names[overload] && @tmp_table_names[overload].each do |table_name, argument_metadata| - sql = "CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n" + sql = +"CREATE GLOBAL TEMPORARY TABLE #{table_name} (\n" element_metadata = argument_metadata[:element] case element_metadata[:data_type] when "PL/SQL RECORD" diff --git a/lib/plsql/procedure_call.rb b/lib/plsql/procedure_call.rb index 017a699d..e7273ceb 100644 --- a/lib/plsql/procedure_call.rb +++ b/lib/plsql/procedure_call.rb @@ -149,10 +149,10 @@ def matching_oracle_types_for_ruby_value(value) end def construct_sql(args) - @declare_sql = "" - @assignment_sql = "" - @call_sql = "" - @return_sql = "" + @declare_sql = +"" + @assignment_sql = +"" + @call_sql = +"" + @return_sql = +"" @return_vars = [] @return_vars_metadata = {} @@ -218,7 +218,7 @@ def construct_sql(args) end add_out_variables - @sql = @declare_sql.empty? ? "" : "DECLARE\n" << @declare_sql + @sql = @declare_sql.empty? ? +"" : +"DECLARE\n" << @declare_sql @sql << "BEGIN\n" << @assignment_sql << dbms_output_enable_sql << @call_sql << @return_sql << "END;\n" end @@ -326,7 +326,7 @@ def add_record_declaration(argument, argument_metadata) "l_#{argument} #{argument_metadata[:sql_type_name]};\n" else fields_metadata = argument_metadata[:fields] - sql = "TYPE t_#{argument} IS RECORD (\n" + sql = +"TYPE t_#{argument} IS RECORD (\n" sql << record_fields_sorted_by_position(fields_metadata).map do |field| metadata = fields_metadata[field] "#{field} #{type_to_sql(metadata)}" @@ -341,7 +341,7 @@ def record_fields_sorted_by_position(fields_metadata) end def record_assignment_sql_values_metadata(argument, argument_metadata, record_value) - sql = "" + sql = +"" bind_values = {} bind_metadata = {} (record_value || {}).each do |key, value| diff --git a/lib/plsql/schema.rb b/lib/plsql/schema.rb index 43acfef7..4dfc1274 100644 --- a/lib/plsql/schema.rb +++ b/lib/plsql/schema.rb @@ -238,7 +238,7 @@ def find_database_object(name, override_schema_name = nil) end def _errors(object_schema_name, object_name, object_type) - result = "" + result = +"" previous_line = 0 select_all( "SELECT e.line, e.position, e.text error_text, s.text source_text diff --git a/lib/plsql/table.rb b/lib/plsql/table.rb index f72aee18..1deece3f 100644 --- a/lib/plsql/table.rb +++ b/lib/plsql/table.rb @@ -87,9 +87,9 @@ def column_names def select(first_or_all, sql_params = "", *bindvars) case first_or_all when :first, :all - select_sql = "SELECT * " + select_sql = +"SELECT * " when :count - select_sql = "SELECT COUNT(*) " + select_sql = +"SELECT COUNT(*) " else raise ArgumentError, "Only :first, :all or :count are supported" end From 160f8846d30c42a19a4984d74c3519872c8181e4 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 01:29:34 +0900 Subject: [PATCH 17/23] Fix Ruby warnings in specs - Wrap splat arguments in parentheses (ambiguous `*`) - Wrap regexp in parentheses for raise_error (ambiguous `/`) - Use .all.each instead of .all with block (block was ignored) Co-Authored-By: Claude Opus 4.6 (1M context) --- spec/plsql/procedure_spec.rb | 2 +- spec/plsql/schema_spec.rb | 2 +- spec/plsql/table_spec.rb | 6 +++--- spec/plsql/view_spec.rb | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/plsql/procedure_spec.rb b/spec/plsql/procedure_spec.rb index 82d877ff..943e5979 100644 --- a/spec/plsql/procedure_spec.rb +++ b/spec/plsql/procedure_spec.rb @@ -1966,7 +1966,7 @@ def new_candidate(status) @fields = [:col1, :col2 ] @rows = (1..3).map { |i| ["row #{i}", i] } - plsql.typed_ref_cursor_table.insert_values *@rows + plsql.typed_ref_cursor_table.insert_values(*@rows) plsql.commit end diff --git a/spec/plsql/schema_spec.rb b/spec/plsql/schema_spec.rb index fc11dca7..0662882b 100644 --- a/spec/plsql/schema_spec.rb +++ b/spec/plsql/schema_spec.rb @@ -304,7 +304,7 @@ class TestModel < TestBaseModel end it "should log output to specified stream in case of exception" do - expect { plsql.test_dbms_output("test_dbms_output", true) }.to raise_error /Test Error/ + expect { plsql.test_dbms_output("test_dbms_output", true) }.to raise_error(/Test Error/) expect(@buffer.string).to eq("DBMS_OUTPUT: test_dbms_output\n") end diff --git a/spec/plsql/table_spec.rb b/spec/plsql/table_spec.rb index 0a68fd3a..9e8c952a 100644 --- a/spec/plsql/table_spec.rb +++ b/spec/plsql/table_spec.rb @@ -239,7 +239,7 @@ end it "should insert many records with array of values" do - plsql.test_employees.insert_values *@employees_all_values + plsql.test_employees.insert_values(*@employees_all_values) expect(plsql.test_employees.all).to eq(@employees) end @@ -332,7 +332,7 @@ plsql.test_employees.update first_name: "Test", where: "employee_id = #{employee_id}" expect(plsql.test_employees.first(employee_id: employee_id)[:first_name]).to eq("Test") # all other records should not be changed - plsql.test_employees.all("WHERE employee_id > :1", employee_id) do |employee| + plsql.test_employees.all("WHERE employee_id > :1", employee_id).each do |employee| expect(employee[:first_name]).not_to eq("Test") end end @@ -340,7 +340,7 @@ it "should update all records in table" do plsql.test_employees.insert @employees plsql.test_employees.update first_name: "Test" - plsql.test_employees.all do |employee| + plsql.test_employees.all.each do |employee| expect(employee[:first_name]).to eq("Test") end end diff --git a/spec/plsql/view_spec.rb b/spec/plsql/view_spec.rb index 9f5a59b2..6d6df830 100644 --- a/spec/plsql/view_spec.rb +++ b/spec/plsql/view_spec.rb @@ -157,7 +157,7 @@ end it "should insert many records with array of values" do - plsql.test_employees_v.insert_values *@employees_all_values + plsql.test_employees_v.insert_values(*@employees_all_values) expect(plsql.test_employees_v.all).to eq(@employees) end @@ -230,7 +230,7 @@ plsql.test_employees_v.update first_name: "Test", where: "employee_id = #{employee_id}" expect(plsql.test_employees_v.first(employee_id: employee_id)[:first_name]).to eq("Test") # all other records should not be changed - plsql.test_employees_v.all("WHERE employee_id > :1", employee_id) do |employee| + plsql.test_employees_v.all("WHERE employee_id > :1", employee_id).each do |employee| expect(employee[:first_name]).not_to eq("Test") end end @@ -238,7 +238,7 @@ it "should update all records in view" do plsql.test_employees_v.insert @employees plsql.test_employees_v.update first_name: "Test" - plsql.test_employees_v.all do |employee| + plsql.test_employees_v.all.each do |employee| expect(employee[:first_name]).to eq("Test") end end From 56a6119710119b56e39670d53d879a88e65c3ca1 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 01:32:09 +0900 Subject: [PATCH 18/23] Replace deprecated :mswin, :mingw platforms with :windows Co-Authored-By: Claude Opus 4.6 (1M context) --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 9265aba8..f35a059b 100644 --- a/Gemfile +++ b/Gemfile @@ -18,7 +18,7 @@ group :test, :development do gem "simplecov", ">= 0" end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem "ruby-oci8", "~> 2.1" end end From f91ffe4df78b9a86e763d208ebf84a55146abf0d Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 01:35:09 +0900 Subject: [PATCH 19/23] Fix XMLType parameter and return value handling on Oracle 12c+ Oracle 12c+ reports XMLType parameters with data_type OPAQUE/XMLTYPE in ALL_ARGUMENTS (changed from UNDEFINED in Oracle 11g). Handle this new data_type in add_argument, add_return_variable, return_variable_value, MATCHING_TYPES, and plsql_to_ruby_data_type. This fixes the XMLType tests that were skipped since issue #114. Co-Authored-By: Claude Opus 4.6 (1M context) --- lib/plsql/oci_connection.rb | 2 +- lib/plsql/procedure_call.rb | 14 +++++++------- spec/plsql/procedure_spec.rb | 7 ++----- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/lib/plsql/oci_connection.rb b/lib/plsql/oci_connection.rb index 1739458b..ca5e9bee 100644 --- a/lib/plsql/oci_connection.rb +++ b/lib/plsql/oci_connection.rb @@ -157,7 +157,7 @@ def plsql_to_ruby_data_type(metadata) [DateTime, nil] when "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE" [Time, nil] - when "TABLE", "VARRAY", "OBJECT", "XMLTYPE" + when "TABLE", "VARRAY", "OBJECT", "XMLTYPE", "OPAQUE/XMLTYPE" # create Ruby class for collection klass = OCI8::Object::Base.get_class_by_typename(metadata[:sql_type_name]) unless klass diff --git a/lib/plsql/procedure_call.rb b/lib/plsql/procedure_call.rb index e7273ceb..8ff30641 100644 --- a/lib/plsql/procedure_call.rb +++ b/lib/plsql/procedure_call.rb @@ -115,7 +115,7 @@ def get_overload_from_arguments_list(args) MATCHING_TYPES = { integer: ["NUMBER", "NATURAL", "NATURALN", "POSITIVE", "POSITIVEN", "SIGNTYPE", "SIMPLE_INTEGER", "PLS_INTEGER", "BINARY_INTEGER"], decimal: ["NUMBER", "BINARY_FLOAT", "BINARY_DOUBLE"], - string: ["VARCHAR", "VARCHAR2", "NVARCHAR2", "CHAR", "NCHAR", "CLOB", "BLOB", "XMLTYPE"], + string: ["VARCHAR", "VARCHAR2", "NVARCHAR2", "CHAR", "NCHAR", "CLOB", "BLOB", "XMLTYPE", "OPAQUE/XMLTYPE"], date: ["DATE"], time: ["DATE", "TIMESTAMP", "TIMESTAMP WITH TIME ZONE", "TIMESTAMP WITH LOCAL TIME ZONE"], boolean: ["PL/SQL BOOLEAN"], @@ -240,8 +240,8 @@ def add_argument(argument, value, argument_metadata = nil) @bind_values[argument] = value.nil? ? nil : (value ? 1 : 0) @bind_metadata[argument] = argument_metadata.merge(data_type: "NUMBER", data_precision: 1) "l_#{argument}" - when "UNDEFINED" - if argument_metadata[:type_name] == "XMLTYPE" + when "UNDEFINED", "XMLTYPE", "OPAQUE/XMLTYPE" + if argument_metadata[:type_name] == "XMLTYPE" || argument_metadata[:data_type] =~ /XMLTYPE/ @declare_sql << "l_#{argument} XMLTYPE;\n" @assignment_sql << "l_#{argument} := XMLTYPE(:#{argument});\n" if not value.nil? @bind_values[argument] = value if not value.nil? @@ -395,8 +395,8 @@ def add_return_variable(argument, argument_metadata, is_return_value = false) end end "l_#{argument} := " if is_return_value - when "UNDEFINED" - if argument_metadata[:type_name] == "XMLTYPE" + when "UNDEFINED", "XMLTYPE", "OPAQUE/XMLTYPE" + if argument_metadata[:type_name] == "XMLTYPE" || argument_metadata[:data_type] =~ /XMLTYPE/ @declare_sql << "l_#{argument} XMLTYPE;\n" if is_return_value bind_variable = :"o_#{argument}" @return_vars << bind_variable @@ -517,8 +517,8 @@ def return_variable_value(argument, argument_metadata) when "PL/SQL BOOLEAN" numeric_value = @cursor[":o_#{argument}"] numeric_value.nil? ? nil : numeric_value == 1 - when "UNDEFINED" - if argument_metadata[:type_name] == "XMLTYPE" + when "UNDEFINED", "XMLTYPE", "OPAQUE/XMLTYPE" + if argument_metadata[:type_name] == "XMLTYPE" || argument_metadata[:data_type] =~ /XMLTYPE/ @cursor[":o_#{argument}"] end else diff --git a/spec/plsql/procedure_spec.rb b/spec/plsql/procedure_spec.rb index 943e5979..89d45e9a 100644 --- a/spec/plsql/procedure_spec.rb +++ b/spec/plsql/procedure_spec.rb @@ -238,9 +238,6 @@ describe "Function or procedure with XMLType parameters" do before(:all) do plsql.connect! CONNECTION_PARAMS - @oracle12c_or_higher = !! plsql.connection.select_all( - "select * from product_component_version where product like 'Oracle%' and to_number(substr(version,1,2)) >= 12") - skip "Skip until furtuer investigation for #114" if @oracle12c_or_higher plsql.execute <<-SQL CREATE OR REPLACE FUNCTION test_xmltype ( p_xml XMLTYPE ) @@ -261,8 +258,8 @@ end after(:all) do - plsql.execute "DROP FUNCTION test_xmltype" unless @oracle12c_or_higher - plsql.execute "DROP PROCEDURE test_xmltype2" unless @oracle12c_or_higher + plsql.execute "DROP FUNCTION test_xmltype" rescue nil + plsql.execute "DROP PROCEDURE test_xmltype2" rescue nil plsql.logoff end From 62bd2e36a0a641fae377db58ee98a50cce6c0ec9 Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 07:53:09 +0900 Subject: [PATCH 20/23] Use 11g server's v14 timezone file via ORA_TZFILE MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Approach: - Oracle 11g XE uses timezone v14; Instant Client 21.15 uses v35 - 11g's DBMS_DST doesn't support upgrading to v35 (GET_LATEST_TIMEZONE_VERSION was added in 12c), so we cannot upgrade the server - Instead, extract v14 files from the 11g container and point the client at them via ORA_TZFILE — client stays at 21.15, just uses v14 tz data - Use bare filename (not absolute path) for ORA_TZFILE since the file lives in oracore/zoneinfo/ under the Instant Client directory Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test_11g.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/test_11g.yml b/.github/workflows/test_11g.yml index 38f9aae7..21002e86 100644 --- a/.github/workflows/test_11g.yml +++ b/.github/workflows/test_11g.yml @@ -68,6 +68,19 @@ jobs: - name: Install JDBC Driver run: | wget -q https://download.oracle.com/otn-pub/otn_software/jdbc/233/ojdbc11.jar -O ./lib/ojdbc11.jar + - name: Configure ORA_TZFILE to match Oracle 11g server + run: | + # Oracle 11g XE uses timezone file v14; Instant Client 21.15 embeds v35. + # This mismatch causes ORA-01805 when ruby-oci8 fetches DATE/TIMESTAMP + # values. Copy the v14 files from the 11g container and point the + # Instant Client at them via ORA_TZFILE. + ORACLE_CONTAINER=$(docker ps --filter "ancestor=gvenzl/oracle-xe:11" -q) + sudo mkdir -p /opt/oracle/instantclient_21_15/oracore/zoneinfo + docker cp "$ORACLE_CONTAINER":/u01/app/oracle/product/11.2.0/xe/oracore/zoneinfo/timezlrg_14.dat /tmp/timezlrg_14.dat + docker cp "$ORACLE_CONTAINER":/u01/app/oracle/product/11.2.0/xe/oracore/zoneinfo/timezone_14.dat /tmp/timezone_14.dat + sudo mv /tmp/timezlrg_14.dat /opt/oracle/instantclient_21_15/oracore/zoneinfo/ + sudo mv /tmp/timezone_14.dat /opt/oracle/instantclient_21_15/oracore/zoneinfo/ + echo "ORA_TZFILE=timezlrg_14.dat" >> $GITHUB_ENV - name: Create database user run: | ./ci/setup_accounts.sh From b85781224ffb97d7ed3cf440b86e2e25c0f2fe9f Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 21:53:51 +0900 Subject: [PATCH 21/23] Add Rails 5.0-8.0 gemfile matrix running minimum required CRuby Add gemfiles for ActiveRecord 7.1, 7.2, and 8.0, and a new test_gemfiles workflow that runs the spec suite once per gemfile against the minimum CRuby version each Rails release supports. This gives the repo per-Rails CI coverage that previously only existed in the Travis config. Existing gemfiles are updated to drop beta/rc adapter pins and to use the :windows platform alias. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/test_gemfiles.yml | 92 +++++++++++++++++++++++++++++ gemfiles/Gemfile.activerecord-5.0 | 2 +- gemfiles/Gemfile.activerecord-5.1 | 2 +- gemfiles/Gemfile.activerecord-5.2 | 6 +- gemfiles/Gemfile.activerecord-6.0 | 6 +- gemfiles/Gemfile.activerecord-6.1 | 4 +- gemfiles/Gemfile.activerecord-7.0 | 2 +- gemfiles/Gemfile.activerecord-7.1 | 21 +++++++ gemfiles/Gemfile.activerecord-7.2 | 21 +++++++ gemfiles/Gemfile.activerecord-8.0 | 21 +++++++ gemfiles/Gemfile.activerecord-main | 2 +- ruby-plsql.gemspec | 7 +++ 12 files changed, 174 insertions(+), 12 deletions(-) create mode 100644 .github/workflows/test_gemfiles.yml create mode 100644 gemfiles/Gemfile.activerecord-7.1 create mode 100644 gemfiles/Gemfile.activerecord-7.2 create mode 100644 gemfiles/Gemfile.activerecord-8.0 diff --git a/.github/workflows/test_gemfiles.yml b/.github/workflows/test_gemfiles.yml new file mode 100644 index 00000000..b37b575e --- /dev/null +++ b/.github/workflows/test_gemfiles.yml @@ -0,0 +1,92 @@ +name: test_gemfiles + +on: + push: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - gemfile: gemfiles/Gemfile.activerecord-5.0 + ruby: '2.4' + - gemfile: gemfiles/Gemfile.activerecord-5.1 + ruby: '2.4' + - gemfile: gemfiles/Gemfile.activerecord-5.2 + ruby: '2.4' + - gemfile: gemfiles/Gemfile.activerecord-6.0 + ruby: '2.5' + - gemfile: gemfiles/Gemfile.activerecord-6.1 + ruby: '2.5' + - gemfile: gemfiles/Gemfile.activerecord-7.0 + ruby: '2.7' + - gemfile: gemfiles/Gemfile.activerecord-7.1 + ruby: '2.7' + - gemfile: gemfiles/Gemfile.activerecord-7.2 + ruby: '3.1' + - gemfile: gemfiles/Gemfile.activerecord-8.0 + ruby: '3.2' + env: + BUNDLE_GEMFILE: ${{ matrix.gemfile }} + ORACLE_HOME: /opt/oracle/instantclient_23_26 + LD_LIBRARY_PATH: /opt/oracle/instantclient_23_26 + NLS_LANG: AMERICAN_AMERICA.AL32UTF8 + TNS_ADMIN: ./ci/network/admin + DATABASE_NAME: FREEPDB1 + TZ: Europe/Riga + DATABASE_SYS_PASSWORD: Oracle18 + + services: + oracle: + image: gvenzl/oracle-free:latest + ports: + - 1521:1521 + env: + TZ: Europe/Riga + ORACLE_PASSWORD: Oracle18 + options: >- + --health-cmd healthcheck.sh + --health-interval 10s + --health-timeout 5s + --health-retries 10 + + steps: + - uses: actions/checkout@v6 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + - name: Create symbolic link for libaio library compatibility + run: | + sudo ln -s /usr/lib/x86_64-linux-gnu/libaio.so.1t64 /usr/lib/x86_64-linux-gnu/libaio.so.1 + - name: Download Oracle instant client + run: | + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-basic-linux.x64-23.26.1.0.0.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-sdk-linux.x64-23.26.1.0.0.zip + wget -q https://download.oracle.com/otn_software/linux/instantclient/2326100/instantclient-sqlplus-linux.x64-23.26.1.0.0.zip + - name: Install Oracle instant client + run: | + sudo unzip -q instantclient-basic-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + sudo unzip -qo instantclient-sdk-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + sudo unzip -qo instantclient-sqlplus-linux.x64-23.26.1.0.0.zip -d /opt/oracle/ + echo "/opt/oracle/instantclient_23_26" >> $GITHUB_PATH + - name: Install JDBC Driver + run: | + wget -q https://download.oracle.com/otn-pub/otn_software/jdbc/233/ojdbc11.jar -O ./lib/ojdbc11.jar + - name: Create database user + run: | + ./ci/setup_accounts.sh + - name: Bundle install + run: | + bundle install --jobs 4 --retry 3 + - name: Run RSpec + run: | + RUBYOPT=-w bundle exec rspec diff --git a/gemfiles/Gemfile.activerecord-5.0 b/gemfiles/Gemfile.activerecord-5.0 index f645292a..16e679ad 100644 --- a/gemfiles/Gemfile.activerecord-5.0 +++ b/gemfiles/Gemfile.activerecord-5.0 @@ -15,7 +15,7 @@ group :test, :development do gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-5.1 b/gemfiles/Gemfile.activerecord-5.1 index 64f6e464..640f2495 100644 --- a/gemfiles/Gemfile.activerecord-5.1 +++ b/gemfiles/Gemfile.activerecord-5.1 @@ -15,7 +15,7 @@ group :test, :development do gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-5.2 b/gemfiles/Gemfile.activerecord-5.2 index 346834bb..cc6e686a 100644 --- a/gemfiles/Gemfile.activerecord-5.2 +++ b/gemfiles/Gemfile.activerecord-5.2 @@ -10,12 +10,12 @@ group :test, :development do gem 'rspec', '~> 3.1' unless ENV['NO_ACTIVERECORD'] - gem 'activerecord', '~> 5.2.0.beta' - gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0.beta' + gem 'activerecord', '~> 5.2.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 5.2.0' gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-6.0 b/gemfiles/Gemfile.activerecord-6.0 index 67a6c88f..6e42d181 100644 --- a/gemfiles/Gemfile.activerecord-6.0 +++ b/gemfiles/Gemfile.activerecord-6.0 @@ -10,12 +10,12 @@ group :test, :development do gem 'rspec', '~> 3.1' unless ENV['NO_ACTIVERECORD'] - gem 'activerecord', '~> 6.0.0.rc1' - gem 'activerecord-oracle_enhanced-adapter', '~>6.0.0.rc1' + gem 'activerecord', '~> 6.0.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 6.0.0' gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-6.1 b/gemfiles/Gemfile.activerecord-6.1 index 4565f578..5370bfc4 100644 --- a/gemfiles/Gemfile.activerecord-6.1 +++ b/gemfiles/Gemfile.activerecord-6.1 @@ -11,11 +11,11 @@ group :test, :development do unless ENV['NO_ACTIVERECORD'] gem 'activerecord', '~> 6.1.0' - gem 'activerecord-oracle_enhanced-adapter', '~>6.1.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 6.1.0' gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-7.0 b/gemfiles/Gemfile.activerecord-7.0 index 0879987c..e954e527 100644 --- a/gemfiles/Gemfile.activerecord-7.0 +++ b/gemfiles/Gemfile.activerecord-7.0 @@ -15,7 +15,7 @@ group :test, :development do gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/gemfiles/Gemfile.activerecord-7.1 b/gemfiles/Gemfile.activerecord-7.1 new file mode 100644 index 00000000..26a1aab8 --- /dev/null +++ b/gemfiles/Gemfile.activerecord-7.1 @@ -0,0 +1,21 @@ +source 'http://rubygems.org' + +group :development do + gem 'juwelier', '~> 2.0' + gem 'rspec_junit_formatter' +end + +group :test, :development do + gem 'rake', '>= 10.0' + gem 'rspec', '~> 3.1' + + unless ENV['NO_ACTIVERECORD'] + gem 'activerecord', '~> 7.1.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 7.1.0' + gem 'simplecov', '>= 0' + end + + platforms :ruby, :windows do + gem 'ruby-oci8', '~> 2.1' + end +end diff --git a/gemfiles/Gemfile.activerecord-7.2 b/gemfiles/Gemfile.activerecord-7.2 new file mode 100644 index 00000000..12925d42 --- /dev/null +++ b/gemfiles/Gemfile.activerecord-7.2 @@ -0,0 +1,21 @@ +source 'http://rubygems.org' + +group :development do + gem 'juwelier', '~> 2.0' + gem 'rspec_junit_formatter' +end + +group :test, :development do + gem 'rake', '>= 10.0' + gem 'rspec', '~> 3.1' + + unless ENV['NO_ACTIVERECORD'] + gem 'activerecord', '~> 7.2.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 7.2.0' + gem 'simplecov', '>= 0' + end + + platforms :ruby, :windows do + gem 'ruby-oci8', '~> 2.1' + end +end diff --git a/gemfiles/Gemfile.activerecord-8.0 b/gemfiles/Gemfile.activerecord-8.0 new file mode 100644 index 00000000..87745340 --- /dev/null +++ b/gemfiles/Gemfile.activerecord-8.0 @@ -0,0 +1,21 @@ +source 'http://rubygems.org' + +group :development do + gem 'juwelier', '~> 2.0' + gem 'rspec_junit_formatter' +end + +group :test, :development do + gem 'rake', '>= 10.0' + gem 'rspec', '~> 3.1' + + unless ENV['NO_ACTIVERECORD'] + gem 'activerecord', '~> 8.0.0' + gem 'activerecord-oracle_enhanced-adapter', '~> 8.0.0' + gem 'simplecov', '>= 0' + end + + platforms :ruby, :windows do + gem 'ruby-oci8', '~> 2.1' + end +end diff --git a/gemfiles/Gemfile.activerecord-main b/gemfiles/Gemfile.activerecord-main index 086b3fc5..1fcbb691 100644 --- a/gemfiles/Gemfile.activerecord-main +++ b/gemfiles/Gemfile.activerecord-main @@ -15,7 +15,7 @@ group :test, :development do gem 'simplecov', '>= 0' end - platforms :ruby, :mswin, :mingw do + platforms :ruby, :windows do gem 'ruby-oci8', '~> 2.1' end end diff --git a/ruby-plsql.gemspec b/ruby-plsql.gemspec index 8c140e37..09b35c55 100644 --- a/ruby-plsql.gemspec +++ b/ruby-plsql.gemspec @@ -36,6 +36,13 @@ Gem::Specification.new do |s| "gemfiles/Gemfile.activerecord-5.0", "gemfiles/Gemfile.activerecord-5.1", "gemfiles/Gemfile.activerecord-5.2", + "gemfiles/Gemfile.activerecord-6.0", + "gemfiles/Gemfile.activerecord-6.1", + "gemfiles/Gemfile.activerecord-7.0", + "gemfiles/Gemfile.activerecord-7.1", + "gemfiles/Gemfile.activerecord-7.2", + "gemfiles/Gemfile.activerecord-8.0", + "gemfiles/Gemfile.activerecord-main", "lib/plsql/connection.rb", "lib/plsql/helpers.rb", "lib/plsql/jdbc_connection.rb", From 8f80fd995596c5e9c441f73d72b5fddca0b0800e Mon Sep 17 00:00:00 2001 From: Yasuo Honda Date: Sat, 11 Apr 2026 21:53:57 +0900 Subject: [PATCH 22/23] Remove Travis CI configuration All Travis coverage (Rails matrix, Oracle 11g setup, account provisioning) is now handled by GitHub Actions: test_gemfiles.yml provides the Rails matrix, and test.yml / test_11g.yml cover modern Ruby against the root Gemfile. Drop .travis.yml, the .travis/ helper scripts, and the corresponding s.files entries in the gemspec. Co-Authored-By: Claude Opus 4.6 (1M context) --- .travis.yml | 105 ------------------------------------- .travis/oracle/download.sh | 15 ------ .travis/oracle/install.sh | 32 ----------- .travis/setup_accounts.sh | 9 ---- ruby-plsql.gemspec | 4 -- 5 files changed, 165 deletions(-) delete mode 100644 .travis.yml delete mode 100755 .travis/oracle/download.sh delete mode 100755 .travis/oracle/install.sh delete mode 100755 .travis/setup_accounts.sh diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0a9a9583..00000000 --- a/.travis.yml +++ /dev/null @@ -1,105 +0,0 @@ -dist: focal -sudo: required - -jdk: - - openjdk8 -env: - global: - - ORACLE_COOKIE=sqldev - - ORACLE_FILE=oracle11g/xe/oracle-xe-11.2.0-1.0.x86_64.rpm.zip - - ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe - - NLS_LANG=AMERICAN_AMERICA.AL32UTF8 - - ORACLE_BASE=/u01/app/oracle - - LD_LIBRARY_PATH=$ORACLE_HOME/lib - - PATH=$PATH:$ORACLE_HOME/jdbc/lib - - DATABASE_VERSION=11.2.0.2 - - ORACLE_SID=XE - - DATABASE_NAME=XE - - ORA_SDTZ='Europe/London' #Needed as a client parameter - - TZ='Europe/London' #Needed as a DB Server parameter - -before_install: - - chmod +x .travis/oracle/download.sh - - chmod +x .travis/oracle/install.sh - - chmod +x .travis/setup_accounts.sh - - 'gem install bundler || gem install bundler -v 1.17.3' - -install: - - .travis/oracle/download.sh - - .travis/oracle/install.sh - - .travis/setup_accounts.sh - - bundle install --without=development - -language: ruby -rvm: - - 3.2.2 - - 3.1.4 - - 3.0.6 - - 2.7.7 - - 2.6.10 - - 2.5.9 - - 2.4.10 - - 2.3.8 - - jruby-9.2.17.0 - - ruby-head - - jruby-head - -gemfile: - - Gemfile - - gemfiles/Gemfile.activerecord-5.0 - - gemfiles/Gemfile.activerecord-5.1 - - gemfiles/Gemfile.activerecord-5.2 - - gemfiles/Gemfile.activerecord-6.0 - - gemfiles/Gemfile.activerecord-6.1 - - gemfiles/Gemfile.activerecord-7.0 - - gemfiles/Gemfile.activerecord-main - -matrix: - exclude: - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: jruby-head - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: jruby-9.2.17.0 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.6.9 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.5.9 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.4.10 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.3.8 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.2.10 - - gemfile: gemfiles/Gemfile.activerecord-6.0 - rvm: 2.4.10 - - gemfile: gemfiles/Gemfile.activerecord-6.0 - rvm: 2.3.8 - - gemfile: gemfiles/Gemfile.activerecord-6.0 - rvm: 2.2.10 - - gemfile: gemfiles/Gemfile.activerecord-6.1 - rvm: 2.4.10 - - gemfile: gemfiles/Gemfile.activerecord-6.1 - rvm: 2.3.8 - - gemfile: gemfiles/Gemfile.activerecord-6.1 - rvm: 2.2.10 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: jruby-head - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: jruby-9.2.17.0 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: 2.6.9 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: 2.5.9 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: 2.4.10 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: 2.3.8 - - gemfile: gemfiles/Gemfile.activerecord-7.0 - rvm: 2.2.10 - allow_failures: - - rvm: ruby-head - - rvm: jruby-head - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 3.0.3 - - gemfile: gemfiles/Gemfile.activerecord-main - rvm: 2.7.5 diff --git a/.travis/oracle/download.sh b/.travis/oracle/download.sh deleted file mode 100755 index c7927005..00000000 --- a/.travis/oracle/download.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -cd "$(dirname "$(readlink -f "$0")")" - -deb_file=oracle-xe_11.2.0-1.0_amd64.deb - -git clone https://github.com/wnameless/docker-oracle-xe-11g.git - -cd docker-oracle-xe-11g/assets && - cat "${deb_file}aa" "${deb_file}ab" "${deb_file}ac" > "${deb_file}" - -pwd - -ls -lAh "${deb_file}" - diff --git a/.travis/oracle/install.sh b/.travis/oracle/install.sh deleted file mode 100755 index b4c7fef8..00000000 --- a/.travis/oracle/install.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -[ -n "$ORACLE_FILE" ] || { echo "Missing ORACLE_FILE environment variable!"; exit 1; } -[ -n "$ORACLE_HOME" ] || { echo "Missing ORACLE_HOME environment variable!"; exit 1; } - -cd "$(dirname "$(readlink -f "$0")")" - -ORACLE_DEB=docker-oracle-xe-11g/assets/oracle-xe_11.2.0-1.0_amd64.deb - -sudo apt-get -qq update -sudo apt-get --no-install-recommends -qq install bc libaio1 - -df -B1 /dev/shm | awk 'END { if ($1 != "shmfs" && $1 != "tmpfs" || $2 < 2147483648) exit 1 }' || - ( sudo rm -r /dev/shm && sudo mkdir /dev/shm && sudo mount -t tmpfs shmfs -o size=2G /dev/shm ) - -test -f /sbin/chkconfig || - ( echo '#!/bin/sh' | sudo tee /sbin/chkconfig > /dev/null && sudo chmod u+x /sbin/chkconfig ) - -test -d /var/lock/subsys || sudo mkdir /var/lock/subsys - -sudo dpkg -i "${ORACLE_DEB}" - -echo 'OS_AUTHENT_PREFIX=""' | sudo tee -a "$ORACLE_HOME/config/scripts/init.ora" > /dev/null -echo 'disk_asynch_io=false' | sudo tee -a "$ORACLE_HOME/config/scripts/init.ora" > /dev/null -sudo usermod -aG dba $USER - -( echo ; echo ; echo travis ; echo travis ; echo n ) | sudo AWK='/usr/bin/awk' /etc/init.d/oracle-xe configure - -"$ORACLE_HOME/bin/sqlplus" -L -S / AS SYSDBA < Date: Sun, 12 Apr 2026 19:34:54 +0900 Subject: [PATCH 23/23] Remove .codeclimate.yml from gemspec s.files list The file itself was removed in 18813c09cb247ec7 but was left in the gemspec file list. Co-Authored-By: Claude Opus 4.6 (1M context) --- ruby-plsql.gemspec | 1 - 1 file changed, 1 deletion(-) diff --git a/ruby-plsql.gemspec b/ruby-plsql.gemspec index d8fcd95a..07d5a69c 100644 --- a/ruby-plsql.gemspec +++ b/ruby-plsql.gemspec @@ -19,7 +19,6 @@ Gem::Specification.new do |s| "README.md" ] s.files = [ - ".codeclimate.yml", ".github/stale.yml", ".rubocop.yml", "Gemfile",