activerecord-oracle_enhanced-adapter 1.1.8 → 1.1.9
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.
- data/History.txt +10 -0
- data/README.txt +7 -66
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +84 -12
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +39 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +149 -798
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +826 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +85 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +4 -9
- data/spec/spec_helper.rb +31 -6
- metadata +7 -4
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 1.1.9 2009-01-02
|
2
|
+
|
3
|
+
* Enhancements
|
4
|
+
* Added support for table and column comments in migrations
|
5
|
+
* Added support for specifying sequence start values
|
6
|
+
* Added :privilege option (e.g. :SYSDBA) to ActiveRecord::Base.establish_connection
|
7
|
+
* Bug fixes:
|
8
|
+
* Do not mark empty decimals, strings and texts (stored as NULL in database) as changed when reassigning them (starting from Rails 2.1)
|
9
|
+
* Create booleans as VARCHAR2(1) columns if emulate_booleans_from_strings is true
|
10
|
+
|
1
11
|
== 1.1.8 2008-10-10
|
2
12
|
|
3
13
|
* Bug fixes:
|
data/README.txt
CHANGED
@@ -7,78 +7,19 @@
|
|
7
7
|
Oracle "enhanced" ActiveRecord adapter contains useful additional methods for working with new and legacy Oracle databases
|
8
8
|
from Rails which are extracted from current real projects' monkey patches of original Oracle adapter.
|
9
9
|
|
10
|
-
See http://
|
10
|
+
See http://github.com/rsim/oracle-enhanced/wikis for more information.
|
11
11
|
|
12
|
-
|
12
|
+
For questions and feature discussion please use http://groups.google.com/group/oracle-enhanced
|
13
13
|
|
14
|
-
|
14
|
+
Blog posts about oracle-enahnced can be found at http://blog.rayapps.com/category/oracle-enhanced
|
15
15
|
|
16
|
-
|
17
|
-
== SYNOPSIS:
|
18
|
-
|
19
|
-
In Rails config/database.yml file use oracle_enhanced as adapter name.
|
20
|
-
|
21
|
-
Create config/initializers/oracle_advanced.rb file in your Rails application and put configuration options there.
|
22
|
-
The following configuration options are available:
|
23
|
-
|
24
|
-
* set to true if columns with DATE in their name should be emulated as Date (and not as Time which is default)
|
25
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
26
|
-
|
27
|
-
* set to true if columns with ID at the end of column name should be emulated as Fixnum (and not as BigDecimal which is default)
|
28
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
29
|
-
|
30
|
-
* set to true if CHAR(1), VARCHAR2(1) columns or VARCHAR2 columns with FLAG or YN at the end of their name
|
31
|
-
should be emulated as booleans (and do not use NUMBER(1) as type for booleans which is default)
|
32
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
33
|
-
|
34
|
-
* specify other date and time formats that should be used when assigning string values to :date and :datetime columns, e.g.:
|
35
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = "%d.%m.%Y"
|
36
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = "%d.%m.%Y %H:%M:%S"
|
37
|
-
|
38
|
-
The following model class methods are available:
|
39
|
-
* specify which table columns should be ignored by ActiveRecord
|
40
|
-
ignore_table_columns :column1, :column2, :column3
|
41
|
-
|
42
|
-
* specify which table columns should be with :date type (without time) or with :datetime type (with date and time) - this could be used
|
43
|
-
if emulation by column names is not working because of different naming conventions
|
44
|
-
set_date_columns :started_on, :finished_on
|
45
|
-
set_datetime_columns :start_date_and_time, :end_date_and_time
|
46
|
-
|
47
|
-
* specify which table columns should be with :boolean type - this should be used together with boolean emulation from strings if
|
48
|
-
there are other boolean columns with different naming convention
|
49
|
-
set_boolean_columns :some_boolean_column
|
50
|
-
|
51
|
-
* specify custom create, update and delete methods which should be used instead of Rails generated INSERT, UPDATE and DELETE statements
|
52
|
-
# should return ID of new record
|
53
|
-
set_create_method do
|
54
|
-
plsql.employees_pkg.create_employee(
|
55
|
-
:p_first_name => first_name,
|
56
|
-
:p_last_name => last_name,
|
57
|
-
:p_employee_id => nil
|
58
|
-
)[:p_employee_id]
|
59
|
-
end
|
60
|
-
set_update_method do
|
61
|
-
plsql.employees_pkg.update_employee(
|
62
|
-
:p_employee_id => id,
|
63
|
-
:p_first_name => first_name,
|
64
|
-
:p_last_name => last_name
|
65
|
-
)
|
66
|
-
end
|
67
|
-
set_delete_method do
|
68
|
-
plsql.employees_pkg.delete_employee(
|
69
|
-
:p_employee_id => id
|
70
|
-
)
|
71
|
-
end
|
72
|
-
|
73
|
-
Oracle enhanced adapter is also compatible with composite_primary_keys gem.
|
74
|
-
|
75
|
-
See History.txt for other enhancements to original Oracle adapter.
|
16
|
+
Bugs and enhancement requests can be reported at http://rsim.lighthouseapp.com/projects/11468-oracle-enhanced
|
76
17
|
|
77
18
|
== REQUIREMENTS:
|
78
19
|
|
79
|
-
* Works with ActiveRecord version 2.0 and 2.
|
20
|
+
* Works (has been tested) with ActiveRecord version 2.0, 2.1 and 2.2 (these are the same as Rails versions)
|
80
21
|
* Requires ruby-oci8 library to connect to Oracle
|
81
|
-
* Requires ruby-plsql gem to support custom create, update and delete methods
|
22
|
+
* Requires ruby-plsql gem to support custom create, update and delete methods (but can be used without ruby-plsql if this functionality is not needed)
|
82
23
|
|
83
24
|
== INSTALL:
|
84
25
|
|
@@ -88,7 +29,7 @@ See History.txt for other enhancements to original Oracle adapter.
|
|
88
29
|
|
89
30
|
(The MIT License)
|
90
31
|
|
91
|
-
Copyright (c)
|
32
|
+
Copyright (c) 2009 Graham Jenkins, Michael Schoen, Raimonds Simanovskis
|
92
33
|
|
93
34
|
Permission is hereby granted, free of charge, to any person obtaining
|
94
35
|
a copy of this software and associated documentation files (the
|
@@ -107,6 +107,10 @@ begin
|
|
107
107
|
alias_method :add_order!, :add_order_with_lobs!
|
108
108
|
end
|
109
109
|
|
110
|
+
# RSI: get table comment from schema definition
|
111
|
+
def self.table_comment
|
112
|
+
self.connection.table_comment(self.table_name)
|
113
|
+
end
|
110
114
|
end
|
111
115
|
|
112
116
|
|
@@ -147,6 +151,12 @@ begin
|
|
147
151
|
return string.to_time if string.is_a?(Date) && !OracleEnhancedAdapter.emulate_dates
|
148
152
|
super
|
149
153
|
end
|
154
|
+
|
155
|
+
# RSI: get column comment from schema definition
|
156
|
+
# will work only if using default ActiveRecord connection
|
157
|
+
def comment
|
158
|
+
ActiveRecord::Base.connection.column_comment(@table_name, name)
|
159
|
+
end
|
150
160
|
|
151
161
|
private
|
152
162
|
def simplified_type(field_type)
|
@@ -308,7 +318,9 @@ begin
|
|
308
318
|
:time => { :name => "DATE" },
|
309
319
|
:date => { :name => "DATE" },
|
310
320
|
:binary => { :name => "BLOB" },
|
311
|
-
:
|
321
|
+
# RSI: if emulate_booleans_from_strings then store booleans in VARCHAR2
|
322
|
+
:boolean => emulate_booleans_from_strings ?
|
323
|
+
{ :name => "VARCHAR2", :limit => 1 } : { :name => "NUMBER", :limit => 1 }
|
312
324
|
}
|
313
325
|
end
|
314
326
|
|
@@ -633,12 +645,16 @@ begin
|
|
633
645
|
end
|
634
646
|
end
|
635
647
|
|
648
|
+
# RSI: default sequence start with value
|
649
|
+
@@default_sequence_start_value = 10000
|
650
|
+
cattr_accessor :default_sequence_start_value
|
651
|
+
|
636
652
|
def create_table(name, options = {}, &block) #:nodoc:
|
637
653
|
create_sequence = options[:id] != false
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
654
|
+
column_comments = {}
|
655
|
+
super(name, options) do |t|
|
656
|
+
# store that primary key was defined in create_table block
|
657
|
+
unless create_sequence
|
642
658
|
class <<t
|
643
659
|
attr_accessor :create_sequence
|
644
660
|
def primary_key(*args)
|
@@ -646,12 +662,34 @@ begin
|
|
646
662
|
super(*args)
|
647
663
|
end
|
648
664
|
end
|
649
|
-
result = block.call(t)
|
650
|
-
create_sequence = t.create_sequence
|
651
665
|
end
|
666
|
+
|
667
|
+
# store column comments
|
668
|
+
class <<t
|
669
|
+
attr_accessor :column_comments
|
670
|
+
def column(name, type, options = {})
|
671
|
+
if options[:comment]
|
672
|
+
self.column_comments ||= {}
|
673
|
+
self.column_comments[name] = options[:comment]
|
674
|
+
end
|
675
|
+
super(name, type, options)
|
676
|
+
end
|
677
|
+
end
|
678
|
+
|
679
|
+
result = block.call(t)
|
680
|
+
create_sequence = create_sequence || t.create_sequence
|
681
|
+
column_comments = t.column_comments if t.column_comments
|
652
682
|
end
|
683
|
+
|
653
684
|
seq_name = options[:sequence_name] || "#{name}_seq"
|
654
|
-
|
685
|
+
seq_start_value = options[:sequence_start_value] || default_sequence_start_value
|
686
|
+
execute "CREATE SEQUENCE #{seq_name} START WITH #{seq_start_value}" if create_sequence
|
687
|
+
|
688
|
+
add_table_comment name, options[:comment]
|
689
|
+
column_comments.each do |column_name, comment|
|
690
|
+
add_comment name, column_name, comment
|
691
|
+
end
|
692
|
+
|
655
693
|
end
|
656
694
|
|
657
695
|
def rename_table(name, new_name) #:nodoc:
|
@@ -687,6 +725,36 @@ begin
|
|
687
725
|
execute "ALTER TABLE #{table_name} DROP COLUMN #{quote_column_name(column_name)}"
|
688
726
|
end
|
689
727
|
|
728
|
+
# RSI: table and column comments
|
729
|
+
def add_comment(table_name, column_name, comment)
|
730
|
+
return if comment.blank?
|
731
|
+
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{column_name} IS '#{comment}'"
|
732
|
+
end
|
733
|
+
|
734
|
+
def add_table_comment(table_name, comment)
|
735
|
+
return if comment.blank?
|
736
|
+
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{comment}'"
|
737
|
+
end
|
738
|
+
|
739
|
+
def table_comment(table_name)
|
740
|
+
(owner, table_name) = @connection.describe(table_name)
|
741
|
+
select_value <<-SQL
|
742
|
+
SELECT comments FROM all_tab_comments
|
743
|
+
WHERE owner = '#{owner}'
|
744
|
+
AND table_name = '#{table_name}'
|
745
|
+
SQL
|
746
|
+
end
|
747
|
+
|
748
|
+
def column_comment(table_name, column_name)
|
749
|
+
(owner, table_name) = @connection.describe(table_name)
|
750
|
+
select_value <<-SQL
|
751
|
+
SELECT comments FROM all_col_comments
|
752
|
+
WHERE owner = '#{owner}'
|
753
|
+
AND table_name = '#{table_name}'
|
754
|
+
AND column_name = '#{column_name.upcase}'
|
755
|
+
SQL
|
756
|
+
end
|
757
|
+
|
690
758
|
# Find a table's primary key and sequence.
|
691
759
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
692
760
|
def pk_and_sequence_for(table_name)
|
@@ -916,8 +984,8 @@ begin
|
|
916
984
|
# The OracleConnectionFactory factors out the code necessary to connect and
|
917
985
|
# configure an Oracle/OCI connection.
|
918
986
|
class OracleEnhancedConnectionFactory #:nodoc:
|
919
|
-
def new_connection(username, password, database, async, prefetch_rows, cursor_sharing)
|
920
|
-
conn = OCI8.new username, password, database
|
987
|
+
def new_connection(username, password, database, async, prefetch_rows, cursor_sharing, privilege)
|
988
|
+
conn = OCI8.new username, password, database, privilege
|
921
989
|
conn.exec %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
|
922
990
|
conn.exec %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'} rescue nil
|
923
991
|
conn.autocommit = true
|
@@ -953,7 +1021,8 @@ begin
|
|
953
1021
|
@prefetch_rows = config[:prefetch_rows] || 100
|
954
1022
|
@cursor_sharing = config[:cursor_sharing] || 'similar'
|
955
1023
|
@factory = factory
|
956
|
-
@
|
1024
|
+
@privilege = config[:privilege]
|
1025
|
+
@connection = @factory.new_connection @username, @password, @database, @async, @prefetch_rows, @cursor_sharing, @privilege
|
957
1026
|
super @connection
|
958
1027
|
end
|
959
1028
|
|
@@ -972,7 +1041,7 @@ begin
|
|
972
1041
|
def reset!
|
973
1042
|
logoff rescue nil
|
974
1043
|
begin
|
975
|
-
@connection = @factory.new_connection @username, @password, @database, @async, @prefetch_rows, @cursor_sharing
|
1044
|
+
@connection = @factory.new_connection @username, @password, @database, @async, @prefetch_rows, @cursor_sharing, @privilege
|
976
1045
|
__setobj__ @connection
|
977
1046
|
@active = true
|
978
1047
|
rescue
|
@@ -1048,3 +1117,6 @@ end
|
|
1048
1117
|
|
1049
1118
|
# RSI: load additional methods for composite_primary_keys support
|
1050
1119
|
require 'active_record/connection_adapters/oracle_enhanced_cpk'
|
1120
|
+
|
1121
|
+
# RSI: load patch for dirty tracking methods
|
1122
|
+
require 'active_record/connection_adapters/oracle_enhanced_dirty'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module ConnectionAdapters #:nodoc:
|
3
|
+
module OracleEnhancedDirty #:nodoc:
|
4
|
+
|
5
|
+
module InstanceMethods
|
6
|
+
private
|
7
|
+
|
8
|
+
def field_changed?(attr, old, value)
|
9
|
+
if column = column_for_attribute(attr)
|
10
|
+
# RSI: added also :decimal type
|
11
|
+
if (column.type == :integer || column.type == :decimal) && column.null && (old.nil? || old == 0)
|
12
|
+
# For nullable integer columns, NULL gets stored in database for blank (i.e. '') values.
|
13
|
+
# Hence we don't record it as a change if the value changes from nil to ''.
|
14
|
+
# If an old value of 0 is set to '' we want this to get changed to nil as otherwise it'll
|
15
|
+
# be typecast back to 0 (''.to_i => 0)
|
16
|
+
value = nil if value.blank?
|
17
|
+
# RSI: Oracle stores empty string '' or empty text (CLOB) as NULL
|
18
|
+
# therefore need to convert empty string value to nil if old value is nil
|
19
|
+
elsif (column.type == :string || column.type == :text) && column.null && old.nil?
|
20
|
+
value = nil if value == ''
|
21
|
+
else
|
22
|
+
value = column.type_cast(value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
old != value
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if ActiveRecord::Base.instance_methods.include?('changed?')
|
36
|
+
ActiveRecord::Base.class_eval do
|
37
|
+
include ActiveRecord::ConnectionAdapters::OracleEnhancedDirty::InstanceMethods
|
38
|
+
end
|
39
|
+
end
|
@@ -2,14 +2,21 @@ require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
|
2
2
|
|
3
3
|
describe "OracleEnhancedAdapter establish connection" do
|
4
4
|
|
5
|
-
|
5
|
+
it "should connect to database" do
|
6
6
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
7
7
|
:database => "xe",
|
8
8
|
:username => "hr",
|
9
9
|
:password => "hr")
|
10
|
+
ActiveRecord::Base.connection.should_not be_nil
|
11
|
+
ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
10
12
|
end
|
11
|
-
|
12
|
-
it "should connect to database" do
|
13
|
+
|
14
|
+
it "should connect to database as SYSDBA" do
|
15
|
+
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
16
|
+
:database => "xe",
|
17
|
+
:username => "sys",
|
18
|
+
:password => "manager",
|
19
|
+
:privilege => :SYSDBA)
|
13
20
|
ActiveRecord::Base.connection.should_not be_nil
|
14
21
|
ActiveRecord::Base.connection.class.should == ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter
|
15
22
|
end
|
@@ -158,432 +165,6 @@ describe "OracleEnhancedAdapter database session store" do
|
|
158
165
|
|
159
166
|
end
|
160
167
|
|
161
|
-
describe "OracleEnhancedAdapter date type detection based on column names" do
|
162
|
-
before(:all) do
|
163
|
-
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
164
|
-
:database => "xe",
|
165
|
-
:username => "hr",
|
166
|
-
:password => "hr")
|
167
|
-
@conn = ActiveRecord::Base.connection
|
168
|
-
@conn.execute <<-SQL
|
169
|
-
CREATE TABLE test_employees (
|
170
|
-
employee_id NUMBER(6,0),
|
171
|
-
first_name VARCHAR2(20),
|
172
|
-
last_name VARCHAR2(25),
|
173
|
-
email VARCHAR2(25),
|
174
|
-
phone_number VARCHAR2(20),
|
175
|
-
hire_date DATE,
|
176
|
-
job_id NUMBER(6,0),
|
177
|
-
salary NUMBER(8,2),
|
178
|
-
commission_pct NUMBER(2,2),
|
179
|
-
manager_id NUMBER(6,0),
|
180
|
-
department_id NUMBER(4,0),
|
181
|
-
created_at DATE,
|
182
|
-
updated_at DATE
|
183
|
-
)
|
184
|
-
SQL
|
185
|
-
@conn.execute <<-SQL
|
186
|
-
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
187
|
-
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
188
|
-
SQL
|
189
|
-
end
|
190
|
-
|
191
|
-
after(:all) do
|
192
|
-
@conn.execute "DROP TABLE test_employees"
|
193
|
-
@conn.execute "DROP SEQUENCE test_employees_seq"
|
194
|
-
end
|
195
|
-
|
196
|
-
it "should set DATE column type as datetime if emulate_dates_by_column_name is false" do
|
197
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
198
|
-
columns = @conn.columns('test_employees')
|
199
|
-
column = columns.detect{|c| c.name == "hire_date"}
|
200
|
-
column.type.should == :datetime
|
201
|
-
end
|
202
|
-
|
203
|
-
it "should set DATE column type as date if column name contains '_date_' and emulate_dates_by_column_name is true" do
|
204
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
205
|
-
columns = @conn.columns('test_employees')
|
206
|
-
column = columns.detect{|c| c.name == "hire_date"}
|
207
|
-
column.type.should == :date
|
208
|
-
end
|
209
|
-
|
210
|
-
it "should set DATE column type as datetime if column name does not contain '_date_' and emulate_dates_by_column_name is true" do
|
211
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
212
|
-
columns = @conn.columns('test_employees')
|
213
|
-
column = columns.detect{|c| c.name == "created_at"}
|
214
|
-
column.type.should == :datetime
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should set DATE column type as datetime if column name contains 'date' as part of other word and emulate_dates_by_column_name is true" do
|
218
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
219
|
-
columns = @conn.columns('test_employees')
|
220
|
-
column = columns.detect{|c| c.name == "updated_at"}
|
221
|
-
column.type.should == :datetime
|
222
|
-
end
|
223
|
-
|
224
|
-
it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
|
225
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
226
|
-
columns = @conn.columns('test_employees')
|
227
|
-
column = columns.detect{|c| c.name == "hire_date"}
|
228
|
-
column.type_cast(Time.now).class.should == Time
|
229
|
-
end
|
230
|
-
|
231
|
-
it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
|
232
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
233
|
-
columns = @conn.columns('test_employees')
|
234
|
-
column = columns.detect{|c| c.name == "hire_date"}
|
235
|
-
column.type_cast(Time.now).class.should == Date
|
236
|
-
end
|
237
|
-
|
238
|
-
describe "/ DATE values from ActiveRecord model" do
|
239
|
-
before(:each) do
|
240
|
-
ActiveRecord::Base.connection.clear_types_for_columns
|
241
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
242
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = false
|
243
|
-
class TestEmployee < ActiveRecord::Base
|
244
|
-
set_table_name "hr.test_employees"
|
245
|
-
set_primary_key :employee_id
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
def create_test_employee
|
250
|
-
@today = Date.new(2008,8,19)
|
251
|
-
@now = Time.local(2008,8,19,17,03,59)
|
252
|
-
@employee = TestEmployee.create(
|
253
|
-
:first_name => "First",
|
254
|
-
:last_name => "Last",
|
255
|
-
:hire_date => @today,
|
256
|
-
:created_at => @now
|
257
|
-
)
|
258
|
-
@employee.reload
|
259
|
-
end
|
260
|
-
|
261
|
-
after(:each) do
|
262
|
-
# @employee.destroy if @employee
|
263
|
-
Object.send(:remove_const, "TestEmployee")
|
264
|
-
end
|
265
|
-
|
266
|
-
it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
|
267
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
268
|
-
create_test_employee
|
269
|
-
@employee.hire_date.class.should == Time
|
270
|
-
end
|
271
|
-
|
272
|
-
it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
|
273
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
274
|
-
create_test_employee
|
275
|
-
@employee.hire_date.class.should == Date
|
276
|
-
end
|
277
|
-
|
278
|
-
it "should return Time value from DATE column if column name does not contain 'date' and emulate_dates_by_column_name is true" do
|
279
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
280
|
-
create_test_employee
|
281
|
-
@employee.created_at.class.should == Time
|
282
|
-
end
|
283
|
-
|
284
|
-
it "should return Date value from DATE column if emulate_dates_by_column_name is false but column is defined as date" do
|
285
|
-
class TestEmployee < ActiveRecord::Base
|
286
|
-
set_date_columns :hire_date
|
287
|
-
end
|
288
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
289
|
-
create_test_employee
|
290
|
-
@employee.hire_date.class.should == Date
|
291
|
-
end
|
292
|
-
|
293
|
-
it "should return Time value from DATE column if emulate_dates_by_column_name is true but column is defined as datetime" do
|
294
|
-
class TestEmployee < ActiveRecord::Base
|
295
|
-
set_datetime_columns :hire_date
|
296
|
-
end
|
297
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
298
|
-
create_test_employee
|
299
|
-
@employee.hire_date.class.should == Time
|
300
|
-
# change to current time with hours, minutes and seconds
|
301
|
-
@employee.hire_date = @now
|
302
|
-
@employee.save!
|
303
|
-
@employee.reload
|
304
|
-
@employee.hire_date.class.should == Time
|
305
|
-
@employee.hire_date.should == @now
|
306
|
-
end
|
307
|
-
|
308
|
-
it "should guess Date or Time value if emulate_dates is true" do
|
309
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = true
|
310
|
-
create_test_employee
|
311
|
-
@employee.hire_date.class.should == Date
|
312
|
-
@employee.created_at.class.should == Time
|
313
|
-
end
|
314
|
-
|
315
|
-
end
|
316
|
-
|
317
|
-
end
|
318
|
-
|
319
|
-
describe "OracleEnhancedAdapter integer type detection based on column names" do
|
320
|
-
before(:all) do
|
321
|
-
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
322
|
-
:database => "xe",
|
323
|
-
:username => "hr",
|
324
|
-
:password => "hr")
|
325
|
-
@conn = ActiveRecord::Base.connection
|
326
|
-
@conn.execute <<-SQL
|
327
|
-
CREATE TABLE test2_employees (
|
328
|
-
id NUMBER,
|
329
|
-
first_name VARCHAR2(20),
|
330
|
-
last_name VARCHAR2(25),
|
331
|
-
email VARCHAR2(25),
|
332
|
-
phone_number VARCHAR2(20),
|
333
|
-
hire_date DATE,
|
334
|
-
job_id NUMBER,
|
335
|
-
salary NUMBER,
|
336
|
-
commission_pct NUMBER(2,2),
|
337
|
-
manager_id NUMBER(6),
|
338
|
-
department_id NUMBER(4,0),
|
339
|
-
created_at DATE
|
340
|
-
)
|
341
|
-
SQL
|
342
|
-
@conn.execute <<-SQL
|
343
|
-
CREATE SEQUENCE test2_employees_seq MINVALUE 1
|
344
|
-
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
345
|
-
SQL
|
346
|
-
end
|
347
|
-
|
348
|
-
after(:all) do
|
349
|
-
@conn.execute "DROP TABLE test2_employees"
|
350
|
-
@conn.execute "DROP SEQUENCE test2_employees_seq"
|
351
|
-
end
|
352
|
-
|
353
|
-
it "should set NUMBER column type as decimal if emulate_integers_by_column_name is false" do
|
354
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
355
|
-
columns = @conn.columns('test2_employees')
|
356
|
-
column = columns.detect{|c| c.name == "job_id"}
|
357
|
-
column.type.should == :decimal
|
358
|
-
end
|
359
|
-
|
360
|
-
it "should set NUMBER column type as integer if emulate_integers_by_column_name is true" do
|
361
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
362
|
-
columns = @conn.columns('test2_employees')
|
363
|
-
column = columns.detect{|c| c.name == "job_id"}
|
364
|
-
column.type.should == :integer
|
365
|
-
column = columns.detect{|c| c.name == "id"}
|
366
|
-
column.type.should == :integer
|
367
|
-
end
|
368
|
-
|
369
|
-
it "should set NUMBER column type as decimal if column name does not contain 'id' and emulate_integers_by_column_name is true" do
|
370
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
371
|
-
columns = @conn.columns('test2_employees')
|
372
|
-
column = columns.detect{|c| c.name == "salary"}
|
373
|
-
column.type.should == :decimal
|
374
|
-
end
|
375
|
-
|
376
|
-
it "should return BigDecimal value from NUMBER column if emulate_integers_by_column_name is false" do
|
377
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
378
|
-
columns = @conn.columns('test2_employees')
|
379
|
-
column = columns.detect{|c| c.name == "job_id"}
|
380
|
-
column.type_cast(1.0).class.should == BigDecimal
|
381
|
-
end
|
382
|
-
|
383
|
-
it "should return Fixnum value from NUMBER column if column name contains 'id' and emulate_integers_by_column_name is true" do
|
384
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
385
|
-
columns = @conn.columns('test2_employees')
|
386
|
-
column = columns.detect{|c| c.name == "job_id"}
|
387
|
-
column.type_cast(1.0).class.should == Fixnum
|
388
|
-
end
|
389
|
-
|
390
|
-
describe "/ NUMBER values from ActiveRecord model" do
|
391
|
-
before(:each) do
|
392
|
-
class Test2Employee < ActiveRecord::Base
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
after(:each) do
|
397
|
-
Object.send(:remove_const, "Test2Employee")
|
398
|
-
end
|
399
|
-
|
400
|
-
def create_employee2
|
401
|
-
@employee2 = Test2Employee.create(
|
402
|
-
:first_name => "First",
|
403
|
-
:last_name => "Last",
|
404
|
-
:job_id => 1,
|
405
|
-
:salary => 1000
|
406
|
-
)
|
407
|
-
@employee2.reload
|
408
|
-
end
|
409
|
-
|
410
|
-
it "should return BigDecimal value from NUMBER column if emulate_integers_by_column_name is false" do
|
411
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = false
|
412
|
-
create_employee2
|
413
|
-
@employee2.job_id.class.should == BigDecimal
|
414
|
-
end
|
415
|
-
|
416
|
-
it "should return Fixnum value from NUMBER column if column name contains 'id' and emulate_integers_by_column_name is true" do
|
417
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
418
|
-
create_employee2
|
419
|
-
@employee2.job_id.class.should == Fixnum
|
420
|
-
end
|
421
|
-
|
422
|
-
it "should return BigDecimal value from NUMBER column if column name does not contain 'id' and emulate_integers_by_column_name is true" do
|
423
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
424
|
-
create_employee2
|
425
|
-
@employee2.salary.class.should == BigDecimal
|
426
|
-
end
|
427
|
-
|
428
|
-
end
|
429
|
-
|
430
|
-
end
|
431
|
-
|
432
|
-
describe "OracleEnhancedAdapter boolean type detection based on string column types and names" do
|
433
|
-
before(:all) do
|
434
|
-
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
435
|
-
:database => "xe",
|
436
|
-
:username => "hr",
|
437
|
-
:password => "hr")
|
438
|
-
@conn = ActiveRecord::Base.connection
|
439
|
-
@conn.execute <<-SQL
|
440
|
-
CREATE TABLE test3_employees (
|
441
|
-
id NUMBER,
|
442
|
-
first_name VARCHAR2(20),
|
443
|
-
last_name VARCHAR2(25),
|
444
|
-
email VARCHAR2(25),
|
445
|
-
phone_number VARCHAR2(20),
|
446
|
-
hire_date DATE,
|
447
|
-
job_id NUMBER,
|
448
|
-
salary NUMBER,
|
449
|
-
commission_pct NUMBER(2,2),
|
450
|
-
manager_id NUMBER(6),
|
451
|
-
department_id NUMBER(4,0),
|
452
|
-
created_at DATE,
|
453
|
-
has_email CHAR(1),
|
454
|
-
has_phone VARCHAR2(1),
|
455
|
-
active_flag VARCHAR2(2),
|
456
|
-
manager_yn VARCHAR2(3),
|
457
|
-
test_boolean VARCHAR2(3)
|
458
|
-
)
|
459
|
-
SQL
|
460
|
-
@conn.execute <<-SQL
|
461
|
-
CREATE SEQUENCE test3_employees_seq MINVALUE 1
|
462
|
-
INCREMENT BY 1 START WITH 10040 CACHE 20 NOORDER NOCYCLE
|
463
|
-
SQL
|
464
|
-
end
|
465
|
-
|
466
|
-
after(:all) do
|
467
|
-
@conn.execute "DROP TABLE test3_employees"
|
468
|
-
@conn.execute "DROP SEQUENCE test3_employees_seq"
|
469
|
-
end
|
470
|
-
|
471
|
-
it "should set CHAR/VARCHAR2 column type as string if emulate_booleans_from_strings is false" do
|
472
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
473
|
-
columns = @conn.columns('test3_employees')
|
474
|
-
%w(has_email has_phone active_flag manager_yn).each do |col|
|
475
|
-
column = columns.detect{|c| c.name == col}
|
476
|
-
column.type.should == :string
|
477
|
-
end
|
478
|
-
end
|
479
|
-
|
480
|
-
it "should set CHAR/VARCHAR2 column type as boolean if emulate_booleans_from_strings is true" do
|
481
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
482
|
-
columns = @conn.columns('test3_employees')
|
483
|
-
%w(has_email has_phone active_flag manager_yn).each do |col|
|
484
|
-
column = columns.detect{|c| c.name == col}
|
485
|
-
column.type.should == :boolean
|
486
|
-
end
|
487
|
-
end
|
488
|
-
|
489
|
-
it "should set VARCHAR2 column type as string if column name does not contain 'flag' or 'yn' and emulate_booleans_from_strings is true" do
|
490
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
491
|
-
columns = @conn.columns('test3_employees')
|
492
|
-
%w(phone_number email).each do |col|
|
493
|
-
column = columns.detect{|c| c.name == col}
|
494
|
-
column.type.should == :string
|
495
|
-
end
|
496
|
-
end
|
497
|
-
|
498
|
-
it "should return string value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
|
499
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
500
|
-
columns = @conn.columns('test3_employees')
|
501
|
-
%w(has_email has_phone active_flag manager_yn).each do |col|
|
502
|
-
column = columns.detect{|c| c.name == col}
|
503
|
-
column.type_cast("Y").class.should == String
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
|
508
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
509
|
-
columns = @conn.columns('test3_employees')
|
510
|
-
%w(has_email has_phone active_flag manager_yn).each do |col|
|
511
|
-
column = columns.detect{|c| c.name == col}
|
512
|
-
column.type_cast("Y").class.should == TrueClass
|
513
|
-
column.type_cast("N").class.should == FalseClass
|
514
|
-
end
|
515
|
-
end
|
516
|
-
|
517
|
-
describe "/ VARCHAR2 boolean values from ActiveRecord model" do
|
518
|
-
before(:each) do
|
519
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
520
|
-
class Test3Employee < ActiveRecord::Base
|
521
|
-
end
|
522
|
-
end
|
523
|
-
|
524
|
-
after(:each) do
|
525
|
-
Object.send(:remove_const, "Test3Employee")
|
526
|
-
end
|
527
|
-
|
528
|
-
def create_employee3(params={})
|
529
|
-
@employee3 = Test3Employee.create(
|
530
|
-
{
|
531
|
-
:first_name => "First",
|
532
|
-
:last_name => "Last",
|
533
|
-
:has_email => true,
|
534
|
-
:has_phone => false,
|
535
|
-
:active_flag => true,
|
536
|
-
:manager_yn => false
|
537
|
-
}.merge(params)
|
538
|
-
)
|
539
|
-
@employee3.reload
|
540
|
-
end
|
541
|
-
|
542
|
-
it "should return String value from VARCHAR2 boolean column if emulate_booleans_from_strings is false" do
|
543
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = false
|
544
|
-
create_employee3
|
545
|
-
%w(has_email has_phone active_flag manager_yn).each do |col|
|
546
|
-
@employee3.send(col.to_sym).class.should == String
|
547
|
-
end
|
548
|
-
end
|
549
|
-
|
550
|
-
it "should return boolean value from VARCHAR2 boolean column if emulate_booleans_from_strings is true" do
|
551
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
552
|
-
create_employee3
|
553
|
-
%w(has_email active_flag).each do |col|
|
554
|
-
@employee3.send(col.to_sym).class.should == TrueClass
|
555
|
-
@employee3.send((col+"_before_type_cast").to_sym).should == "Y"
|
556
|
-
end
|
557
|
-
%w(has_phone manager_yn).each do |col|
|
558
|
-
@employee3.send(col.to_sym).class.should == FalseClass
|
559
|
-
@employee3.send((col+"_before_type_cast").to_sym).should == "N"
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
|
-
it "should return string value from VARCHAR2 column if it is not boolean column and emulate_booleans_from_strings is true" do
|
564
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
565
|
-
create_employee3
|
566
|
-
@employee3.first_name.class.should == String
|
567
|
-
end
|
568
|
-
|
569
|
-
it "should return boolean value from VARCHAR2 boolean column if column specified in set_boolean_columns" do
|
570
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
571
|
-
class Test3Employee < ActiveRecord::Base
|
572
|
-
set_boolean_columns :test_boolean
|
573
|
-
end
|
574
|
-
create_employee3(:test_boolean => true)
|
575
|
-
@employee3.test_boolean.class.should == TrueClass
|
576
|
-
@employee3.test_boolean_before_type_cast.should == "Y"
|
577
|
-
create_employee3(:test_boolean => false)
|
578
|
-
@employee3.test_boolean.class.should == FalseClass
|
579
|
-
@employee3.test_boolean_before_type_cast.should == "N"
|
580
|
-
end
|
581
|
-
|
582
|
-
end
|
583
|
-
|
584
|
-
end
|
585
|
-
|
586
|
-
|
587
168
|
describe "OracleEnhancedAdapter ignore specified table columns" do
|
588
169
|
before(:all) do
|
589
170
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
@@ -647,453 +228,223 @@ describe "OracleEnhancedAdapter ignore specified table columns" do
|
|
647
228
|
|
648
229
|
end
|
649
230
|
|
231
|
+
describe "OracleEnhancedAdapter table and sequence creation with non-default primary key" do
|
650
232
|
|
651
|
-
describe "OracleEnhancedAdapter timestamp with timezone support" do
|
652
233
|
before(:all) do
|
653
234
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
654
235
|
:database => "xe",
|
655
236
|
:username => "hr",
|
656
237
|
:password => "hr")
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
job_id NUMBER(6,0),
|
667
|
-
salary NUMBER(8,2),
|
668
|
-
commission_pct NUMBER(2,2),
|
669
|
-
manager_id NUMBER(6,0),
|
670
|
-
department_id NUMBER(4,0),
|
671
|
-
created_at TIMESTAMP,
|
672
|
-
created_at_tz TIMESTAMP WITH TIME ZONE,
|
673
|
-
created_at_ltz TIMESTAMP WITH LOCAL TIME ZONE
|
674
|
-
)
|
675
|
-
SQL
|
676
|
-
@conn.execute <<-SQL
|
677
|
-
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
678
|
-
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
679
|
-
SQL
|
680
|
-
end
|
681
|
-
|
682
|
-
after(:all) do
|
683
|
-
@conn.execute "DROP TABLE test_employees"
|
684
|
-
@conn.execute "DROP SEQUENCE test_employees_seq"
|
685
|
-
end
|
686
|
-
|
687
|
-
it "should set TIMESTAMP columns type as datetime" do
|
688
|
-
columns = @conn.columns('test_employees')
|
689
|
-
ts_columns = columns.select{|c| c.name =~ /created_at/}
|
690
|
-
ts_columns.each {|c| c.type.should == :timestamp}
|
691
|
-
end
|
692
|
-
|
693
|
-
describe "/ TIMESTAMP WITH TIME ZONE values from ActiveRecord model" do
|
694
|
-
before(:all) do
|
695
|
-
class TestEmployee < ActiveRecord::Base
|
696
|
-
set_primary_key :employee_id
|
238
|
+
ActiveRecord::Schema.define do
|
239
|
+
suppress_messages do
|
240
|
+
create_table :keyboards, :force => true, :id => false do |t|
|
241
|
+
t.primary_key :key_number
|
242
|
+
t.string :name
|
243
|
+
end
|
244
|
+
create_table :id_keyboards, :force => true do |t|
|
245
|
+
t.string :name
|
246
|
+
end
|
697
247
|
end
|
698
248
|
end
|
699
|
-
|
700
|
-
|
701
|
-
Object.send(:remove_const, "TestEmployee")
|
249
|
+
class Keyboard < ActiveRecord::Base
|
250
|
+
set_primary_key :key_number
|
702
251
|
end
|
703
|
-
|
704
|
-
it "should return Time value from TIMESTAMP columns" do
|
705
|
-
# currently fractional seconds are not retrieved from database
|
706
|
-
@now = Time.local(2008,5,26,23,11,11,0)
|
707
|
-
@employee = TestEmployee.create(
|
708
|
-
:created_at => @now,
|
709
|
-
:created_at_tz => @now,
|
710
|
-
:created_at_ltz => @now
|
711
|
-
)
|
712
|
-
@employee.reload
|
713
|
-
[:created_at, :created_at_tz, :created_at_ltz].each do |c|
|
714
|
-
@employee.send(c).class.should == Time
|
715
|
-
@employee.send(c).to_f.should == @now.to_f
|
716
|
-
end
|
252
|
+
class IdKeyboard < ActiveRecord::Base
|
717
253
|
end
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
723
|
-
:
|
724
|
-
:
|
725
|
-
:created_at_ltz => @now
|
726
|
-
)
|
727
|
-
@employee.reload
|
728
|
-
[:created_at, :created_at_tz, :created_at_ltz].each do |c|
|
729
|
-
@employee.send(c).class.should == Time
|
730
|
-
@employee.send(c).to_f.should == @now.to_f.to_i.to_f # remove fractional seconds
|
254
|
+
end
|
255
|
+
|
256
|
+
after(:all) do
|
257
|
+
ActiveRecord::Schema.define do
|
258
|
+
suppress_messages do
|
259
|
+
drop_table :keyboards
|
260
|
+
drop_table :id_keyboards
|
731
261
|
end
|
732
262
|
end
|
733
|
-
|
263
|
+
Object.send(:remove_const, "Keyboard")
|
264
|
+
Object.send(:remove_const, "IdKeyboard")
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should create sequence for non-default primary key" do
|
268
|
+
ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name).should_not be_nil
|
734
269
|
end
|
735
270
|
|
271
|
+
it "should create sequence for default primary key" do
|
272
|
+
ActiveRecord::Base.connection.next_sequence_value(IdKeyboard.sequence_name).should_not be_nil
|
273
|
+
end
|
736
274
|
end
|
737
275
|
|
276
|
+
describe "OracleEnhancedAdapter without composite_primary_keys" do
|
738
277
|
|
739
|
-
describe "OracleEnhancedAdapter date and timestamp with different NLS date formats" do
|
740
278
|
before(:all) do
|
741
279
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
742
280
|
:database => "xe",
|
743
281
|
:username => "hr",
|
744
282
|
:password => "hr")
|
745
|
-
|
746
|
-
|
747
|
-
CREATE TABLE test_employees (
|
748
|
-
employee_id NUMBER(6,0),
|
749
|
-
first_name VARCHAR2(20),
|
750
|
-
last_name VARCHAR2(25),
|
751
|
-
email VARCHAR2(25),
|
752
|
-
phone_number VARCHAR2(20),
|
753
|
-
hire_date DATE,
|
754
|
-
job_id NUMBER(6,0),
|
755
|
-
salary NUMBER(8,2),
|
756
|
-
commission_pct NUMBER(2,2),
|
757
|
-
manager_id NUMBER(6,0),
|
758
|
-
department_id NUMBER(4,0),
|
759
|
-
created_at DATE,
|
760
|
-
created_at_ts TIMESTAMP
|
761
|
-
)
|
762
|
-
SQL
|
763
|
-
@conn.execute <<-SQL
|
764
|
-
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
765
|
-
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
766
|
-
SQL
|
767
|
-
# @conn.execute %q{alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'}
|
768
|
-
@conn.execute %q{alter session set nls_date_format = 'DD-MON-YYYY HH24:MI:SS'}
|
769
|
-
# @conn.execute %q{alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS'}
|
770
|
-
@conn.execute %q{alter session set nls_timestamp_format = 'DD-MON-YYYY HH24:MI:SS'}
|
771
|
-
end
|
772
|
-
|
773
|
-
after(:all) do
|
774
|
-
@conn.execute "DROP TABLE test_employees"
|
775
|
-
@conn.execute "DROP SEQUENCE test_employees_seq"
|
776
|
-
end
|
777
|
-
|
778
|
-
before(:each) do
|
779
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = false
|
780
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
781
|
-
class TestEmployee < ActiveRecord::Base
|
283
|
+
Object.send(:remove_const, 'CompositePrimaryKeys') if defined?(CompositePrimaryKeys)
|
284
|
+
class Employee < ActiveRecord::Base
|
782
285
|
set_primary_key :employee_id
|
783
286
|
end
|
784
|
-
@today = Date.new(2008,6,28)
|
785
|
-
@now = Time.local(2008,6,28,13,34,33)
|
786
287
|
end
|
787
288
|
|
788
|
-
|
789
|
-
|
790
|
-
end
|
791
|
-
|
792
|
-
def create_test_employee
|
793
|
-
@employee = TestEmployee.create(
|
794
|
-
:first_name => "First",
|
795
|
-
:last_name => "Last",
|
796
|
-
:hire_date => @today,
|
797
|
-
:created_at => @now,
|
798
|
-
:created_at_ts => @now
|
799
|
-
)
|
800
|
-
@employee.reload
|
801
|
-
end
|
802
|
-
|
803
|
-
it "should return Time value from DATE column if emulate_dates_by_column_name is false" do
|
804
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = false
|
805
|
-
create_test_employee
|
806
|
-
@employee.hire_date.class.should == Time
|
807
|
-
@employee.hire_date.should == @today.to_time
|
808
|
-
end
|
809
|
-
|
810
|
-
it "should return Date value from DATE column if column name contains 'date' and emulate_dates_by_column_name is true" do
|
811
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
812
|
-
create_test_employee
|
813
|
-
@employee.hire_date.class.should == Date
|
814
|
-
@employee.hire_date.should == @today
|
815
|
-
end
|
816
|
-
|
817
|
-
it "should return Time value from DATE column if column name does not contain 'date' and emulate_dates_by_column_name is true" do
|
818
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
819
|
-
create_test_employee
|
820
|
-
@employee.created_at.class.should == Time
|
821
|
-
@employee.created_at.should == @now
|
822
|
-
end
|
823
|
-
|
824
|
-
it "should return Time value from TIMESTAMP columns" do
|
825
|
-
create_test_employee
|
826
|
-
@employee.created_at_ts.class.should == Time
|
827
|
-
@employee.created_at_ts.should == @now
|
828
|
-
end
|
829
|
-
|
830
|
-
it "should quote Date values with TO_DATE" do
|
831
|
-
@conn.quote(@today).should == "TO_DATE('#{@today.year}-#{"%02d" % @today.month}-#{"%02d" % @today.day}','YYYY-MM-DD HH24:MI:SS')"
|
832
|
-
end
|
833
|
-
|
834
|
-
it "should quote Time values with TO_DATE" do
|
835
|
-
@conn.quote(@now).should == "TO_DATE('#{@now.year}-#{"%02d" % @now.month}-#{"%02d" % @now.day} "+
|
836
|
-
"#{"%02d" % @now.hour}:#{"%02d" % @now.min}:#{"%02d" % @now.sec}','YYYY-MM-DD HH24:MI:SS')"
|
289
|
+
it "should tell ActiveRecord that count distinct is supported" do
|
290
|
+
ActiveRecord::Base.connection.supports_count_distinct?.should be_true
|
837
291
|
end
|
838
292
|
|
839
|
-
it "should
|
840
|
-
|
841
|
-
@conn.quote(@ts).should == "TO_TIMESTAMP('#{@ts.year}-#{"%02d" % @ts.month}-#{"%02d" % @ts.day} "+
|
842
|
-
"#{"%02d" % @ts.hour}:#{"%02d" % @ts.min}:#{"%02d" % @ts.sec}.100000','YYYY-MM-DD HH24:MI:SS.FF6')"
|
293
|
+
it "should execute correct SQL COUNT DISTINCT statement" do
|
294
|
+
lambda { Employee.count(:employee_id, :distinct => true) }.should_not raise_error
|
843
295
|
end
|
844
296
|
|
845
297
|
end
|
846
298
|
|
847
|
-
describe "OracleEnhancedAdapter
|
299
|
+
describe "OracleEnhancedAdapter sequence creation parameters" do
|
300
|
+
|
848
301
|
before(:all) do
|
849
302
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
850
303
|
:database => "xe",
|
851
304
|
:username => "hr",
|
852
305
|
:password => "hr")
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
SQL
|
864
|
-
@conn.execute <<-SQL
|
865
|
-
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
866
|
-
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
867
|
-
SQL
|
868
|
-
class TestEmployee < ActiveRecord::Base
|
869
|
-
set_primary_key :employee_id
|
306
|
+
end
|
307
|
+
|
308
|
+
def create_test_employees_table(sequence_start_value = nil)
|
309
|
+
ActiveRecord::Schema.define do
|
310
|
+
suppress_messages do
|
311
|
+
create_table :test_employees, sequence_start_value ? {:sequence_start_value => sequence_start_value} : {} do |t|
|
312
|
+
t.string :first_name
|
313
|
+
t.string :last_name
|
314
|
+
end
|
315
|
+
end
|
870
316
|
end
|
871
317
|
end
|
872
318
|
|
873
|
-
|
874
|
-
|
875
|
-
|
876
|
-
|
319
|
+
def save_default_sequence_start_value
|
320
|
+
@saved_sequence_start_value = ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value
|
321
|
+
end
|
322
|
+
|
323
|
+
def restore_default_sequence_start_value
|
324
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = @saved_sequence_start_value
|
877
325
|
end
|
878
326
|
|
879
327
|
before(:each) do
|
880
|
-
|
881
|
-
@today_iso = "2008-06-28"
|
882
|
-
@today_nls = "28.06.2008"
|
883
|
-
@nls_date_format = "%d.%m.%Y"
|
884
|
-
@now = Time.local(2008,6,28,13,34,33)
|
885
|
-
@now_iso = "2008-06-28 13:34:33"
|
886
|
-
@now_nls = "28.06.2008 13:34:33"
|
887
|
-
@nls_time_format = "%d.%m.%Y %H:%M:%S"
|
888
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
328
|
+
save_default_sequence_start_value
|
889
329
|
end
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
@employee.hire_date.should == @today
|
330
|
+
after(:each) do
|
331
|
+
restore_default_sequence_start_value
|
332
|
+
ActiveRecord::Schema.define do
|
333
|
+
suppress_messages do
|
334
|
+
drop_table :test_employees
|
335
|
+
end
|
336
|
+
end
|
337
|
+
Object.send(:remove_const, "TestEmployee")
|
899
338
|
end
|
900
339
|
|
901
|
-
it "should
|
902
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.
|
903
|
-
@employee = TestEmployee.create(
|
904
|
-
:first_name => "First",
|
905
|
-
:last_name => "Last",
|
906
|
-
:hire_date => @today_nls
|
907
|
-
)
|
908
|
-
@employee.reload
|
909
|
-
@employee.hire_date.should == @today
|
910
|
-
end
|
340
|
+
it "should use default sequence start value 10000" do
|
341
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value.should == 10000
|
911
342
|
|
912
|
-
|
913
|
-
|
914
|
-
:first_name => "First",
|
915
|
-
:last_name => "Last",
|
916
|
-
:hire_date => @now_iso
|
917
|
-
)
|
918
|
-
@employee.reload
|
919
|
-
@employee.hire_date.should == @today
|
920
|
-
end
|
343
|
+
create_test_employees_table
|
344
|
+
class TestEmployee < ActiveRecord::Base; end
|
921
345
|
|
922
|
-
|
923
|
-
|
924
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
|
925
|
-
@employee = TestEmployee.create(
|
926
|
-
:first_name => "First",
|
927
|
-
:last_name => "Last",
|
928
|
-
:hire_date => @now_nls
|
929
|
-
)
|
930
|
-
@employee.reload
|
931
|
-
@employee.hire_date.should == @today
|
346
|
+
employee = TestEmployee.create!
|
347
|
+
employee.id.should == 10000
|
932
348
|
end
|
933
349
|
|
934
|
-
it "should
|
935
|
-
|
936
|
-
:first_name => "First",
|
937
|
-
:last_name => "Last",
|
938
|
-
:last_login_at => @now_iso
|
939
|
-
)
|
940
|
-
@employee.reload
|
941
|
-
@employee.last_login_at.should == @now
|
942
|
-
end
|
350
|
+
it "should use specified default sequence start value" do
|
351
|
+
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
|
943
352
|
|
944
|
-
|
945
|
-
|
946
|
-
ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
|
947
|
-
@employee = TestEmployee.create(
|
948
|
-
:first_name => "First",
|
949
|
-
:last_name => "Last",
|
950
|
-
:last_login_at => @now_nls
|
951
|
-
)
|
952
|
-
@employee.reload
|
953
|
-
@employee.last_login_at.should == @now
|
954
|
-
end
|
955
|
-
|
956
|
-
it "should assign ISO date string to datetime column" do
|
957
|
-
@employee = TestEmployee.create(
|
958
|
-
:first_name => "First",
|
959
|
-
:last_name => "Last",
|
960
|
-
:last_login_at => @today_iso
|
961
|
-
)
|
962
|
-
@employee.reload
|
963
|
-
@employee.last_login_at.should == @today.to_time
|
964
|
-
end
|
353
|
+
create_test_employees_table
|
354
|
+
class TestEmployee < ActiveRecord::Base; end
|
965
355
|
|
966
|
-
|
967
|
-
|
968
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = @nls_time_format
|
969
|
-
@employee = TestEmployee.create(
|
970
|
-
:first_name => "First",
|
971
|
-
:last_name => "Last",
|
972
|
-
:last_login_at => @today_nls
|
973
|
-
)
|
974
|
-
@employee.reload
|
975
|
-
@employee.last_login_at.should == @today.to_time
|
356
|
+
employee = TestEmployee.create!
|
357
|
+
employee.id.should == 1
|
976
358
|
end
|
977
|
-
|
978
|
-
end
|
979
359
|
|
980
|
-
|
981
|
-
|
982
|
-
ActiveRecord::Base
|
983
|
-
:database => "xe",
|
984
|
-
:username => "hr",
|
985
|
-
:password => "hr")
|
986
|
-
@conn = ActiveRecord::Base.connection
|
987
|
-
@conn.execute <<-SQL
|
988
|
-
CREATE TABLE test_employees (
|
989
|
-
employee_id NUMBER(6,0),
|
990
|
-
first_name VARCHAR2(20),
|
991
|
-
last_name VARCHAR2(25),
|
992
|
-
comments CLOB
|
993
|
-
)
|
994
|
-
SQL
|
995
|
-
@conn.execute <<-SQL
|
996
|
-
CREATE SEQUENCE test_employees_seq MINVALUE 1
|
997
|
-
INCREMENT BY 1 CACHE 20 NOORDER NOCYCLE
|
998
|
-
SQL
|
999
|
-
class TestEmployee < ActiveRecord::Base
|
1000
|
-
set_primary_key :employee_id
|
1001
|
-
end
|
1002
|
-
end
|
1003
|
-
|
1004
|
-
after(:all) do
|
1005
|
-
Object.send(:remove_const, "TestEmployee")
|
1006
|
-
@conn.execute "DROP TABLE test_employees"
|
1007
|
-
@conn.execute "DROP SEQUENCE test_employees_seq"
|
1008
|
-
end
|
360
|
+
it "should use sequence start value from table definition" do
|
361
|
+
create_test_employees_table(10)
|
362
|
+
class TestEmployee < ActiveRecord::Base; end
|
1009
363
|
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
it "should create record without CLOB data when attribute is serialized" do
|
1014
|
-
TestEmployee.serialize :comments
|
1015
|
-
@employee = TestEmployee.create!(
|
1016
|
-
:first_name => "First",
|
1017
|
-
:last_name => "Last"
|
1018
|
-
)
|
1019
|
-
@employee.should be_valid
|
364
|
+
employee = TestEmployee.create!
|
365
|
+
employee.id.should == 10
|
1020
366
|
end
|
1021
367
|
|
1022
|
-
it "should
|
1023
|
-
|
1024
|
-
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
TestEmployee.find(:all, :order => "comments").should_not be_empty
|
1031
|
-
TestEmployee.find(:all, :order => " comments ").should_not be_empty
|
1032
|
-
TestEmployee.find(:all, :order => :comments).should_not be_empty
|
1033
|
-
TestEmployee.find(:all, :order => " first_name DESC, last_name ASC ").should_not be_empty
|
368
|
+
it "should use sequence start value and other options from table definition" do
|
369
|
+
create_test_employees_table("100 NOCACHE INCREMENT BY 10")
|
370
|
+
class TestEmployee < ActiveRecord::Base; end
|
371
|
+
|
372
|
+
employee = TestEmployee.create!
|
373
|
+
employee.id.should == 100
|
374
|
+
employee = TestEmployee.create!
|
375
|
+
employee.id.should == 110
|
1034
376
|
end
|
1035
|
-
|
377
|
+
|
1036
378
|
end
|
1037
379
|
|
1038
|
-
describe "OracleEnhancedAdapter table and
|
380
|
+
describe "OracleEnhancedAdapter table and column comments" do
|
381
|
+
|
1039
382
|
before(:all) do
|
1040
383
|
ActiveRecord::Base.establish_connection(:adapter => "oracle_enhanced",
|
1041
384
|
:database => "xe",
|
1042
385
|
:username => "hr",
|
1043
386
|
:password => "hr")
|
387
|
+
@conn = ActiveRecord::Base.connection
|
388
|
+
end
|
389
|
+
|
390
|
+
def create_test_employees_table(table_comment=nil, column_comments={})
|
1044
391
|
ActiveRecord::Schema.define do
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
t.string :name
|
392
|
+
suppress_messages do
|
393
|
+
create_table :test_employees, :comment => table_comment do |t|
|
394
|
+
t.string :first_name, :comment => column_comments[:first_name]
|
395
|
+
t.string :last_name, :comment => column_comments[:last_name]
|
396
|
+
end
|
1051
397
|
end
|
1052
398
|
end
|
1053
|
-
class Keyboard < ActiveRecord::Base
|
1054
|
-
set_primary_key :key_number
|
1055
|
-
end
|
1056
|
-
class IdKeyboard < ActiveRecord::Base
|
1057
|
-
end
|
1058
399
|
end
|
1059
|
-
|
1060
|
-
after(:
|
400
|
+
|
401
|
+
after(:each) do
|
1061
402
|
ActiveRecord::Schema.define do
|
1062
|
-
|
1063
|
-
|
403
|
+
suppress_messages do
|
404
|
+
drop_table :test_employees
|
405
|
+
end
|
1064
406
|
end
|
1065
|
-
Object.send(:remove_const, "
|
1066
|
-
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
it "should create sequence for non-default primary key" do
|
1070
|
-
ActiveRecord::Base.connection.next_sequence_value(Keyboard.sequence_name).should_not be_nil
|
407
|
+
Object.send(:remove_const, "TestEmployee")
|
408
|
+
ActiveRecord::Base.table_name_prefix = nil
|
1071
409
|
end
|
1072
410
|
|
1073
|
-
it "should create
|
1074
|
-
|
411
|
+
it "should create table with table comment" do
|
412
|
+
table_comment = "Test Employees"
|
413
|
+
create_test_employees_table(table_comment)
|
414
|
+
class TestEmployee < ActiveRecord::Base; end
|
415
|
+
|
416
|
+
@conn.table_comment("test_employees").should == table_comment
|
417
|
+
TestEmployee.table_comment.should == table_comment
|
1075
418
|
end
|
1076
|
-
end
|
1077
419
|
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
ActiveRecord::Base
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
420
|
+
it "should create table with columns comment" do
|
421
|
+
column_comments = {:first_name => "Given Name", :last_name => "Surname"}
|
422
|
+
create_test_employees_table(nil, column_comments)
|
423
|
+
class TestEmployee < ActiveRecord::Base; end
|
424
|
+
|
425
|
+
[:first_name, :last_name].each do |attr|
|
426
|
+
@conn.column_comment("test_employees", attr.to_s).should == column_comments[attr]
|
427
|
+
end
|
428
|
+
[:first_name, :last_name].each do |attr|
|
429
|
+
TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
|
1088
430
|
end
|
1089
431
|
end
|
1090
432
|
|
1091
|
-
it "should
|
1092
|
-
ActiveRecord::Base.
|
1093
|
-
|
1094
|
-
|
1095
|
-
|
1096
|
-
|
433
|
+
it "should create table with table and columns comment and custom table name prefix" do
|
434
|
+
ActiveRecord::Base.table_name_prefix = "xxx_"
|
435
|
+
table_comment = "Test Employees"
|
436
|
+
column_comments = {:first_name => "Given Name", :last_name => "Surname"}
|
437
|
+
create_test_employees_table(table_comment, column_comments)
|
438
|
+
class TestEmployee < ActiveRecord::Base; end
|
439
|
+
|
440
|
+
@conn.table_comment(TestEmployee.table_name).should == table_comment
|
441
|
+
TestEmployee.table_comment.should == table_comment
|
442
|
+
[:first_name, :last_name].each do |attr|
|
443
|
+
@conn.column_comment(TestEmployee.table_name, attr.to_s).should == column_comments[attr]
|
444
|
+
end
|
445
|
+
[:first_name, :last_name].each do |attr|
|
446
|
+
TestEmployee.columns_hash[attr.to_s].comment.should == column_comments[attr]
|
447
|
+
end
|
1097
448
|
end
|
1098
449
|
|
1099
450
|
end
|