activerecord-oracle_enhanced-adapter 1.7.11 → 1.8.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.
- checksums.yaml +4 -4
- data/History.md +206 -4
- data/README.md +37 -1
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -59
- data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -50
- data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +11 -11
- data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -117
- data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +37 -27
- data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +56 -71
- data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +0 -7
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +51 -69
- data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
- data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +76 -76
- data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +14 -43
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -64
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -47
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +150 -160
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +95 -133
- data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -3
- data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +66 -101
- data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
- data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +290 -533
- data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -10
- data/lib/active_record/oracle_enhanced/type/integer.rb +3 -4
- data/lib/active_record/oracle_enhanced/type/json.rb +8 -0
- data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -1
- data/lib/active_record/oracle_enhanced/type/raw.rb +2 -3
- data/lib/active_record/oracle_enhanced/type/string.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/text.rb +2 -2
- data/lib/active_record/oracle_enhanced/type/timestamptz.rb +23 -0
- data/lib/activerecord-oracle_enhanced-adapter.rb +2 -2
- data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +55 -162
- data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +32 -34
- data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +44 -42
- data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +250 -357
- data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -6
- data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +3 -5
- data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +115 -124
- data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -3
- data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +68 -72
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +64 -80
- data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +223 -329
- data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +18 -20
- data/spec/spec_config.yaml.template +11 -0
- data/spec/spec_helper.rb +59 -59
- data/spec/support/alter_system_user_password.sql +2 -0
- data/spec/support/create_oracle_enhanced_users.sql +31 -0
- metadata +25 -25
- data/.rspec +0 -2
- data/Gemfile +0 -22
- data/RUNNING_TESTS.md +0 -83
- data/Rakefile +0 -45
- data/activerecord-oracle_enhanced-adapter.gemspec +0 -94
- data/lib/active_record/connection_adapters/oracle_enhanced/cpk.rb +0 -19
- data/spec/active_record/connection_adapters/oracle_enhanced_cpk_spec.rb +0 -113
@@ -28,17 +28,18 @@
|
|
28
28
|
# contribution.
|
29
29
|
# portions Copyright 2005 Graham Jenkins
|
30
30
|
|
31
|
-
require
|
32
|
-
require
|
33
|
-
require
|
34
|
-
require
|
35
|
-
require
|
36
|
-
require
|
37
|
-
require
|
38
|
-
require
|
39
|
-
require
|
40
|
-
|
41
|
-
|
31
|
+
require "active_record/connection_adapters/abstract_adapter"
|
32
|
+
require "active_record/connection_adapters/statement_pool"
|
33
|
+
require "active_record/connection_adapters/oracle_enhanced/connection"
|
34
|
+
require "active_record/connection_adapters/oracle_enhanced/database_statements"
|
35
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_statements"
|
36
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_statements_ext"
|
37
|
+
require "active_record/connection_adapters/oracle_enhanced/column_dumper"
|
38
|
+
require "active_record/connection_adapters/oracle_enhanced/context_index"
|
39
|
+
require "active_record/connection_adapters/oracle_enhanced/column"
|
40
|
+
require "active_record/connection_adapters/oracle_enhanced/quoting"
|
41
|
+
|
42
|
+
require "digest/sha1"
|
42
43
|
|
43
44
|
ActiveRecord::Base.class_eval do
|
44
45
|
class_attribute :custom_create_method, :custom_update_method, :custom_delete_method
|
@@ -46,89 +47,12 @@ end
|
|
46
47
|
|
47
48
|
module ActiveRecord
|
48
49
|
class Base
|
49
|
-
# Specify table columns which should be ignored by ActiveRecord, e.g.:
|
50
|
-
#
|
51
|
-
# ignore_table_columns :attribute1, :attribute2
|
52
|
-
def self.ignore_table_columns(*args)
|
53
|
-
connection.ignore_table_columns(table_name,*args)
|
54
|
-
end
|
55
|
-
|
56
|
-
# Specify which table columns should be typecasted to Date (without time), e.g.:
|
57
|
-
#
|
58
|
-
# set_date_columns :created_on, :updated_on
|
59
|
-
def self.set_date_columns(*args)
|
60
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
61
|
-
'set_date_columns` has been deprecated. Please use Rails attribute API.
|
62
|
-
MSG
|
63
|
-
# connection.set_type_for_columns(table_name,:date,*args)
|
64
|
-
end
|
65
|
-
|
66
|
-
# Specify which table columns should be typecasted to Time (or DateTime), e.g.:
|
67
|
-
#
|
68
|
-
# set_datetime_columns :created_date, :updated_date
|
69
|
-
def self.set_datetime_columns(*args)
|
70
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
71
|
-
'set_datetime_columns` has been deprecated. Please use Rails attribute API.
|
72
|
-
MSG
|
73
|
-
# connection.set_type_for_columns(table_name,:datetime,*args)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Specify which table columns should be typecasted to boolean values +true+ or +false+, e.g.:
|
77
|
-
#
|
78
|
-
# set_boolean_columns :is_valid, :is_completed
|
79
|
-
def self.set_boolean_columns(*args)
|
80
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
81
|
-
'set_boolean_columns` has been deprecated. Please use Rails attribute API.
|
82
|
-
MSG
|
83
|
-
# connection.set_type_for_columns(table_name,:boolean,*args)
|
84
|
-
end
|
85
|
-
|
86
|
-
# Specify which table columns should be typecasted to integer values.
|
87
|
-
# Might be useful to force NUMBER(1) column to be integer and not boolean, or force NUMBER column without
|
88
|
-
# scale to be retrieved as integer and not decimal. Example:
|
89
|
-
#
|
90
|
-
# set_integer_columns :version_number, :object_identifier
|
91
|
-
def self.set_integer_columns(*args)
|
92
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
93
|
-
'set_integer_columns` has been deprecated. Please use Rails attribute API.
|
94
|
-
MSG
|
95
|
-
# connection.set_type_for_columns(table_name,:integer,*args)
|
96
|
-
end
|
97
|
-
|
98
|
-
# Specify which table columns should be typecasted to string values.
|
99
|
-
# Might be useful to specify that columns should be string even if its name matches boolean column criteria.
|
100
|
-
#
|
101
|
-
# set_string_columns :active_flag
|
102
|
-
def self.set_string_columns(*args)
|
103
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
104
|
-
'set_string_columns` has been deprecated. Please use Rails attribute API.
|
105
|
-
MSG
|
106
|
-
# connection.set_type_for_columns(table_name,:string,*args)
|
107
|
-
end
|
108
|
-
|
109
|
-
# Get table comment from schema definition.
|
110
|
-
def self.table_comment
|
111
|
-
#TODO: may be deprecated
|
112
|
-
connection.table_comment(self.table_name)
|
113
|
-
end
|
114
|
-
|
115
50
|
def self.lob_columns
|
116
51
|
columns.select do |column|
|
117
52
|
column.respond_to?(:lob?) && column.lob?
|
118
53
|
end
|
119
54
|
end
|
120
55
|
|
121
|
-
def self.virtual_columns
|
122
|
-
columns.select do |column|
|
123
|
-
column.respond_to?(:virtual?) && column.virtual?
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def arel_attributes_with_values(attribute_names)
|
128
|
-
virtual_column_names = self.class.virtual_columns.map(&:name)
|
129
|
-
super(attribute_names - virtual_column_names)
|
130
|
-
end
|
131
|
-
|
132
56
|
# After setting large objects to empty, select the OCI8::LOB
|
133
57
|
# and write back the data.
|
134
58
|
before_update :record_changed_lobs
|
@@ -136,21 +60,21 @@ module ActiveRecord
|
|
136
60
|
|
137
61
|
private
|
138
62
|
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
63
|
+
def enhanced_write_lobs
|
64
|
+
if self.class.connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
|
65
|
+
!(
|
66
|
+
(self.class.custom_create_method || self.class.custom_create_method) ||
|
67
|
+
(self.class.custom_update_method || self.class.custom_update_method)
|
68
|
+
)
|
69
|
+
self.class.connection.write_lobs(self.class.table_name, self.class, attributes, @changed_lob_columns)
|
70
|
+
end
|
146
71
|
end
|
147
|
-
end
|
148
72
|
|
149
|
-
|
150
|
-
|
151
|
-
|
73
|
+
def record_changed_lobs
|
74
|
+
@changed_lob_columns = self.class.lob_columns.select do |col|
|
75
|
+
self.attribute_changed?(col.name) && !self.class.readonly_attributes.to_a.include?(col.name)
|
76
|
+
end
|
152
77
|
end
|
153
|
-
end
|
154
78
|
end
|
155
79
|
end
|
156
80
|
|
@@ -161,7 +85,7 @@ module ActiveRecord
|
|
161
85
|
if config[:emulate_oracle_adapter] == true
|
162
86
|
# allows the enhanced adapter to look like the OracleAdapter. Useful to pick up
|
163
87
|
# conditionals in the rails activerecord test suite
|
164
|
-
require
|
88
|
+
require "active_record/connection_adapters/emulation/oracle_adapter"
|
165
89
|
ConnectionAdapters::OracleAdapter.new(
|
166
90
|
ConnectionAdapters::OracleEnhancedConnection.create(config), logger, config)
|
167
91
|
else
|
@@ -258,92 +182,16 @@ module ActiveRecord
|
|
258
182
|
|
259
183
|
##
|
260
184
|
# :singleton-method:
|
261
|
-
#
|
262
|
-
# to
|
263
|
-
# If you wish that DATE values with hour, minutes and seconds equal to 0 are typecasted
|
264
|
-
# to Date then you can add the following line to your initializer file:
|
185
|
+
# OracleEnhancedAdapter will use the default tablespace, but if you want specific types of
|
186
|
+
# objects to go into specific tablespaces, specify them like this in an initializer:
|
265
187
|
#
|
266
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.
|
188
|
+
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
|
189
|
+
# {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
|
267
190
|
#
|
268
|
-
#
|
269
|
-
#
|
270
|
-
cattr_accessor :emulate_dates
|
271
|
-
self.emulate_dates = false
|
272
|
-
|
273
|
-
##
|
274
|
-
# :singleton-method:
|
275
|
-
# OracleEnhancedAdapter will use the default tablespace, but if you want specific types of
|
276
|
-
# objects to go into specific tablespaces, specify them like this in an initializer:
|
277
|
-
#
|
278
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
|
279
|
-
# {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
|
280
|
-
#
|
281
|
-
# Using the :tablespace option where available (e.g create_table) will take precedence
|
282
|
-
# over these settings.
|
191
|
+
# Using the :tablespace option where available (e.g create_table) will take precedence
|
192
|
+
# over these settings.
|
283
193
|
cattr_accessor :default_tablespaces
|
284
|
-
self.default_tablespaces={}
|
285
|
-
|
286
|
-
##
|
287
|
-
# :singleton-method:
|
288
|
-
# By default, the OracleEnhancedAdapter will typecast all columns of type <tt>DATE</tt>
|
289
|
-
# to Time or DateTime (if value is out of Time value range) value.
|
290
|
-
# If you wish that DATE columns with "date" in their name (e.g. "creation_date") are typecasted
|
291
|
-
# to Date then you can add the following line to your initializer file:
|
292
|
-
#
|
293
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_dates_by_column_name = true
|
294
|
-
#
|
295
|
-
# As this option can have side effects when unnecessary typecasting is done it is recommended
|
296
|
-
# that Date columns are explicily defined with +set_date_columns+ method.
|
297
|
-
cattr_accessor :emulate_dates_by_column_name
|
298
|
-
self.emulate_dates_by_column_name = false
|
299
|
-
|
300
|
-
# Check column name to identify if it is Date (and not Time) column.
|
301
|
-
# Is used if +emulate_dates_by_column_name+ option is set to +true+.
|
302
|
-
# Override this method definition in initializer file if different Date column recognition is needed.
|
303
|
-
def self.is_date_column?(name, table_name = nil)
|
304
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
305
|
-
`self.is_date_column?` has been deprecated. Please use Rails attribute API.
|
306
|
-
MSG
|
307
|
-
return false
|
308
|
-
# name =~ /(^|_)date(_|$)/i
|
309
|
-
end
|
310
|
-
|
311
|
-
# instance method uses at first check if column type defined at class level
|
312
|
-
def is_date_column?(name, table_name = nil) #:nodoc:
|
313
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
314
|
-
`is_date_column?` has been deprecated. Please use Rails attribute API.
|
315
|
-
MSG
|
316
|
-
return false
|
317
|
-
#case get_type_for_column(table_name, name)
|
318
|
-
#when nil
|
319
|
-
# self.class.is_date_column?(name, table_name)
|
320
|
-
#when :date
|
321
|
-
# true
|
322
|
-
#else
|
323
|
-
# false
|
324
|
-
#end
|
325
|
-
end
|
326
|
-
|
327
|
-
##
|
328
|
-
# :singleton-method:
|
329
|
-
# By default, the OracleEnhancedAdapter will typecast all columns of type <tt>NUMBER</tt>
|
330
|
-
# (without precision or scale) to Float or BigDecimal value.
|
331
|
-
# If you wish that NUMBER columns with name "id" or that end with "_id" are typecasted
|
332
|
-
# to Integer then you can add the following line to your initializer file:
|
333
|
-
#
|
334
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.emulate_integers_by_column_name = true
|
335
|
-
cattr_accessor :emulate_integers_by_column_name
|
336
|
-
self.emulate_integers_by_column_name = false
|
337
|
-
|
338
|
-
# Check column name to identify if it is Integer (and not Float or BigDecimal) column.
|
339
|
-
# Is used if +emulate_integers_by_column_name+ option is set to +true+.
|
340
|
-
# Override this method definition in initializer file if different Integer column recognition is needed.
|
341
|
-
def self.is_integer_column?(name, table_name = nil)
|
342
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
343
|
-
`is_integer_column?` has been deprecated. Please use Rails attribute API.
|
344
|
-
MSG
|
345
|
-
return false
|
346
|
-
end
|
194
|
+
self.default_tablespaces = {}
|
347
195
|
|
348
196
|
##
|
349
197
|
# :singleton-method:
|
@@ -354,40 +202,6 @@ module ActiveRecord
|
|
354
202
|
cattr_accessor :emulate_booleans_from_strings
|
355
203
|
self.emulate_booleans_from_strings = false
|
356
204
|
|
357
|
-
# Check column name to identify if it is boolean (and not String) column.
|
358
|
-
# Is used if +emulate_booleans_from_strings+ option is set to +true+.
|
359
|
-
# Override this method definition in initializer file if different boolean column recognition is needed.
|
360
|
-
def self.is_boolean_column?(name, sql_type, table_name = nil)
|
361
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
362
|
-
`is_boolean_column?` has been deprecated. Please use Rails attribute API.
|
363
|
-
MSG
|
364
|
-
return false
|
365
|
-
# return true if ["CHAR(1)","VARCHAR2(1)"].include?(sql_type)
|
366
|
-
# sql_type =~ /^VARCHAR2/ && (name =~ /_flag$/i || name =~ /_yn$/i)
|
367
|
-
end
|
368
|
-
|
369
|
-
# How boolean value should be quoted to String.
|
370
|
-
# Used if +emulate_booleans_from_strings+ option is set to +true+.
|
371
|
-
def self.boolean_to_string(bool)
|
372
|
-
bool ? "Y" : "N"
|
373
|
-
end
|
374
|
-
|
375
|
-
##
|
376
|
-
# :singleton-method:
|
377
|
-
# Specify non-default date format that should be used when assigning string values to :date columns, e.g.:
|
378
|
-
#
|
379
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_date_format = “%d.%m.%Y”
|
380
|
-
cattr_accessor :string_to_date_format
|
381
|
-
self.string_to_date_format = nil
|
382
|
-
|
383
|
-
##
|
384
|
-
# :singleton-method:
|
385
|
-
# Specify non-default time format that should be used when assigning string values to :datetime columns, e.g.:
|
386
|
-
#
|
387
|
-
# ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.string_to_time_format = “%d.%m.%Y %H:%M:%S”
|
388
|
-
cattr_accessor :string_to_time_format
|
389
|
-
self.string_to_time_format = nil
|
390
|
-
|
391
205
|
##
|
392
206
|
# :singleton-method:
|
393
207
|
# By default, OracleEnhanced adapter will use Oracle12 visitor
|
@@ -399,44 +213,21 @@ module ActiveRecord
|
|
399
213
|
cattr_accessor :use_old_oracle_visitor
|
400
214
|
self.use_old_oracle_visitor = false
|
401
215
|
|
402
|
-
class StatementPool
|
403
|
-
|
216
|
+
class StatementPool < ConnectionAdapters::StatementPool
|
217
|
+
private
|
404
218
|
|
405
|
-
|
406
|
-
|
407
|
-
@max = max
|
408
|
-
@cache = {}
|
409
|
-
end
|
410
|
-
|
411
|
-
def each(&block); @cache.each(&block); end
|
412
|
-
def key?(key); @cache.key?(key); end
|
413
|
-
def [](key); @cache[key]; end
|
414
|
-
def length; @cache.length; end
|
415
|
-
def delete(key); @cache.delete(key); end
|
416
|
-
|
417
|
-
def []=(sql, key)
|
418
|
-
while @max <= @cache.size
|
419
|
-
@cache.shift.last.close
|
420
|
-
end
|
421
|
-
@cache[sql] = key
|
422
|
-
end
|
423
|
-
|
424
|
-
def clear
|
425
|
-
@cache.values.each do |cursor|
|
426
|
-
cursor.close
|
219
|
+
def dealloc(stmt)
|
220
|
+
stmt.close
|
427
221
|
end
|
428
|
-
@cache.clear
|
429
|
-
end
|
430
222
|
end
|
431
223
|
|
432
224
|
def initialize(connection, logger = nil, config = {}) # :nodoc:
|
433
225
|
super(connection, logger, config)
|
434
|
-
@
|
435
|
-
@statements = StatementPool.new(connection, config.fetch(:statement_limit) { 250 })
|
226
|
+
@statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
|
436
227
|
@enable_dbms_output = false
|
437
228
|
end
|
438
229
|
|
439
|
-
ADAPTER_NAME =
|
230
|
+
ADAPTER_NAME = "OracleEnhanced".freeze
|
440
231
|
|
441
232
|
def adapter_name #:nodoc:
|
442
233
|
ADAPTER_NAME
|
@@ -450,14 +241,6 @@ module ActiveRecord
|
|
450
241
|
end
|
451
242
|
end
|
452
243
|
|
453
|
-
def supports_migrations? #:nodoc:
|
454
|
-
true
|
455
|
-
end
|
456
|
-
|
457
|
-
def supports_primary_key? #:nodoc:
|
458
|
-
true
|
459
|
-
end
|
460
|
-
|
461
244
|
def supports_savepoints? #:nodoc:
|
462
245
|
true
|
463
246
|
end
|
@@ -470,12 +253,16 @@ module ActiveRecord
|
|
470
253
|
true
|
471
254
|
end
|
472
255
|
|
256
|
+
def supports_foreign_keys_in_create?
|
257
|
+
supports_foreign_keys?
|
258
|
+
end
|
259
|
+
|
473
260
|
def supports_views?
|
474
261
|
true
|
475
262
|
end
|
476
263
|
|
477
264
|
def supports_fetch_first_n_rows_and_offset?
|
478
|
-
if !use_old_oracle_visitor && @connection.database_version
|
265
|
+
if !use_old_oracle_visitor && @connection.database_version.first >= 12
|
479
266
|
true
|
480
267
|
else
|
481
268
|
false
|
@@ -483,9 +270,7 @@ module ActiveRecord
|
|
483
270
|
end
|
484
271
|
|
485
272
|
def supports_datetime_with_precision?
|
486
|
-
|
487
|
-
#to map :datetime as DATE
|
488
|
-
@connection.database_version.first >= 9
|
273
|
+
true
|
489
274
|
end
|
490
275
|
|
491
276
|
def supports_comments?
|
@@ -496,47 +281,77 @@ module ActiveRecord
|
|
496
281
|
@connection.database_version.to_s >= [11, 2].to_s
|
497
282
|
end
|
498
283
|
|
284
|
+
def supports_virtual_columns?
|
285
|
+
@connection.database_version.first >= 11
|
286
|
+
end
|
287
|
+
|
288
|
+
def supports_json?
|
289
|
+
# No migration supported for :json type due to there is no `JSON` data type
|
290
|
+
# in Oracle Database itself.
|
291
|
+
#
|
292
|
+
# 1.Define :string or :text in migration
|
293
|
+
#
|
294
|
+
# create_table :test_posts, force: true do |t|
|
295
|
+
# t.string :title
|
296
|
+
# t.text :article
|
297
|
+
# end
|
298
|
+
#
|
299
|
+
# 2. Set :json attributes
|
300
|
+
#
|
301
|
+
# class TestPost < ActiveRecord::Base
|
302
|
+
# attribute :title, :json
|
303
|
+
# attribute :article, :json
|
304
|
+
# end
|
305
|
+
#
|
306
|
+
# 3. Add `is json` database constraints by running sql statements
|
307
|
+
#
|
308
|
+
# alter table test_posts add constraint test_posts_title_is_json check (title is json)
|
309
|
+
# alter table test_posts add constraint test_posts_article_is_json check (article is json)
|
310
|
+
#
|
311
|
+
@connection.database_version.first >= 12
|
312
|
+
end
|
313
|
+
|
499
314
|
#:stopdoc:
|
500
315
|
DEFAULT_NLS_PARAMETERS = {
|
501
|
-
:
|
502
|
-
:
|
503
|
-
:
|
504
|
-
:
|
505
|
-
:
|
506
|
-
:
|
507
|
-
:
|
508
|
-
:
|
509
|
-
:
|
510
|
-
:
|
511
|
-
:
|
512
|
-
:
|
513
|
-
:
|
514
|
-
:
|
515
|
-
:
|
516
|
-
:
|
517
|
-
:
|
316
|
+
nls_calendar: nil,
|
317
|
+
nls_comp: nil,
|
318
|
+
nls_currency: nil,
|
319
|
+
nls_date_format: "YYYY-MM-DD HH24:MI:SS",
|
320
|
+
nls_date_language: nil,
|
321
|
+
nls_dual_currency: nil,
|
322
|
+
nls_iso_currency: nil,
|
323
|
+
nls_language: nil,
|
324
|
+
nls_length_semantics: "CHAR",
|
325
|
+
nls_nchar_conv_excp: nil,
|
326
|
+
nls_numeric_characters: nil,
|
327
|
+
nls_sort: nil,
|
328
|
+
nls_territory: nil,
|
329
|
+
nls_timestamp_format: "YYYY-MM-DD HH24:MI:SS:FF6",
|
330
|
+
nls_timestamp_tz_format: nil,
|
331
|
+
nls_time_format: nil,
|
332
|
+
nls_time_tz_format: nil
|
518
333
|
}
|
519
334
|
|
520
335
|
#:stopdoc:
|
521
336
|
NATIVE_DATABASE_TYPES = {
|
522
|
-
:
|
523
|
-
:
|
524
|
-
:
|
525
|
-
:
|
526
|
-
:
|
527
|
-
:
|
528
|
-
:
|
529
|
-
:
|
530
|
-
:
|
531
|
-
:
|
532
|
-
:
|
533
|
-
:
|
534
|
-
:
|
535
|
-
:
|
337
|
+
primary_key: "NUMBER(38) NOT NULL PRIMARY KEY",
|
338
|
+
string: { name: "VARCHAR2", limit: 255 },
|
339
|
+
text: { name: "CLOB" },
|
340
|
+
integer: { name: "NUMBER", limit: 38 },
|
341
|
+
float: { name: "BINARY_FLOAT" },
|
342
|
+
decimal: { name: "DECIMAL" },
|
343
|
+
datetime: { name: "TIMESTAMP" },
|
344
|
+
timestamp: { name: "TIMESTAMP" },
|
345
|
+
time: { name: "TIMESTAMP" },
|
346
|
+
date: { name: "DATE" },
|
347
|
+
binary: { name: "BLOB" },
|
348
|
+
boolean: { name: "NUMBER", limit: 1 },
|
349
|
+
raw: { name: "RAW", limit: 2000 },
|
350
|
+
bigint: { name: "NUMBER", limit: 19 }
|
536
351
|
}
|
537
352
|
# if emulate_booleans_from_strings then store booleans in VARCHAR2
|
538
353
|
NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS = NATIVE_DATABASE_TYPES.dup.merge(
|
539
|
-
:
|
354
|
+
boolean: { name: "VARCHAR2", limit: 1 }
|
540
355
|
)
|
541
356
|
#:startdoc:
|
542
357
|
|
@@ -586,7 +401,6 @@ module ActiveRecord
|
|
586
401
|
def in_clause_length
|
587
402
|
1000
|
588
403
|
end
|
589
|
-
alias ids_in_list_limit in_clause_length
|
590
404
|
|
591
405
|
# CONNECTION MANAGEMENT ====================================
|
592
406
|
#
|
@@ -638,7 +452,7 @@ module ActiveRecord
|
|
638
452
|
end
|
639
453
|
|
640
454
|
# use in set_sequence_name to avoid fetching primary key value from sequence
|
641
|
-
AUTOGENERATED_SEQUENCE_NAME =
|
455
|
+
AUTOGENERATED_SEQUENCE_NAME = "autogenerated".freeze
|
642
456
|
|
643
457
|
# Returns the next sequence value from a sequence generator. Not generally
|
644
458
|
# called directly; used by ActiveRecord to get the next primary key value
|
@@ -674,8 +488,8 @@ module ActiveRecord
|
|
674
488
|
|
675
489
|
def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil) #:nodoc:
|
676
490
|
return nil unless data_source_exists?(table_name)
|
677
|
-
unless primary_key
|
678
|
-
|
491
|
+
unless primary_key && sequence_name
|
492
|
+
# *Note*: Only primary key is implemented - sequence will be nil.
|
679
493
|
primary_key, sequence_name = pk_and_sequence_for(table_name)
|
680
494
|
# TODO This sequence_name implemantation is just enough
|
681
495
|
# to satisty fixures. To get correct sequence_name always
|
@@ -703,13 +517,7 @@ module ActiveRecord
|
|
703
517
|
|
704
518
|
# Writes LOB values from attributes for specified columns
|
705
519
|
def write_lobs(table_name, klass, attributes, columns) #:nodoc:
|
706
|
-
|
707
|
-
is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
|
708
|
-
if is_with_cpk
|
709
|
-
id = klass.primary_key.map {|pk| attributes[pk.to_s] }
|
710
|
-
else
|
711
|
-
id = quote(attributes[klass.primary_key])
|
712
|
-
end
|
520
|
+
id = quote(attributes[klass.primary_key])
|
713
521
|
columns.each do |col|
|
714
522
|
value = attributes[col.name]
|
715
523
|
# changed sequence of next two lines - should check if value is nil before converting to yaml
|
@@ -718,9 +526,8 @@ module ActiveRecord
|
|
718
526
|
value = klass.attribute_types[col.name].serialize(value)
|
719
527
|
end
|
720
528
|
uncached do
|
721
|
-
sql =
|
722
|
-
|
723
|
-
unless lob_record = select_one(sql, 'Writable Large Object')
|
529
|
+
sql = "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE"
|
530
|
+
unless lob_record = select_one(sql, "Writable Large Object")
|
724
531
|
raise ActiveRecord::RecordNotFound, "statement #{sql} returned no rows"
|
725
532
|
end
|
726
533
|
lob = lob_record[col.name]
|
@@ -731,6 +538,8 @@ module ActiveRecord
|
|
731
538
|
|
732
539
|
# Current database name
|
733
540
|
def current_database
|
541
|
+
select_value("SELECT SYS_CONTEXT('userenv', 'con_name') FROM dual")
|
542
|
+
rescue ActiveRecord::StatementInvalid
|
734
543
|
select_value("SELECT SYS_CONTEXT('userenv', 'db_name') FROM dual")
|
735
544
|
end
|
736
545
|
|
@@ -749,39 +558,40 @@ module ActiveRecord
|
|
749
558
|
select_value("SELECT LOWER(default_tablespace) FROM user_users WHERE username = SYS_CONTEXT('userenv', 'current_schema')")
|
750
559
|
end
|
751
560
|
|
752
|
-
def tables
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
MSG
|
758
|
-
|
759
|
-
if name
|
760
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
761
|
-
Passing arguments to #tables is deprecated without replacement.
|
762
|
-
MSG
|
763
|
-
end
|
764
|
-
|
765
|
-
data_sources
|
561
|
+
def tables #:nodoc:
|
562
|
+
select_values(<<-SQL, "SCHEMA")
|
563
|
+
SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name)
|
564
|
+
FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'
|
565
|
+
SQL
|
766
566
|
end
|
767
567
|
|
768
568
|
def data_sources
|
769
|
-
|
770
|
-
"SELECT DECODE(table_name, UPPER(table_name), LOWER(table_name), table_name) FROM all_tables WHERE owner = SYS_CONTEXT('userenv', 'current_schema') AND secondary = 'N'",
|
771
|
-
'SCHEMA')
|
569
|
+
super
|
772
570
|
end
|
773
571
|
|
774
572
|
def table_exists?(table_name)
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
573
|
+
table_name = table_name.to_s
|
574
|
+
if table_name.include?("@")
|
575
|
+
# db link is not table
|
576
|
+
false
|
577
|
+
else
|
578
|
+
default_owner = current_schema
|
579
|
+
end
|
580
|
+
real_name = ActiveRecord::ConnectionAdapters::OracleEnhanced::Quoting.valid_table_name?(table_name) ?
|
581
|
+
table_name.upcase : table_name
|
582
|
+
if real_name.include?(".")
|
583
|
+
table_owner, table_name = real_name.split(".")
|
584
|
+
else
|
585
|
+
table_owner, table_name = default_owner, real_name
|
586
|
+
end
|
587
|
+
select_values(<<-SQL, "SCHEMA").any?
|
588
|
+
SELECT owner, table_name
|
589
|
+
FROM all_tables
|
590
|
+
WHERE owner = '#{table_owner}'
|
591
|
+
AND table_name = q'[#{table_name}]'
|
592
|
+
SQL
|
782
593
|
end
|
783
594
|
|
784
|
-
# Will return true if database object exists (to be able to use also views and synonyms for ActiveRecord models)
|
785
595
|
# Needs to consider how to support synonyms in Rails 5.1
|
786
596
|
def data_source_exists?(table_name)
|
787
597
|
(_owner, table_name, _db_link) = @connection.describe(table_name)
|
@@ -791,7 +601,7 @@ module ActiveRecord
|
|
791
601
|
end
|
792
602
|
|
793
603
|
def views # :nodoc:
|
794
|
-
select_values("SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', '
|
604
|
+
select_values("SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')")
|
795
605
|
end
|
796
606
|
|
797
607
|
def materialized_views #:nodoc:
|
@@ -806,7 +616,7 @@ module ActiveRecord
|
|
806
616
|
(owner, table_name, db_link) = @connection.describe(table_name)
|
807
617
|
unless all_schema_indexes
|
808
618
|
default_tablespace_name = default_tablespace
|
809
|
-
result = select_all(<<-SQL.strip.gsub(/\s+/,
|
619
|
+
result = select_all(<<-SQL.strip.gsub(/\s+/, " "))
|
810
620
|
SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
|
811
621
|
i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
|
812
622
|
LOWER(i.tablespace_name) AS tablespace_name,
|
@@ -831,10 +641,10 @@ module ActiveRecord
|
|
831
641
|
result.each do |row|
|
832
642
|
# have to keep track of indexes because above query returns dups
|
833
643
|
# there is probably a better query we could figure out
|
834
|
-
if current_index != row[
|
644
|
+
if current_index != row["index_name"]
|
835
645
|
statement_parameters = nil
|
836
|
-
if row[
|
837
|
-
procedure_name = default_datastore_procedure(row[
|
646
|
+
if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
|
647
|
+
procedure_name = default_datastore_procedure(row["index_name"])
|
838
648
|
source = select_values(<<-SQL).join
|
839
649
|
SELECT text
|
840
650
|
FROM all_source#{db_link}
|
@@ -847,82 +657,36 @@ module ActiveRecord
|
|
847
657
|
end
|
848
658
|
end
|
849
659
|
all_schema_indexes << OracleEnhanced::IndexDefinition.new(
|
850
|
-
row[
|
851
|
-
row[
|
852
|
-
row[
|
660
|
+
row["table_name"],
|
661
|
+
row["index_name"],
|
662
|
+
row["uniqueness"] == "UNIQUE",
|
853
663
|
[],
|
854
664
|
nil,
|
855
665
|
nil,
|
856
666
|
nil,
|
857
|
-
row[
|
667
|
+
row["index_type"] == "DOMAIN" ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
|
858
668
|
nil,
|
859
|
-
row[
|
669
|
+
row["parameters"],
|
860
670
|
statement_parameters,
|
861
|
-
row[
|
862
|
-
current_index = row[
|
671
|
+
row["tablespace_name"] == default_tablespace_name ? nil : row["tablespace_name"])
|
672
|
+
current_index = row["index_name"]
|
863
673
|
end
|
864
674
|
|
865
675
|
# Functional index columns and virtual columns both get stored as column expressions,
|
866
676
|
# but re-creating a virtual column index as an expression (instead of using the virtual column's name)
|
867
677
|
# results in a ORA-54018 error. Thus, we only want the column expression value returned
|
868
678
|
# when the column is not virtual.
|
869
|
-
if row[
|
870
|
-
all_schema_indexes.last.columns << row[
|
679
|
+
if row["column_expression"] && row["virtual_column"] != "YES"
|
680
|
+
all_schema_indexes.last.columns << row["column_expression"]
|
871
681
|
else
|
872
|
-
all_schema_indexes.last.columns << row[
|
682
|
+
all_schema_indexes.last.columns << row["column_name"].downcase
|
873
683
|
end
|
874
684
|
end
|
875
685
|
end
|
876
686
|
|
877
687
|
# Return the indexes just for the requested table, since AR is structured that way
|
878
688
|
table_name = table_name.downcase
|
879
|
-
all_schema_indexes.select{|i| i.table == table_name}
|
880
|
-
end
|
881
|
-
|
882
|
-
@@ignore_table_columns = nil #:nodoc:
|
883
|
-
|
884
|
-
# set ignored columns for table
|
885
|
-
def ignore_table_columns(table_name, *args) #:nodoc:
|
886
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
887
|
-
`ignore_table_columns` will be deprecated in next version of Oracle enhanced adapter
|
888
|
-
since Rails 5 introduces `ignored_columns`. Use `ignored_columns` instead of `ignore_table_columns`.
|
889
|
-
MSG
|
890
|
-
@@ignore_table_columns ||= {}
|
891
|
-
@@ignore_table_columns[table_name] ||= []
|
892
|
-
@@ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
|
893
|
-
@@ignore_table_columns[table_name].uniq!
|
894
|
-
end
|
895
|
-
|
896
|
-
def ignored_table_columns(table_name) #:nodoc:
|
897
|
-
@@ignore_table_columns ||= {}
|
898
|
-
@@ignore_table_columns[table_name]
|
899
|
-
end
|
900
|
-
|
901
|
-
# used just in tests to clear ignored table columns
|
902
|
-
def clear_ignored_table_columns #:nodoc:
|
903
|
-
@@ignore_table_columns = nil
|
904
|
-
end
|
905
|
-
|
906
|
-
@@table_column_type = nil #:nodoc:
|
907
|
-
|
908
|
-
# set explicit type for specified table columns
|
909
|
-
def set_type_for_columns(table_name, column_type, *args) #:nodoc:
|
910
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
911
|
-
`set_type_for_columns` has been deprecated. Please use Rails attribute API.
|
912
|
-
MSG
|
913
|
-
end
|
914
|
-
|
915
|
-
def get_type_for_column(table_name, column_name) #:nodoc:
|
916
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
917
|
-
`get_type_for_columns` has been deprecated. Please use Rails attribute API.
|
918
|
-
MSG
|
919
|
-
end
|
920
|
-
|
921
|
-
# used just in tests to clear column data type definitions
|
922
|
-
def clear_types_for_columns #:nodoc:
|
923
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
924
|
-
`clear_types_for_columns` has been deprecated. Please use Rails attribute API.
|
925
|
-
MSG
|
689
|
+
all_schema_indexes.select { |i| i.table == table_name }
|
926
690
|
end
|
927
691
|
|
928
692
|
# check if table has primary key trigger with _pkt suffix
|
@@ -934,12 +698,12 @@ module ActiveRecord
|
|
934
698
|
SELECT trigger_name
|
935
699
|
FROM all_triggers#{db_link}
|
936
700
|
WHERE owner = '#{owner}'
|
937
|
-
AND trigger_name = '#{trigger_name}'
|
701
|
+
AND trigger_name = q'[#{trigger_name}]'
|
938
702
|
AND table_owner = '#{owner}'
|
939
|
-
AND table_name = '#{desc_table_name}'
|
703
|
+
AND table_name = q'[#{desc_table_name}]'
|
940
704
|
AND status = 'ENABLED'
|
941
705
|
SQL
|
942
|
-
select_value(pkt_sql,
|
706
|
+
select_value(pkt_sql, "Primary Key Trigger") ? true : false
|
943
707
|
end
|
944
708
|
|
945
709
|
##
|
@@ -963,15 +727,13 @@ module ActiveRecord
|
|
963
727
|
|
964
728
|
def columns_without_cache(table_name, name = nil) #:nodoc:
|
965
729
|
table_name = table_name.to_s
|
966
|
-
# get ignored_columns by original table name
|
967
|
-
ignored_columns = ignored_table_columns(table_name)
|
968
730
|
|
969
731
|
(owner, desc_table_name, db_link) = @connection.describe(table_name)
|
970
732
|
|
971
733
|
# reset do_not_prefetch_primary_key cache for this table
|
972
734
|
@@do_not_prefetch_primary_key[table_name] = nil
|
973
735
|
|
974
|
-
table_cols = <<-SQL.strip.gsub(/\s+/,
|
736
|
+
table_cols = <<-SQL.strip.gsub(/\s+/, " ")
|
975
737
|
SELECT cols.column_name AS name, cols.data_type AS sql_type,
|
976
738
|
cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
|
977
739
|
cols.data_type_owner AS sql_type_owner,
|
@@ -985,7 +747,7 @@ module ActiveRecord
|
|
985
747
|
comments.comments as column_comment
|
986
748
|
FROM all_tab_cols#{db_link} cols, all_col_comments#{db_link} comments
|
987
749
|
WHERE cols.owner = '#{owner}'
|
988
|
-
AND cols.table_name =
|
750
|
+
AND cols.table_name = #{quote(desc_table_name)}
|
989
751
|
AND cols.hidden_column = 'NO'
|
990
752
|
AND cols.owner = comments.owner
|
991
753
|
AND cols.table_name = comments.table_name
|
@@ -994,46 +756,44 @@ module ActiveRecord
|
|
994
756
|
SQL
|
995
757
|
|
996
758
|
# added deletion of ignored columns
|
997
|
-
select_all(table_cols, name).to_a.
|
998
|
-
|
999
|
-
end.map do |row|
|
1000
|
-
limit, scale = row['limit'], row['scale']
|
759
|
+
select_all(table_cols, name).to_a.map do |row|
|
760
|
+
limit, scale = row["limit"], row["scale"]
|
1001
761
|
if limit || scale
|
1002
|
-
row[
|
762
|
+
row["sql_type"] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
|
1003
763
|
end
|
1004
764
|
|
1005
|
-
if row[
|
1006
|
-
row[
|
765
|
+
if row["sql_type_owner"]
|
766
|
+
row["sql_type"] = row["sql_type_owner"] + "." + row["sql_type"]
|
1007
767
|
end
|
1008
768
|
|
1009
|
-
is_virtual = row[
|
769
|
+
is_virtual = row["virtual_column"] == "YES"
|
1010
770
|
|
1011
771
|
# clean up odd default spacing from Oracle
|
1012
|
-
if row[
|
1013
|
-
row[
|
772
|
+
if row["data_default"] && !is_virtual
|
773
|
+
row["data_default"].sub!(/^(.*?)\s*$/, '\1')
|
1014
774
|
|
1015
775
|
# If a default contains a newline these cleanup regexes need to
|
1016
776
|
# match newlines.
|
1017
|
-
row[
|
1018
|
-
row[
|
777
|
+
row["data_default"].sub!(/^'(.*)'$/m, '\1')
|
778
|
+
row["data_default"] = nil if row["data_default"] =~ /^(null|empty_[bc]lob\(\))$/i
|
1019
779
|
# TODO: Needs better fix to fallback "N" to false
|
1020
|
-
row[
|
780
|
+
row["data_default"] = false if (row["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings)
|
1021
781
|
end
|
1022
782
|
|
1023
|
-
type_metadata = fetch_type_metadata(row[
|
1024
|
-
new_column(oracle_downcase(row[
|
1025
|
-
row[
|
783
|
+
type_metadata = fetch_type_metadata(row["sql_type"])
|
784
|
+
new_column(oracle_downcase(row["name"]),
|
785
|
+
row["data_default"],
|
1026
786
|
type_metadata,
|
1027
|
-
row[
|
787
|
+
row["nullable"] == "Y",
|
1028
788
|
table_name,
|
1029
789
|
is_virtual,
|
1030
790
|
false,
|
1031
|
-
row[
|
791
|
+
row["column_comment"]
|
1032
792
|
)
|
1033
793
|
end
|
1034
794
|
end
|
1035
795
|
|
1036
|
-
def new_column(name, default, sql_type_metadata = nil, null = true, table_name = nil, virtual = false, returning_id = false,comment = nil) # :nodoc:
|
796
|
+
def new_column(name, default, sql_type_metadata = nil, null = true, table_name = nil, virtual = false, returning_id = false, comment = nil) # :nodoc:
|
1037
797
|
OracleEnhancedColumn.new(name, default, sql_type_metadata, null, table_name, virtual, returning_id, comment)
|
1038
798
|
end
|
1039
799
|
|
@@ -1061,7 +821,7 @@ module ActiveRecord
|
|
1061
821
|
|
1062
822
|
# Find a table's primary key and sequence.
|
1063
823
|
# *Note*: Only primary key is implemented - sequence will be nil.
|
1064
|
-
def pk_and_sequence_for(table_name, owner=nil, desc_table_name=nil, db_link=nil) #:nodoc:
|
824
|
+
def pk_and_sequence_for(table_name, owner = nil, desc_table_name = nil, db_link = nil) #:nodoc:
|
1065
825
|
if @@cache_columns
|
1066
826
|
@@pk_and_sequence_for_cache ||= {}
|
1067
827
|
if @@pk_and_sequence_for_cache.key?(table_name)
|
@@ -1074,22 +834,22 @@ module ActiveRecord
|
|
1074
834
|
end
|
1075
835
|
end
|
1076
836
|
|
1077
|
-
def pk_and_sequence_for_without_cache(table_name, owner=nil, desc_table_name=nil, db_link=nil) #:nodoc:
|
837
|
+
def pk_and_sequence_for_without_cache(table_name, owner = nil, desc_table_name = nil, db_link = nil) #:nodoc:
|
1078
838
|
(owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
|
1079
839
|
|
1080
|
-
seqs = select_values(<<-SQL.strip.gsub(/\s+/,
|
840
|
+
seqs = select_values(<<-SQL.strip.gsub(/\s+/, " "), "Sequence")
|
1081
841
|
select us.sequence_name
|
1082
842
|
from all_sequences#{db_link} us
|
1083
843
|
where us.sequence_owner = '#{owner}'
|
1084
|
-
and us.sequence_name =
|
844
|
+
and us.sequence_name = upper(#{quote(default_sequence_name(desc_table_name))})
|
1085
845
|
SQL
|
1086
846
|
|
1087
847
|
# changed back from user_constraints to all_constraints for consistency
|
1088
|
-
pks = select_values(<<-SQL.strip.gsub(/\s+/,
|
848
|
+
pks = select_values(<<-SQL.strip.gsub(/\s+/, " "), "Primary Key")
|
1089
849
|
SELECT cc.column_name
|
1090
850
|
FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
|
1091
851
|
WHERE c.owner = '#{owner}'
|
1092
|
-
AND c.table_name =
|
852
|
+
AND c.table_name = #{quote(desc_table_name)}
|
1093
853
|
AND c.constraint_type = 'P'
|
1094
854
|
AND cc.owner = c.owner
|
1095
855
|
AND cc.constraint_name = c.constraint_name
|
@@ -1112,14 +872,14 @@ module ActiveRecord
|
|
1112
872
|
pk_and_sequence && pk_and_sequence.first
|
1113
873
|
end
|
1114
874
|
|
1115
|
-
def has_primary_key?(table_name, owner=nil, desc_table_name=nil, db_link=nil) #:nodoc:
|
875
|
+
def has_primary_key?(table_name, owner = nil, desc_table_name = nil, db_link = nil) #:nodoc:
|
1116
876
|
!pk_and_sequence_for(table_name, owner, desc_table_name, db_link).nil?
|
1117
877
|
end
|
1118
878
|
|
1119
879
|
def primary_keys(table_name) # :nodoc:
|
1120
880
|
(owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
|
1121
881
|
|
1122
|
-
pks = select_values(<<-SQL.strip_heredoc,
|
882
|
+
pks = select_values(<<-SQL.strip_heredoc, "Primary Keys")
|
1123
883
|
SELECT cc.column_name
|
1124
884
|
FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
|
1125
885
|
WHERE c.owner = '#{owner}'
|
@@ -1129,7 +889,7 @@ module ActiveRecord
|
|
1129
889
|
AND cc.constraint_name = c.constraint_name
|
1130
890
|
order by cc.position
|
1131
891
|
SQL
|
1132
|
-
pks.map {|pk| oracle_downcase(pk)}
|
892
|
+
pks.map { |pk| oracle_downcase(pk) }
|
1133
893
|
end
|
1134
894
|
|
1135
895
|
def columns_for_distinct(columns, orders) #:nodoc:
|
@@ -1138,30 +898,18 @@ module ActiveRecord
|
|
1138
898
|
# the inclusion of these columns doesn't invalidate the DISTINCT
|
1139
899
|
#
|
1140
900
|
# It does not construct DISTINCT clause. Just return column names for distinct.
|
1141
|
-
order_columns = orders.reject(&:blank?).map{ |s|
|
1142
|
-
|
1143
|
-
|
1144
|
-
|
1145
|
-
}.reject(&:blank?).map.with_index { |column,i|
|
901
|
+
order_columns = orders.reject(&:blank?).map { |s|
|
902
|
+
s = s.to_sql unless s.is_a?(String)
|
903
|
+
# remove any ASC/DESC modifiers
|
904
|
+
s.gsub(/\s+(ASC|DESC)\s*?/i, "")
|
905
|
+
}.reject(&:blank?).map.with_index { |column, i|
|
1146
906
|
"FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
|
1147
907
|
}
|
1148
|
-
|
908
|
+
[super, *order_columns].join(", ")
|
1149
909
|
end
|
1150
910
|
|
1151
911
|
def temporary_table?(table_name) #:nodoc:
|
1152
|
-
select_value("SELECT temporary FROM all_tables WHERE table_name = '#{table_name.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')") ==
|
1153
|
-
end
|
1154
|
-
|
1155
|
-
# construct additional wrapper subquery if select.offset is used to avoid generation of invalid subquery
|
1156
|
-
# ... IN ( SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM ( ... ) raw_sql_ ) WHERE raw_rnum_ > ... )
|
1157
|
-
def join_to_update(update, select, key) #:nodoc:
|
1158
|
-
#TODO: Need to validate if we can remove join_to_update from Oracle enhanced adapter after testing
|
1159
|
-
# older version of Oracle 11gR2
|
1160
|
-
super
|
1161
|
-
end
|
1162
|
-
|
1163
|
-
def valid_type?(type)
|
1164
|
-
!native_database_types[type].nil?
|
912
|
+
select_value("SELECT temporary FROM all_tables WHERE table_name = '#{table_name.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')") == "Y"
|
1165
913
|
end
|
1166
914
|
|
1167
915
|
def combine_bind_parameters(
|
@@ -1173,7 +921,7 @@ module ActiveRecord
|
|
1173
921
|
offset: nil
|
1174
922
|
) # :nodoc:
|
1175
923
|
result = from_clause + join_clause + where_clause + having_clause
|
1176
|
-
if RUBY_ENGINE ==
|
924
|
+
if RUBY_ENGINE == "jruby" && !supports_fetch_first_n_rows_and_offset? && offset && limit
|
1177
925
|
result << offset
|
1178
926
|
result << limit
|
1179
927
|
result << offset
|
@@ -1190,67 +938,72 @@ module ActiveRecord
|
|
1190
938
|
|
1191
939
|
protected
|
1192
940
|
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
|
1199
|
-
|
1200
|
-
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1208
|
-
|
1209
|
-
|
1210
|
-
|
941
|
+
def initialize_type_map(m)
|
942
|
+
super
|
943
|
+
# oracle
|
944
|
+
register_class_with_precision m, %r(ZONE)i, ActiveRecord::OracleEnhanced::Type::TimestampTz
|
945
|
+
register_class_with_limit m, %r(raw)i, ActiveRecord::OracleEnhanced::Type::Raw
|
946
|
+
register_class_with_limit m, %r(char)i, ActiveRecord::OracleEnhanced::Type::String
|
947
|
+
register_class_with_limit m, %r(clob)i, ActiveRecord::OracleEnhanced::Type::Text
|
948
|
+
|
949
|
+
m.register_type "NCHAR", ActiveRecord::OracleEnhanced::Type::NationalCharacterString.new
|
950
|
+
m.alias_type %r(NVARCHAR2)i, "NCHAR"
|
951
|
+
|
952
|
+
m.register_type(%r(NUMBER)i) do |sql_type|
|
953
|
+
scale = extract_scale(sql_type)
|
954
|
+
precision = extract_precision(sql_type)
|
955
|
+
limit = extract_limit(sql_type)
|
956
|
+
if scale == 0
|
957
|
+
ActiveRecord::OracleEnhanced::Type::Integer.new(precision: precision, limit: limit)
|
958
|
+
else
|
959
|
+
Type::Decimal.new(precision: precision, scale: scale)
|
960
|
+
end
|
1211
961
|
end
|
1212
|
-
end
|
1213
962
|
|
1214
|
-
|
1215
|
-
|
1216
|
-
|
1217
|
-
|
1218
|
-
|
963
|
+
if OracleEnhancedAdapter.emulate_booleans
|
964
|
+
if OracleEnhancedAdapter.emulate_booleans_from_strings
|
965
|
+
m.register_type %r(^VARCHAR2\(1\))i, ActiveRecord::OracleEnhanced::Type::Boolean.new
|
966
|
+
else
|
967
|
+
m.register_type %r(^NUMBER\(1\))i, Type::Boolean.new
|
968
|
+
end
|
1219
969
|
end
|
1220
970
|
end
|
1221
|
-
end
|
1222
971
|
|
1223
|
-
|
1224
|
-
|
1225
|
-
|
1226
|
-
|
1227
|
-
|
1228
|
-
|
972
|
+
def extract_limit(sql_type) #:nodoc:
|
973
|
+
case sql_type
|
974
|
+
when /^bigint/i
|
975
|
+
19
|
976
|
+
when /\((.*)\)/
|
977
|
+
$1.to_i
|
978
|
+
end
|
1229
979
|
end
|
1230
|
-
end
|
1231
980
|
|
1232
|
-
|
1233
|
-
|
1234
|
-
|
1235
|
-
|
1236
|
-
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
|
981
|
+
def translate_exception(exception, message) #:nodoc:
|
982
|
+
case @connection.error_code(exception)
|
983
|
+
when 1
|
984
|
+
RecordNotUnique.new(message)
|
985
|
+
when 942, 955, 1418
|
986
|
+
ActiveRecord::StatementInvalid.new(message)
|
987
|
+
when 1400
|
988
|
+
ActiveRecord::NotNullViolation.new(message)
|
989
|
+
when 2291
|
990
|
+
InvalidForeignKey.new(message)
|
991
|
+
when 12899
|
992
|
+
ValueTooLong.new(message)
|
993
|
+
else
|
994
|
+
super
|
995
|
+
end
|
1242
996
|
end
|
1243
|
-
end
|
1244
997
|
|
1245
998
|
private
|
1246
999
|
|
1247
|
-
|
1248
|
-
|
1249
|
-
|
1000
|
+
def oracle_downcase(column_name)
|
1001
|
+
@connection.oracle_downcase(column_name)
|
1002
|
+
end
|
1250
1003
|
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1004
|
+
def compress_lines(string, join_with = "\n")
|
1005
|
+
string.split($/).map { |line| line.strip }.join(join_with)
|
1006
|
+
end
|
1254
1007
|
|
1255
1008
|
public
|
1256
1009
|
# DBMS_OUTPUT =============================================
|
@@ -1280,84 +1033,88 @@ module ActiveRecord
|
|
1280
1033
|
end
|
1281
1034
|
|
1282
1035
|
protected
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
|
1036
|
+
def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
|
1037
|
+
super
|
1038
|
+
ensure
|
1039
|
+
log_dbms_output if dbms_output_enabled?
|
1040
|
+
end
|
1288
1041
|
|
1289
1042
|
private
|
1290
1043
|
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1044
|
+
def set_dbms_output_plsql_connection
|
1045
|
+
raise OracleEnhancedConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
|
1046
|
+
# do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
|
1047
|
+
unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
|
1048
|
+
plsql(:dbms_output).connection = raw_connection
|
1049
|
+
end
|
1296
1050
|
end
|
1297
|
-
end
|
1298
1051
|
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1052
|
+
def log_dbms_output
|
1053
|
+
while true do
|
1054
|
+
result = plsql(:dbms_output).sys.dbms_output.get_line(line: "", status: 0)
|
1055
|
+
break unless result[:status] == 0
|
1056
|
+
@logger.debug "DBMS_OUTPUT: #{result[:line]}" if @logger
|
1057
|
+
end
|
1304
1058
|
end
|
1305
|
-
end
|
1306
1059
|
end
|
1307
1060
|
end
|
1308
1061
|
end
|
1309
1062
|
|
1310
1063
|
# Implementation of standard schema definition statements and extensions for schema definition
|
1311
|
-
require
|
1312
|
-
require
|
1064
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_statements"
|
1065
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_statements_ext"
|
1313
1066
|
|
1314
1067
|
# Extensions for schema definition
|
1315
|
-
require
|
1068
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_definitions"
|
1316
1069
|
|
1317
1070
|
# Extensions for context index definition
|
1318
|
-
require
|
1319
|
-
|
1320
|
-
# Load additional methods for composite_primary_keys support
|
1321
|
-
require 'active_record/connection_adapters/oracle_enhanced/cpk'
|
1071
|
+
require "active_record/connection_adapters/oracle_enhanced/context_index"
|
1322
1072
|
|
1323
1073
|
# Patches and enhancements for schema dumper
|
1324
|
-
require
|
1074
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_dumper"
|
1325
1075
|
|
1326
1076
|
# Implementation of structure dump
|
1327
|
-
require
|
1077
|
+
require "active_record/connection_adapters/oracle_enhanced/structure_dump"
|
1328
1078
|
|
1329
|
-
require
|
1079
|
+
require "active_record/connection_adapters/oracle_enhanced/version"
|
1330
1080
|
|
1331
1081
|
module ActiveRecord
|
1332
|
-
autoload :OracleEnhancedProcedures,
|
1082
|
+
autoload :OracleEnhancedProcedures, "active_record/connection_adapters/oracle_enhanced/procedures"
|
1333
1083
|
end
|
1334
1084
|
|
1335
1085
|
# Patches and enhancements for column dumper
|
1336
|
-
require
|
1086
|
+
require "active_record/connection_adapters/oracle_enhanced/column_dumper"
|
1337
1087
|
|
1338
1088
|
# Moved SchemaCreation class
|
1339
|
-
require
|
1089
|
+
require "active_record/connection_adapters/oracle_enhanced/schema_creation"
|
1340
1090
|
|
1341
1091
|
# Moved DatabaseStetements
|
1342
|
-
require
|
1092
|
+
require "active_record/connection_adapters/oracle_enhanced/database_statements"
|
1343
1093
|
|
1344
1094
|
# Add Type:Raw
|
1345
|
-
require
|
1095
|
+
require "active_record/oracle_enhanced/type/raw"
|
1346
1096
|
|
1347
1097
|
# Add OracleEnhanced::Type::Integer
|
1348
|
-
require
|
1098
|
+
require "active_record/oracle_enhanced/type/integer"
|
1349
1099
|
|
1350
1100
|
# Add OracleEnhanced::Type::String
|
1351
|
-
require
|
1101
|
+
require "active_record/oracle_enhanced/type/string"
|
1352
1102
|
|
1353
1103
|
# Add OracleEnhanced::Type::NationalCharacterString
|
1354
|
-
require
|
1104
|
+
require "active_record/oracle_enhanced/type/national_character_string"
|
1355
1105
|
|
1356
1106
|
# Add OracleEnhanced::Type::Text
|
1357
|
-
require
|
1107
|
+
require "active_record/oracle_enhanced/type/text"
|
1358
1108
|
|
1359
1109
|
# Add OracleEnhanced::Type::Boolean
|
1360
|
-
require
|
1110
|
+
require "active_record/oracle_enhanced/type/boolean"
|
1361
1111
|
|
1362
1112
|
# To use :boolean type for Attribute API, each type needs registered explicitly.
|
1363
1113
|
ActiveRecord::Type.register(:boolean, ActiveRecord::OracleEnhanced::Type::Boolean, adapter: :oracleenhanced)
|
1114
|
+
|
1115
|
+
# Add JSON attribute support
|
1116
|
+
require "active_record/oracle_enhanced/type/json"
|
1117
|
+
ActiveRecord::Type.register(:json, ActiveRecord::OracleEnhanced::Type::Json, adapter: :oracleenhanced)
|
1118
|
+
|
1119
|
+
# Add Type:TimestampTz
|
1120
|
+
require "active_record/oracle_enhanced/type/timestamptz"
|