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