Skip to content

Conversation

@andynu
Copy link
Contributor

@andynu andynu commented Oct 23, 2025

This PR brings full Rails 8.1 compatibility to the Oracle Enhanced adapter, building on excellent work by @akostadinov (Aleksandar N. Kostadinov) in PR #2471.

I've added only two additional fixes:

  • CLOB insertion with disabled prepared statements,
  • removal of the obsolete ExplainSubscriber reference that Rails 8.1 refactored away.

Credits

The vast majority of this work was done by Aleksandar N. Kostadinov (@akostadinov) and Daria Mayorova (@mayorova). Their comprehensive compatibility updates fixed nearly all Rails 8.1 issues.

Changes from @akostadinov's PR #2471

Core Rails 8.1 API Compatibility

  • Column constructor signature change (Eliminate queries loading dumped model schema on Postgres rails/rails#54333)
    • Updated OracleEnhanced::Column.new to accept cast_type as second parameter
    • Modified schema_statements.rb and schema_creation.rb to call lookup_cast_type and pass cast types to column
      constructors
    • Updated tests to use new column constructor signature
  • Schema dumping method rename
    • Changed dump_schema_information → dump_schema_versions throughout codebase
    • Updated method calls and comments in schema_statements.rb and test specs
  • Native database types refactoring
    • Moved native_database_types to class method to support Rails 8.1's static type resolution
    • Instance method now delegates to class method
    • Maintains backward compatibility with emulate_booleans_from_strings setting
  • Distinct column API changes (by @mayorova)
    • Updated distinct_relation_for_primary_key to use Rails 7.1+ distinct column API
    • Changed internal method call from previous API to distinct(column_name)

Test Infrastructure & Coverage

  • Rails 7.1 composite primary key tests
    • Added comprehensive test suite for composite primary keys (composite_spec.rb)
    • Tests unique constraints, validations, and composite key behavior
    • 84 lines of new test coverage
  • Test reliability improvements
    • Fixed emulate_booleans test to properly clear type map and re-establish connections
    • Changed from instance variable @conn to leased connections for thread safety
    • Added proper connection cleanup in test teardown
  • Schema enhancement follow-up (Remove `OracleEnhancedAdapter.default_tablespaces[native_database_typ… #1544)
    • Updated create_sequence call to use proper keyword arguments
    • Modernized sequence creation syntax

My Contributions (this PR)

CLOB Insertion Fix

Rails 8.1 ExplainSubscriber Removal

  • Removed obsolete ActiveRecord::ExplainSubscriber reference (commit 85618af)
    • Rails 8.1 removed ExplainSubscriber class
      (rails/rails@f488878)
    • ExplainSubscriber functionality refactored into ExplainRegistry with lazy subscription
    • Rails 8.1 now subscribes only when .explain is first called
    • Removed manual subscription line from spec_helper.rb that was causing NameError

Testing

All tests pass against Rails 8.1 (8-1-stable branch).

yahonda and others added 20 commits June 23, 2025 21:43
Merge pull request rsim#2462 from yahonda/update_readme_for_80
Update bug report template configuration to be compatible with
release80 branch environment and CIs run these files.

- With this commit
```ruby
$ ruby -v
ruby 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-linux]
$ ruby active_record_gem.rb
Fetching https://github.com/kubo/ruby-oci8.git
Fetching https://github.com/rsim/oracle-enhanced.git
Fetching https://github.com/rails/rails.git
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
-- create_table(:posts, {force: true})
D, [2025-06-29T09:20:53.289823 #1660953] DEBUG -- :    (13.4ms)  DROP TABLE "POSTS"
D, [2025-06-29T09:20:53.294321 #1660953] DEBUG -- :    (4.2ms)  DROP SEQUENCE "POSTS_SEQ"
D, [2025-06-29T09:20:53.300123 #1660953] DEBUG -- :    (5.6ms)  CREATE TABLE "POSTS" ("ID" NUMBER(38) NOT NULL PRIMARY KEY)
D, [2025-06-29T09:20:53.302264 #1660953] DEBUG -- :    (2.0ms)  CREATE SEQUENCE "POSTS_SEQ" START WITH 1
   -> 0.1497s
-- create_table(:comments, {force: true})
D, [2025-06-29T09:20:53.415485 #1660953] DEBUG -- :    (12.6ms)  DROP TABLE "COMMENTS"
D, [2025-06-29T09:20:53.418772 #1660953] DEBUG -- :    (3.0ms)  DROP SEQUENCE "COMMENTS_SEQ"
D, [2025-06-29T09:20:53.423895 #1660953] DEBUG -- :    (4.9ms)  CREATE TABLE "COMMENTS" ("ID" NUMBER(38) NOT NULL PRIMARY KEY, "POST_ID" NUMBER(38))
D, [2025-06-29T09:20:53.425852 #1660953] DEBUG -- :    (1.8ms)  CREATE SEQUENCE "COMMENTS_SEQ" START WITH 1
   -> 0.1235s
D, [2025-06-29T09:20:53.437179 #1660953] DEBUG -- :   ActiveRecord::InternalMetadata Load (0.5ms)  SELECT * FROM (SELECT * FROM "AR_INTERNAL_METADATA" WHERE "AR_INTERNAL_METADATA"."KEY" = :a1 ORDER BY "AR_INTERNAL_METADATA"."KEY" ASC ) WHERE ROWNUM <= 1  [[nil, "environment"]]
Run options: --seed 2150

D, [2025-06-29T09:20:53.973878 #1660953] DEBUG -- :   Post Create (22.2ms)  INSERT INTO "POSTS" ("ID") VALUES (:a1)  [["id", 1]]
D, [2025-06-29T09:20:54.403818 #1660953] DEBUG -- :   Comment Create (17.3ms)  INSERT INTO "COMMENTS" ("ID") VALUES (:a1)  [["id", 1]]
D, [2025-06-29T09:20:54.410472 #1660953] DEBUG -- :   Comment Update (3.0ms)  UPDATE "COMMENTS" SET "POST_ID" = :a1 WHERE "COMMENTS"."ID" = :a2  [["post_id", 1], ["id", 1]]
D, [2025-06-29T09:20:54.414855 #1660953] DEBUG -- :   Comment Count (2.6ms)  SELECT COUNT(*) FROM "COMMENTS" WHERE "COMMENTS"."POST_ID" = :a1  [["post_id", 1]]
D, [2025-06-29T09:20:54.416336 #1660953] DEBUG -- :   Comment Count (1.3ms)  SELECT COUNT(*) FROM "COMMENTS"
D, [2025-06-29T09:20:54.418215 #1660953] DEBUG -- :   Comment Load (1.1ms)  SELECT * FROM (SELECT "COMMENTS".* FROM "COMMENTS" ORDER BY "COMMENTS"."ID" ASC ) WHERE ROWNUM <= :a1  [["LIMIT", 1]]
D, [2025-06-29T09:20:54.420601 #1660953] DEBUG -- :   Post Load (1.7ms)  SELECT "POSTS".* FROM "POSTS" WHERE "POSTS"."ID" = :a1 AND ROWNUM <= :a2   [["id", 1], ["LIMIT", 1]]
.

Finished in 0.955570s, 1.0465 runs/s, 3.1395 assertions/s.

1 runs, 3 assertions, 0 failures, 0 errors, 0 skips
yahonda@myubuntu:~/src/github.com/rsim/oracle-enhanced/guides/bug_report_templates$ ruby active_record_gem_spec.rb
Fetching https://github.com/kubo/ruby-oci8.git
Fetching https://github.com/rsim/oracle-enhanced.git
Fetching https://github.com/rails/rails.git
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
-- create_table(:posts, {force: true})
D, [2025-06-29T09:21:03.308979 #1661232] DEBUG -- :    (15.6ms)  DROP TABLE "POSTS"
D, [2025-06-29T09:21:03.313359 #1661232] DEBUG -- :    (4.1ms)  DROP SEQUENCE "POSTS_SEQ"
D, [2025-06-29T09:21:03.320263 #1661232] DEBUG -- :    (6.4ms)  CREATE TABLE "POSTS" ("ID" NUMBER(38) NOT NULL PRIMARY KEY)
D, [2025-06-29T09:21:03.322988 #1661232] DEBUG -- :    (2.5ms)  CREATE SEQUENCE "POSTS_SEQ" START WITH 1
   -> 0.1535s
-- create_table(:comments, {force: true})
D, [2025-06-29T09:21:03.434660 #1661232] DEBUG -- :    (10.4ms)  DROP TABLE "COMMENTS"
D, [2025-06-29T09:21:03.437557 #1661232] DEBUG -- :    (2.7ms)  DROP SEQUENCE "COMMENTS_SEQ"
D, [2025-06-29T09:21:03.443303 #1661232] DEBUG -- :    (5.5ms)  CREATE TABLE "COMMENTS" ("ID" NUMBER(38) NOT NULL PRIMARY KEY, "POST_ID" NUMBER(38))
D, [2025-06-29T09:21:03.446023 #1661232] DEBUG -- :    (2.5ms)  CREATE SEQUENCE "COMMENTS_SEQ" START WITH 1
   -> 0.1230s
D, [2025-06-29T09:21:03.458293 #1661232] DEBUG -- :   ActiveRecord::InternalMetadata Load (0.5ms)  SELECT * FROM (SELECT * FROM "AR_INTERNAL_METADATA" WHERE "AR_INTERNAL_METADATA"."KEY" = :a1 ORDER BY "AR_INTERNAL_METADATA"."KEY" ASC ) WHERE ROWNUM <= 1  [[nil, "environment"]]
D, [2025-06-29T09:21:03.978427 #1661232] DEBUG -- :   Post Create (27.0ms)  INSERT INTO "POSTS" ("ID") VALUES (:a1)  [["id", 1]]
D, [2025-06-29T09:21:04.399606 #1661232] DEBUG -- :   Comment Create (4.3ms)  INSERT INTO "COMMENTS" ("ID") VALUES (:a1)  [["id", 1]]
D, [2025-06-29T09:21:04.408651 #1661232] DEBUG -- :   Comment Update (3.5ms)  UPDATE "COMMENTS" SET "POST_ID" = :a1 WHERE "COMMENTS"."ID" = :a2  [["post_id", 1], ["id", 1]]
D, [2025-06-29T09:21:04.413675 #1661232] DEBUG -- :   Comment Count (3.3ms)  SELECT COUNT(*) FROM "COMMENTS" WHERE "COMMENTS"."POST_ID" = :a1  [["post_id", 1]]
D, [2025-06-29T09:21:04.415549 #1661232] DEBUG -- :   Comment Count (1.2ms)  SELECT COUNT(*) FROM "COMMENTS"
D, [2025-06-29T09:21:04.416853 #1661232] DEBUG -- :   Comment Load (1.0ms)  SELECT * FROM (SELECT "COMMENTS".* FROM "COMMENTS" ORDER BY "COMMENTS"."ID" ASC ) WHERE ROWNUM <= :a1  [["LIMIT", 1]]
D, [2025-06-29T09:21:04.419228 #1661232] DEBUG -- :   Post Load (1.7ms)  SELECT "POSTS".* FROM "POSTS" WHERE "POSTS"."ID" = :a1 AND ROWNUM <= :a2   [["id", 1], ["LIMIT", 1]]
.

Finished in 1.29 seconds (files took 0.29285 seconds to load)
1 example, 0 failures

yahonda@myubuntu:~/src/github.com/rsim/oracle-enhanced/guides/bug_report_templates$
…lease80

Fix bug report templates for 8.0 stable branch
Add after_create callbacks to LOB module to handle CLOB/BLOB writing
when using empty_clob()/empty_blob() placeholders in INSERT statements.

Previously, the LOB module only had after_update callbacks, causing
CLOB data to be lost when records were created with prepared_statements
disabled (which generates SQL with empty_clob() literals instead of
bind parameters).

Changes:
- Add before_create :record_lobs_for_create callback
- Add after_create :enhanced_write_lobs callback
- Add record_lobs_for_create method to track non-nil LOB columns on
create
- Add tests for CLOB creation with prepared_statements disabled

This fixes the issue where CLOBs would be empty after creation in
environments where prepared_statements defaults to false. Issue rsim#2477
Rails 8.1 removed the ExplainSubscriber class (commit f488878f1bc),
causing test failures with: NameError: uninitialized constant
ActiveRecord::ExplainSubscriber

The ExplainSubscriber functionality was refactored into ExplainRegistry
with lazy subscription - instead of subscribing at initialization,
Rails 8.1 now subscribes only when .explain is first called via
ExplainRegistry.start.

The spec_helper.rb line that manually subscribed to ExplainSubscriber
is no longer needed or valid. Rails 8.1 handles the subscription
automatically and lazily.

Related Rails commit:
- f488878f1bc "Refactor ExplainRegistry to only be subscribed once used"
- Author: Jean Boussier
- Date: Thu Sep 25 10:37:09 2025 +0200
- Link:
rails/rails@f488878
Switch from pre-release alpha constraint to stable release constraint
for ActiveRecord 8.1.0 dependency, following Rails 8.1 stable release.
Document Rails 8.1 support with installation instructions, including
the gem version constraint for activerecord-oracle_enhanced-adapter 8.1.
@andynu andynu force-pushed the rails-8-1-support branch from f942020 to e834b46 Compare October 23, 2025 21:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

CLOB/BLOB Inserts Fail When prepared_statements: false (which happens when config.active_record.query_log_tags_enabled = true)

4 participants