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