activerecord-oracle_enhanced-adapter 1.5.4 → 1.5.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/History.md +14 -0
- data/VERSION +1 -1
- data/activerecord-oracle_enhanced-adapter.gemspec +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +37 -20
- data/lib/active_record/connection_adapters/oracle_enhanced_column.rb +21 -4
- data/lib/active_record/connection_adapters/oracle_enhanced_column_dumper.rb +9 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +7 -7
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +1 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +5 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +25 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +4 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +55 -13
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +13 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +181 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b1f1f3ee668e111001b017dd37db4d5e70bb315f
|
4
|
+
data.tar.gz: 10e4fdff8ab461b4e48ac248e8a61ccaa4fd1870
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58dddb4992f8ae81c79ee379d0c26a0dcfe869df5e052e1892679a9f03ba440b623fe7b6b2d6c4a85e589bc80989b47e1285d8ad9139e19a64e249872701d566
|
7
|
+
data.tar.gz: d42acd789d7733e82e7e70d8c81c453e9dbd0a3a3dc0b196901ed9552ad09580540559ee5dbb0ec30102ef83d389b313ba932bfe22dc5c7ef0cefda1347ff1db
|
data/History.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## 1.5.5 / 2014-05-23
|
2
|
+
|
3
|
+
* Enhancements
|
4
|
+
* Oracle NUMBER datatype can be handled as Rails :float datatype [#418]
|
5
|
+
- Default NUMBER datatype handled as :decimal to keep compatibility
|
6
|
+
- Configured by setting `self.number_datatype_coercion = :float`
|
7
|
+
* Add link to supported Oracle database version, JDK and Oracle JDBC Driver version [#438]
|
8
|
+
* Support `without_prepared_statements?` to handle `unprepared_statement` [#447]
|
9
|
+
|
10
|
+
* Bug Fix
|
11
|
+
* Associations with name `record` do not work correctly since Rails 4 [#435]
|
12
|
+
* Skip another Oracle Text test when Oracle 12c used [#437]
|
13
|
+
* Tag bind params with a bind param object [#444]
|
14
|
+
|
1
15
|
## 1.5.4 / 2014-03-25
|
2
16
|
|
3
17
|
* Enhancements
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.5.
|
1
|
+
1.5.5
|
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{activerecord-oracle_enhanced-adapter}
|
8
|
-
s.version = "1.5.
|
8
|
+
s.version = "1.5.5"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.license = 'MIT'
|
12
12
|
s.authors = [%q{Raimonds Simanovskis}]
|
13
|
-
s.date = %q{2014-
|
13
|
+
s.date = %q{2014-05-23}
|
14
14
|
s.description = %q{Oracle "enhanced" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases.
|
15
15
|
This adapter is superset of original ActiveRecord Oracle adapter.
|
16
16
|
}
|
@@ -271,6 +271,13 @@ module ActiveRecord
|
|
271
271
|
cattr_accessor :emulate_dates_by_column_name
|
272
272
|
self.emulate_dates_by_column_name = false
|
273
273
|
|
274
|
+
##
|
275
|
+
# :singleton-method:
|
276
|
+
# Specify how `NUMBER` datatype columns, without precision and scale, are handled in Rails world.
|
277
|
+
# Default is :decimal and other valid option is :float. Be wary of setting it to other values.
|
278
|
+
cattr_accessor :number_datatype_coercion
|
279
|
+
self.number_datatype_coercion = :decimal
|
280
|
+
|
274
281
|
# Check column name to identify if it is Date (and not Time) column.
|
275
282
|
# Is used if +emulate_dates_by_column_name+ option is set to +true+.
|
276
283
|
# Override this method definition in initializer file if different Date column recognition is needed.
|
@@ -305,7 +312,7 @@ module ActiveRecord
|
|
305
312
|
# Is used if +emulate_integers_by_column_name+ option is set to +true+.
|
306
313
|
# Override this method definition in initializer file if different Integer column recognition is needed.
|
307
314
|
def self.is_integer_column?(name, table_name = nil)
|
308
|
-
name =~ /(^|_)id$/i
|
315
|
+
!!(name =~ /(^|_)id$/i)
|
309
316
|
end
|
310
317
|
|
311
318
|
##
|
@@ -389,6 +396,7 @@ module ActiveRecord
|
|
389
396
|
@enable_dbms_output = false
|
390
397
|
if config.fetch(:prepared_statements) { true }
|
391
398
|
@visitor = Arel::Visitors::Oracle.new self
|
399
|
+
@prepared_statements = true
|
392
400
|
else
|
393
401
|
@visitor = unprepared_visitor
|
394
402
|
end
|
@@ -420,6 +428,8 @@ module ActiveRecord
|
|
420
428
|
true
|
421
429
|
end
|
422
430
|
|
431
|
+
NUMBER_MAX_PRECISION = 38
|
432
|
+
|
423
433
|
#:stopdoc:
|
424
434
|
DEFAULT_NLS_PARAMETERS = {
|
425
435
|
:nls_calendar => nil,
|
@@ -443,10 +453,10 @@ module ActiveRecord
|
|
443
453
|
|
444
454
|
#:stopdoc:
|
445
455
|
NATIVE_DATABASE_TYPES = {
|
446
|
-
:primary_key => "NUMBER(
|
456
|
+
:primary_key => "NUMBER(#{NUMBER_MAX_PRECISION}) NOT NULL PRIMARY KEY",
|
447
457
|
:string => { :name => "VARCHAR2", :limit => 255 },
|
448
458
|
:text => { :name => "CLOB" },
|
449
|
-
:integer => { :name => "NUMBER", :limit =>
|
459
|
+
:integer => { :name => "NUMBER", :limit => NUMBER_MAX_PRECISION },
|
450
460
|
:float => { :name => "NUMBER" },
|
451
461
|
:decimal => { :name => "DECIMAL" },
|
452
462
|
:datetime => { :name => "DATE" },
|
@@ -728,7 +738,7 @@ module ActiveRecord
|
|
728
738
|
end
|
729
739
|
|
730
740
|
def substitute_at(column, index)
|
731
|
-
Arel.
|
741
|
+
Arel::Nodes::BindParam.new (":a#{index + 1}")
|
732
742
|
end
|
733
743
|
|
734
744
|
def clear_cache!
|
@@ -742,7 +752,7 @@ module ActiveRecord
|
|
742
752
|
log(sql, name, type_casted_binds) do
|
743
753
|
cursor = nil
|
744
754
|
cached = false
|
745
|
-
if binds
|
755
|
+
if without_prepared_statement?(binds)
|
746
756
|
cursor = @connection.prepare(sql)
|
747
757
|
else
|
748
758
|
unless @statements.key? sql
|
@@ -834,22 +844,29 @@ module ActiveRecord
|
|
834
844
|
|
835
845
|
# New method in ActiveRecord 3.1
|
836
846
|
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil)
|
837
|
-
|
847
|
+
type_casted_binds = binds.map { |col, val|
|
848
|
+
[col, type_cast(val, col)]
|
849
|
+
}
|
850
|
+
log(sql, name, type_casted_binds) do
|
838
851
|
returning_id_col = returning_id_index = nil
|
839
|
-
|
840
|
-
@
|
852
|
+
if without_prepared_statement?(binds)
|
853
|
+
cursor = @connection.prepare(sql)
|
841
854
|
else
|
842
|
-
@statements
|
843
|
-
|
855
|
+
unless @statements.key? (sql)
|
856
|
+
@statements[sql] = @connection.prepare(sql)
|
857
|
+
end
|
844
858
|
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
859
|
+
cursor = @statements[sql]
|
860
|
+
|
861
|
+
binds.each_with_index do |bind, i|
|
862
|
+
col, val = bind
|
863
|
+
if col.returning_id?
|
864
|
+
returning_id_col = [col]
|
865
|
+
returning_id_index = i + 1
|
866
|
+
cursor.bind_returning_param(returning_id_index, Integer)
|
867
|
+
else
|
868
|
+
cursor.bind_param(i + 1, type_cast(val, col), col)
|
869
|
+
end
|
853
870
|
end
|
854
871
|
end
|
855
872
|
|
@@ -868,7 +885,7 @@ module ActiveRecord
|
|
868
885
|
def exec_update(sql, name, binds)
|
869
886
|
log(sql, name, binds) do
|
870
887
|
cached = false
|
871
|
-
if binds
|
888
|
+
if without_prepared_statement?(binds)
|
872
889
|
cursor = @connection.prepare(sql)
|
873
890
|
else
|
874
891
|
cursor = if @statements.key?(sql)
|
@@ -1260,7 +1277,7 @@ module ActiveRecord
|
|
1260
1277
|
end.map do |row|
|
1261
1278
|
limit, scale = row['limit'], row['scale']
|
1262
1279
|
if limit || scale
|
1263
|
-
row['sql_type'] += "(#{(limit ||
|
1280
|
+
row['sql_type'] += "(#{(limit || NUMBER_MAX_PRECISION).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
|
1264
1281
|
end
|
1265
1282
|
|
1266
1283
|
if row['sql_type_owner']
|
@@ -23,9 +23,24 @@ module ActiveRecord
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def type_cast(value) #:nodoc:
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
case type
|
27
|
+
when :raw
|
28
|
+
OracleEnhancedColumn.string_to_raw(value)
|
29
|
+
when :datetime
|
30
|
+
OracleEnhancedAdapter.emulate_dates ? guess_date_or_time(value) : super
|
31
|
+
when :float
|
32
|
+
!value.nil? ? self.class.value_to_decimal(value) : super
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def type_cast_code(var_name)
|
39
|
+
type == :float ? "#{self.class.name}.value_to_decimal(#{var_name})" : super
|
40
|
+
end
|
41
|
+
|
42
|
+
def klass
|
43
|
+
type == :float ? BigDecimal : super
|
29
44
|
end
|
30
45
|
|
31
46
|
def virtual?
|
@@ -85,12 +100,14 @@ module ActiveRecord
|
|
85
100
|
forced_column_type ||
|
86
101
|
case field_type
|
87
102
|
when /decimal|numeric|number/i
|
88
|
-
if OracleEnhancedAdapter.emulate_booleans && field_type ==
|
103
|
+
if OracleEnhancedAdapter.emulate_booleans && field_type.upcase == "NUMBER(1)"
|
89
104
|
:boolean
|
90
105
|
elsif extract_scale(field_type) == 0 ||
|
91
106
|
# if column name is ID or ends with _ID
|
92
107
|
OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(name, table_name)
|
93
108
|
:integer
|
109
|
+
elsif field_type.upcase == "NUMBER"
|
110
|
+
OracleEnhancedAdapter.number_datatype_coercion
|
94
111
|
else
|
95
112
|
:decimal
|
96
113
|
end
|
@@ -39,15 +39,23 @@ module ActiveRecord #:nodoc:
|
|
39
39
|
return prepare_column_options_without_oracle_enhanced(column, types) unless oracle_enhanced_adapter?
|
40
40
|
|
41
41
|
spec = {}
|
42
|
+
|
42
43
|
spec[:name] = column.name.inspect
|
43
44
|
spec[:type] = column.virtual? ? 'virtual' : column.type.to_s
|
44
|
-
spec[:virtual_type] = column.type.inspect if column.virtual? && column.sql_type != 'NUMBER'
|
45
45
|
spec[:limit] = column.limit.inspect if column.limit != types[column.type][:limit] && column.type != :decimal
|
46
46
|
spec[:precision] = column.precision.inspect if !column.precision.nil?
|
47
47
|
spec[:scale] = column.scale.inspect if !column.scale.nil?
|
48
48
|
spec[:null] = 'false' if !column.null
|
49
49
|
spec[:as] = column.virtual_column_data_default if column.virtual?
|
50
50
|
spec[:default] = default_string(column.default) if column.has_default? && !column.virtual?
|
51
|
+
|
52
|
+
if column.virtual?
|
53
|
+
# Supports backwards compatibility with older OracleEnhancedAdapter versions where 'NUMBER' virtual column type is not included in dump
|
54
|
+
if column.sql_type != "NUMBER" || ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.number_datatype_coercion != :decimal
|
55
|
+
spec[:virtual_type] = column.type.inspect
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
51
59
|
spec
|
52
60
|
end
|
53
61
|
|
@@ -4,19 +4,19 @@ module ActiveRecord #:nodoc:
|
|
4
4
|
|
5
5
|
module InstanceMethods #:nodoc:
|
6
6
|
private
|
7
|
-
|
7
|
+
|
8
8
|
def _field_changed?(attr, old, value)
|
9
9
|
if column = column_for_attribute(attr)
|
10
10
|
# Added also :decimal type
|
11
|
-
if (
|
12
|
-
# For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
|
11
|
+
if ([:integer, :decimal, :float].include? column.type) && column.null && (old.nil? || old == 0) && value.blank?
|
12
|
+
# For nullable integer/decimal/float columns, NULL gets stored in database for blank (i.e. '') values.
|
13
13
|
# Hence we don't record it as a change if the value changes from nil to ''.
|
14
14
|
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
|
15
15
|
# be typecast back to 0 (''.to_i => 0)
|
16
16
|
value = nil
|
17
|
-
# Oracle stores empty string '' as NULL
|
18
|
-
# therefore need to convert empty string value to nil if old value is nil
|
19
17
|
elsif column.type == :string && column.null && old.nil?
|
18
|
+
# Oracle stores empty string '' as NULL
|
19
|
+
# therefore need to convert empty string value to nil if old value is nil
|
20
20
|
value = nil if value == ''
|
21
21
|
elsif old == 0 && value.is_a?(String) && value.present? && non_zero?(value)
|
22
22
|
value = nil
|
@@ -30,8 +30,8 @@ module ActiveRecord #:nodoc:
|
|
30
30
|
|
31
31
|
def non_zero?(value)
|
32
32
|
value !~ /\A0+(\.0+)?\z/
|
33
|
-
end
|
34
|
-
|
33
|
+
end
|
34
|
+
|
35
35
|
end
|
36
36
|
|
37
37
|
end
|
@@ -27,6 +27,7 @@ begin
|
|
27
27
|
ojdbc_jars.any? do |ojdbc_jar|
|
28
28
|
if File.exists?(file_path = File.join(dir, ojdbc_jar))
|
29
29
|
puts "WARNING: JDK #{java_version} is not officially supported by #{ojdbc_jar}" if java_version >= '1.8'
|
30
|
+
puts "See http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_03 for supported versions"
|
30
31
|
require file_path
|
31
32
|
true
|
32
33
|
end
|
@@ -98,7 +98,7 @@ module ActiveRecord #:nodoc:
|
|
98
98
|
|
99
99
|
# Creates a record with custom create method
|
100
100
|
# and returns its id.
|
101
|
-
def
|
101
|
+
def _create_record
|
102
102
|
# check if class has custom create method
|
103
103
|
if self.class.custom_create_method
|
104
104
|
# run before/after callbacks defined in model
|
@@ -133,7 +133,7 @@ module ActiveRecord #:nodoc:
|
|
133
133
|
|
134
134
|
# Updates the associated record with custom update method
|
135
135
|
# Returns the number of affected rows.
|
136
|
-
def
|
136
|
+
def _update_record(attribute_names = @attributes.keys)
|
137
137
|
# check if class has custom update method
|
138
138
|
if self.class.custom_update_method
|
139
139
|
# run before/after callbacks defined in model
|
@@ -187,5 +187,8 @@ module ActiveRecord #:nodoc:
|
|
187
187
|
def log_custom_method(*args)
|
188
188
|
self.class.connection.send(:log, *args) { yield }
|
189
189
|
end
|
190
|
+
|
191
|
+
alias_method :update_record, :_update_record if private_method_defined?(:_update_record)
|
192
|
+
alias_method :create_record, :_create_record if private_method_defined?(:_create_record)
|
190
193
|
end
|
191
194
|
end
|
@@ -686,4 +686,29 @@ describe "OracleEnhancedAdapter" do
|
|
686
686
|
explain.should include("INDEX UNIQUE SCAN")
|
687
687
|
end
|
688
688
|
end if ENV['RAILS_GEM_VERSION'] >= '3.2'
|
689
|
+
|
690
|
+
describe ".is_integer_column?" do
|
691
|
+
before(:all) do
|
692
|
+
@adapter = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
693
|
+
end
|
694
|
+
|
695
|
+
it "should return TrueClass or FalseClass" do
|
696
|
+
@adapter.is_integer_column?("adapter_id").should be_a TrueClass
|
697
|
+
@adapter.is_integer_column?("").should be_a FalseClass
|
698
|
+
end
|
699
|
+
|
700
|
+
it "should return true if name is 'id'" do
|
701
|
+
@adapter.is_integer_column?("id").should be_true
|
702
|
+
end
|
703
|
+
|
704
|
+
it "should return true if name ends with '_id'" do
|
705
|
+
@adapter.is_integer_column?("_id").should be_true
|
706
|
+
@adapter.is_integer_column?("foo_id").should be_true
|
707
|
+
end
|
708
|
+
|
709
|
+
it "should return false if name is 'something_else'" do
|
710
|
+
@adapter.is_integer_column?("something_else").should be_false
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
689
714
|
end
|
@@ -381,6 +381,9 @@ describe "OracleEnhancedAdapter context index" do
|
|
381
381
|
|
382
382
|
describe "with table prefix and suffix" do
|
383
383
|
before(:all) do
|
384
|
+
@conn = ActiveRecord::Base.connection
|
385
|
+
@oracle12c = !! @conn.select_value(
|
386
|
+
"select * from product_component_version where product like 'Oracle%' and to_number(substr(version,1,2)) = 12")
|
384
387
|
ActiveRecord::Base.table_name_prefix = 'xxx_'
|
385
388
|
ActiveRecord::Base.table_name_suffix = '_xxx'
|
386
389
|
create_tables
|
@@ -405,6 +408,7 @@ describe "OracleEnhancedAdapter context index" do
|
|
405
408
|
end
|
406
409
|
|
407
410
|
it "should dump definition of multiple table index with options" do
|
411
|
+
pending "It always fails when Oracle 12c 12.1.0 used." if @oracle12c
|
408
412
|
options = {
|
409
413
|
name: 'xxx_post_and_comments_i',
|
410
414
|
index_column: :all_text, index_column_trigger_on: :updated_at,
|
@@ -206,6 +206,7 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
206
206
|
job_id NUMBER,
|
207
207
|
salary NUMBER,
|
208
208
|
commission_pct NUMBER(2,2),
|
209
|
+
unwise_name_id NUMBER(2,2),
|
209
210
|
manager_id NUMBER(6),
|
210
211
|
is_manager NUMBER(1),
|
211
212
|
department_id NUMBER(4,0),
|
@@ -218,17 +219,46 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
218
219
|
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
219
220
|
SQL
|
220
221
|
end
|
221
|
-
|
222
|
+
|
222
223
|
after(:all) do
|
223
224
|
@conn.execute "DROP TABLE test2_employees"
|
224
225
|
@conn.execute "DROP SEQUENCE test2_employees_seq"
|
225
226
|
end
|
226
227
|
|
227
|
-
|
228
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.
|
229
|
-
|
230
|
-
column
|
231
|
-
|
228
|
+
context "when number_datatype_coercion is :decimal" do
|
229
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:decimal) }
|
230
|
+
|
231
|
+
it "should set NUMBER column type as decimal if emulate_integers_by_column_name is false" do
|
232
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
233
|
+
columns = @conn.columns('test2_employees')
|
234
|
+
column = columns.detect{|c| c.name == "job_id"}
|
235
|
+
column.type.should == :decimal
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should set NUMBER column type as decimal if column name is not 'id' and does not ends with '_id' and emulate_integers_by_column_name is true" do
|
239
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
240
|
+
columns = @conn.columns('test2_employees')
|
241
|
+
column = columns.detect{|c| c.name == "salary"}
|
242
|
+
column.type.should == :decimal
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
context "when number_datatype_coercion is :float" do
|
247
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:float) }
|
248
|
+
|
249
|
+
it "should set NUMBER column type as float if emulate_integers_by_column_name is false" do
|
250
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
251
|
+
columns = @conn.columns('test2_employees')
|
252
|
+
column = columns.detect{|c| c.name == "job_id"}
|
253
|
+
column.type.should == :float
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should set NUMBER column type as float if column name is not 'id' and does not ends with '_id' and emulate_integers_by_column_name is true" do
|
257
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
258
|
+
columns = @conn.columns('test2_employees')
|
259
|
+
column = columns.detect{|c| c.name == "salary"}
|
260
|
+
column.type.should == :float
|
261
|
+
end
|
232
262
|
end
|
233
263
|
|
234
264
|
it "should set NUMBER column type as integer if emulate_integers_by_column_name is true" do
|
@@ -240,10 +270,24 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
240
270
|
column.type.should == :integer
|
241
271
|
end
|
242
272
|
|
243
|
-
it "should set NUMBER column type as
|
273
|
+
it "should set NUMBER(p,0) column type as integer" do
|
244
274
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
245
275
|
columns = @conn.columns('test2_employees')
|
246
|
-
column = columns.detect{|c| c.name == "
|
276
|
+
column = columns.detect{|c| c.name == "department_id"}
|
277
|
+
column.type.should == :integer
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should set NUMBER(p,s) column type as integer if column name ends with '_id' and emulate_integers_by_column_name is true" do
|
281
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
282
|
+
columns = @conn.columns('test2_employees')
|
283
|
+
column = columns.detect{|c| c.name == "unwise_name_id"}
|
284
|
+
column.type.should == :integer
|
285
|
+
end
|
286
|
+
|
287
|
+
it "should set NUMBER(p,s) column type as decimal if column name ends with '_id' and emulate_integers_by_column_name is false" do
|
288
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
289
|
+
columns = @conn.columns('test2_employees')
|
290
|
+
column = columns.detect{|c| c.name == "unwise_name_id"}
|
247
291
|
column.type.should == :decimal
|
248
292
|
end
|
249
293
|
|
@@ -254,7 +298,7 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
254
298
|
column.type_cast(1.0).class.should == BigDecimal
|
255
299
|
end
|
256
300
|
|
257
|
-
it "should return Fixnum value from NUMBER column if column name
|
301
|
+
it "should return Fixnum value from NUMBER column if column name ends with '_id' and emulate_integers_by_column_name is true" do
|
258
302
|
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
259
303
|
columns = @conn.columns('test2_employees')
|
260
304
|
column = columns.detect{|c| c.name == "job_id"}
|
@@ -266,7 +310,7 @@ describe "OracleEnhancedAdapter integer type detection based on column names" do
|
|
266
310
|
class ::Test2Employee < ActiveRecord::Base
|
267
311
|
end
|
268
312
|
end
|
269
|
-
|
313
|
+
|
270
314
|
after(:each) do
|
271
315
|
Object.send(:remove_const, "Test2Employee")
|
272
316
|
@conn.clear_types_for_columns
|
@@ -606,7 +650,6 @@ describe "OracleEnhancedAdapter timestamp with timezone support" do
|
|
606
650
|
|
607
651
|
end
|
608
652
|
|
609
|
-
|
610
653
|
describe "OracleEnhancedAdapter date and timestamp with different NLS date formats" do
|
611
654
|
before(:all) do
|
612
655
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
@@ -863,7 +906,7 @@ describe "OracleEnhancedAdapter assign string to :date and :datetime columns" do
|
|
863
906
|
@employee.reload
|
864
907
|
@employee.last_login_at.should == @today.to_time
|
865
908
|
end
|
866
|
-
|
909
|
+
|
867
910
|
end
|
868
911
|
|
869
912
|
describe "OracleEnhancedAdapter handling of CLOB columns" do
|
@@ -1301,7 +1344,6 @@ describe "OracleEnhancedAdapter handling of RAW columns" do
|
|
1301
1344
|
end
|
1302
1345
|
end
|
1303
1346
|
|
1304
|
-
|
1305
1347
|
describe "OracleEnhancedAdapter quoting of NCHAR and NVARCHAR2 columns" do
|
1306
1348
|
before(:all) do
|
1307
1349
|
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
@@ -16,6 +16,7 @@ if ActiveRecord::Base.method_defined?(:changed?)
|
|
16
16
|
last_name VARCHAR2(25),
|
17
17
|
job_id NUMBER(6,0) NULL,
|
18
18
|
salary NUMBER(8,2),
|
19
|
+
pto_per_hour NUMBER,
|
19
20
|
comments CLOB,
|
20
21
|
hire_date DATE
|
21
22
|
)
|
@@ -27,7 +28,7 @@ if ActiveRecord::Base.method_defined?(:changed?)
|
|
27
28
|
class TestEmployee < ActiveRecord::Base
|
28
29
|
end
|
29
30
|
end
|
30
|
-
|
31
|
+
|
31
32
|
after(:all) do
|
32
33
|
Object.send(:remove_const, "TestEmployee")
|
33
34
|
@conn.execute "DROP TABLE test_employees"
|
@@ -62,6 +63,16 @@ if ActiveRecord::Base.method_defined?(:changed?)
|
|
62
63
|
@employee.should_not be_changed
|
63
64
|
end
|
64
65
|
|
66
|
+
it "should not mark empty float (stored as NULL) as changed when reassigning it" do
|
67
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion) { :float }
|
68
|
+
@employee = TestEmployee.create!(:pto_per_hour => '')
|
69
|
+
@employee.pto_per_hour = ''
|
70
|
+
@employee.should_not be_changed
|
71
|
+
@employee.reload
|
72
|
+
@employee.pto_per_hour = ''
|
73
|
+
@employee.should_not be_changed
|
74
|
+
end
|
75
|
+
|
65
76
|
it "should not mark empty text (stored as NULL) as changed when reassigning it" do
|
66
77
|
@employee = TestEmployee.create!(:comments => nil)
|
67
78
|
@employee.comments = nil
|
@@ -111,7 +122,7 @@ if ActiveRecord::Base.method_defined?(:changed?)
|
|
111
122
|
@employee = TestEmployee.new
|
112
123
|
@employee.job_id = 0
|
113
124
|
@employee.save!.should be_true
|
114
|
-
|
125
|
+
|
115
126
|
@employee.should_not be_changed
|
116
127
|
|
117
128
|
@employee.job_id = '0'
|
@@ -376,7 +376,7 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
376
376
|
t.virtual :full_name, :as => "first_name || ', ' || last_name"
|
377
377
|
t.virtual :short_name, :as => "COALESCE(first_name, last_name)", :type => :string, :limit => 300
|
378
378
|
t.virtual :abbrev_name, :as => "SUBSTR(first_name,1,50) || ' ' || SUBSTR(last_name,1,1) || '.'", :type => "VARCHAR(100)"
|
379
|
-
t.virtual :name_ratio, :as=>'(LENGTH(first_name)
|
379
|
+
t.virtual :name_ratio, :as=>'(LENGTH(first_name)/LENGTH(last_name))'
|
380
380
|
t.column :full_name_length, :virtual, :as => "length(first_name || ', ' || last_name)", :type => :integer
|
381
381
|
t.virtual :field_with_leading_space, :as => "' ' || first_name || ' '", :limit => 300, :type => :string
|
382
382
|
end
|
@@ -402,13 +402,30 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
402
402
|
end
|
403
403
|
end
|
404
404
|
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
405
|
+
context "when number_datatype_coercion is :float" do
|
406
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:float) }
|
407
|
+
|
408
|
+
it 'should dump correctly' do
|
409
|
+
standard_dump.should =~ /t\.virtual "full_name",(\s*)limit: 512,(\s*)as: "\\"FIRST_NAME\\"\|\|', '\|\|\\"LAST_NAME\\"",(\s*)type: :string/
|
410
|
+
standard_dump.should =~ /t\.virtual "short_name",(\s*)limit: 300,(\s*)as:(.*),(\s*)type: :string/
|
411
|
+
standard_dump.should =~ /t\.virtual "full_name_length",(\s*)precision: 38,(\s*)scale: 0,(\s*)as:(.*),(\s*)type: :integer/
|
412
|
+
standard_dump.should =~ /t\.virtual "name_ratio",(\s*)as:(.*),(\s*)type: :float$/
|
413
|
+
standard_dump.should =~ /t\.virtual "abbrev_name",(\s*)limit: 100,(\s*)as:(.*),(\s*)type: :string/
|
414
|
+
standard_dump.should =~ /t\.virtual "field_with_leading_space",(\s*)limit: 300,(\s*)as: "' '\|\|\\"FIRST_NAME\\"\|\|' '",(\s*)type: :string/
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
context "when number_datatype_coercion is :decimal" do
|
419
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:decimal) }
|
420
|
+
|
421
|
+
it 'should dump correctly' do
|
422
|
+
standard_dump.should =~ /t\.virtual "full_name",(\s*)limit: 512,(\s*)as: "\\"FIRST_NAME\\"\|\|', '\|\|\\"LAST_NAME\\"",(\s*)type: :string/
|
423
|
+
standard_dump.should =~ /t\.virtual "short_name",(\s*)limit: 300,(\s*)as:(.*),(\s*)type: :string/
|
424
|
+
standard_dump.should =~ /t\.virtual "full_name_length",(\s*)precision: 38,(\s*)scale: 0,(\s*)as:(.*),(\s*)type: :integer/
|
425
|
+
standard_dump.should =~ /t\.virtual "name_ratio",(\s*)as:(.*)\"$/
|
426
|
+
standard_dump.should =~ /t\.virtual "abbrev_name",(\s*)limit: 100,(\s*)as:(.*),(\s*)type: :string/
|
427
|
+
standard_dump.should =~ /t\.virtual "field_with_leading_space",(\s*)limit: 300,(\s*)as: "' '\|\|\\"FIRST_NAME\\"\|\|' '",(\s*)type: :string/
|
428
|
+
end
|
412
429
|
end
|
413
430
|
|
414
431
|
context 'with column cache' do
|
@@ -454,4 +471,160 @@ describe "OracleEnhancedAdapter schema dump" do
|
|
454
471
|
end
|
455
472
|
end
|
456
473
|
|
474
|
+
describe "NUMBER columns" do
|
475
|
+
after(:each) do
|
476
|
+
schema_define do
|
477
|
+
drop_table "test_numbers"
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
let(:value_within_max_precision) { (10 ** @conn.class::NUMBER_MAX_PRECISION) - 1 }
|
482
|
+
let(:value_exceeding_max_precision) { (10 ** @conn.class::NUMBER_MAX_PRECISION) + 1 }
|
483
|
+
|
484
|
+
context "when using ActiveRecord::Schema.define and ActiveRecord::ConnectionAdapters::TableDefinition#float" do
|
485
|
+
before :each do
|
486
|
+
schema_define do
|
487
|
+
create_table :test_numbers, :force => true do |t|
|
488
|
+
t.float :value
|
489
|
+
end
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
context "when number_datatype_coercion is :float" do
|
494
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:float) }
|
495
|
+
|
496
|
+
it "should dump correctly" do
|
497
|
+
standard_dump.should =~ /t\.float "value"$/
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
context "when number_datatype_coercion is :decimal" do
|
502
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:decimal) }
|
503
|
+
|
504
|
+
it "should dump correctly" do
|
505
|
+
standard_dump.should =~ /t\.decimal "value"$/
|
506
|
+
end
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
context "when using handwritten 'CREATE_TABLE' SQL" do
|
511
|
+
before :each do
|
512
|
+
ActiveRecord::Base.establish_connection(CONNECTION_PARAMS)
|
513
|
+
@conn = ActiveRecord::Base.connection
|
514
|
+
@conn.execute <<-SQL
|
515
|
+
CREATE TABLE test_numbers (
|
516
|
+
id NUMBER(#{@conn.class::NUMBER_MAX_PRECISION},0) PRIMARY KEY,
|
517
|
+
value NUMBER
|
518
|
+
)
|
519
|
+
SQL
|
520
|
+
@conn.execute <<-SQL
|
521
|
+
CREATE SEQUENCE test_numbers_seq MINVALUE 1
|
522
|
+
INCREMENT BY 1 START WITH 1 CACHE 20 NOORDER NOCYCLE
|
523
|
+
SQL
|
524
|
+
end
|
525
|
+
|
526
|
+
context "when number_datatype_coercion is :float" do
|
527
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:float) }
|
528
|
+
|
529
|
+
it "should dump correctly" do
|
530
|
+
standard_dump.should =~ /t\.float "value"$/
|
531
|
+
end
|
532
|
+
|
533
|
+
describe "ActiveRecord saving" do
|
534
|
+
before :each do
|
535
|
+
class ::TestNumber < ActiveRecord::Base
|
536
|
+
self.table_name = "test_numbers"
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
it "should allow saving of values within NUMBER_MAX_PRECISION" do
|
541
|
+
number = TestNumber.new(value: value_within_max_precision)
|
542
|
+
number.save!
|
543
|
+
number.reload
|
544
|
+
number.value.should eq(value_within_max_precision)
|
545
|
+
end
|
546
|
+
|
547
|
+
it "should allow saving of values larger than NUMBER_MAX_PRECISION" do
|
548
|
+
number = TestNumber.new(value: value_exceeding_max_precision)
|
549
|
+
number.save!
|
550
|
+
number.reload
|
551
|
+
number.value.should eq(value_exceeding_max_precision)
|
552
|
+
end
|
553
|
+
|
554
|
+
it "should be recreatable from dump and have same properties" do
|
555
|
+
# Simulating db:schema:dump & db:test:load
|
556
|
+
2.times do
|
557
|
+
create_table_dump = standard_dump[/(create_table.+?end)/m]
|
558
|
+
|
559
|
+
schema_define do
|
560
|
+
drop_table "test_numbers"
|
561
|
+
end
|
562
|
+
|
563
|
+
schema_define(&eval("-> * { #{create_table_dump} }"))
|
564
|
+
end
|
565
|
+
|
566
|
+
number = TestNumber.new(value: value_within_max_precision)
|
567
|
+
number.save!
|
568
|
+
|
569
|
+
number2 = TestNumber.new(value: value_exceeding_max_precision)
|
570
|
+
number2.save!
|
571
|
+
end
|
572
|
+
end
|
573
|
+
end
|
574
|
+
|
575
|
+
context "when number_datatype_coercion is :decimal" do
|
576
|
+
before { ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.stub(:number_datatype_coercion).and_return(:decimal) }
|
577
|
+
|
578
|
+
it "should dump correctly" do
|
579
|
+
standard_dump.should =~ /t\.decimal "value"$/
|
580
|
+
end
|
581
|
+
|
582
|
+
describe "ActiveRecord saving" do
|
583
|
+
before :each do
|
584
|
+
class ::TestNumber < ActiveRecord::Base
|
585
|
+
self.table_name = "test_numbers"
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
it "should allow saving of values within NUMBER_MAX_PRECISION" do
|
590
|
+
number = TestNumber.new(value: value_within_max_precision)
|
591
|
+
number.save!
|
592
|
+
number.reload
|
593
|
+
number.value.should eq(value_within_max_precision)
|
594
|
+
end
|
595
|
+
|
596
|
+
it "should allow saving of values larger than NUMBER_MAX_PRECISION" do
|
597
|
+
number = TestNumber.new(value: value_exceeding_max_precision)
|
598
|
+
number.save!
|
599
|
+
number.reload
|
600
|
+
number.value.should eq(value_exceeding_max_precision)
|
601
|
+
end
|
602
|
+
|
603
|
+
it "should be recreatable from dump and have same properties" do
|
604
|
+
# Simulating db:schema:dump & db:test:load
|
605
|
+
2.times do |i|
|
606
|
+
create_table_dump = standard_dump[/(create_table.+?end)/m]
|
607
|
+
|
608
|
+
schema_define do
|
609
|
+
drop_table "test_numbers"
|
610
|
+
end
|
611
|
+
|
612
|
+
schema_define(&eval("-> * { #{create_table_dump} }"))
|
613
|
+
end
|
614
|
+
|
615
|
+
number = TestNumber.new(value: value_within_max_precision)
|
616
|
+
number.save!
|
617
|
+
|
618
|
+
# Raises 'ORA-01438' as :value column type isn't FLOAT'ish
|
619
|
+
number2 = TestNumber.new(value: value_exceeding_max_precision)
|
620
|
+
lambda do
|
621
|
+
number2.save!
|
622
|
+
end.should raise_error() { |e| e.message.should =~ /ORA-01438/ }
|
623
|
+
end
|
624
|
+
end
|
625
|
+
end # context (:decimal)
|
626
|
+
|
627
|
+
end # context (handwritten)
|
628
|
+
end # describe (NUMBER columns)
|
629
|
+
|
457
630
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-oracle_enhanced-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.5.
|
4
|
+
version: 1.5.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Raimonds Simanovskis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jeweler
|