activerecord-oracle_enhanced-adapter 7.2.1-java → 8.1.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.md +1 -7
- data/README.md +85 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +17 -2
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +66 -36
- data/lib/active_record/connection_adapters/oracle_enhanced/dbms_output.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +82 -14
- data/lib/active_record/connection_adapters/oracle_enhanced/lob.rb +12 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +8 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +5 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +28 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +25 -4
- data/spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb +6 -2
- data/spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb +84 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb +19 -4
- data/spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb +63 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/schema_statements_spec.rb +29 -0
- data/spec/active_record/connection_adapters/oracle_enhanced/structure_dump_spec.rb +12 -1
- data/spec/active_record/oracle_enhanced/type/integer_spec.rb +11 -9
- data/spec/active_record/oracle_enhanced/type/national_character_string_spec.rb +1 -2
- data/spec/active_record/oracle_enhanced/type/text_spec.rb +51 -0
- data/spec/active_record/oracle_enhanced/type/timestamp_spec.rb +34 -4
- data/spec/spec_helper.rb +13 -2
- metadata +10 -6
|
@@ -266,6 +266,24 @@ module ActiveRecord
|
|
|
266
266
|
super
|
|
267
267
|
end
|
|
268
268
|
|
|
269
|
+
# Opens a database console session via sqlplus.
|
|
270
|
+
#
|
|
271
|
+
# Called by Rails' `bin/rails dbconsole` command on the adapter class
|
|
272
|
+
# returned from adapter registration. Builds an Oracle logon string of
|
|
273
|
+
# the form `user[/password]@database` and execs `sqlplus`.
|
|
274
|
+
def self.dbconsole(config, options = {})
|
|
275
|
+
oracle_config = config.configuration_hash
|
|
276
|
+
logon = +""
|
|
277
|
+
|
|
278
|
+
if oracle_config[:username]
|
|
279
|
+
logon << oracle_config[:username]
|
|
280
|
+
logon << "/#{oracle_config[:password]}" if oracle_config[:password] && options[:include_password]
|
|
281
|
+
logon << "@#{config.database}" if config.database
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
find_cmd_and_exec(ActiveRecord.database_cli[:oracle] || "sqlplus", logon)
|
|
285
|
+
end
|
|
286
|
+
|
|
269
287
|
def build_statement_pool
|
|
270
288
|
StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
|
|
271
289
|
end
|
|
@@ -410,7 +428,7 @@ module ActiveRecord
|
|
|
410
428
|
# :startdoc:
|
|
411
429
|
|
|
412
430
|
def native_database_types # :nodoc:
|
|
413
|
-
|
|
431
|
+
self.class.native_database_types
|
|
414
432
|
end
|
|
415
433
|
|
|
416
434
|
# CONNECTION MANAGEMENT ====================================
|
|
@@ -670,7 +688,7 @@ module ActiveRecord
|
|
|
670
688
|
# remove any ASC/DESC modifiers
|
|
671
689
|
s.gsub(/\s+(ASC|DESC)\s*?/i, "")
|
|
672
690
|
}.reject(&:blank?).map.with_index { |column, i|
|
|
673
|
-
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
|
|
691
|
+
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns.join(', ')} ORDER BY #{column}) AS alias_#{i}__"
|
|
674
692
|
}
|
|
675
693
|
(order_columns << super).join(", ")
|
|
676
694
|
end
|
|
@@ -711,6 +729,10 @@ module ActiveRecord
|
|
|
711
729
|
end
|
|
712
730
|
|
|
713
731
|
class << self
|
|
732
|
+
def native_database_types
|
|
733
|
+
emulate_booleans_from_strings ? NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS : NATIVE_DATABASE_TYPES
|
|
734
|
+
end
|
|
735
|
+
|
|
714
736
|
def type_map
|
|
715
737
|
@type_map ||= Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
|
716
738
|
@type_map
|
|
@@ -848,8 +870,7 @@ module ActiveRecord
|
|
|
848
870
|
end
|
|
849
871
|
|
|
850
872
|
# Workaround for https://github.com/jruby/jruby/issues/6267
|
|
851
|
-
# JRuby
|
|
852
|
-
# internal `map` field this workaround reads does not exist anymore.
|
|
873
|
+
# Fixed in JRuby 9.3.0.0 or higher via https://github.com/jruby/jruby/pull/6683
|
|
853
874
|
if RUBY_ENGINE == "jruby" && !ObjectSpace::WeakMap.method_defined?(:values)
|
|
854
875
|
require "jruby"
|
|
855
876
|
|
|
@@ -25,11 +25,15 @@ describe "compatibility migrations" do
|
|
|
25
25
|
end
|
|
26
26
|
}.new
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
ActiveRecord::Migration.suppress_messages do
|
|
29
|
+
migration.migrate(:up)
|
|
30
|
+
end
|
|
29
31
|
expect(@conn.table_exists?(:new_test_employees)).to be_truthy
|
|
30
32
|
expect(@conn.table_exists?(:test_employees)).not_to be_truthy
|
|
31
33
|
|
|
32
|
-
|
|
34
|
+
ActiveRecord::Migration.suppress_messages do
|
|
35
|
+
migration.migrate(:down)
|
|
36
|
+
end
|
|
33
37
|
expect(@conn.table_exists?(:new_test_employees)).not_to be_truthy
|
|
34
38
|
expect(@conn.table_exists?(:test_employees)).to be_truthy
|
|
35
39
|
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe "OracleEnhancedAdapter should support composite primary" do
|
|
4
|
+
include SchemaSpecHelper
|
|
5
|
+
|
|
6
|
+
before(:all) do
|
|
7
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
8
|
+
schema_define do
|
|
9
|
+
create_table :test_authors, force: true do |t|
|
|
10
|
+
t.string :first_name, limit: 20
|
|
11
|
+
t.string :last_name, limit: 25
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
create_table :test_books, force: true do |t|
|
|
15
|
+
t.string :title, limit: 20
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
create_table :test_authors_test_books, primary_key: ["test_author_id", "test_book_id"], force: true do |t|
|
|
19
|
+
t.integer "test_author_id", precision: 38, null: false
|
|
20
|
+
t.integer "test_book_id", precision: 38, null: false
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
after(:all) do
|
|
26
|
+
schema_define do
|
|
27
|
+
drop_table :test_authors
|
|
28
|
+
drop_table :test_books
|
|
29
|
+
drop_table :test_authors_test_books
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
before(:each) do
|
|
34
|
+
class ::TestAuthor < ActiveRecord::Base
|
|
35
|
+
has_many :test_authors_test_books
|
|
36
|
+
has_many :test_books, through: :test_authors_test_books, inverse_of: :test_authors
|
|
37
|
+
end
|
|
38
|
+
class ::TestBook < ActiveRecord::Base
|
|
39
|
+
has_many :test_authors_test_books
|
|
40
|
+
has_many :test_authors, through: :test_authors_test_books, inverse_of: :test_books
|
|
41
|
+
end
|
|
42
|
+
class ::TestAuthorsTestBook < ActiveRecord::Base
|
|
43
|
+
self.primary_key = [:test_author_id, :test_book_id]
|
|
44
|
+
belongs_to :test_author, foreign_key: :test_author_id
|
|
45
|
+
belongs_to :test_book, foreign_key: :test_book_id
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
@author = TestAuthor.create!(
|
|
49
|
+
first_name: "First",
|
|
50
|
+
last_name: "Last",
|
|
51
|
+
)
|
|
52
|
+
@book = TestBook.create!(title: "Nice book")
|
|
53
|
+
@testRel = TestAuthorsTestBook.create!(test_author: @author, test_book: @book)
|
|
54
|
+
expect([@book]).to eq(@author.test_books)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
after(:each) do
|
|
58
|
+
TestAuthor.delete_all
|
|
59
|
+
TestBook.delete_all
|
|
60
|
+
TestAuthorsTestBook.delete_all
|
|
61
|
+
Object.send(:remove_const, "TestAuthor")
|
|
62
|
+
Object.send(:remove_const, "TestBook")
|
|
63
|
+
Object.send(:remove_const, "TestAuthorsTestBook")
|
|
64
|
+
ActiveRecord::Base.clear_cache!
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should support distinct" do
|
|
68
|
+
expect(TestAuthor.distinct.count).to eq(1)
|
|
69
|
+
skip "this appears to be a rails bug https://github.com/rails/rails/issues/55401"
|
|
70
|
+
expect(TestAuthorsTestBook.distinct.count).to eq(1)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should support includes when requesting the first record by a referenced composite idx association" do
|
|
74
|
+
expect([@book]).to eq(@author.test_books)
|
|
75
|
+
expect(TestAuthor.includes(:test_authors_test_books).references(:test_authors_test_books).merge(TestAuthorsTestBook.where(test_author: @author)).take).to eq(@author)
|
|
76
|
+
expect(TestAuthor.includes(:test_authors_test_books).references(:test_authors_test_books).merge(TestAuthorsTestBook.where(test_author: @author)).first).to eq(@author)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "should support includes when requesting the first record by a referenced association" do
|
|
80
|
+
expect([@book]).to eq(@author.test_books)
|
|
81
|
+
expect(TestAuthorsTestBook.includes(:test_author).references(:test_author).merge(TestAuthor.where(first_name: "First")).take).to eq(@testRel)
|
|
82
|
+
expect(TestAuthorsTestBook.includes(:test_author).references(:test_author).merge(TestAuthor.where(first_name: "First")).first).to eq(@testRel)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -65,16 +65,20 @@ describe "OracleEnhancedAdapter establish connection" do
|
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
it "should not encrypt JDBC network connection" do
|
|
68
|
+
skip "Oracle 11g XE does not support native network encryption" if ENV["DATABASE_VERSION"] == "11.2.0.2"
|
|
68
69
|
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
69
70
|
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_connect_properties: { "oracle.net.encryption_client" => "REJECTED" }))
|
|
70
|
-
|
|
71
|
+
conn = ActiveRecord::Base.connection.send(:_connection)
|
|
72
|
+
expect(conn.select("SELECT COUNT(*) Records FROM v$Session_Connect_Info WHERE SID=SYS_CONTEXT('USERENV', 'SID') AND Network_Service_Banner LIKE '%Encryption service adapter%'")).to eq([{ "records" => 0 }])
|
|
71
73
|
end
|
|
72
74
|
end
|
|
73
75
|
|
|
74
76
|
it "should encrypt JDBC network connection" do
|
|
77
|
+
skip "Oracle 11g XE does not support native network encryption" if ENV["DATABASE_VERSION"] == "11.2.0.2"
|
|
75
78
|
if ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
76
79
|
ActiveRecord::Base.establish_connection(SYSTEM_CONNECTION_PARAMS.merge(jdbc_connect_properties: { "oracle.net.encryption_client" => "REQUESTED" }))
|
|
77
|
-
|
|
80
|
+
conn = ActiveRecord::Base.connection.send(:_connection)
|
|
81
|
+
expect(conn.select("SELECT COUNT(*) Records FROM v$Session_Connect_Info WHERE SID=SYS_CONTEXT('USERENV', 'SID') AND Network_Service_Banner LIKE '%Encryption service adapter%'")).to eq([{ "records" => 1 }])
|
|
78
82
|
end
|
|
79
83
|
end
|
|
80
84
|
|
|
@@ -116,6 +120,13 @@ describe "OracleEnhancedConnection" do
|
|
|
116
120
|
it "should be in autocommit mode after connection" do
|
|
117
121
|
expect(@conn).to be_autocommit
|
|
118
122
|
end
|
|
123
|
+
|
|
124
|
+
it "should raise ArgumentError when JDBC exec is called with bindvars" do
|
|
125
|
+
skip unless ORACLE_ENHANCED_CONNECTION == :jdbc
|
|
126
|
+
expect {
|
|
127
|
+
@conn.exec("SELECT ? FROM dual", 1)
|
|
128
|
+
}.to raise_error(ArgumentError, /JDBC exec does not support bindvars/)
|
|
129
|
+
end
|
|
119
130
|
end
|
|
120
131
|
|
|
121
132
|
describe "create connection with schema option" do
|
|
@@ -403,19 +414,23 @@ describe "OracleEnhancedConnection" do
|
|
|
403
414
|
describe "SQL with bind parameters when NLS_NUMERIC_CHARACTERS is set to ', '" do
|
|
404
415
|
before(:all) do
|
|
405
416
|
ENV["NLS_NUMERIC_CHARACTERS"] = ", "
|
|
406
|
-
|
|
417
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
418
|
+
@conn_base = ActiveRecord::Base.connection
|
|
419
|
+
@conn = @conn_base.send(:_connection)
|
|
407
420
|
@conn.exec "CREATE TABLE test_employees (age NUMBER(10,2))"
|
|
408
421
|
end
|
|
409
422
|
|
|
410
423
|
after(:all) do
|
|
411
424
|
ENV["NLS_NUMERIC_CHARACTERS"] = nil
|
|
412
425
|
@conn.exec "DROP TABLE test_employees" rescue nil
|
|
426
|
+
ActiveRecord::Base.clear_cache!
|
|
413
427
|
end
|
|
414
428
|
|
|
415
429
|
it "should execute prepared statement with decimal bind parameter" do
|
|
416
430
|
cursor = @conn.prepare("INSERT INTO test_employees VALUES(:1)")
|
|
417
431
|
type_metadata = ActiveRecord::ConnectionAdapters::SqlTypeMetadata.new(sql_type: "NUMBER", type: :decimal, limit: 10, precision: nil, scale: 2)
|
|
418
|
-
|
|
432
|
+
cast_type = @conn_base.lookup_cast_type("NUMBER(10,2)")
|
|
433
|
+
column = ActiveRecord::ConnectionAdapters::OracleEnhanced::Column.new("age", cast_type, nil, type_metadata, false, comment: nil)
|
|
419
434
|
expect(column.type).to eq(:decimal)
|
|
420
435
|
# Here 1.5 expects that this value has been type casted already
|
|
421
436
|
# it should use bind_params in the long term.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe "Oracle Enhanced adapter dbconsole" do
|
|
4
|
+
subject { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter }
|
|
5
|
+
|
|
6
|
+
it "uses sqlplus with user@db when password is not requested" do
|
|
7
|
+
expect(subject).to receive(:find_cmd_and_exec).with("sqlplus", "user@db")
|
|
8
|
+
|
|
9
|
+
config = make_db_config(adapter: "oracle_enhanced", database: "db", username: "user", password: "secret")
|
|
10
|
+
|
|
11
|
+
subject.dbconsole(config)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "uses sqlplus with user/password@db when include_password is true" do
|
|
15
|
+
expect(subject).to receive(:find_cmd_and_exec).with("sqlplus", "user/secret@db")
|
|
16
|
+
|
|
17
|
+
config = make_db_config(adapter: "oracle_enhanced", database: "db", username: "user", password: "secret")
|
|
18
|
+
|
|
19
|
+
subject.dbconsole(config, include_password: true)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "omits @database when no database is configured" do
|
|
23
|
+
expect(subject).to receive(:find_cmd_and_exec).with("sqlplus", "user")
|
|
24
|
+
|
|
25
|
+
config = make_db_config(adapter: "oracle_enhanced", username: "user")
|
|
26
|
+
|
|
27
|
+
subject.dbconsole(config)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "passes an empty logon string when no username is configured" do
|
|
31
|
+
expect(subject).to receive(:find_cmd_and_exec).with("sqlplus", "")
|
|
32
|
+
|
|
33
|
+
config = make_db_config(adapter: "oracle_enhanced", database: "db")
|
|
34
|
+
|
|
35
|
+
subject.dbconsole(config)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "is inherited by the emulated OracleAdapter" do
|
|
39
|
+
require "active_record/connection_adapters/emulation/oracle_adapter"
|
|
40
|
+
expect(ActiveRecord::ConnectionAdapters::OracleAdapter).to receive(:find_cmd_and_exec).with("sqlplus", "user@db")
|
|
41
|
+
|
|
42
|
+
config = make_db_config(adapter: "oracle", database: "db", username: "user", password: "secret")
|
|
43
|
+
|
|
44
|
+
ActiveRecord::ConnectionAdapters::OracleAdapter.dbconsole(config)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "respects ActiveRecord.database_cli[:oracle] when set" do
|
|
48
|
+
original = ActiveRecord.database_cli[:oracle]
|
|
49
|
+
ActiveRecord.database_cli[:oracle] = "sqlcl"
|
|
50
|
+
expect(subject).to receive(:find_cmd_and_exec).with("sqlcl", "user@db")
|
|
51
|
+
|
|
52
|
+
config = make_db_config(adapter: "oracle_enhanced", database: "db", username: "user")
|
|
53
|
+
|
|
54
|
+
subject.dbconsole(config)
|
|
55
|
+
ensure
|
|
56
|
+
ActiveRecord.database_cli[:oracle] = original
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
def make_db_config(config)
|
|
61
|
+
ActiveRecord::DatabaseConfigurations::HashConfig.new("test", "primary", config)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -69,6 +69,35 @@ describe "OracleEnhancedAdapter schema definition" do
|
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
+
describe "primary_key inside create_table block with type and keyword options" do
|
|
73
|
+
before(:all) do
|
|
74
|
+
@conn = ActiveRecord::Base.connection
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
after(:each) do
|
|
78
|
+
schema_define do
|
|
79
|
+
drop_table :test_lookups, if_exists: true
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it "accepts a type argument and keyword options without raising ArgumentError" do
|
|
84
|
+
expect {
|
|
85
|
+
schema_define do
|
|
86
|
+
create_table :test_lookups, force: true, id: false do |t|
|
|
87
|
+
t.primary_key :zlookupid, :string, limit: 1, null: false
|
|
88
|
+
t.string :name
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
}.not_to raise_error
|
|
92
|
+
|
|
93
|
+
columns = @conn.columns(:test_lookups)
|
|
94
|
+
pk = columns.find { |c| c.name == "zlookupid" }
|
|
95
|
+
expect(pk).not_to be_nil
|
|
96
|
+
expect(pk.sql_type).to match(/VARCHAR2\(1\)/i)
|
|
97
|
+
expect(pk.null).to be(false)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
72
101
|
describe "default sequence name" do
|
|
73
102
|
it "should return sequence name without truncating too much" do
|
|
74
103
|
seq_name_length = ActiveRecord::Base.connection.sequence_name_length
|
|
@@ -216,6 +216,17 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
|
216
216
|
expect(dump).to match(/CREATE TABLE "BARS" \(\n "ID" NUMBER\(38,0\) NOT NULL,\n "SUPER" RAW\(255\)/)
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
+
it "should dump check constraints" do
|
|
220
|
+
@conn.execute <<~SQL
|
|
221
|
+
ALTER TABLE test_posts ADD CONSTRAINT test_posts_title_check CHECK (LENGTH(title) > 0)
|
|
222
|
+
SQL
|
|
223
|
+
dump = ActiveRecord::Base.connection.structure_dump_check_constraints("test_posts")
|
|
224
|
+
expect(dump.first).to match(/ALTER TABLE "TEST_POSTS" ADD CONSTRAINT "TEST_POSTS_TITLE_CHECK" CHECK/)
|
|
225
|
+
|
|
226
|
+
dump = ActiveRecord::Base.connection.structure_dump
|
|
227
|
+
expect(dump).to match(/ALTER TABLE "TEST_POSTS" ADD CONSTRAINT "TEST_POSTS_TITLE_CHECK" CHECK/)
|
|
228
|
+
end
|
|
229
|
+
|
|
219
230
|
it "should dump table comments" do
|
|
220
231
|
comment_sql = %Q(COMMENT ON TABLE "TEST_POSTS" IS 'Test posts with ''some'' "quotes"')
|
|
221
232
|
@conn.execute comment_sql
|
|
@@ -331,7 +342,7 @@ describe "OracleEnhancedAdapter structure dump" do
|
|
|
331
342
|
end
|
|
332
343
|
end
|
|
333
344
|
|
|
334
|
-
let(:dump) { ActiveRecord::Base.connection.
|
|
345
|
+
let(:dump) { ActiveRecord::Base.connection.dump_schema_versions }
|
|
335
346
|
|
|
336
347
|
before do
|
|
337
348
|
ActiveRecord::Base.connection_pool.schema_migration.create_table
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
describe "OracleEnhancedAdapter integer type detection based on attribute settings" do
|
|
4
4
|
before(:all) do
|
|
5
5
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
conn = ActiveRecord::Base.lease_connection
|
|
7
|
+
conn.execute "DROP TABLE test2_employees" rescue nil
|
|
8
|
+
conn.execute <<~SQL
|
|
9
9
|
CREATE TABLE test2_employees (
|
|
10
10
|
id NUMBER PRIMARY KEY,
|
|
11
11
|
first_name VARCHAR2(20),
|
|
@@ -22,16 +22,18 @@ describe "OracleEnhancedAdapter integer type detection based on attribute settin
|
|
|
22
22
|
created_at DATE
|
|
23
23
|
)
|
|
24
24
|
SQL
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
conn.execute "DROP SEQUENCE test2_employees_seq" rescue nil
|
|
26
|
+
conn.execute <<~SQL
|
|
27
27
|
CREATE SEQUENCE test2_employees_seq MINVALUE 1
|
|
28
28
|
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
|
29
29
|
SQL
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
after(:all) do
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
conn = ActiveRecord::Base.lease_connection
|
|
34
|
+
conn.execute "DROP TABLE test2_employees"
|
|
35
|
+
conn.execute "DROP SEQUENCE test2_employees_seq"
|
|
36
|
+
ActiveRecord::Base.release_connection
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
describe "/ NUMBER values from ActiveRecord model" do
|
|
@@ -43,6 +45,7 @@ describe "OracleEnhancedAdapter integer type detection based on attribute settin
|
|
|
43
45
|
after(:each) do
|
|
44
46
|
Object.send(:remove_const, "Test2Employee")
|
|
45
47
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = true
|
|
48
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.clear_type_map!
|
|
46
49
|
ActiveRecord::Base.clear_cache!
|
|
47
50
|
end
|
|
48
51
|
|
|
@@ -90,8 +93,7 @@ describe "OracleEnhancedAdapter integer type detection based on attribute settin
|
|
|
90
93
|
|
|
91
94
|
it "should return Integer value from NUMBER(1) column if emulate_booleans is set to false" do
|
|
92
95
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = false
|
|
93
|
-
ActiveRecord::
|
|
94
|
-
ActiveRecord::Base.clear_cache!
|
|
96
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
|
95
97
|
create_employee2
|
|
96
98
|
expect(@employee2.is_manager).to be_a(Integer)
|
|
97
99
|
end
|
|
@@ -35,10 +35,9 @@ describe "OracleEnhancedAdapter quoting of NCHAR and NVARCHAR2 columns" do
|
|
|
35
35
|
columns = @conn.columns("test_items")
|
|
36
36
|
%w(nchar_column nvarchar2_column char_column varchar2_column).each do |col|
|
|
37
37
|
column = columns.detect { |c| c.name == col }
|
|
38
|
-
type = @conn.
|
|
38
|
+
type = @conn.lookup_cast_type(column.sql_type)
|
|
39
39
|
value = type.serialize("abc")
|
|
40
40
|
expect(@conn.quote(value)).to eq(column.sql_type[0, 1] == "N" ? "N'abc'" : "'abc'")
|
|
41
|
-
type = @conn.lookup_cast_type_from_column(column)
|
|
42
41
|
nilvalue = type.serialize(nil)
|
|
43
42
|
expect(@conn.quote(nilvalue)).to eq("NULL")
|
|
44
43
|
end
|
|
@@ -241,4 +241,55 @@ describe "OracleEnhancedAdapter handling of CLOB columns" do
|
|
|
241
241
|
)
|
|
242
242
|
expect(Test2Employee.where(comments: search_data)).to have_attributes(count: 1)
|
|
243
243
|
end
|
|
244
|
+
|
|
245
|
+
describe "with prepared_statements disabled" do
|
|
246
|
+
around(:each) do |example|
|
|
247
|
+
old_prepared_statements = @conn.prepared_statements
|
|
248
|
+
@conn.instance_variable_set(:@prepared_statements, false)
|
|
249
|
+
example.run
|
|
250
|
+
@conn.instance_variable_set(:@prepared_statements, old_prepared_statements)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
it "should create record with CLOB data when prepared_statements is false" do
|
|
254
|
+
@employee = TestEmployee.create!(
|
|
255
|
+
first_name: "First",
|
|
256
|
+
last_name: "Last",
|
|
257
|
+
comments: @char_data
|
|
258
|
+
)
|
|
259
|
+
@employee.reload
|
|
260
|
+
expect(@employee.comments).to eq(@char_data)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "should create record with short CLOB data when prepared_statements is false" do
|
|
264
|
+
short_data = "Short CLOB content"
|
|
265
|
+
@employee = TestEmployee.create!(
|
|
266
|
+
first_name: "First",
|
|
267
|
+
last_name: "Last",
|
|
268
|
+
comments: short_data
|
|
269
|
+
)
|
|
270
|
+
@employee.reload
|
|
271
|
+
expect(@employee.comments).to eq(short_data)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
it "should create record with empty CLOB when prepared_statements is false" do
|
|
275
|
+
@employee = TestEmployee.create!(
|
|
276
|
+
first_name: "First",
|
|
277
|
+
last_name: "Last",
|
|
278
|
+
comments: ""
|
|
279
|
+
)
|
|
280
|
+
@employee.reload
|
|
281
|
+
expect(@employee.comments).to eq("")
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
it "should create record with serialized CLOB data when prepared_statements is false" do
|
|
285
|
+
ruby_data = { "test" => ["ruby", :data, 123] }
|
|
286
|
+
@employee = Test2Employee.create!(
|
|
287
|
+
first_name: "First",
|
|
288
|
+
last_name: "Last",
|
|
289
|
+
comments: ruby_data
|
|
290
|
+
)
|
|
291
|
+
@employee.reload
|
|
292
|
+
expect(@employee.comments).to eq(ruby_data)
|
|
293
|
+
end
|
|
294
|
+
end
|
|
244
295
|
end
|
|
@@ -4,10 +4,6 @@ describe "OracleEnhancedAdapter timestamp with timezone support" do
|
|
|
4
4
|
include SchemaSpecHelper
|
|
5
5
|
|
|
6
6
|
before(:all) do
|
|
7
|
-
skip if ENV["DATABASE_SERVER_AND_CLIENT_VERSION_DO_NOT_MATCH"] == "true"
|
|
8
|
-
if ENV["DATABASE_VERSION"] == "11.2.0.2" && ENV["ORACLE_HOME"] == "/usr/lib/oracle/21/client64"
|
|
9
|
-
skip
|
|
10
|
-
end
|
|
11
7
|
ActiveRecord.default_timezone = :local
|
|
12
8
|
ActiveRecord::Base.establish_connection(CONNECTION_WITH_TIMEZONE_PARAMS)
|
|
13
9
|
@conn = ActiveRecord::Base.connection
|
|
@@ -73,5 +69,39 @@ describe "OracleEnhancedAdapter timestamp with timezone support" do
|
|
|
73
69
|
expect(@employee.send(c).to_f).to eq(@now.to_f)
|
|
74
70
|
end
|
|
75
71
|
end
|
|
72
|
+
|
|
73
|
+
it "should return Time value with millisecond fractional seconds from TIMESTAMP columns" do
|
|
74
|
+
@now = Time.local(2008, 5, 26, 23, 11, 11, 123_000) # 123 ms = 123_000 μs
|
|
75
|
+
@employee = TestEmployee.create(
|
|
76
|
+
created_at: @now,
|
|
77
|
+
created_at_tz: @now,
|
|
78
|
+
created_at_ltz: @now
|
|
79
|
+
)
|
|
80
|
+
@employee.reload
|
|
81
|
+
[:created_at, :created_at_tz, :created_at_ltz].each do |c|
|
|
82
|
+
expect(@employee.send(c).class).to eq(Time)
|
|
83
|
+
expect(@employee.send(c).to_f).to eq(@now.to_f)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "should preserve microsecond precision when binding Time values" do
|
|
88
|
+
# Guard against the JDBC bind path going through Float (which can drift
|
|
89
|
+
# by 1 ms for current epoch values). Assert on Time#to_i and Time#usec
|
|
90
|
+
# directly instead of Time#to_f, which is too coarse to catch drift.
|
|
91
|
+
# Note: the TIMESTAMP columns above use the default fractional precision
|
|
92
|
+
# of 6, so the round-trip is truncated to microseconds.
|
|
93
|
+
@now = Time.local(2008, 5, 26, 23, 11, 11, 123_456)
|
|
94
|
+
@employee = TestEmployee.create(
|
|
95
|
+
created_at: @now,
|
|
96
|
+
created_at_tz: @now,
|
|
97
|
+
created_at_ltz: @now
|
|
98
|
+
)
|
|
99
|
+
@employee.reload
|
|
100
|
+
[:created_at, :created_at_tz, :created_at_ltz].each do |c|
|
|
101
|
+
expect(@employee.send(c).to_i).to eq(@now.to_i)
|
|
102
|
+
expect(@employee.send(c).usec).to eq(@now.usec)
|
|
103
|
+
expect(@employee.send(c).nsec).to eq(@now.nsec)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
76
106
|
end
|
|
77
107
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -33,9 +33,21 @@ require "active_support/log_subscriber"
|
|
|
33
33
|
require "active_record/log_subscriber"
|
|
34
34
|
|
|
35
35
|
require "logger"
|
|
36
|
-
require "ruby-plsql"
|
|
37
36
|
|
|
37
|
+
# On JRuby, load the oracle_enhanced adapter first so that the JDBC driver
|
|
38
|
+
# (ojdbc17.jar) is registered with DriverManager before ruby-plsql tries to
|
|
39
|
+
# load it. ruby-plsql only looks for ojdbc6/7.jar and would fail otherwise.
|
|
40
|
+
#
|
|
41
|
+
# File.exists? was removed in Ruby 3.2. Restore it temporarily so that
|
|
42
|
+
# ruby-plsql's JDBC connection code can load under JRuby 10.x (Ruby 3.4).
|
|
38
43
|
require "active_record/connection_adapters/oracle_enhanced_adapter"
|
|
44
|
+
File.singleton_class.alias_method(:exists?, :exist?) unless File.respond_to?(:exists?)
|
|
45
|
+
# ruby-plsql calls ActiveRecord::Base.default_timezone (moved to ActiveRecord
|
|
46
|
+
# module in Rails 7.0). Restore the class-level accessor as a shim.
|
|
47
|
+
unless ActiveRecord::Base.respond_to?(:default_timezone)
|
|
48
|
+
ActiveRecord::Base.define_singleton_method(:default_timezone) { ActiveRecord.default_timezone }
|
|
49
|
+
end
|
|
50
|
+
require "ruby-plsql"
|
|
39
51
|
|
|
40
52
|
puts "==> Effective ActiveRecord version #{ActiveRecord::VERSION::STRING}"
|
|
41
53
|
|
|
@@ -53,7 +65,6 @@ module LoggerSpecHelper
|
|
|
53
65
|
ActiveSupport::Notifications.notifier = @notifier
|
|
54
66
|
|
|
55
67
|
ActiveRecord::LogSubscriber.attach_to(:active_record)
|
|
56
|
-
ActiveSupport::Notifications.subscribe("sql.active_record", ActiveRecord::ExplainSubscriber.new)
|
|
57
68
|
end
|
|
58
69
|
|
|
59
70
|
class MockLogger
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: activerecord-oracle_enhanced-adapter
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 8.1.0
|
|
5
5
|
platform: java
|
|
6
6
|
authors:
|
|
7
7
|
- Raimonds Simanovskis
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: activerecord
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 8.1.0
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
25
|
+
version: 8.1.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: ruby-plsql
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -90,9 +90,11 @@ files:
|
|
|
90
90
|
- lib/arel/visitors/oracle_common.rb
|
|
91
91
|
- spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb
|
|
92
92
|
- spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb
|
|
93
|
+
- spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb
|
|
93
94
|
- spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb
|
|
94
95
|
- spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb
|
|
95
96
|
- spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb
|
|
97
|
+
- spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb
|
|
96
98
|
- spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb
|
|
97
99
|
- spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb
|
|
98
100
|
- spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb
|
|
@@ -132,22 +134,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
132
134
|
requirements:
|
|
133
135
|
- - ">="
|
|
134
136
|
- !ruby/object:Gem::Version
|
|
135
|
-
version: 3.
|
|
137
|
+
version: 3.2.0
|
|
136
138
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
137
139
|
requirements:
|
|
138
140
|
- - ">="
|
|
139
141
|
- !ruby/object:Gem::Version
|
|
140
142
|
version: 1.8.11
|
|
141
143
|
requirements: []
|
|
142
|
-
rubygems_version:
|
|
144
|
+
rubygems_version: 4.0.10
|
|
143
145
|
specification_version: 4
|
|
144
146
|
summary: Oracle enhanced adapter for ActiveRecord
|
|
145
147
|
test_files:
|
|
146
148
|
- spec/active_record/connection_adapters/emulation/oracle_adapter_spec.rb
|
|
147
149
|
- spec/active_record/connection_adapters/oracle_enhanced/compatibility_spec.rb
|
|
150
|
+
- spec/active_record/connection_adapters/oracle_enhanced/composite_spec.rb
|
|
148
151
|
- spec/active_record/connection_adapters/oracle_enhanced/connection_spec.rb
|
|
149
152
|
- spec/active_record/connection_adapters/oracle_enhanced/context_index_spec.rb
|
|
150
153
|
- spec/active_record/connection_adapters/oracle_enhanced/database_tasks_spec.rb
|
|
154
|
+
- spec/active_record/connection_adapters/oracle_enhanced/dbconsole_spec.rb
|
|
151
155
|
- spec/active_record/connection_adapters/oracle_enhanced/dbms_output_spec.rb
|
|
152
156
|
- spec/active_record/connection_adapters/oracle_enhanced/procedures_spec.rb
|
|
153
157
|
- spec/active_record/connection_adapters/oracle_enhanced/quoting_spec.rb
|