activerecord-oracle_enhanced-adapter 1.1.8 → 1.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|