Skip to content

Preliminary Rails 8.1 support #2471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
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.
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
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