activerecord-oracle_enhanced-adapter 1.2.1 → 1.2.2
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 +34 -0
- data/README.rdoc +10 -5
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced.rake +4 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +534 -170
- data/lib/active_record/connection_adapters/oracle_enhanced_connection.rb +53 -3
- data/lib/active_record/connection_adapters/oracle_enhanced_core_ext.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced_cpk.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced_dirty.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced_jdbc_connection.rb +86 -58
- data/lib/active_record/connection_adapters/oracle_enhanced_oci_connection.rb +105 -68
- data/lib/active_record/connection_adapters/oracle_enhanced_procedures.rb +27 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_definitions.rb +164 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_dumper.rb +122 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_schema_statements_ext.rb +224 -0
- data/lib/active_record/connection_adapters/oracle_enhanced_tasks.rb +2 -2
- data/lib/active_record/connection_adapters/oracle_enhanced_version.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +230 -455
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +37 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_core_ext_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +6 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +21 -4
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +63 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +1 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +1 -1
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +255 -0
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_spec.rb +720 -0
- data/spec/spec_helper.rb +38 -7
- metadata +13 -15
data/History.txt
CHANGED
@@ -1,3 +1,37 @@
|
|
1
|
+
== 1.2.2 2009-09-28
|
2
|
+
|
3
|
+
* Enhancements
|
4
|
+
* improved RDoc documentation of public methods
|
5
|
+
* structure dump optionally (database.yml environment has db_stored_code: yes) extracts
|
6
|
+
packages, procedures, functions, views, triggers and synonyms
|
7
|
+
* automatically generated too long index names are shortened down to 30 characters
|
8
|
+
* create tables with primary key triggers
|
9
|
+
* use 'set_sequence_name :autogenerated' for inserting into legacy tables with trigger populated primary keys
|
10
|
+
* access to tables over database link (need to define local synonym to remote table and use local synonym in set_table_name)
|
11
|
+
* [JRuby] support JDBC connection using TNS_ADMIN environment variable and TNS database alias
|
12
|
+
* changed cursor_sharing option default from 'similar' to 'force'
|
13
|
+
* optional dbms_output logging to ActiveRecord log file (requires ruby-plsql gem)
|
14
|
+
* use add_foreign_key and remove_foreign_key to define foreign key constraints
|
15
|
+
(the same syntax as in http://github.com/matthuhiggins/foreigner and similar
|
16
|
+
to http://github.com/eyestreet/active_record_oracle_extensions)
|
17
|
+
* raise RecordNotUnique and InvalidForeignKey exceptions if caused by corresponding ORA errors
|
18
|
+
(these new exceptions are supported just by current ActiveRecord master branch)
|
19
|
+
* implemented disable_referential_integrity
|
20
|
+
(enables safe loading of fixtures in schema with foreign key constraints)
|
21
|
+
* use add_synonym and remove_synonym to define database synonyms
|
22
|
+
* add_foreign_key and add_synonym are also exported to schema.rb
|
23
|
+
* Bug fixes:
|
24
|
+
* [JRuby] do not raise LoadError if ojdbc14.jar cannot be required (rely on application server to add it to class path)
|
25
|
+
* [JRuby] 'execute' can be used to create triggers with :NEW reference
|
26
|
+
* support create_table without a block
|
27
|
+
* support create_table with Symbol table name
|
28
|
+
* use ActiveRecord functionality to do time zone conversion
|
29
|
+
* rake tasks such as db:test:clone are redefined only if oracle_enhanced is current adapter in use
|
30
|
+
* VARCHAR2 and CHAR column sizes are defined in characters and not in bytes (expected behavior from ActiveRecord)
|
31
|
+
* set_date_columns, set_datetime_columns, ignore_table_columns will work after reestablishing connection
|
32
|
+
* ignore :limit option for :text and :binary columns in migrations
|
33
|
+
* patches for ActiveRecord schema dumper to remove table prefixes and suffixes from schema.rb
|
34
|
+
|
1
35
|
== 1.2.1 2009-06-07
|
2
36
|
|
3
37
|
* Enhancements
|
data/README.rdoc
CHANGED
@@ -1,13 +1,15 @@
|
|
1
|
-
=
|
1
|
+
= Activerecord Oracle enhanced adapter
|
2
2
|
|
3
|
-
* http://
|
3
|
+
* http://github.com/rsim/oracle-enhanced
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
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://github.com/rsim/oracle-enhanced/wikis for
|
10
|
+
See http://github.com/rsim/oracle-enhanced/wikis for usage information.
|
11
|
+
|
12
|
+
See http://oracle-enhanced.rubyforge.org/rdoc for detailed API documentation.
|
11
13
|
|
12
14
|
For questions and feature discussion please use http://groups.google.com/group/oracle-enhanced
|
13
15
|
|
@@ -22,12 +24,12 @@ Bugs and enhancement requests can be reported at http://rsim.lighthouseapp.com/p
|
|
22
24
|
* MRI - requires ruby-oci8 1.x or 2.x library to connect to Oracle
|
23
25
|
* Ruby/YARV 1.9.1 - requires ruby-oci8 2.x library to connect to Oracle
|
24
26
|
unicode_utils gem is recommended for Unicode aware string upcase and downcase
|
25
|
-
* JRuby - uses JDBC driver ojdbc14.jar to connect to Oracle (should be in JRUBY_HOME/lib or in
|
27
|
+
* JRuby - uses JDBC driver ojdbc14.jar to connect to Oracle (should be in JRUBY_HOME/lib or in Java class path)
|
26
28
|
* 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)
|
27
29
|
|
28
30
|
== INSTALL:
|
29
31
|
|
30
|
-
* sudo gem install activerecord-oracle_enhanced-adapter
|
32
|
+
* [sudo] gem install activerecord-oracle_enhanced-adapter
|
31
33
|
|
32
34
|
== CONTRIBUTORS:
|
33
35
|
|
@@ -39,6 +41,9 @@ Bugs and enhancement requests can be reported at http://rsim.lighthouseapp.com/p
|
|
39
41
|
* Edgars Beigarts
|
40
42
|
* Lachlan Laycock
|
41
43
|
* toddwf
|
44
|
+
* Anton Jenkins
|
45
|
+
* Dave Smylie
|
46
|
+
* Alex Rothenberg
|
42
47
|
|
43
48
|
== LICENSE:
|
44
49
|
|
@@ -20,6 +20,10 @@ namespace :db do
|
|
20
20
|
if ActiveRecord::Base.connection.supports_migrations?
|
21
21
|
File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
|
22
22
|
end
|
23
|
+
if abcs[RAILS_ENV]['structure_dump'] == "db_stored_code"
|
24
|
+
File.open("db/#{RAILS_ENV}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.structure_dump_db_stored_code }
|
25
|
+
end
|
26
|
+
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
@@ -32,9 +32,12 @@ require 'active_record/connection_adapters/abstract_adapter'
|
|
32
32
|
|
33
33
|
require 'active_record/connection_adapters/oracle_enhanced_connection'
|
34
34
|
|
35
|
+
require 'digest/sha1'
|
36
|
+
|
35
37
|
module ActiveRecord
|
36
38
|
class Base
|
37
|
-
|
39
|
+
# Establishes a connection to the database that's used by all Active Record objects.
|
40
|
+
def self.oracle_enhanced_connection(config) #:nodoc:
|
38
41
|
if config[:emulate_oracle_adapter] == true
|
39
42
|
# allows the enhanced adapter to look like the OracleAdapter. Useful to pick up
|
40
43
|
# conditionals in the rails activerecord test suite
|
@@ -47,22 +50,30 @@ module ActiveRecord
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
|
50
|
-
#
|
53
|
+
# Specify table columns which should be ignored by ActiveRecord, e.g.:
|
54
|
+
#
|
55
|
+
# ignore_table_columns :attribute1, :attribute2
|
51
56
|
def self.ignore_table_columns(*args)
|
52
57
|
connection.ignore_table_columns(table_name,*args)
|
53
58
|
end
|
54
59
|
|
55
|
-
#
|
60
|
+
# Specify which table columns should be typecasted to Date (without time), e.g.:
|
61
|
+
#
|
62
|
+
# set_date_columns :created_on, :updated_on
|
56
63
|
def self.set_date_columns(*args)
|
57
64
|
connection.set_type_for_columns(table_name,:date,*args)
|
58
65
|
end
|
59
66
|
|
60
|
-
#
|
67
|
+
# Specify which table columns should be typecasted to Time (or DateTime), e.g.:
|
68
|
+
#
|
69
|
+
# set_datetime_columns :created_date, :updated_date
|
61
70
|
def self.set_datetime_columns(*args)
|
62
71
|
connection.set_type_for_columns(table_name,:datetime,*args)
|
63
72
|
end
|
64
73
|
|
65
|
-
#
|
74
|
+
# Specify which table columns should be typecasted to boolean values +true+ or +false+, e.g.:
|
75
|
+
#
|
76
|
+
# set_boolean_columns :is_valid, :is_completed
|
66
77
|
def self.set_boolean_columns(*args)
|
67
78
|
connection.set_type_for_columns(table_name,:boolean,*args)
|
68
79
|
end
|
@@ -79,7 +90,7 @@ module ActiveRecord
|
|
79
90
|
private :enhanced_write_lobs
|
80
91
|
|
81
92
|
class << self
|
82
|
-
#
|
93
|
+
# patch ORDER BY to work with LOBs
|
83
94
|
def add_order_with_lobs!(sql, order, scope = :auto)
|
84
95
|
if connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter)
|
85
96
|
order = connection.lob_order_by_expression(self, order) if order
|
@@ -98,11 +109,13 @@ module ActiveRecord
|
|
98
109
|
add_order_without_lobs!(sql, order, scope = :auto)
|
99
110
|
end
|
100
111
|
private :add_order_with_lobs!
|
112
|
+
#:stopdoc:
|
101
113
|
alias_method :add_order_without_lobs!, :add_order!
|
102
114
|
alias_method :add_order!, :add_order_with_lobs!
|
115
|
+
#:startdoc:
|
103
116
|
end
|
104
117
|
|
105
|
-
#
|
118
|
+
# Get table comment from schema definition.
|
106
119
|
def self.table_comment
|
107
120
|
connection.table_comment(self.table_name)
|
108
121
|
end
|
@@ -110,24 +123,24 @@ module ActiveRecord
|
|
110
123
|
|
111
124
|
|
112
125
|
module ConnectionAdapters #:nodoc:
|
113
|
-
class OracleEnhancedColumn < Column
|
126
|
+
class OracleEnhancedColumn < Column
|
114
127
|
|
115
|
-
attr_reader :table_name, :forced_column_type
|
128
|
+
attr_reader :table_name, :forced_column_type #:nodoc:
|
116
129
|
|
117
|
-
def initialize(name, default, sql_type = nil, null = true, table_name = nil, forced_column_type = nil)
|
130
|
+
def initialize(name, default, sql_type = nil, null = true, table_name = nil, forced_column_type = nil) #:nodoc:
|
118
131
|
@table_name = table_name
|
119
132
|
@forced_column_type = forced_column_type
|
120
133
|
super(name, default, sql_type, null)
|
121
134
|
end
|
122
135
|
|
123
|
-
def type_cast(value)
|
136
|
+
def type_cast(value) #:nodoc:
|
124
137
|
return guess_date_or_time(value) if type == :datetime && OracleEnhancedAdapter.emulate_dates
|
125
138
|
super
|
126
139
|
end
|
127
140
|
|
128
141
|
# convert something to a boolean
|
129
|
-
#
|
130
|
-
def self.value_to_boolean(value)
|
142
|
+
# added y as boolean value
|
143
|
+
def self.value_to_boolean(value) #:nodoc:
|
131
144
|
if value == true || value == false
|
132
145
|
value
|
133
146
|
elsif value.is_a?(String) && value.blank?
|
@@ -137,20 +150,20 @@ module ActiveRecord
|
|
137
150
|
end
|
138
151
|
end
|
139
152
|
|
140
|
-
#
|
141
|
-
def self.string_to_date(string)
|
153
|
+
# convert Time or DateTime value to Date for :date columns
|
154
|
+
def self.string_to_date(string) #:nodoc:
|
142
155
|
return string.to_date if string.is_a?(Time) || string.is_a?(DateTime)
|
143
156
|
super
|
144
157
|
end
|
145
158
|
|
146
|
-
#
|
147
|
-
def self.string_to_time(string)
|
159
|
+
# convert Date value to Time for :datetime columns
|
160
|
+
def self.string_to_time(string) #:nodoc:
|
148
161
|
return string.to_time if string.is_a?(Date) && !OracleEnhancedAdapter.emulate_dates
|
149
162
|
super
|
150
163
|
end
|
151
164
|
|
152
|
-
#
|
153
|
-
#
|
165
|
+
# Get column comment from schema definition.
|
166
|
+
# Will work only if using default ActiveRecord connection.
|
154
167
|
def comment
|
155
168
|
ActiveRecord::Base.connection.column_comment(@table_name, name)
|
156
169
|
end
|
@@ -171,7 +184,7 @@ module ActiveRecord
|
|
171
184
|
when /time/i then :datetime
|
172
185
|
when /decimal|numeric|number/i
|
173
186
|
return :integer if extract_scale(field_type) == 0
|
174
|
-
#
|
187
|
+
# if column name is ID or ends with _ID
|
175
188
|
return :integer if OracleEnhancedAdapter.emulate_integers_by_column_name && OracleEnhancedAdapter.is_integer_column?(name, table_name)
|
176
189
|
:decimal
|
177
190
|
else super
|
@@ -186,21 +199,21 @@ module ActiveRecord
|
|
186
199
|
class <<self
|
187
200
|
protected
|
188
201
|
|
189
|
-
def fallback_string_to_date(string)
|
202
|
+
def fallback_string_to_date(string) #:nodoc:
|
190
203
|
if OracleEnhancedAdapter.string_to_date_format || OracleEnhancedAdapter.string_to_time_format
|
191
204
|
return (string_to_date_or_time_using_format(string).to_date rescue super)
|
192
205
|
end
|
193
206
|
super
|
194
207
|
end
|
195
208
|
|
196
|
-
def fallback_string_to_time(string)
|
209
|
+
def fallback_string_to_time(string) #:nodoc:
|
197
210
|
if OracleEnhancedAdapter.string_to_time_format || OracleEnhancedAdapter.string_to_date_format
|
198
211
|
return (string_to_date_or_time_using_format(string).to_time rescue super)
|
199
212
|
end
|
200
213
|
super
|
201
214
|
end
|
202
215
|
|
203
|
-
def string_to_date_or_time_using_format(string)
|
216
|
+
def string_to_date_or_time_using_format(string) #:nodoc:
|
204
217
|
if OracleEnhancedAdapter.string_to_time_format && dt=Date._strptime(string, OracleEnhancedAdapter.string_to_time_format)
|
205
218
|
return Time.mktime(*dt.values_at(:year, :mon, :mday, :hour, :min, :sec, :zone, :wday))
|
206
219
|
end
|
@@ -211,54 +224,94 @@ module ActiveRecord
|
|
211
224
|
end
|
212
225
|
|
213
226
|
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
227
|
+
# Oracle enhanced adapter will work with both
|
228
|
+
# Ruby 1.8/1.9 ruby-oci8 gem (which provides interface to Oracle OCI client)
|
229
|
+
# or with JRuby and Oracle JDBC driver.
|
230
|
+
#
|
231
|
+
# It should work with Oracle 9i, 10g and 11g databases.
|
232
|
+
# Limited set of functionality should work on Oracle 8i as well but several features
|
233
|
+
# rely on newer functionality in Oracle database.
|
219
234
|
#
|
220
235
|
# Usage notes:
|
221
236
|
# * Key generation assumes a "${table_name}_seq" sequence is available
|
222
237
|
# for all tables; the sequence name can be changed using
|
223
238
|
# ActiveRecord::Base.set_sequence_name. When using Migrations, these
|
224
239
|
# sequences are created automatically.
|
240
|
+
# Use set_sequence_name :autogenerated with legacy tables that have
|
241
|
+
# triggers that populate primary keys automatically.
|
225
242
|
# * Oracle uses DATE or TIMESTAMP datatypes for both dates and times.
|
226
243
|
# Consequently some hacks are employed to map data back to Date or Time
|
227
|
-
# in Ruby.
|
228
|
-
# Else if the hours/minutes/seconds are 0, I make it a Ruby Date. Else
|
229
|
-
# it's a Ruby Time. This is a bit nasty - but if you use Duck Typing
|
230
|
-
# you'll probably not care very much. In 9i and up it's tempting to
|
231
|
-
# map DATE to Date and TIMESTAMP to Time, but too many databases use
|
232
|
-
# DATE for both. Timezones and sub-second precision on timestamps are
|
244
|
+
# in Ruby. Timezones and sub-second precision on timestamps are
|
233
245
|
# not supported.
|
234
246
|
# * Default values that are functions (such as "SYSDATE") are not
|
235
247
|
# supported. This is a restriction of the way ActiveRecord supports
|
236
248
|
# default values.
|
237
|
-
# * Support for Oracle8 is limited by Rails' use of ANSI join syntax, which
|
238
|
-
# is supported in Oracle9i and later. You will need to use #finder_sql for
|
239
|
-
# has_and_belongs_to_many associations to run against Oracle8.
|
240
249
|
#
|
241
250
|
# Required parameters:
|
242
251
|
#
|
243
252
|
# * <tt>:username</tt>
|
244
253
|
# * <tt>:password</tt>
|
245
|
-
# * <tt>:database</tt>
|
254
|
+
# * <tt>:database</tt> - either TNS alias or connection string for OCI client or database name in JDBC connection string
|
255
|
+
#
|
256
|
+
# Optional parameters:
|
257
|
+
#
|
258
|
+
# * <tt>:host</tt> - host name for JDBC connection, defaults to "localhost"
|
259
|
+
# * <tt>:port</tt> - port number for JDBC connection, defaults to 1521
|
260
|
+
# * <tt>:privilege</tt> - set "SYSDBA" if you want to connect with this privilege
|
261
|
+
# * <tt>:allow_concurrency</tt> - set to "true" if non-blocking mode should be enabled (just for OCI client)
|
262
|
+
# * <tt>:prefetch_rows</tt> - how many rows should be fetched at one time to increase performance, defaults to 100
|
263
|
+
# * <tt>:cursor_sharing</tt> - cursor sharing mode to minimize amount of unique statements, defaults to "force"
|
264
|
+
# * <tt>:nls_length_semantics</tt> - semantics of size of VARCHAR2 and CHAR columns, defaults to "CHAR"
|
265
|
+
# (meaning that size specifies number of characters and not bytes)
|
246
266
|
class OracleEnhancedAdapter < AbstractAdapter
|
247
267
|
|
248
|
-
|
268
|
+
##
|
269
|
+
# :singleton-method:
|
270
|
+
# By default, the OracleEnhancedAdapter will consider all columns of type <tt>NUMBER(1)</tt>
|
271
|
+
# as boolean. If you wish to disable this emulation you can add the following line
|
272
|
+
# to your initializer file:
|
273
|
+
#
|
274
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans = false
|
249
275
|
cattr_accessor :emulate_booleans
|
250
|
-
|
251
|
-
|
276
|
+
self.emulate_booleans = true
|
277
|
+
|
278
|
+
##
|
279
|
+
# :singleton-method:
|
280
|
+
# By default, the OracleEnhancedAdapter will typecast all columns of type <tt>DATE</tt>
|
281
|
+
# to Time or DateTime (if value is out of Time value range) value.
|
282
|
+
# If you wish that DATE values with hour, minutes and seconds equal to 0 are typecasted
|
283
|
+
# to Date then you can add the following line to your initializer file:
|
284
|
+
#
|
285
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates = true
|
286
|
+
#
|
287
|
+
# As this option can have side effects when unnecessary typecasting is done it is recommended
|
288
|
+
# that Date columns are explicily defined with +set_date_columns+ method.
|
252
289
|
cattr_accessor :emulate_dates
|
253
|
-
|
254
|
-
|
255
|
-
|
290
|
+
self.emulate_dates = false
|
291
|
+
|
292
|
+
##
|
293
|
+
# :singleton-method:
|
294
|
+
# By default, the OracleEnhancedAdapter will typecast all columns of type <tt>DATE</tt>
|
295
|
+
# to Time or DateTime (if value is out of Time value range) value.
|
296
|
+
# If you wish that DATE columns with "date" in their name (e.g. "creation_date") are typecasted
|
297
|
+
# to Date then you can add the following line to your initializer file:
|
298
|
+
#
|
299
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
300
|
+
#
|
301
|
+
# As this option can have side effects when unnecessary typecasting is done it is recommended
|
302
|
+
# that Date columns are explicily defined with +set_date_columns+ method.
|
256
303
|
cattr_accessor :emulate_dates_by_column_name
|
304
|
+
self.emulate_dates_by_column_name = false
|
305
|
+
|
306
|
+
# Check column name to identify if it is Date (and not Time) column.
|
307
|
+
# Is used if +emulate_dates_by_column_name+ option is set to +true+.
|
308
|
+
# Override this method definition in initializer file if different Date column recognition is needed.
|
257
309
|
def self.is_date_column?(name, table_name = nil)
|
258
310
|
name =~ /(^|_)date(_|$)/i
|
259
311
|
end
|
260
|
-
|
261
|
-
|
312
|
+
|
313
|
+
# instance method uses at first check if column type defined at class level
|
314
|
+
def is_date_column?(name, table_name = nil) #:nodoc:
|
262
315
|
case get_type_for_column(table_name, name)
|
263
316
|
when nil
|
264
317
|
self.class.is_date_column?(name, table_name)
|
@@ -269,28 +322,63 @@ module ActiveRecord
|
|
269
322
|
end
|
270
323
|
end
|
271
324
|
|
272
|
-
|
273
|
-
|
325
|
+
##
|
326
|
+
# :singleton-method:
|
327
|
+
# By default, the OracleEnhancedAdapter will typecast all columns of type <tt>NUMBER</tt>
|
328
|
+
# (without precision or scale) to Float or BigDecimal value.
|
329
|
+
# If you wish that NUMBER columns with name "id" or that end with "_id" are typecasted
|
330
|
+
# to Integer then you can add the following line to your initializer file:
|
331
|
+
#
|
332
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
274
333
|
cattr_accessor :emulate_integers_by_column_name
|
334
|
+
self.emulate_integers_by_column_name = false
|
335
|
+
|
336
|
+
# Check column name to identify if it is Integer (and not Float or BigDecimal) column.
|
337
|
+
# Is used if +emulate_integers_by_column_name+ option is set to +true+.
|
338
|
+
# Override this method definition in initializer file if different Integer column recognition is needed.
|
275
339
|
def self.is_integer_column?(name, table_name = nil)
|
276
340
|
name =~ /(^|_)id$/i
|
277
341
|
end
|
278
342
|
|
279
|
-
|
280
|
-
#
|
281
|
-
|
343
|
+
##
|
344
|
+
# :singleton-method:
|
345
|
+
# If you wish that CHAR(1), VARCHAR2(1) columns or VARCHAR2 columns with FLAG or YN at the end of their name
|
346
|
+
# are typecasted to booleans then you can add the following line to your initializer file:
|
347
|
+
#
|
348
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_booleans_from_strings = true
|
282
349
|
cattr_accessor :emulate_booleans_from_strings
|
350
|
+
self.emulate_booleans_from_strings = false
|
351
|
+
|
352
|
+
# Check column name to identify if it is boolean (and not String) column.
|
353
|
+
# Is used if +emulate_booleans_from_strings+ option is set to +true+.
|
354
|
+
# Override this method definition in initializer file if different boolean column recognition is needed.
|
283
355
|
def self.is_boolean_column?(name, field_type, table_name = nil)
|
284
356
|
return true if ["CHAR(1)","VARCHAR2(1)"].include?(field_type)
|
285
357
|
field_type =~ /^VARCHAR2/ && (name =~ /_flag$/i || name =~ /_yn$/i)
|
286
358
|
end
|
359
|
+
|
360
|
+
# How boolean value should be quoted to String.
|
361
|
+
# Used if +emulate_booleans_from_strings+ option is set to +true+.
|
287
362
|
def self.boolean_to_string(bool)
|
288
363
|
bool ? "Y" : "N"
|
289
364
|
end
|
290
365
|
|
291
|
-
#
|
292
|
-
|
293
|
-
|
366
|
+
# Specify non-default date format that should be used when assigning string values to :date columns, e.g.:
|
367
|
+
#
|
368
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = “%d.%m.%Y”
|
369
|
+
cattr_accessor :string_to_date_format
|
370
|
+
self.string_to_date_format = nil
|
371
|
+
|
372
|
+
# Specify non-default time format that should be used when assigning string values to :datetime columns, e.g.:
|
373
|
+
#
|
374
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = “%d.%m.%Y %H:%M:%S”
|
375
|
+
cattr_accessor :string_to_time_format
|
376
|
+
self.string_to_time_format = nil
|
377
|
+
|
378
|
+
def initialize(connection, logger = nil) #:nodoc:
|
379
|
+
super
|
380
|
+
@quoted_column_names, @quoted_table_names = {}, {}
|
381
|
+
end
|
294
382
|
|
295
383
|
def adapter_name #:nodoc:
|
296
384
|
'OracleEnhanced'
|
@@ -309,53 +397,48 @@ module ActiveRecord
|
|
309
397
|
:float => { :name => "NUMBER" },
|
310
398
|
:decimal => { :name => "DECIMAL" },
|
311
399
|
:datetime => { :name => "DATE" },
|
312
|
-
#
|
400
|
+
# changed to native TIMESTAMP type
|
313
401
|
# :timestamp => { :name => "DATE" },
|
314
402
|
:timestamp => { :name => "TIMESTAMP" },
|
315
403
|
:time => { :name => "DATE" },
|
316
404
|
:date => { :name => "DATE" },
|
317
405
|
:binary => { :name => "BLOB" },
|
318
|
-
#
|
406
|
+
# if emulate_booleans_from_strings then store booleans in VARCHAR2
|
319
407
|
:boolean => emulate_booleans_from_strings ?
|
320
408
|
{ :name => "VARCHAR2", :limit => 1 } : { :name => "NUMBER", :limit => 1 }
|
321
409
|
}
|
322
410
|
end
|
323
411
|
|
324
|
-
|
325
|
-
|
326
|
-
end
|
412
|
+
# maximum length of Oracle identifiers
|
413
|
+
IDENTIFIER_MAX_LENGTH = 30
|
327
414
|
|
328
|
-
|
329
|
-
|
330
|
-
def select_rows(sql, name = nil)
|
331
|
-
# last parameter indicates to return also column list
|
332
|
-
result, columns = select(sql, name, true)
|
333
|
-
result.map{ |v| columns.map{|c| v[c]} }
|
415
|
+
def table_alias_length #:nodoc:
|
416
|
+
IDENTIFIER_MAX_LENGTH
|
334
417
|
end
|
335
418
|
|
336
419
|
# QUOTING ==================================================
|
337
420
|
#
|
338
421
|
# see: abstract/quoting.rb
|
339
422
|
|
340
|
-
# camelCase column names need to be quoted; not that anyone using Oracle
|
341
|
-
# would really do this, but handling this case means we pass the test...
|
342
423
|
def quote_column_name(name) #:nodoc:
|
343
|
-
|
424
|
+
# camelCase column names need to be quoted; not that anyone using Oracle
|
425
|
+
# would really do this, but handling this case means we pass the test...
|
426
|
+
@quoted_column_names[name] = name.to_s =~ /[A-Z]/ ? "\"#{name}\"" : quote_oracle_reserved_words(name)
|
344
427
|
end
|
345
428
|
|
346
429
|
# unescaped table name should start with letter and
|
347
430
|
# contain letters, digits, _, $ or #
|
348
431
|
# can be prefixed with schema name
|
349
432
|
# CamelCase table names should be quoted
|
350
|
-
def self.valid_table_name?(name)
|
433
|
+
def self.valid_table_name?(name) #:nodoc:
|
351
434
|
name = name.to_s
|
352
|
-
name =~
|
353
|
-
name =~
|
435
|
+
name =~ /\A([A-Za-z_0-9]+\.)?[a-z][a-z_0-9\$#]*(@[A-Za-z_0-9\.]+)?\Z/ ||
|
436
|
+
name =~ /\A([A-Za-z_0-9]+\.)?[A-Z][A-Z_0-9\$#]*(@[A-Za-z_0-9\.]+)?\Z/ ? true : false
|
354
437
|
end
|
355
438
|
|
356
|
-
|
357
|
-
|
358
|
-
if self.class.valid_table_name?(name)
|
439
|
+
def quote_table_name(name) #:nodoc:
|
440
|
+
# abstract_adapter calls quote_column_name from quote_table_name, so prevent that
|
441
|
+
@quoted_table_names[name] ||= if self.class.valid_table_name?(name)
|
359
442
|
name
|
360
443
|
else
|
361
444
|
"\"#{name}\""
|
@@ -371,10 +454,10 @@ module ActiveRecord
|
|
371
454
|
case column.type
|
372
455
|
when :text, :binary
|
373
456
|
%Q{empty_#{ column.sql_type.downcase rescue 'blob' }()}
|
374
|
-
#
|
457
|
+
# NLS_DATE_FORMAT independent TIMESTAMP support
|
375
458
|
when :timestamp
|
376
459
|
quote_timestamp_with_to_timestamp(value)
|
377
|
-
#
|
460
|
+
# NLS_DATE_FORMAT independent DATE support
|
378
461
|
when :date, :time, :datetime
|
379
462
|
quote_date_with_to_date(value)
|
380
463
|
else
|
@@ -389,25 +472,25 @@ module ActiveRecord
|
|
389
472
|
end
|
390
473
|
end
|
391
474
|
|
392
|
-
def quoted_true
|
475
|
+
def quoted_true #:nodoc:
|
393
476
|
return "'#{self.class.boolean_to_string(true)}'" if emulate_booleans_from_strings
|
394
477
|
"1"
|
395
478
|
end
|
396
479
|
|
397
|
-
def quoted_false
|
480
|
+
def quoted_false #:nodoc:
|
398
481
|
return "'#{self.class.boolean_to_string(false)}'" if emulate_booleans_from_strings
|
399
482
|
"0"
|
400
483
|
end
|
401
484
|
|
402
|
-
|
403
|
-
|
404
|
-
value = value
|
485
|
+
def quote_date_with_to_date(value) #:nodoc:
|
486
|
+
# should support that composite_primary_keys gem will pass date as string
|
487
|
+
value = quoted_date(value) if value.acts_like?(:date) || value.acts_like?(:time)
|
405
488
|
"TO_DATE('#{value}','YYYY-MM-DD HH24:MI:SS')"
|
406
489
|
end
|
407
490
|
|
408
|
-
def quote_timestamp_with_to_timestamp(value)
|
491
|
+
def quote_timestamp_with_to_timestamp(value) #:nodoc:
|
409
492
|
# add up to 9 digits of fractional seconds to inserted time
|
410
|
-
value = "#{value
|
493
|
+
value = "#{quoted_date(value)}.#{("%.6f"%value.to_f).split('.')[1]}" if value.acts_like?(:time)
|
411
494
|
"TO_TIMESTAMP('#{value}','YYYY-MM-DD HH24:MI:SS.FF6')"
|
412
495
|
end
|
413
496
|
|
@@ -417,19 +500,21 @@ module ActiveRecord
|
|
417
500
|
# If SQL statement fails due to lost connection then reconnect
|
418
501
|
# and retry SQL statement if autocommit mode is enabled.
|
419
502
|
# By default this functionality is disabled.
|
503
|
+
attr_reader :auto_retry #:nodoc:
|
420
504
|
@auto_retry = false
|
421
|
-
|
422
|
-
def auto_retry=(value)
|
505
|
+
|
506
|
+
def auto_retry=(value) #:nodoc:
|
423
507
|
@auto_retry = value
|
424
508
|
@connection.auto_retry = value if @connection
|
425
509
|
end
|
426
510
|
|
511
|
+
# return raw OCI8 or JDBC connection
|
427
512
|
def raw_connection
|
428
513
|
@connection.raw_connection
|
429
514
|
end
|
430
515
|
|
431
516
|
# Returns true if the connection is active.
|
432
|
-
def active?
|
517
|
+
def active? #:nodoc:
|
433
518
|
# Pings the connection to check if it's still good. Note that an
|
434
519
|
# #active? method is also available, but that simply returns the
|
435
520
|
# last known state, which isn't good enough if the connection has
|
@@ -440,31 +525,61 @@ module ActiveRecord
|
|
440
525
|
end
|
441
526
|
|
442
527
|
# Reconnects to the database.
|
443
|
-
def reconnect!
|
528
|
+
def reconnect! #:nodoc:
|
444
529
|
@connection.reset!
|
445
530
|
rescue OracleEnhancedConnectionException => e
|
446
|
-
@logger.warn "#{adapter_name} automatic reconnection failed: #{e.message}"
|
531
|
+
@logger.warn "#{adapter_name} automatic reconnection failed: #{e.message}" if @logger
|
447
532
|
end
|
448
533
|
|
449
534
|
# Disconnects from the database.
|
450
|
-
def disconnect!
|
535
|
+
def disconnect! #:nodoc:
|
451
536
|
@connection.logoff rescue nil
|
452
537
|
end
|
453
538
|
|
454
|
-
|
455
539
|
# DATABASE STATEMENTS ======================================
|
456
540
|
#
|
457
541
|
# see: abstract/database_statements.rb
|
458
542
|
|
459
|
-
|
460
|
-
|
543
|
+
# Executes a SQL statement
|
544
|
+
def execute(sql, name = nil)
|
545
|
+
# hack to pass additional "with_returning" option without changing argument list
|
546
|
+
log(sql, name) { sql.instance_variable_get(:@with_returning) ? @connection.exec_with_returning(sql) : @connection.exec(sql) }
|
461
547
|
end
|
462
548
|
|
549
|
+
# Returns an array of arrays containing the field values.
|
550
|
+
# Order is the same as that returned by #columns.
|
551
|
+
def select_rows(sql, name = nil)
|
552
|
+
# last parameter indicates to return also column list
|
553
|
+
result, columns = select(sql, name, true)
|
554
|
+
result.map{ |v| columns.map{|c| v[c]} }
|
555
|
+
end
|
556
|
+
|
557
|
+
# Executes an INSERT statement and returns the new record's ID
|
558
|
+
def insert_sql(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil) #:nodoc:
|
559
|
+
# if primary key value is already prefetched from sequence
|
560
|
+
# or if there is no primary key
|
561
|
+
if id_value || pk.nil?
|
562
|
+
execute(sql, name)
|
563
|
+
return id_value
|
564
|
+
end
|
565
|
+
|
566
|
+
sql_with_returning = sql.dup << @connection.returning_clause(quote_column_name(pk))
|
567
|
+
# hack to pass additional "with_returning" option without changing argument list
|
568
|
+
sql_with_returning.instance_variable_set(:@with_returning, true)
|
569
|
+
clear_query_cache
|
570
|
+
execute(sql_with_returning, name)
|
571
|
+
end
|
572
|
+
protected :insert_sql
|
573
|
+
|
574
|
+
AUTOGENERATED_SEQUENCE_NAME = 'autogenerated'.freeze #:nodoc:
|
575
|
+
|
463
576
|
# Returns the next sequence value from a sequence generator. Not generally
|
464
577
|
# called directly; used by ActiveRecord to get the next primary key value
|
465
578
|
# when inserting a new database record (see #prefetch_primary_key?).
|
466
579
|
def next_sequence_value(sequence_name)
|
467
|
-
|
580
|
+
# if sequence_name is set to :autogenerated then it means that primary key will be populated by trigger
|
581
|
+
return nil if sequence_name == AUTOGENERATED_SEQUENCE_NAME
|
582
|
+
select_one("SELECT #{quote_table_name(sequence_name)}.NEXTVAL id FROM dual")['id']
|
468
583
|
end
|
469
584
|
|
470
585
|
def begin_db_transaction #:nodoc:
|
@@ -484,7 +599,7 @@ module ActiveRecord
|
|
484
599
|
end
|
485
600
|
|
486
601
|
def add_limit_offset!(sql, options) #:nodoc:
|
487
|
-
#
|
602
|
+
# added to_i for limit and offset to protect from SQL injection
|
488
603
|
offset = (options[:offset] || 0).to_i
|
489
604
|
|
490
605
|
if limit = options[:limit]
|
@@ -495,19 +610,29 @@ module ActiveRecord
|
|
495
610
|
end
|
496
611
|
end
|
497
612
|
|
613
|
+
@@do_not_prefetch_primary_key = {}
|
614
|
+
|
498
615
|
# Returns true for Oracle adapter (since Oracle requires primary key
|
499
616
|
# values to be pre-fetched before insert). See also #next_sequence_value.
|
500
617
|
def prefetch_primary_key?(table_name = nil)
|
501
|
-
|
618
|
+
! @@do_not_prefetch_primary_key[table_name.to_s]
|
502
619
|
end
|
503
620
|
|
504
|
-
|
505
|
-
|
621
|
+
# used just in tests to clear prefetch primary key flag for all tables
|
622
|
+
def clear_prefetch_primary_key #:nodoc:
|
623
|
+
@@do_not_prefetch_primary_key = {}
|
506
624
|
end
|
507
625
|
|
626
|
+
# Returns default sequence name for table.
|
627
|
+
# Will take all or first 26 characters of table name and append _seq suffix
|
628
|
+
def default_sequence_name(table_name, primary_key = nil)
|
629
|
+
# TODO: remove schema prefix if present before truncating
|
630
|
+
# truncate table name if necessary to fit in max length of identifier
|
631
|
+
"#{table_name.to_s[0,IDENTIFIER_MAX_LENGTH-4]}_seq"
|
632
|
+
end
|
508
633
|
|
509
634
|
# Inserts the given fixture into the table. Overridden to properly handle lobs.
|
510
|
-
def insert_fixture(fixture, table_name)
|
635
|
+
def insert_fixture(fixture, table_name) #:nodoc:
|
511
636
|
super
|
512
637
|
|
513
638
|
klass = fixture.class_name.constantize rescue nil
|
@@ -517,7 +642,7 @@ module ActiveRecord
|
|
517
642
|
end
|
518
643
|
|
519
644
|
# Writes LOB values from attributes, as indicated by the LOB columns of klass.
|
520
|
-
def write_lobs(table_name, klass, attributes)
|
645
|
+
def write_lobs(table_name, klass, attributes) #:nodoc:
|
521
646
|
# is class with composite primary key>
|
522
647
|
is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
|
523
648
|
if is_with_cpk
|
@@ -527,7 +652,7 @@ module ActiveRecord
|
|
527
652
|
end
|
528
653
|
klass.columns.select { |col| col.sql_type =~ /LOB$/i }.each do |col|
|
529
654
|
value = attributes[col.name]
|
530
|
-
#
|
655
|
+
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
531
656
|
next if value.nil? || (value == '')
|
532
657
|
value = value.to_yaml if col.text? && klass.serialized_attributes[col.name]
|
533
658
|
uncached do
|
@@ -538,14 +663,14 @@ module ActiveRecord
|
|
538
663
|
lob = select_one("SELECT #{col.name} FROM #{table_name} WHERE #{klass.primary_key} = #{id} FOR UPDATE",
|
539
664
|
'Writable Large Object')[col.name]
|
540
665
|
end
|
541
|
-
@connection.write_lob(lob, value, col.type == :binary)
|
666
|
+
@connection.write_lob(lob, value.to_s, col.type == :binary)
|
542
667
|
end
|
543
668
|
end
|
544
669
|
end
|
545
670
|
|
546
|
-
#
|
671
|
+
# change LOB column for ORDER BY clause
|
547
672
|
# just first 100 characters are taken for ordering
|
548
|
-
def lob_order_by_expression(klass, order)
|
673
|
+
def lob_order_by_expression(klass, order) #:nodoc:
|
549
674
|
return order if order.nil?
|
550
675
|
changed = false
|
551
676
|
new_order = order.to_s.strip.split(/, */).map do |order_by_col|
|
@@ -568,21 +693,21 @@ module ActiveRecord
|
|
568
693
|
select_one("select sys_context('userenv','db_name') db from dual")["db"]
|
569
694
|
end
|
570
695
|
|
571
|
-
# RSI: changed select from user_tables to all_tables - much faster in large data dictionaries
|
572
696
|
def tables(name = nil) #:nodoc:
|
697
|
+
# changed select from user_tables to all_tables - much faster in large data dictionaries
|
573
698
|
select_all("select decode(table_name,upper(table_name),lower(table_name),table_name) name from all_tables where owner = sys_context('userenv','session_user')").map {|t| t['name']}
|
574
699
|
end
|
575
700
|
|
576
|
-
cattr_accessor :all_schema_indexes
|
701
|
+
cattr_accessor :all_schema_indexes #:nodoc:
|
577
702
|
|
578
703
|
# This method selects all indexes at once, and caches them in a class variable.
|
579
704
|
# Subsequent index calls get them from the variable, without going to the DB.
|
580
|
-
def indexes(table_name, name = nil)
|
581
|
-
(owner, table_name) = @connection.describe(table_name)
|
705
|
+
def indexes(table_name, name = nil) #:nodoc:
|
706
|
+
(owner, table_name, db_link) = @connection.describe(table_name)
|
582
707
|
unless all_schema_indexes
|
583
708
|
result = select_all(<<-SQL)
|
584
709
|
SELECT lower(i.table_name) as table_name, lower(i.index_name) as index_name, i.uniqueness, lower(c.column_name) as column_name
|
585
|
-
FROM all_indexes i, all_ind_columns c
|
710
|
+
FROM all_indexes#{db_link} i, all_ind_columns#{db_link} c
|
586
711
|
WHERE i.owner = '#{owner}'
|
587
712
|
AND i.table_owner = '#{owner}'
|
588
713
|
AND c.index_name = i.index_name
|
@@ -611,57 +736,88 @@ module ActiveRecord
|
|
611
736
|
all_schema_indexes.select{|i| i.table == table_name}
|
612
737
|
end
|
613
738
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
739
|
+
@@ignore_table_columns = nil #:nodoc:
|
740
|
+
|
741
|
+
# set ignored columns for table
|
742
|
+
def ignore_table_columns(table_name, *args) #:nodoc:
|
743
|
+
@@ignore_table_columns ||= {}
|
744
|
+
@@ignore_table_columns[table_name] ||= []
|
745
|
+
@@ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
|
746
|
+
@@ignore_table_columns[table_name].uniq!
|
620
747
|
end
|
621
748
|
|
622
|
-
def ignored_table_columns(table_name)
|
623
|
-
|
624
|
-
|
749
|
+
def ignored_table_columns(table_name) #:nodoc:
|
750
|
+
@@ignore_table_columns ||= {}
|
751
|
+
@@ignore_table_columns[table_name]
|
625
752
|
end
|
626
753
|
|
627
|
-
#
|
628
|
-
def
|
629
|
-
|
630
|
-
|
754
|
+
# used just in tests to clear ignored table columns
|
755
|
+
def clear_ignored_table_columns #:nodoc:
|
756
|
+
@@ignore_table_columns = nil
|
757
|
+
end
|
758
|
+
|
759
|
+
@@table_column_type = nil #:nodoc:
|
760
|
+
|
761
|
+
# set explicit type for specified table columns
|
762
|
+
def set_type_for_columns(table_name, column_type, *args) #:nodoc:
|
763
|
+
@@table_column_type ||= {}
|
764
|
+
@@table_column_type[table_name] ||= {}
|
631
765
|
args.each do |col|
|
632
|
-
|
766
|
+
@@table_column_type[table_name][col.to_s.downcase] = column_type
|
633
767
|
end
|
634
768
|
end
|
635
769
|
|
636
|
-
def get_type_for_column(table_name, column_name)
|
637
|
-
|
770
|
+
def get_type_for_column(table_name, column_name) #:nodoc:
|
771
|
+
@@table_column_type && @@table_column_type[table_name] && @@table_column_type[table_name][column_name.to_s.downcase]
|
638
772
|
end
|
639
773
|
|
640
|
-
|
641
|
-
|
774
|
+
# used just in tests to clear column data type definitions
|
775
|
+
def clear_types_for_columns #:nodoc:
|
776
|
+
@@table_column_type = nil
|
777
|
+
end
|
778
|
+
|
779
|
+
# check if table has primary key trigger with _pkt suffix
|
780
|
+
def has_primary_key_trigger?(table_name, owner = nil, desc_table_name = nil, db_link = nil)
|
781
|
+
(owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
|
782
|
+
|
783
|
+
trigger_name = default_trigger_name(table_name).upcase
|
784
|
+
pkt_sql = <<-SQL
|
785
|
+
SELECT trigger_name
|
786
|
+
FROM all_triggers#{db_link}
|
787
|
+
WHERE owner = '#{owner}'
|
788
|
+
AND trigger_name = '#{trigger_name}'
|
789
|
+
AND table_owner = '#{owner}'
|
790
|
+
AND table_name = '#{desc_table_name}'
|
791
|
+
AND status = 'ENABLED'
|
792
|
+
SQL
|
793
|
+
select_value(pkt_sql) ? true : false
|
642
794
|
end
|
643
795
|
|
644
796
|
def columns(table_name, name = nil) #:nodoc:
|
645
|
-
#
|
797
|
+
# get ignored_columns by original table name
|
646
798
|
ignored_columns = ignored_table_columns(table_name)
|
647
799
|
|
648
|
-
(owner, desc_table_name) = @connection.describe(table_name)
|
800
|
+
(owner, desc_table_name, db_link) = @connection.describe(table_name)
|
801
|
+
|
802
|
+
if has_primary_key_trigger?(table_name, owner, desc_table_name, db_link)
|
803
|
+
@@do_not_prefetch_primary_key[table_name] = true
|
804
|
+
end
|
649
805
|
|
650
806
|
table_cols = <<-SQL
|
651
807
|
select column_name as name, data_type as sql_type, data_default, nullable,
|
652
808
|
decode(data_type, 'NUMBER', data_precision,
|
653
809
|
'FLOAT', data_precision,
|
654
|
-
'VARCHAR2', data_length,
|
655
|
-
'CHAR', data_length,
|
810
|
+
'VARCHAR2', decode(char_used, 'C', char_length, data_length),
|
811
|
+
'CHAR', decode(char_used, 'C', char_length, data_length),
|
656
812
|
null) as limit,
|
657
813
|
decode(data_type, 'NUMBER', data_scale, null) as scale
|
658
|
-
from all_tab_columns
|
814
|
+
from all_tab_columns#{db_link}
|
659
815
|
where owner = '#{owner}'
|
660
816
|
and table_name = '#{desc_table_name}'
|
661
817
|
order by column_id
|
662
818
|
SQL
|
663
819
|
|
664
|
-
#
|
820
|
+
# added deletion of ignored columns
|
665
821
|
select_all(table_cols, name).delete_if do |row|
|
666
822
|
ignored_columns && ignored_columns.include?(row['name'].downcase)
|
667
823
|
end.map do |row|
|
@@ -681,18 +837,52 @@ module ActiveRecord
|
|
681
837
|
row['data_default'],
|
682
838
|
row['sql_type'],
|
683
839
|
row['nullable'] == 'Y',
|
684
|
-
#
|
840
|
+
# pass table name for table specific column definitions
|
685
841
|
table_name,
|
686
|
-
#
|
842
|
+
# pass column type if specified in class definition
|
687
843
|
get_type_for_column(table_name, oracle_downcase(row['name'])))
|
688
844
|
end
|
689
845
|
end
|
690
846
|
|
691
|
-
|
692
|
-
|
847
|
+
##
|
848
|
+
# :singleton-method:
|
849
|
+
# Specify default sequence start with value (by default 10000 if not explicitly set), e.g.:
|
850
|
+
#
|
851
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_sequence_start_value = 1
|
693
852
|
cattr_accessor :default_sequence_start_value
|
853
|
+
self.default_sequence_start_value = 10000
|
694
854
|
|
695
|
-
|
855
|
+
# Additional options for +create_table+ method in migration files.
|
856
|
+
#
|
857
|
+
# You can specify individual starting value in table creation migration file, e.g.:
|
858
|
+
#
|
859
|
+
# create_table :users, :sequence_start_value => 100 do |t|
|
860
|
+
# # ...
|
861
|
+
# end
|
862
|
+
#
|
863
|
+
# You can also specify other sequence definition additional parameters, e.g.:
|
864
|
+
#
|
865
|
+
# create_table :users, :sequence_start_value => “100 NOCACHE INCREMENT BY 10” do |t|
|
866
|
+
# # ...
|
867
|
+
# end
|
868
|
+
#
|
869
|
+
# Create primary key trigger (so that you can skip primary key value in INSERT statement).
|
870
|
+
# By default trigger name will be "table_name_pkt", you can override the name with
|
871
|
+
# :trigger_name option (but it is not recommended to override it as then this trigger will
|
872
|
+
# not be detected by ActiveRecord model and it will still do prefetching of sequence value).
|
873
|
+
# Example:
|
874
|
+
#
|
875
|
+
# create_table :users, :primary_key_trigger => true do |t|
|
876
|
+
# # ...
|
877
|
+
# end
|
878
|
+
#
|
879
|
+
# It is possible to add table and column comments in table creation migration files:
|
880
|
+
#
|
881
|
+
# create_table :employees, :comment => “Employees and contractors” do |t|
|
882
|
+
# t.string :first_name, :comment => “Given name”
|
883
|
+
# t.string :last_name, :comment => “Surname”
|
884
|
+
# end
|
885
|
+
def create_table(name, options = {}, &block)
|
696
886
|
create_sequence = options[:id] != false
|
697
887
|
column_comments = {}
|
698
888
|
super(name, options) do |t|
|
@@ -719,14 +909,12 @@ module ActiveRecord
|
|
719
909
|
end
|
720
910
|
end
|
721
911
|
|
722
|
-
result = block.call(t)
|
912
|
+
result = block.call(t) if block
|
723
913
|
create_sequence = create_sequence || t.create_sequence
|
724
914
|
column_comments = t.column_comments if t.column_comments
|
725
915
|
end
|
726
916
|
|
727
|
-
|
728
|
-
seq_start_value = options[:sequence_start_value] || default_sequence_start_value
|
729
|
-
execute "CREATE SEQUENCE #{seq_name} START WITH #{seq_start_value}" if create_sequence
|
917
|
+
create_sequence_and_trigger(name, options) if create_sequence
|
730
918
|
|
731
919
|
add_table_comment name, options[:comment]
|
732
920
|
column_comments.each do |column_name, comment|
|
@@ -742,12 +930,12 @@ module ActiveRecord
|
|
742
930
|
|
743
931
|
def drop_table(name, options = {}) #:nodoc:
|
744
932
|
super(name)
|
745
|
-
seq_name = options[:sequence_name] ||
|
746
|
-
execute "DROP SEQUENCE #{seq_name}" rescue nil
|
933
|
+
seq_name = options[:sequence_name] || default_sequence_name(name)
|
934
|
+
execute "DROP SEQUENCE #{quote_table_name(seq_name)}" rescue nil
|
747
935
|
end
|
748
936
|
|
749
937
|
# clear cached indexes when adding new index
|
750
|
-
def add_index(table_name, column_name, options = {})
|
938
|
+
def add_index(table_name, column_name, options = {}) #:nodoc:
|
751
939
|
self.all_schema_indexes = nil
|
752
940
|
super
|
753
941
|
end
|
@@ -757,8 +945,28 @@ module ActiveRecord
|
|
757
945
|
self.all_schema_indexes = nil
|
758
946
|
execute "DROP INDEX #{index_name(table_name, options)}"
|
759
947
|
end
|
948
|
+
|
949
|
+
# returned shortened index name if default is too large
|
950
|
+
def index_name(table_name, options) #:nodoc:
|
951
|
+
default_name = super(table_name, options)
|
952
|
+
return default_name if default_name.length <= IDENTIFIER_MAX_LENGTH
|
953
|
+
|
954
|
+
# remove 'index', 'on' and 'and' keywords
|
955
|
+
shortened_name = "i_#{table_name}_#{Array(options[:column]) * '_'}"
|
956
|
+
|
957
|
+
# leave just first three letters from each word
|
958
|
+
if shortened_name.length > IDENTIFIER_MAX_LENGTH
|
959
|
+
shortened_name = shortened_name.split('_').map{|w| w[0,3]}.join('_')
|
960
|
+
end
|
961
|
+
# generate unique name using hash function
|
962
|
+
if shortened_name.length > OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH
|
963
|
+
shortened_name = 'i'+Digest::SHA1.hexdigest(default_name)[0,OracleEnhancedAdapter::IDENTIFIER_MAX_LENGTH-1]
|
964
|
+
end
|
965
|
+
@logger.warn "#{adapter_name} shortened default index name #{default_name} to #{shortened_name}" if @logger
|
966
|
+
shortened_name
|
967
|
+
end
|
760
968
|
|
761
|
-
def add_column(table_name, column_name, type, options = {})
|
969
|
+
def add_column(table_name, column_name, type, options = {}) #:nodoc:
|
762
970
|
add_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
|
763
971
|
options[:type] = type
|
764
972
|
add_column_options!(add_column_sql, options)
|
@@ -769,7 +977,7 @@ module ActiveRecord
|
|
769
977
|
execute "ALTER TABLE #{quote_table_name(table_name)} MODIFY #{quote_column_name(column_name)} DEFAULT #{quote(default)}"
|
770
978
|
end
|
771
979
|
|
772
|
-
def change_column_null(table_name, column_name, null, default = nil)
|
980
|
+
def change_column_null(table_name, column_name, null, default = nil) #:nodoc:
|
773
981
|
column = column_for(table_name, column_name)
|
774
982
|
|
775
983
|
unless null || default.nil?
|
@@ -802,45 +1010,52 @@ module ActiveRecord
|
|
802
1010
|
execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
|
803
1011
|
end
|
804
1012
|
|
805
|
-
|
806
|
-
def add_comment(table_name, column_name, comment)
|
1013
|
+
def add_comment(table_name, column_name, comment) #:nodoc:
|
807
1014
|
return if comment.blank?
|
808
1015
|
execute "COMMENT ON COLUMN #{quote_table_name(table_name)}.#{column_name} IS '#{comment}'"
|
809
1016
|
end
|
810
1017
|
|
811
|
-
def add_table_comment(table_name, comment)
|
1018
|
+
def add_table_comment(table_name, comment) #:nodoc:
|
812
1019
|
return if comment.blank?
|
813
1020
|
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{comment}'"
|
814
1021
|
end
|
815
1022
|
|
816
|
-
def table_comment(table_name)
|
817
|
-
(owner, table_name) = @connection.describe(table_name)
|
1023
|
+
def table_comment(table_name) #:nodoc:
|
1024
|
+
(owner, table_name, db_link) = @connection.describe(table_name)
|
818
1025
|
select_value <<-SQL
|
819
|
-
SELECT comments FROM all_tab_comments
|
1026
|
+
SELECT comments FROM all_tab_comments#{db_link}
|
820
1027
|
WHERE owner = '#{owner}'
|
821
1028
|
AND table_name = '#{table_name}'
|
822
1029
|
SQL
|
823
1030
|
end
|
824
1031
|
|
825
|
-
def column_comment(table_name, column_name)
|
826
|
-
(owner, table_name) = @connection.describe(table_name)
|
1032
|
+
def column_comment(table_name, column_name) #:nodoc:
|
1033
|
+
(owner, table_name, db_link) = @connection.describe(table_name)
|
827
1034
|
select_value <<-SQL
|
828
|
-
SELECT comments FROM all_col_comments
|
1035
|
+
SELECT comments FROM all_col_comments#{db_link}
|
829
1036
|
WHERE owner = '#{owner}'
|
830
1037
|
AND table_name = '#{table_name}'
|
831
1038
|
AND column_name = '#{column_name.upcase}'
|
832
1039
|
SQL
|
833
1040
|
end
|
834
1041
|
|
1042
|
+
# Maps logical Rails types to Oracle-specific data types.
|
1043
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
1044
|
+
# Ignore options for :text and :binary columns
|
1045
|
+
return super(type, nil, nil, nil) if ['text', 'binary'].include?(type.to_s)
|
1046
|
+
|
1047
|
+
super
|
1048
|
+
end
|
1049
|
+
|
835
1050
|
# Find a table's primary key and sequence.
|
836
1051
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
837
|
-
def pk_and_sequence_for(table_name)
|
838
|
-
(owner, table_name) = @connection.describe(table_name)
|
1052
|
+
def pk_and_sequence_for(table_name) #:nodoc:
|
1053
|
+
(owner, table_name, db_link) = @connection.describe(table_name)
|
839
1054
|
|
840
|
-
#
|
1055
|
+
# changed select from all_constraints to user_constraints - much faster in large data dictionaries
|
841
1056
|
pks = select_values(<<-SQL, 'Primary Key')
|
842
1057
|
select cc.column_name
|
843
|
-
from user_constraints c, user_cons_columns cc
|
1058
|
+
from user_constraints#{db_link} c, user_cons_columns#{db_link} cc
|
844
1059
|
where c.owner = '#{owner}'
|
845
1060
|
and c.table_name = '#{table_name}'
|
846
1061
|
and c.constraint_type = 'P'
|
@@ -857,7 +1072,7 @@ module ActiveRecord
|
|
857
1072
|
structure << "create sequence #{seq.to_a.first.last};\n\n"
|
858
1073
|
end
|
859
1074
|
|
860
|
-
#
|
1075
|
+
# changed select from user_tables to all_tables - much faster in large data dictionaries
|
861
1076
|
select_all("select table_name from all_tables where owner = sys_context('userenv','session_user') order by 1").inject(s) do |structure, table|
|
862
1077
|
ddl = "create table #{table.to_a.first.last} (\n "
|
863
1078
|
cols = select_all(%Q{
|
@@ -885,17 +1100,59 @@ module ActiveRecord
|
|
885
1100
|
end
|
886
1101
|
end
|
887
1102
|
|
1103
|
+
# Extract all stored procedures, packages, synonyms and views.
|
1104
|
+
def structure_dump_db_stored_code #:nodoc:
|
1105
|
+
structure = "\n"
|
1106
|
+
select_all("select distinct name, type
|
1107
|
+
from all_source
|
1108
|
+
where type in ('PROCEDURE', 'PACKAGE', 'PACKAGE BODY', 'FUNCTION')
|
1109
|
+
and owner = sys_context('userenv','session_user')").inject("\n\n") do |structure, source|
|
1110
|
+
ddl = "create or replace \n "
|
1111
|
+
lines = select_all(%Q{
|
1112
|
+
select text
|
1113
|
+
from all_source
|
1114
|
+
where name = '#{source['name']}'
|
1115
|
+
and type = '#{source['type']}'
|
1116
|
+
and owner = sys_context('userenv','session_user')
|
1117
|
+
order by line
|
1118
|
+
}).map do |row|
|
1119
|
+
ddl << row['text'] if row['text'].size > 1
|
1120
|
+
end
|
1121
|
+
ddl << ";"
|
1122
|
+
structure << ddl << "\n"
|
1123
|
+
end
|
1124
|
+
|
1125
|
+
# export views
|
1126
|
+
select_all("select view_name, text from user_views").inject(structure) do |structure, view|
|
1127
|
+
ddl = "create or replace view #{view['view_name']} AS\n "
|
1128
|
+
# any views with empty lines will cause OCI to barf when loading. remove blank lines =/
|
1129
|
+
ddl << view['text'].gsub(/^\n/, '')
|
1130
|
+
ddl << ";\n\n"
|
1131
|
+
structure << ddl
|
1132
|
+
end
|
1133
|
+
|
1134
|
+
# export synonyms
|
1135
|
+
select_all("select owner, synonym_name, table_name, table_owner
|
1136
|
+
from all_synonyms
|
1137
|
+
where table_owner = sys_context('userenv','session_user') ").inject(structure) do |structure, synonym|
|
1138
|
+
ddl = "create or replace #{synonym['owner'] == 'PUBLIC' ? 'PUBLIC' : '' } SYNONYM #{synonym['synonym_name']} for #{synonym['table_owner']}.#{synonym['table_name']};\n\n"
|
1139
|
+
structure << ddl;
|
1140
|
+
end
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
|
888
1144
|
def structure_drop #:nodoc:
|
889
1145
|
s = select_all("select sequence_name from user_sequences order by 1").inject("") do |drop, seq|
|
890
1146
|
drop << "drop sequence #{seq.to_a.first.last};\n\n"
|
891
1147
|
end
|
892
1148
|
|
893
|
-
#
|
1149
|
+
# changed select from user_tables to all_tables - much faster in large data dictionaries
|
894
1150
|
select_all("select table_name from all_tables where owner = sys_context('userenv','session_user') order by 1").inject(s) do |drop, table|
|
895
1151
|
drop << "drop table #{table.to_a.first.last} cascade constraints;\n\n"
|
896
1152
|
end
|
897
1153
|
end
|
898
1154
|
|
1155
|
+
|
899
1156
|
def add_column_options!(sql, options) #:nodoc:
|
900
1157
|
type = options[:type] || ((column = options[:column]) && column.type)
|
901
1158
|
type = type && type.to_sym
|
@@ -926,7 +1183,7 @@ module ActiveRecord
|
|
926
1183
|
# making every row the same.
|
927
1184
|
#
|
928
1185
|
# distinct("posts.id", "posts.created_at desc")
|
929
|
-
def distinct(columns, order_by)
|
1186
|
+
def distinct(columns, order_by) #:nodoc:
|
930
1187
|
return "DISTINCT #{columns}" if order_by.blank?
|
931
1188
|
|
932
1189
|
# construct a valid DISTINCT clause, ie. one that includes the ORDER BY columns, using
|
@@ -942,7 +1199,7 @@ module ActiveRecord
|
|
942
1199
|
# ORDER BY clause for the passed order option.
|
943
1200
|
#
|
944
1201
|
# Uses column aliases as defined by #distinct.
|
945
|
-
def add_order_by_for_association_limiting!(sql, options)
|
1202
|
+
def add_order_by_for_association_limiting!(sql, options) #:nodoc:
|
946
1203
|
return sql if options[:order].blank?
|
947
1204
|
|
948
1205
|
order = options[:order].split(',').collect { |s| s.strip }.reject(&:blank?)
|
@@ -952,6 +1209,19 @@ module ActiveRecord
|
|
952
1209
|
sql << " ORDER BY #{order}"
|
953
1210
|
end
|
954
1211
|
|
1212
|
+
protected
|
1213
|
+
|
1214
|
+
def translate_exception(exception, message) #:nodoc:
|
1215
|
+
case @connection.error_code(exception)
|
1216
|
+
when 1
|
1217
|
+
RecordNotUnique.new(message, exception)
|
1218
|
+
when 2291
|
1219
|
+
InvalidForeignKey.new(message, exception)
|
1220
|
+
else
|
1221
|
+
super
|
1222
|
+
end
|
1223
|
+
end
|
1224
|
+
|
955
1225
|
private
|
956
1226
|
|
957
1227
|
def select(sql, name = nil, return_column_names = false)
|
@@ -971,22 +1241,107 @@ module ActiveRecord
|
|
971
1241
|
column
|
972
1242
|
end
|
973
1243
|
|
1244
|
+
def create_sequence_and_trigger(table_name, options)
|
1245
|
+
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
1246
|
+
seq_start_value = options[:sequence_start_value] || default_sequence_start_value
|
1247
|
+
execute "CREATE SEQUENCE #{quote_table_name(seq_name)} START WITH #{seq_start_value}"
|
1248
|
+
|
1249
|
+
create_primary_key_trigger(table_name, options) if options[:primary_key_trigger]
|
1250
|
+
end
|
1251
|
+
|
1252
|
+
def create_primary_key_trigger(table_name, options)
|
1253
|
+
seq_name = options[:sequence_name] || default_sequence_name(table_name)
|
1254
|
+
trigger_name = options[:trigger_name] || default_trigger_name(table_name)
|
1255
|
+
primary_key = options[:primary_key] || Base.get_primary_key(table_name.to_s.singularize)
|
1256
|
+
execute compress_lines(<<-SQL)
|
1257
|
+
CREATE OR REPLACE TRIGGER #{quote_table_name(trigger_name)}
|
1258
|
+
BEFORE INSERT ON #{quote_table_name(table_name)} FOR EACH ROW
|
1259
|
+
BEGIN
|
1260
|
+
IF inserting THEN
|
1261
|
+
IF :new.#{quote_column_name(primary_key)} IS NULL THEN
|
1262
|
+
SELECT #{quote_table_name(seq_name)}.NEXTVAL INTO :new.#{quote_column_name(primary_key)} FROM dual;
|
1263
|
+
END IF;
|
1264
|
+
END IF;
|
1265
|
+
END;
|
1266
|
+
SQL
|
1267
|
+
end
|
1268
|
+
|
1269
|
+
def default_trigger_name(table_name)
|
1270
|
+
# truncate table name if necessary to fit in max length of identifier
|
1271
|
+
"#{table_name.to_s[0,IDENTIFIER_MAX_LENGTH-4]}_pkt"
|
1272
|
+
end
|
1273
|
+
|
1274
|
+
def compress_lines(string, spaced = true)
|
1275
|
+
string.split($/).map { |line| line.strip }.join(spaced ? ' ' : '')
|
1276
|
+
end
|
1277
|
+
|
1278
|
+
public
|
1279
|
+
# DBMS_OUTPUT =============================================
|
1280
|
+
#
|
1281
|
+
# PL/SQL in Oracle uses dbms_output for logging print statements
|
1282
|
+
# These methods stick that output into the Rails log so Ruby and PL/SQL
|
1283
|
+
# code can can be debugged together in a single application
|
1284
|
+
DBMS_OUTPUT_BUFFER_SIZE = 10000 #can be 1-1000000
|
1285
|
+
# Turn DBMS_Output logging on
|
1286
|
+
def enable_dbms_output
|
1287
|
+
set_dbms_output_plsql_connection
|
1288
|
+
@enable_dbms_output = true
|
1289
|
+
plsql(:dbms_output).sys.dbms_output.enable(DBMS_OUTPUT_BUFFER_SIZE)
|
1290
|
+
end
|
1291
|
+
# Turn DBMS_Output logging off
|
1292
|
+
def disable_dbms_output
|
1293
|
+
set_dbms_output_plsql_connection
|
1294
|
+
@enable_dbms_output = false
|
1295
|
+
plsql(:dbms_output).sys.dbms_output.disable
|
1296
|
+
end
|
1297
|
+
# Is DBMS_Output logging enabled?
|
1298
|
+
def dbms_output_enabled?
|
1299
|
+
@enable_dbms_output
|
1300
|
+
end
|
1301
|
+
|
1302
|
+
protected
|
1303
|
+
def log(sql, name) #:nodoc:
|
1304
|
+
super sql, name
|
1305
|
+
ensure
|
1306
|
+
log_dbms_output if dbms_output_enabled?
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
private
|
1310
|
+
|
1311
|
+
def set_dbms_output_plsql_connection
|
1312
|
+
raise OracleEnhancedConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
|
1313
|
+
# do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
|
1314
|
+
unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
|
1315
|
+
plsql(:dbms_output).connection = raw_connection
|
1316
|
+
end
|
1317
|
+
end
|
1318
|
+
|
1319
|
+
def log_dbms_output
|
1320
|
+
while true do
|
1321
|
+
result = plsql(:dbms_output).sys.dbms_output.get_line(:line => '', :status => 0)
|
1322
|
+
break unless result[:status] == 0
|
1323
|
+
@logger.debug "DBMS_OUTPUT: #{result[:line]}"
|
1324
|
+
end
|
1325
|
+
end
|
1326
|
+
|
974
1327
|
end
|
975
1328
|
end
|
976
1329
|
end
|
977
1330
|
|
978
|
-
#
|
1331
|
+
# Added LOB writing callback for sessions stored in database
|
979
1332
|
# Otherwise it is not working as Session class is defined before OracleAdapter is loaded in Rails 2.0
|
980
1333
|
if defined?(CGI::Session::ActiveRecordStore::Session)
|
981
1334
|
if !CGI::Session::ActiveRecordStore::Session.respond_to?(:after_save_callback_chain) ||
|
982
1335
|
CGI::Session::ActiveRecordStore::Session.after_save_callback_chain.detect{|cb| cb.method == :enhanced_write_lobs}.nil?
|
1336
|
+
#:stopdoc:
|
983
1337
|
class CGI::Session::ActiveRecordStore::Session
|
984
1338
|
after_save :enhanced_write_lobs
|
985
1339
|
end
|
1340
|
+
#:startdoc:
|
986
1341
|
end
|
987
1342
|
end
|
988
1343
|
|
989
|
-
#
|
1344
|
+
# Load custom create, update, delete methods functionality
|
990
1345
|
# rescue LoadError if ruby-plsql gem cannot be loaded
|
991
1346
|
begin
|
992
1347
|
require 'active_record/connection_adapters/oracle_enhanced_procedures'
|
@@ -997,21 +1352,30 @@ rescue LoadError
|
|
997
1352
|
end
|
998
1353
|
end
|
999
1354
|
|
1000
|
-
#
|
1355
|
+
# Load additional methods for composite_primary_keys support
|
1001
1356
|
require 'active_record/connection_adapters/oracle_enhanced_cpk'
|
1002
1357
|
|
1003
|
-
#
|
1358
|
+
# Load patch for dirty tracking methods
|
1004
1359
|
require 'active_record/connection_adapters/oracle_enhanced_dirty'
|
1005
1360
|
|
1006
|
-
#
|
1361
|
+
# Load rake tasks definitions
|
1007
1362
|
begin
|
1008
1363
|
require 'active_record/connection_adapters/oracle_enhanced_tasks'
|
1009
1364
|
rescue LoadError
|
1010
1365
|
end if defined?(RAILS_ROOT)
|
1011
1366
|
|
1012
|
-
#
|
1367
|
+
# Handles quoting of oracle reserved words
|
1013
1368
|
require 'active_record/connection_adapters/oracle_enhanced_reserved_words'
|
1014
1369
|
|
1015
|
-
#
|
1370
|
+
# Patches and enhancements for schema dumper
|
1371
|
+
require 'active_record/connection_adapters/oracle_enhanced_schema_dumper'
|
1372
|
+
|
1373
|
+
# Extensions for schema definition statements
|
1374
|
+
require 'active_record/connection_adapters/oracle_enhanced_schema_statements_ext'
|
1375
|
+
|
1376
|
+
# Extensions for schema definition
|
1377
|
+
require 'active_record/connection_adapters/oracle_enhanced_schema_definitions'
|
1378
|
+
|
1379
|
+
# Add BigDecimal#to_d, Fixnum#to_d and Bignum#to_d methods if not already present
|
1016
1380
|
require 'active_record/connection_adapters/oracle_enhanced_core_ext'
|
1017
1381
|
|