Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5ed1bf0
Release 8.0.0.rc1
yahonda Jun 23, 2025
f34d8d6
Merge pull request #2462 from yahonda/update_readme_for_80
yahonda Jun 26, 2025
0235b57
Merge pull request #2463 from yahonda/backport_2462_to_release80
yahonda Jun 26, 2025
1153e51
Release 8.0.0
yahonda Jun 26, 2025
b898c80
Fix bug report templates for 8.0 stable branch
yahonda Jun 29, 2025
c1094bc
Merge pull request #2464 from yahonda/run-bug-report-templates-release80
yahonda Jun 29, 2025
460718e
just a bit of troubleshooting info
akostadinov Jul 11, 2025
14055e5
Rails 8.1 API compatibility with rails/rails#54333
akostadinov Jul 15, 2025
be44216
activerecord 7.1 distinct column api change
mayorova Jul 17, 2025
d4093a7
test rails 7.1 composite indices
akostadinov Jul 17, 2025
b003908
follow through on #1544
akostadinov Jul 23, 2025
3f21968
Rails compat - #native_database_types
akostadinov Jul 23, 2025
98e1b3a
Rails #dump_schema_information -> #dump_schema_versions
akostadinov Jul 24, 2025
98d401c
emulate_booleans test reliable on newer Rails
akostadinov Jul 25, 2025
0a4ad58
Fix CLOB insertion when prepared_statements is false
andynu Oct 14, 2025
21a4fdc
Switch to Rails 8.1 (8-1-stable branch) for compatibility testing
andynu Oct 23, 2025
b36a5d4
Merge branch 'pr-2471' into rails-8-1-support-akostadinov
andynu Oct 23, 2025
85618af
Remove obsolete ActiveRecord::ExplainSubscriber reference for Rails 8.1
andynu Oct 23, 2025
909db24
Update ActiveRecord dependency to stable 8.1.0 release
andynu Oct 23, 2025
e834b46
Add Rails 8.1 installation section to README
andynu Oct 23, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ruby_head.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ jobs:
run: |
bundle exec rspec
- name: Run bug report templates
if: false
run: |
cd guides/bug_report_templates
ruby active_record_gem.rb
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ jobs:
run: |
bundle exec rspec
- name: Run bug report templates
if: "false"
run: |
cd guides/bug_report_templates
ruby active_record_gem.rb
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/test_11g.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ jobs:
run: |
bundle exec rspec
- name: Run bug report templates
if: "false"
run: |
cd guides/bug_report_templates
ruby active_record_gem.rb
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ group :development do
gem "rspec"
gem "rdoc"
gem "rake"
gem "activerecord", github: "rails/rails", branch: "main"
gem "activerecord", github: "rails/rails", branch: "8-1-stable"
gem "ruby-plsql", github: "rsim/ruby-plsql", branch: "master"

platforms :ruby do
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ Oracle enhanced adapter for ActiveRecord
DESCRIPTION
-----------

Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby on Rails applications. Oracle enhanced adapter can be used from Ruby on Rails versions between 2.3.x and 8.0 and it is working with Oracle database versions 10g and higher
Oracle enhanced ActiveRecord adapter provides Oracle database access from Ruby on Rails applications. Oracle enhanced adapter can be used from Ruby on Rails versions between 2.3.x and 8.1 and it is working with Oracle database versions 10g and higher

INSTALLATION
------------
### Rails 8.1

Oracle enhanced adapter version 8.1 supports Rails 8.1
When using Ruby on Rails version 8.1 then in Gemfile include

```ruby
# Use oracle as the database for Active Record
gem 'activerecord-oracle_enhanced-adapter', '~> 8.1.0'
```

### Rails 8.0

Oracle enhanced adapter version 8.0 supports Rails 8.0
Expand Down
4 changes: 4 additions & 0 deletions RUNNING_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,7 @@ If no Oracle database with SYS and SYSTEM user access is available, try the dock
```sh
bundle exec rake spec
```

# Troubleshooting

If you observe strange errors when running tests, make sure the activerecord version loaded by the tests is the expected one for the oracle_enhanced version.
2 changes: 1 addition & 1 deletion activerecord-oracle_enhanced-adapter.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ This adapter is superset of original ActiveRecord Oracle adapter.
"rubygems_mfa_required" => "true"
}

s.add_runtime_dependency("activerecord", ["~> 8.1.0.alpha"])
s.add_runtime_dependency("activerecord", ["~> 8.1.0"])
s.add_runtime_dependency("ruby-plsql", [">= 0.6.0"])
if /java/.match?(RUBY_PLATFORM)
s.platform = Gem::Platform.new("java")
Expand Down
4 changes: 2 additions & 2 deletions guides/bug_report_templates/active_record_gem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem "activerecord", github: "rails/rails", branch: "main"
gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "master"
gem "activerecord", github: "rails/rails", branch: "8-0-stable"
gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "release80"
gem "minitest"

platforms :ruby do
Expand Down
4 changes: 2 additions & 2 deletions guides/bug_report_templates/active_record_gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem "activerecord", github: "rails/rails", branch: "main"
gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "master"
gem "activerecord", github: "rails/rails", branch: "8-0-stable"
gem "activerecord-oracle_enhanced-adapter", github: "rsim/oracle-enhanced", branch: "release80"
gem "rspec", require: "rspec/autorun"

platforms :ruby do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ module OracleEnhanced
class Column < ActiveRecord::ConnectionAdapters::Column
delegate :virtual, to: :sql_type_metadata, allow_nil: true

def initialize(name, default, sql_type_metadata = nil, null = true, comment: nil) # :nodoc:
super(name, default, sql_type_metadata, null, comment: comment)
def initialize(name, cast_type, default, sql_type_metadata = nil, null = true, comment: nil) # :nodoc:
super(name, cast_type, default, sql_type_metadata, null, comment: comment)
end

def virtual?
Expand Down
9 changes: 9 additions & 0 deletions lib/active_record/connection_adapters/oracle_enhanced/lob.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ module Lob # :nodoc:

# After setting large objects to empty, select the OCI8::LOB
# and write back the data.
before_create :record_lobs_for_create
after_create :enhanced_write_lobs
before_update :record_changed_lobs
after_update :enhanced_write_lobs
end
Expand All @@ -30,6 +32,13 @@ def enhanced_write_lobs
self.class.connection.write_lobs(self.class.table_name, self.class, attributes, @changed_lob_columns)
end
end

def record_lobs_for_create
@changed_lob_columns = self.class.lob_columns.select do |col|
!attributes[col.name].nil? && !self.class.readonly_attributes.to_a.include?(col.name)
end
end

def record_changed_lobs
@changed_lob_columns = self.class.lob_columns.select do |col|
self.will_save_change_to_attribute?(col.name) && !self.class.readonly_attributes.to_a.include?(col.name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def visit_ColumnDefinition(o)
@lob_tablespaces[o.name] = tablespace
end
end
o.cast_type = lookup_cast_type(sql_type)
super
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ def insert_versions_sql(versions) # :nodoc:
} << "SELECT * FROM DUAL\n"
else
if versions.is_a?(Array)
# called from ActiveRecord::Base.connection#dump_schema_information
# called from ActiveRecord::Base.connection#dump_schema_versions
versions.map { |version|
"INSERT INTO #{sm_table} (version) VALUES (#{quote(version)})"
}.join("\n\n/\n\n")
Expand Down Expand Up @@ -674,6 +674,7 @@ def new_column_from_field(table_name, field, definitions)
default_value = extract_value_from_default(field["data_default"])
default_value = nil if is_virtual
OracleEnhanced::Column.new(oracle_downcase(field["name"]),
lookup_cast_type(field["sql_type"]),
default_value,
type_metadata,
field["nullable"] == "Y",
Expand All @@ -698,7 +699,7 @@ def tablespace_for(obj_type, tablespace_option, table_name = nil, column_name =
end

def default_tablespace_for(type)
(default_tablespaces[type] || default_tablespaces[native_database_types[type][:name]]) rescue nil
default_tablespaces[type]
end

def column_for(table_name, column_name)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,7 @@ def supports_longer_identifier?
# :startdoc:

def native_database_types # :nodoc:
emulate_booleans_from_strings ? NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS : NATIVE_DATABASE_TYPES
self.class.native_database_types
end

# CONNECTION MANAGEMENT ====================================
Expand Down Expand Up @@ -670,7 +670,7 @@ def columns_for_distinct(columns, orders) # :nodoc:
# remove any ASC/DESC modifiers
s.gsub(/\s+(ASC|DESC)\s*?/i, "")
}.reject(&:blank?).map.with_index { |column, i|
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns.join(', ')} ORDER BY #{column}) AS alias_#{i}__"
}
(order_columns << super).join(", ")
end
Expand Down Expand Up @@ -711,6 +711,10 @@ def check_version
end

class << self
def native_database_types
emulate_booleans_from_strings ? NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS : NATIVE_DATABASE_TYPES
end

def type_map
@type_map ||= Type::TypeMap.new.tap { |m| initialize_type_map(m) }
@type_map
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# frozen_string_literal: true

describe "OracleEnhancedAdapter should support composite primary" do
include SchemaSpecHelper

before(:all) do
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
schema_define do
create_table :test_authors, force: true do |t|
t.string :first_name, limit: 20
t.string :last_name, limit: 25
end

create_table :test_books, force: true do |t|
t.string :title, limit: 20
end

create_table :test_authors_test_books, primary_key: ["test_author_id", "test_book_id"], force: true do |t|
t.integer "test_author_id", precision: 38, null: false
t.integer "test_book_id", precision: 38, null: false
end
end
end

after(:all) do
schema_define do
drop_table :test_authors
drop_table :test_books
drop_table :test_authors_test_books
end
end

before(:each) do
class ::TestAuthor < ActiveRecord::Base
has_many :test_authors_test_books
has_many :test_books, through: :test_authors_test_books, inverse_of: :test_authors
end
class ::TestBook < ActiveRecord::Base
has_many :test_authors_test_books
has_many :test_authors, through: :test_authors_test_books, inverse_of: :test_books
end
class ::TestAuthorsTestBook < ActiveRecord::Base
self.primary_key = [:test_author_id, :test_book_id]
belongs_to :test_author, foreign_key: :test_author_id
belongs_to :test_book, foreign_key: :test_book_id
end

@author = TestAuthor.create!(
first_name: "First",
last_name: "Last",
)
@book = TestBook.create!(title: "Nice book")
@testRel = TestAuthorsTestBook.create!(test_author: @author, test_book: @book)
expect([@book]).to eq(@author.test_books)
end

after(:each) do
TestAuthor.delete_all
TestBook.delete_all
TestAuthorsTestBook.delete_all
Object.send(:remove_const, "TestAuthor")
Object.send(:remove_const, "TestBook")
Object.send(:remove_const, "TestAuthorsTestBook")
ActiveRecord::Base.clear_cache!
end

it "should support distinct" do
TestAuthor.distinct.count.should == 1
skip "this appears to be a rails bug https://github.com/rails/rails/issues/55401"
TestAuthorsTestBook.distinct.count.should == 1
end

it "should support includes when requesting the first record by a referenced composite idx association" do
expect([@book]).to eq(@author.test_books)
expect(TestAuthor.includes(:test_authors_test_books).references(:test_authors_test_books).merge(TestAuthorsTestBook.where(test_author: @author)).take).to eq(@author)
expect(TestAuthor.includes(:test_authors_test_books).references(:test_authors_test_books).merge(TestAuthorsTestBook.where(test_author: @author)).first).to eq(@author)
end

it "should support includes when requesting the first record by a referenced association" do
expect([@book]).to eq(@author.test_books)
expect(TestAuthorsTestBook.includes(:test_author).references(:test_author).merge(TestAuthor.where(first_name: "First")).take).to eq(@testRel)
expect(TestAuthorsTestBook.includes(:test_author).references(:test_author).merge(TestAuthor.where(first_name: "First")).first).to eq(@testRel)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -403,19 +403,23 @@ def lookup(path)
describe "SQL with bind parameters when NLS_NUMERIC_CHARACTERS is set to ', '" do
before(:all) do
ENV["NLS_NUMERIC_CHARACTERS"] = ", "
@conn = ActiveRecord::ConnectionAdapters::OracleEnhanced::Connection.create(CONNECTION_PARAMS)
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
@conn_base = ActiveRecord::Base.connection
@conn = @conn_base.send(:_connection)
@conn.exec "CREATE TABLE test_employees (age NUMBER(10,2))"
end

after(:all) do
ENV["NLS_NUMERIC_CHARACTERS"] = nil
@conn.exec "DROP TABLE test_employees" rescue nil
ActiveRecord::Base.clear_cache!
end

it "should execute prepared statement with decimal bind parameter" do
cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "NUMBER", type: :decimal, limit: 10, precision: nil, scale: 2)
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", nil, type_metadata, false, comment: nil)
cast_type = @conn_base.lookup_cast_type("NUMBER(10)")
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", cast_type, nil, type_metadata, false, comment: nil)
expect(column.type).to eq(:decimal)
# Here 1.5 expects that this value has been type casted already
# it should use bind_params in the long term.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ class ::TestPost < ActiveRecord::Base
end
end

let(:dump) { ActiveRecord::Base.connection.dump_schema_information }
let(:dump) { ActiveRecord::Base.connection.dump_schema_versions }

before do
ActiveRecord::Base.connection_pool.schema_migration.create_table
Expand Down
20 changes: 11 additions & 9 deletions spec/active_record/oracle_enhanced/type/integer_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
describe "OracleEnhancedAdapter integer type detection based on attribute settings" do
before(:all) do
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
@conn = ActiveRecord::Base.connection
@conn.execute "DROP TABLE test2_employees" rescue nil
@conn.execute <<~SQL
conn = ActiveRecord::Base.lease_connection
conn.execute "DROP TABLE test2_employees" rescue nil
conn.execute <<~SQL
CREATE TABLE test2_employees (
id NUMBER PRIMARY KEY,
first_name VARCHAR2(20),
Expand All @@ -22,16 +22,18 @@
created_at DATE
)
SQL
@conn.execute "DROP SEQUENCE test2_employees_seq" rescue nil
@conn.execute <<~SQL
conn.execute "DROP SEQUENCE test2_employees_seq" rescue nil
conn.execute <<~SQL
CREATE SEQUENCE test2_employees_seq MINVALUE 1
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
SQL
end

after(:all) do
@conn.execute "DROP TABLE test2_employees"
@conn.execute "DROP SEQUENCE test2_employees_seq"
conn = ActiveRecord::Base.lease_connection
conn.execute "DROP TABLE test2_employees"
conn.execute "DROP SEQUENCE test2_employees_seq"
ActiveRecord::Base.release_connection
end

describe "/ NUMBER values from ActiveRecord model" do
Expand All @@ -43,6 +45,7 @@ class ::Test2Employee < ActiveRecord::Base
after(:each) do
Object.send(:remove_const, "Test2Employee")
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.clear_type_map!
ActiveRecord::Base.clear_cache!
end

Expand Down Expand Up @@ -90,8 +93,7 @@ class ::Test2Employee < ActiveRecord::Base

it "should return Integer value from NUMBER(1) column if emulate_booleans is set to false" do
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = false
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.clear_type_map!
ActiveRecord::Base.clear_cache!
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
create_employee2
expect(@employee2.is_manager).to be_a(Integer)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,9 @@ class ::TestItem < ActiveRecord::Base
columns = @conn.columns("test_items")
%w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
column = columns.detect { |c| c.name == col }
type = @conn.lookup_cast_type_from_column(column)
type = @conn.lookup_cast_type(column.sql_type)
value = type.serialize("abc")
expect(@conn.quote(value)).to eq(column.sql_type[0, 1] == "N" ? "N'abc'" : "'abc'")
type = @conn.lookup_cast_type_from_column(column)
nilvalue = type.serialize(nil)
expect(@conn.quote(nilvalue)).to eq("NULL")
end
Expand Down
Loading