activerecord-oracle_enhanced-adapter 1.7.3 → 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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +288 -0
  3. data/README.md +44 -0
  4. data/VERSION +1 -1
  5. data/lib/active_record/connection_adapters/emulation/oracle_adapter.rb +1 -1
  6. data/lib/active_record/connection_adapters/oracle_enhanced/column.rb +7 -63
  7. data/lib/active_record/connection_adapters/oracle_enhanced/column_dumper.rb +6 -52
  8. data/lib/active_record/connection_adapters/oracle_enhanced/connection.rb +13 -16
  9. data/lib/active_record/connection_adapters/oracle_enhanced/context_index.rb +117 -119
  10. data/lib/active_record/connection_adapters/oracle_enhanced/database_statements.rb +33 -27
  11. data/lib/active_record/connection_adapters/oracle_enhanced/database_tasks.rb +10 -10
  12. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_connection.rb +59 -77
  13. data/lib/active_record/connection_adapters/oracle_enhanced/jdbc_quoting.rb +0 -4
  14. data/lib/active_record/connection_adapters/oracle_enhanced/oci_connection.rb +56 -82
  15. data/lib/active_record/connection_adapters/oracle_enhanced/oci_quoting.rb +4 -4
  16. data/lib/active_record/connection_adapters/oracle_enhanced/procedures.rb +77 -77
  17. data/lib/active_record/connection_adapters/oracle_enhanced/quoting.rb +16 -45
  18. data/lib/active_record/connection_adapters/oracle_enhanced/schema_creation.rb +60 -65
  19. data/lib/active_record/connection_adapters/oracle_enhanced/schema_definitions.rb +33 -51
  20. data/lib/active_record/connection_adapters/oracle_enhanced/schema_dumper.rb +149 -162
  21. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements.rb +119 -122
  22. data/lib/active_record/connection_adapters/oracle_enhanced/schema_statements_ext.rb +3 -4
  23. data/lib/active_record/connection_adapters/oracle_enhanced/structure_dump.rb +69 -107
  24. data/lib/active_record/connection_adapters/oracle_enhanced/version.rb +1 -1
  25. data/lib/active_record/connection_adapters/oracle_enhanced_adapter.rb +315 -538
  26. data/lib/active_record/oracle_enhanced/type/boolean.rb +7 -11
  27. data/lib/active_record/oracle_enhanced/type/integer.rb +4 -5
  28. data/lib/active_record/oracle_enhanced/type/json.rb +8 -0
  29. data/lib/active_record/oracle_enhanced/type/national_character_string.rb +1 -2
  30. data/lib/active_record/oracle_enhanced/type/raw.rb +2 -4
  31. data/lib/active_record/oracle_enhanced/type/string.rb +2 -3
  32. data/lib/active_record/oracle_enhanced/type/text.rb +2 -4
  33. data/lib/active_record/oracle_enhanced/type/timestamptz.rb +23 -0
  34. data/lib/activerecord-oracle_enhanced-adapter.rb +14 -13
  35. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +129 -166
  36. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +50 -33
  37. data/spec/active_record/connection_adapters/oracle_enhanced_context_index_spec.rb +44 -42
  38. data/spec/active_record/connection_adapters/oracle_enhanced_data_types_spec.rb +283 -378
  39. data/spec/active_record/connection_adapters/oracle_enhanced_database_tasks_spec.rb +14 -7
  40. data/spec/active_record/connection_adapters/oracle_enhanced_dbms_output_spec.rb +5 -7
  41. data/spec/active_record/connection_adapters/oracle_enhanced_dirty_spec.rb +118 -127
  42. data/spec/active_record/connection_adapters/oracle_enhanced_emulate_oracle_adapter_spec.rb +2 -3
  43. data/spec/active_record/connection_adapters/oracle_enhanced_procedures_spec.rb +74 -78
  44. data/spec/active_record/connection_adapters/oracle_enhanced_schema_dump_spec.rb +68 -83
  45. data/spec/active_record/connection_adapters/oracle_enhanced_schema_statements_spec.rb +308 -321
  46. data/spec/active_record/connection_adapters/oracle_enhanced_structure_dump_spec.rb +103 -48
  47. data/spec/spec_config.yaml.template +11 -0
  48. data/spec/spec_helper.rb +59 -60
  49. data/spec/support/alter_system_user_password.sql +2 -0
  50. data/spec/support/create_oracle_enhanced_users.sql +31 -0
  51. metadata +25 -25
  52. data/.rspec +0 -2
  53. data/Gemfile +0 -22
  54. data/RUNNING_TESTS.md +0 -50
  55. data/Rakefile +0 -45
  56. data/activerecord-oracle_enhanced-adapter.gemspec +0 -95
  57. data/lib/active_record/connection_adapters/oracle_enhanced/cpk.rb +0 -21
  58. 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 'active_record/connection_adapters/abstract_adapter'
32
- require 'active_record/connection_adapters/oracle_enhanced/connection'
33
- require 'active_record/connection_adapters/oracle_enhanced/database_statements'
34
- require 'active_record/connection_adapters/oracle_enhanced/schema_statements'
35
- require 'active_record/connection_adapters/oracle_enhanced/schema_statements_ext'
36
- require 'active_record/connection_adapters/oracle_enhanced/column_dumper'
37
- require 'active_record/connection_adapters/oracle_enhanced/context_index'
38
- require 'active_record/connection_adapters/oracle_enhanced/column'
39
- require 'active_record/connection_adapters/oracle_enhanced/quoting'
40
-
41
- require 'digest/sha1'
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
- def enhanced_write_lobs
141
- if self.class.connection.is_a?(ConnectionAdapters::OracleEnhancedAdapter) &&
142
- !(
143
- (self.class.custom_create_method || self.class.custom_create_method) ||
144
- (self.class.custom_update_method || self.class.custom_update_method)
145
- )
146
- self.class.connection.write_lobs(self.class.table_name, self.class, attributes, @changed_lob_columns)
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
- def record_changed_lobs
151
- @changed_lob_columns = self.class.lob_columns.select do |col|
152
- self.attribute_changed?(col.name) && !self.class.readonly_attributes.to_a.include?(col.name)
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 'active_record/connection_adapters/emulation/oracle_adapter'
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
- # By default, the OracleEnhancedAdapter will typecast all columns of type <tt>DATE</tt>
264
- # to Time or DateTime (if value is out of Time value range) value.
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.emulate_dates = true
188
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.default_tablespaces =
189
+ # {:clob => 'TS_LOB', :blob => 'TS_LOB', :index => 'TS_INDEX', :table => 'TS_DATA'}
269
190
  #
270
- # As this option can have side effects when unnecessary typecasting is done it is recommended
271
- # that Date columns are explicily defined with +set_date_columns+ method.
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,78 +202,32 @@ 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
205
  ##
378
206
  # :singleton-method:
379
- # Specify non-default date format that should be used when assigning string values to :date columns, e.g.:
207
+ # By default, OracleEnhanced adapter will use Oracle12 visitor
208
+ # if database version is Oracle 12.1.
209
+ # If you wish to use Oracle visitor which is intended to work with Oracle 11.2 or lower
210
+ # for Oracle 12.1 database you can add the following line to your initializer file:
380
211
  #
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
212
+ # ActiveRecord::ConnectionAdapters::OracleEnhancedAdapter.use_old_oracle_visitor = true
213
+ cattr_accessor :use_old_oracle_visitor
214
+ self.use_old_oracle_visitor = false
384
215
 
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
- class StatementPool
394
- include Enumerable
395
-
396
- def initialize(connection, max = 300)
397
- @connection = connection
398
- @max = max
399
- @cache = {}
400
- end
401
-
402
- def each(&block); @cache.each(&block); end
403
- def key?(key); @cache.key?(key); end
404
- def [](key); @cache[key]; end
405
- def length; @cache.length; end
406
- def delete(key); @cache.delete(key); end
407
-
408
- def []=(sql, key)
409
- while @max <= @cache.size
410
- @cache.shift.last.close
411
- end
412
- @cache[sql] = key
413
- end
216
+ class StatementPool < ConnectionAdapters::StatementPool
217
+ private
414
218
 
415
- def clear
416
- @cache.values.each do |cursor|
417
- cursor.close
219
+ def dealloc(stmt)
220
+ stmt.close
418
221
  end
419
- @cache.clear
420
- end
421
222
  end
422
223
 
423
224
  def initialize(connection, logger = nil, config = {}) # :nodoc:
424
225
  super(connection, logger, config)
425
- @quoted_column_names, @quoted_table_names = {}, {}
426
- @statements = StatementPool.new(connection, config.fetch(:statement_limit) { 250 })
226
+ @statements = StatementPool.new(self.class.type_cast_config_to_integer(config[:statement_limit]))
427
227
  @enable_dbms_output = false
428
228
  end
429
229
 
430
- ADAPTER_NAME = 'OracleEnhanced'.freeze
230
+ ADAPTER_NAME = "OracleEnhanced".freeze
431
231
 
432
232
  def adapter_name #:nodoc:
433
233
  ADAPTER_NAME
@@ -441,14 +241,6 @@ module ActiveRecord
441
241
  end
442
242
  end
443
243
 
444
- def supports_migrations? #:nodoc:
445
- true
446
- end
447
-
448
- def supports_primary_key? #:nodoc:
449
- true
450
- end
451
-
452
244
  def supports_savepoints? #:nodoc:
453
245
  true
454
246
  end
@@ -461,12 +253,16 @@ module ActiveRecord
461
253
  true
462
254
  end
463
255
 
256
+ def supports_foreign_keys_in_create?
257
+ supports_foreign_keys?
258
+ end
259
+
464
260
  def supports_views?
465
261
  true
466
262
  end
467
263
 
468
264
  def supports_fetch_first_n_rows_and_offset?
469
- if @connection.database_version == [12,1]
265
+ if !use_old_oracle_visitor && @connection.database_version.first >= 12
470
266
  true
471
267
  else
472
268
  false
@@ -474,56 +270,88 @@ module ActiveRecord
474
270
  end
475
271
 
476
272
  def supports_datetime_with_precision?
477
- #TODO: Needs to consider to return false to keep old behaviour
478
- #to map :datetime as DATE
479
- @connection.database_version.first >= 9
273
+ true
480
274
  end
481
275
 
482
276
  def supports_comments?
483
277
  true
484
278
  end
485
279
 
280
+ def supports_multi_insert?
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
312
+ end
313
+
486
314
  #:stopdoc:
487
315
  DEFAULT_NLS_PARAMETERS = {
488
- :nls_calendar => nil,
489
- :nls_comp => nil,
490
- :nls_currency => nil,
491
- :nls_date_format => 'YYYY-MM-DD HH24:MI:SS',
492
- :nls_date_language => nil,
493
- :nls_dual_currency => nil,
494
- :nls_iso_currency => nil,
495
- :nls_language => nil,
496
- :nls_length_semantics => 'CHAR',
497
- :nls_nchar_conv_excp => nil,
498
- :nls_numeric_characters => nil,
499
- :nls_sort => nil,
500
- :nls_territory => nil,
501
- :nls_timestamp_format => 'YYYY-MM-DD HH24:MI:SS:FF6',
502
- :nls_timestamp_tz_format => nil,
503
- :nls_time_format => nil,
504
- :nls_time_tz_format => nil
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
505
333
  }
506
334
 
507
335
  #:stopdoc:
508
336
  NATIVE_DATABASE_TYPES = {
509
- :primary_key => "NUMBER(38) NOT NULL PRIMARY KEY",
510
- :string => { :name => "VARCHAR2", :limit => 255 },
511
- :text => { :name => "CLOB" },
512
- :integer => { :name => "NUMBER", :limit => 38 },
513
- :float => { :name => "BINARY_FLOAT" },
514
- :decimal => { :name => "DECIMAL" },
515
- :datetime => { :name => "TIMESTAMP" },
516
- :timestamp => { :name => "TIMESTAMP" },
517
- :time => { :name => "TIMESTAMP" },
518
- :date => { :name => "DATE" },
519
- :binary => { :name => "BLOB" },
520
- :boolean => { :name => "NUMBER", :limit => 1 },
521
- :raw => { :name => "RAW", :limit => 2000 },
522
- :bigint => { :name => "NUMBER", :limit => 19 }
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 }
523
351
  }
524
352
  # if emulate_booleans_from_strings then store booleans in VARCHAR2
525
353
  NATIVE_DATABASE_TYPES_BOOLEAN_STRINGS = NATIVE_DATABASE_TYPES.dup.merge(
526
- :boolean => { :name => "VARCHAR2", :limit => 1 }
354
+ boolean: { name: "VARCHAR2", limit: 1 }
527
355
  )
528
356
  #:startdoc:
529
357
 
@@ -573,7 +401,6 @@ module ActiveRecord
573
401
  def in_clause_length
574
402
  1000
575
403
  end
576
- alias ids_in_list_limit in_clause_length
577
404
 
578
405
  # CONNECTION MANAGEMENT ====================================
579
406
  #
@@ -625,7 +452,7 @@ module ActiveRecord
625
452
  end
626
453
 
627
454
  # use in set_sequence_name to avoid fetching primary key value from sequence
628
- AUTOGENERATED_SEQUENCE_NAME = 'autogenerated'.freeze
455
+ AUTOGENERATED_SEQUENCE_NAME = "autogenerated".freeze
629
456
 
630
457
  # Returns the next sequence value from a sequence generator. Not generally
631
458
  # called directly; used by ActiveRecord to get the next primary key value
@@ -661,8 +488,8 @@ module ActiveRecord
661
488
 
662
489
  def reset_pk_sequence!(table_name, primary_key = nil, sequence_name = nil) #:nodoc:
663
490
  return nil unless data_source_exists?(table_name)
664
- unless primary_key and sequence_name
665
- # *Note*: Only primary key is implemented - sequence will be nil.
491
+ unless primary_key && sequence_name
492
+ # *Note*: Only primary key is implemented - sequence will be nil.
666
493
  primary_key, sequence_name = pk_and_sequence_for(table_name)
667
494
  # TODO This sequence_name implemantation is just enough
668
495
  # to satisty fixures. To get correct sequence_name always
@@ -690,24 +517,17 @@ module ActiveRecord
690
517
 
691
518
  # Writes LOB values from attributes for specified columns
692
519
  def write_lobs(table_name, klass, attributes, columns) #:nodoc:
693
- # is class with composite primary key>
694
- is_with_cpk = klass.respond_to?(:composite?) && klass.composite?
695
- if is_with_cpk
696
- id = klass.primary_key.map {|pk| attributes[pk.to_s] }
697
- else
698
- id = quote(attributes[klass.primary_key])
699
- end
520
+ id = quote(attributes[klass.primary_key])
700
521
  columns.each do |col|
701
522
  value = attributes[col.name]
702
523
  # changed sequence of next two lines - should check if value is nil before converting to yaml
703
- next if value.nil? || (value == '')
524
+ next if value.blank?
704
525
  if klass.attribute_types[col.name].is_a? ActiveRecord::Type::Serialized
705
526
  value = klass.attribute_types[col.name].serialize(value)
706
527
  end
707
528
  uncached do
708
- sql = is_with_cpk ? "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{klass.composite_where_clause(id)} FOR UPDATE" :
709
- "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE"
710
- 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")
711
531
  raise ActiveRecord::RecordNotFound, "statement #{sql} returned no rows"
712
532
  end
713
533
  lob = lob_record[col.name]
@@ -718,6 +538,8 @@ module ActiveRecord
718
538
 
719
539
  # Current database name
720
540
  def current_database
541
+ select_value("SELECT SYS_CONTEXT('userenv', 'con_name') FROM dual")
542
+ rescue ActiveRecord::StatementInvalid
721
543
  select_value("SELECT SYS_CONTEXT('userenv', 'db_name') FROM dual")
722
544
  end
723
545
 
@@ -736,40 +558,40 @@ module ActiveRecord
736
558
  select_value("SELECT LOWER(default_tablespace) FROM user_users WHERE username = SYS_CONTEXT('userenv', 'current_schema')")
737
559
  end
738
560
 
739
- def tables(name = nil) #:nodoc:
740
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
741
- #tables currently returns both tables and views.
742
- This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
743
- Use #data_sources instead.
744
- MSG
745
-
746
- if name
747
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
748
- Passing arguments to #tables is deprecated without replacement.
749
- MSG
750
- end
751
-
752
- 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
753
566
  end
754
567
 
755
-
756
568
  def data_sources
757
- select_values(
758
- "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'",
759
- 'SCHEMA')
569
+ super
760
570
  end
761
571
 
762
572
  def table_exists?(table_name)
763
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
764
- #table_exists? currently checks both tables and views.
765
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
766
- Use #data_source_exists? instead.
767
- MSG
768
-
769
- data_source_exists?(table_name)
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
770
593
  end
771
594
 
772
- # Will return true if database object exists (to be able to use also views and synonyms for ActiveRecord models)
773
595
  # Needs to consider how to support synonyms in Rails 5.1
774
596
  def data_source_exists?(table_name)
775
597
  (_owner, table_name, _db_link) = @connection.describe(table_name)
@@ -779,7 +601,7 @@ module ActiveRecord
779
601
  end
780
602
 
781
603
  def views # :nodoc:
782
- select_values("SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'session_user')")
604
+ select_values("SELECT LOWER(view_name) FROM all_views WHERE owner = SYS_CONTEXT('userenv', 'current_schema')")
783
605
  end
784
606
 
785
607
  def materialized_views #:nodoc:
@@ -794,7 +616,7 @@ module ActiveRecord
794
616
  (owner, table_name, db_link) = @connection.describe(table_name)
795
617
  unless all_schema_indexes
796
618
  default_tablespace_name = default_tablespace
797
- result = select_all(<<-SQL.strip.gsub(/\s+/, ' '))
619
+ result = select_all(<<-SQL.strip.gsub(/\s+/, " "))
798
620
  SELECT LOWER(i.table_name) AS table_name, LOWER(i.index_name) AS index_name, i.uniqueness,
799
621
  i.index_type, i.ityp_owner, i.ityp_name, i.parameters,
800
622
  LOWER(i.tablespace_name) AS tablespace_name,
@@ -819,10 +641,10 @@ module ActiveRecord
819
641
  result.each do |row|
820
642
  # have to keep track of indexes because above query returns dups
821
643
  # there is probably a better query we could figure out
822
- if current_index != row['index_name']
644
+ if current_index != row["index_name"]
823
645
  statement_parameters = nil
824
- if row['index_type'] == 'DOMAIN' && row['ityp_owner'] == 'CTXSYS' && row['ityp_name'] == 'CONTEXT'
825
- procedure_name = default_datastore_procedure(row['index_name'])
646
+ if row["index_type"] == "DOMAIN" && row["ityp_owner"] == "CTXSYS" && row["ityp_name"] == "CONTEXT"
647
+ procedure_name = default_datastore_procedure(row["index_name"])
826
648
  source = select_values(<<-SQL).join
827
649
  SELECT text
828
650
  FROM all_source#{db_link}
@@ -835,82 +657,36 @@ module ActiveRecord
835
657
  end
836
658
  end
837
659
  all_schema_indexes << OracleEnhanced::IndexDefinition.new(
838
- row['table_name'],
839
- row['index_name'],
840
- row['uniqueness'] == "UNIQUE",
660
+ row["table_name"],
661
+ row["index_name"],
662
+ row["uniqueness"] == "UNIQUE",
841
663
  [],
842
664
  nil,
843
665
  nil,
844
666
  nil,
845
- row['index_type'] == 'DOMAIN' ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
667
+ row["index_type"] == "DOMAIN" ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
846
668
  nil,
847
- row['parameters'],
669
+ row["parameters"],
848
670
  statement_parameters,
849
- row['tablespace_name'] == default_tablespace_name ? nil : row['tablespace_name'])
850
- current_index = row['index_name']
671
+ row["tablespace_name"] == default_tablespace_name ? nil : row["tablespace_name"])
672
+ current_index = row["index_name"]
851
673
  end
852
674
 
853
675
  # Functional index columns and virtual columns both get stored as column expressions,
854
676
  # but re-creating a virtual column index as an expression (instead of using the virtual column's name)
855
677
  # results in a ORA-54018 error. Thus, we only want the column expression value returned
856
678
  # when the column is not virtual.
857
- if row['column_expression'] && row['virtual_column'] != 'YES'
858
- all_schema_indexes.last.columns << row['column_expression']
679
+ if row["column_expression"] && row["virtual_column"] != "YES"
680
+ all_schema_indexes.last.columns << row["column_expression"]
859
681
  else
860
- all_schema_indexes.last.columns << row['column_name'].downcase
682
+ all_schema_indexes.last.columns << row["column_name"].downcase
861
683
  end
862
684
  end
863
685
  end
864
686
 
865
687
  # Return the indexes just for the requested table, since AR is structured that way
866
688
  table_name = table_name.downcase
867
- all_schema_indexes.select{|i| i.table == table_name}
868
- end
869
-
870
- @@ignore_table_columns = nil #:nodoc:
871
-
872
- # set ignored columns for table
873
- def ignore_table_columns(table_name, *args) #:nodoc:
874
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
875
- `ignore_table_columns` will be deprecated in next version of Oracle enhanced adapter
876
- since Rails 5 introduces `ignored_columns`. Use `ignored_columns` instead of `ignore_table_columns`.
877
- MSG
878
- @@ignore_table_columns ||= {}
879
- @@ignore_table_columns[table_name] ||= []
880
- @@ignore_table_columns[table_name] += args.map{|a| a.to_s.downcase}
881
- @@ignore_table_columns[table_name].uniq!
882
- end
883
-
884
- def ignored_table_columns(table_name) #:nodoc:
885
- @@ignore_table_columns ||= {}
886
- @@ignore_table_columns[table_name]
887
- end
888
-
889
- # used just in tests to clear ignored table columns
890
- def clear_ignored_table_columns #:nodoc:
891
- @@ignore_table_columns = nil
892
- end
893
-
894
- @@table_column_type = nil #:nodoc:
895
-
896
- # set explicit type for specified table columns
897
- def set_type_for_columns(table_name, column_type, *args) #:nodoc:
898
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
899
- `set_type_for_columns` has been deprecated. Please use Rails attribute API.
900
- MSG
901
- end
902
-
903
- def get_type_for_column(table_name, column_name) #:nodoc:
904
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
905
- `get_type_for_columns` has been deprecated. Please use Rails attribute API.
906
- MSG
907
- end
908
-
909
- # used just in tests to clear column data type definitions
910
- def clear_types_for_columns #:nodoc:
911
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
912
- `clear_types_for_columns` has been deprecated. Please use Rails attribute API.
913
- MSG
689
+ all_schema_indexes.select { |i| i.table == table_name }
914
690
  end
915
691
 
916
692
  # check if table has primary key trigger with _pkt suffix
@@ -922,12 +698,12 @@ module ActiveRecord
922
698
  SELECT trigger_name
923
699
  FROM all_triggers#{db_link}
924
700
  WHERE owner = '#{owner}'
925
- AND trigger_name = '#{trigger_name}'
701
+ AND trigger_name = q'[#{trigger_name}]'
926
702
  AND table_owner = '#{owner}'
927
- AND table_name = '#{desc_table_name}'
703
+ AND table_name = q'[#{desc_table_name}]'
928
704
  AND status = 'ENABLED'
929
705
  SQL
930
- select_value(pkt_sql, 'Primary Key Trigger') ? true : false
706
+ select_value(pkt_sql, "Primary Key Trigger") ? true : false
931
707
  end
932
708
 
933
709
  ##
@@ -951,17 +727,15 @@ module ActiveRecord
951
727
 
952
728
  def columns_without_cache(table_name, name = nil) #:nodoc:
953
729
  table_name = table_name.to_s
954
- # get ignored_columns by original table name
955
- ignored_columns = ignored_table_columns(table_name)
956
730
 
957
731
  (owner, desc_table_name, db_link) = @connection.describe(table_name)
958
732
 
959
733
  # reset do_not_prefetch_primary_key cache for this table
960
734
  @@do_not_prefetch_primary_key[table_name] = nil
961
735
 
962
- table_cols = <<-SQL.strip.gsub(/\s+/, ' ')
963
- SELECT cols.column_name AS name, cols.data_type AS sql_type,
964
- cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
736
+ table_cols = <<-SQL.strip.gsub(/\s+/, " ")
737
+ SELECT cols.column_name AS name, cols.data_type AS sql_type,
738
+ cols.data_default, cols.nullable, cols.virtual_column, cols.hidden_column,
965
739
  cols.data_type_owner AS sql_type_owner,
966
740
  DECODE(cols.data_type, 'NUMBER', data_precision,
967
741
  'FLOAT', data_precision,
@@ -973,7 +747,7 @@ module ActiveRecord
973
747
  comments.comments as column_comment
974
748
  FROM all_tab_cols#{db_link} cols, all_col_comments#{db_link} comments
975
749
  WHERE cols.owner = '#{owner}'
976
- AND cols.table_name = '#{desc_table_name}'
750
+ AND cols.table_name = #{quote(desc_table_name)}
977
751
  AND cols.hidden_column = 'NO'
978
752
  AND cols.owner = comments.owner
979
753
  AND cols.table_name = comments.table_name
@@ -982,46 +756,44 @@ module ActiveRecord
982
756
  SQL
983
757
 
984
758
  # added deletion of ignored columns
985
- select_all(table_cols, name).to_a.delete_if do |row|
986
- ignored_columns && ignored_columns.include?(row['name'].downcase)
987
- end.map do |row|
988
- limit, scale = row['limit'], row['scale']
759
+ select_all(table_cols, name).to_a.map do |row|
760
+ limit, scale = row["limit"], row["scale"]
989
761
  if limit || scale
990
- row['sql_type'] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
762
+ row["sql_type"] += "(#{(limit || 38).to_i}" + ((scale = scale.to_i) > 0 ? ",#{scale})" : ")")
991
763
  end
992
764
 
993
- if row['sql_type_owner']
994
- row['sql_type'] = row['sql_type_owner'] + '.' + row['sql_type']
765
+ if row["sql_type_owner"]
766
+ row["sql_type"] = row["sql_type_owner"] + "." + row["sql_type"]
995
767
  end
996
768
 
997
- is_virtual = row['virtual_column']=='YES'
769
+ is_virtual = row["virtual_column"] == "YES"
998
770
 
999
771
  # clean up odd default spacing from Oracle
1000
- if row['data_default'] && !is_virtual
1001
- row['data_default'].sub!(/^(.*?)\s*$/, '\1')
772
+ if row["data_default"] && !is_virtual
773
+ row["data_default"].sub!(/^(.*?)\s*$/, '\1')
1002
774
 
1003
775
  # If a default contains a newline these cleanup regexes need to
1004
776
  # match newlines.
1005
- row['data_default'].sub!(/^'(.*)'$/m, '\1')
1006
- row['data_default'] = nil if row['data_default'] =~ /^(null|empty_[bc]lob\(\))$/i
777
+ row["data_default"].sub!(/^'(.*)'$/m, '\1')
778
+ row["data_default"] = nil if row["data_default"] =~ /^(null|empty_[bc]lob\(\))$/i
1007
779
  # TODO: Needs better fix to fallback "N" to false
1008
- row['data_default'] = false if (row['data_default'] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings)
780
+ row["data_default"] = false if (row["data_default"] == "N" && OracleEnhancedAdapter.emulate_booleans_from_strings)
1009
781
  end
1010
782
 
1011
- type_metadata = fetch_type_metadata(row['sql_type'])
1012
- new_column(oracle_downcase(row['name']),
1013
- row['data_default'],
783
+ type_metadata = fetch_type_metadata(row["sql_type"])
784
+ new_column(oracle_downcase(row["name"]),
785
+ row["data_default"],
1014
786
  type_metadata,
1015
- row['nullable'] == 'Y',
787
+ row["nullable"] == "Y",
1016
788
  table_name,
1017
789
  is_virtual,
1018
790
  false,
1019
- row['column_comment']
791
+ row["column_comment"]
1020
792
  )
1021
793
  end
1022
794
  end
1023
795
 
1024
- 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:
1025
797
  OracleEnhancedColumn.new(name, default, sql_type_metadata, null, table_name, virtual, returning_id, comment)
1026
798
  end
1027
799
 
@@ -1049,7 +821,7 @@ module ActiveRecord
1049
821
 
1050
822
  # Find a table's primary key and sequence.
1051
823
  # *Note*: Only primary key is implemented - sequence will be nil.
1052
- 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:
1053
825
  if @@cache_columns
1054
826
  @@pk_and_sequence_for_cache ||= {}
1055
827
  if @@pk_and_sequence_for_cache.key?(table_name)
@@ -1062,22 +834,22 @@ module ActiveRecord
1062
834
  end
1063
835
  end
1064
836
 
1065
- 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:
1066
838
  (owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
1067
839
 
1068
- seqs = select_values(<<-SQL.strip.gsub(/\s+/, ' '), 'Sequence')
840
+ seqs = select_values(<<-SQL.strip.gsub(/\s+/, " "), "Sequence")
1069
841
  select us.sequence_name
1070
842
  from all_sequences#{db_link} us
1071
843
  where us.sequence_owner = '#{owner}'
1072
- and us.sequence_name = '#{desc_table_name}_SEQ'
844
+ and us.sequence_name = upper(#{quote(default_sequence_name(desc_table_name))})
1073
845
  SQL
1074
846
 
1075
847
  # changed back from user_constraints to all_constraints for consistency
1076
- pks = select_values(<<-SQL.strip.gsub(/\s+/, ' '), 'Primary Key')
848
+ pks = select_values(<<-SQL.strip.gsub(/\s+/, " "), "Primary Key")
1077
849
  SELECT cc.column_name
1078
850
  FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
1079
851
  WHERE c.owner = '#{owner}'
1080
- AND c.table_name = '#{desc_table_name}'
852
+ AND c.table_name = #{quote(desc_table_name)}
1081
853
  AND c.constraint_type = 'P'
1082
854
  AND cc.owner = c.owner
1083
855
  AND cc.constraint_name = c.constraint_name
@@ -1100,14 +872,14 @@ module ActiveRecord
1100
872
  pk_and_sequence && pk_and_sequence.first
1101
873
  end
1102
874
 
1103
- 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:
1104
876
  !pk_and_sequence_for(table_name, owner, desc_table_name, db_link).nil?
1105
877
  end
1106
878
 
1107
879
  def primary_keys(table_name) # :nodoc:
1108
880
  (owner, desc_table_name, db_link) = @connection.describe(table_name) unless owner
1109
881
 
1110
- pks = select_values(<<-SQL.strip_heredoc, 'Primary Keys')
882
+ pks = select_values(<<-SQL.strip_heredoc, "Primary Keys")
1111
883
  SELECT cc.column_name
1112
884
  FROM all_constraints#{db_link} c, all_cons_columns#{db_link} cc
1113
885
  WHERE c.owner = '#{owner}'
@@ -1117,7 +889,7 @@ module ActiveRecord
1117
889
  AND cc.constraint_name = c.constraint_name
1118
890
  order by cc.position
1119
891
  SQL
1120
- pks.map {|pk| oracle_downcase(pk)}
892
+ pks.map { |pk| oracle_downcase(pk) }
1121
893
  end
1122
894
 
1123
895
  def columns_for_distinct(columns, orders) #:nodoc:
@@ -1126,30 +898,18 @@ module ActiveRecord
1126
898
  # the inclusion of these columns doesn't invalidate the DISTINCT
1127
899
  #
1128
900
  # It does not construct DISTINCT clause. Just return column names for distinct.
1129
- order_columns = orders.reject(&:blank?).map{ |s|
1130
- s = s.to_sql unless s.is_a?(String)
1131
- # remove any ASC/DESC modifiers
1132
- s.gsub(/\s+(ASC|DESC)\s*?/i, '')
1133
- }.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|
1134
906
  "FIRST_VALUE(#{column}) OVER (PARTITION BY #{columns} ORDER BY #{column}) AS alias_#{i}__"
1135
907
  }
1136
- [super, *order_columns].join(', ')
908
+ [super, *order_columns].join(", ")
1137
909
  end
1138
910
 
1139
911
  def temporary_table?(table_name) #:nodoc:
1140
- select_value("SELECT temporary FROM all_tables WHERE table_name = '#{table_name.upcase}' and owner = SYS_CONTEXT('userenv', 'session_user')") == 'Y'
1141
- end
1142
-
1143
- # construct additional wrapper subquery if select.offset is used to avoid generation of invalid subquery
1144
- # ... IN ( SELECT * FROM ( SELECT raw_sql_.*, rownum raw_rnum_ FROM ( ... ) raw_sql_ ) WHERE raw_rnum_ > ... )
1145
- def join_to_update(update, select, key) #:nodoc:
1146
- #TODO: Need to validate if we can remove join_to_update from Oracle enhanced adapter after testing
1147
- # older version of Oracle 11gR2
1148
- super
1149
- end
1150
-
1151
- def valid_type?(type)
1152
- !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"
1153
913
  end
1154
914
 
1155
915
  def combine_bind_parameters(
@@ -1161,78 +921,89 @@ module ActiveRecord
1161
921
  offset: nil
1162
922
  ) # :nodoc:
1163
923
  result = from_clause + join_clause + where_clause + having_clause
1164
- if offset
924
+ if RUBY_ENGINE == "jruby" && !supports_fetch_first_n_rows_and_offset? && offset && limit
1165
925
  result << offset
1166
- end
1167
- if limit
1168
926
  result << limit
927
+ result << offset
928
+ else
929
+ if offset
930
+ result << offset
931
+ end
932
+ if limit
933
+ result << limit
934
+ end
1169
935
  end
1170
936
  result
1171
937
  end
1172
938
 
1173
939
  protected
1174
940
 
1175
- def initialize_type_map(m)
1176
- super
1177
- # oracle
1178
- register_class_with_limit m, %r(raw)i, ActiveRecord::OracleEnhanced::Type::Raw
1179
- register_class_with_limit m, %r(char)i, ActiveRecord::OracleEnhanced::Type::String
1180
- register_class_with_limit m, %r(clob)i, ActiveRecord::OracleEnhanced::Type::Text
1181
-
1182
- m.register_type 'NCHAR', ActiveRecord::OracleEnhanced::Type::NationalCharacterString.new
1183
- m.alias_type %r(NVARCHAR2)i, 'NCHAR'
1184
-
1185
- m.register_type(%r(NUMBER)i) do |sql_type|
1186
- scale = extract_scale(sql_type)
1187
- precision = extract_precision(sql_type)
1188
- limit = extract_limit(sql_type)
1189
- if scale == 0
1190
- ActiveRecord::OracleEnhanced::Type::Integer.new(precision: precision, limit: limit)
1191
- else
1192
- Type::Decimal.new(precision: precision, scale: scale)
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
1193
961
  end
1194
- end
1195
962
 
1196
- if OracleEnhancedAdapter.emulate_booleans
1197
- if OracleEnhancedAdapter.emulate_booleans_from_strings
1198
- m.register_type %r(^VARCHAR2\(1\))i, ActiveRecord::OracleEnhanced::Type::Boolean.new
1199
- else
1200
- m.register_type %r(^NUMBER\(1\))i, Type::Boolean.new
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
1201
969
  end
1202
970
  end
1203
- end
1204
971
 
1205
- def extract_limit(sql_type) #:nodoc:
1206
- case sql_type
1207
- when /^bigint/i
1208
- 19
1209
- when /\((.*)\)/
1210
- $1.to_i
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
1211
979
  end
1212
- end
1213
980
 
1214
- def translate_exception(exception, message) #:nodoc:
1215
- case @connection.error_code(exception)
1216
- when 1
1217
- RecordNotUnique.new(message)
1218
- when 2291
1219
- InvalidForeignKey.new(message)
1220
- when 12899
1221
- ValueTooLong.new(message)
1222
- else
1223
- super
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
1224
996
  end
1225
- end
1226
997
 
1227
998
  private
1228
999
 
1229
- def oracle_downcase(column_name)
1230
- @connection.oracle_downcase(column_name)
1231
- end
1000
+ def oracle_downcase(column_name)
1001
+ @connection.oracle_downcase(column_name)
1002
+ end
1232
1003
 
1233
- def compress_lines(string, join_with = "\n")
1234
- string.split($/).map { |line| line.strip }.join(join_with)
1235
- end
1004
+ def compress_lines(string, join_with = "\n")
1005
+ string.split($/).map { |line| line.strip }.join(join_with)
1006
+ end
1236
1007
 
1237
1008
  public
1238
1009
  # DBMS_OUTPUT =============================================
@@ -1262,82 +1033,88 @@ module ActiveRecord
1262
1033
  end
1263
1034
 
1264
1035
  protected
1265
- def log(sql, name = "SQL", binds = [], statement_name = nil) #:nodoc:
1266
- super
1267
- ensure
1268
- log_dbms_output if dbms_output_enabled?
1269
- end
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
1270
1041
 
1271
1042
  private
1272
1043
 
1273
- def set_dbms_output_plsql_connection
1274
- raise OracleEnhancedConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
1275
- # do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
1276
- unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
1277
- plsql(:dbms_output).connection = raw_connection
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
1278
1050
  end
1279
- end
1280
1051
 
1281
- def log_dbms_output
1282
- while true do
1283
- result = plsql(:dbms_output).sys.dbms_output.get_line(:line => '', :status => 0)
1284
- break unless result[:status] == 0
1285
- @logger.debug "DBMS_OUTPUT: #{result[:line]}" if @logger
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
1286
1058
  end
1287
- end
1288
-
1289
1059
  end
1290
1060
  end
1291
1061
  end
1292
1062
 
1293
1063
  # Implementation of standard schema definition statements and extensions for schema definition
1294
- require 'active_record/connection_adapters/oracle_enhanced/schema_statements'
1295
- require 'active_record/connection_adapters/oracle_enhanced/schema_statements_ext'
1064
+ require "active_record/connection_adapters/oracle_enhanced/schema_statements"
1065
+ require "active_record/connection_adapters/oracle_enhanced/schema_statements_ext"
1296
1066
 
1297
1067
  # Extensions for schema definition
1298
- require 'active_record/connection_adapters/oracle_enhanced/schema_definitions'
1068
+ require "active_record/connection_adapters/oracle_enhanced/schema_definitions"
1299
1069
 
1300
1070
  # Extensions for context index definition
1301
- require 'active_record/connection_adapters/oracle_enhanced/context_index'
1302
-
1303
- # Load additional methods for composite_primary_keys support
1304
- require 'active_record/connection_adapters/oracle_enhanced/cpk'
1071
+ require "active_record/connection_adapters/oracle_enhanced/context_index"
1305
1072
 
1306
1073
  # Patches and enhancements for schema dumper
1307
- require 'active_record/connection_adapters/oracle_enhanced/schema_dumper'
1074
+ require "active_record/connection_adapters/oracle_enhanced/schema_dumper"
1308
1075
 
1309
1076
  # Implementation of structure dump
1310
- require 'active_record/connection_adapters/oracle_enhanced/structure_dump'
1077
+ require "active_record/connection_adapters/oracle_enhanced/structure_dump"
1311
1078
 
1312
- require 'active_record/connection_adapters/oracle_enhanced/version'
1079
+ require "active_record/connection_adapters/oracle_enhanced/version"
1313
1080
 
1314
1081
  module ActiveRecord
1315
- autoload :OracleEnhancedProcedures, 'active_record/connection_adapters/oracle_enhanced/procedures'
1082
+ autoload :OracleEnhancedProcedures, "active_record/connection_adapters/oracle_enhanced/procedures"
1316
1083
  end
1317
1084
 
1318
1085
  # Patches and enhancements for column dumper
1319
- require 'active_record/connection_adapters/oracle_enhanced/column_dumper'
1086
+ require "active_record/connection_adapters/oracle_enhanced/column_dumper"
1320
1087
 
1321
1088
  # Moved SchemaCreation class
1322
- require 'active_record/connection_adapters/oracle_enhanced/schema_creation'
1089
+ require "active_record/connection_adapters/oracle_enhanced/schema_creation"
1323
1090
 
1324
1091
  # Moved DatabaseStetements
1325
- require 'active_record/connection_adapters/oracle_enhanced/database_statements'
1092
+ require "active_record/connection_adapters/oracle_enhanced/database_statements"
1326
1093
 
1327
1094
  # Add Type:Raw
1328
- require 'active_record/oracle_enhanced/type/raw'
1095
+ require "active_record/oracle_enhanced/type/raw"
1329
1096
 
1330
1097
  # Add OracleEnhanced::Type::Integer
1331
- require 'active_record/oracle_enhanced/type/integer'
1098
+ require "active_record/oracle_enhanced/type/integer"
1332
1099
 
1333
1100
  # Add OracleEnhanced::Type::String
1334
- require 'active_record/oracle_enhanced/type/string'
1101
+ require "active_record/oracle_enhanced/type/string"
1335
1102
 
1336
1103
  # Add OracleEnhanced::Type::NationalCharacterString
1337
- require 'active_record/oracle_enhanced/type/national_character_string'
1104
+ require "active_record/oracle_enhanced/type/national_character_string"
1338
1105
 
1339
1106
  # Add OracleEnhanced::Type::Text
1340
- require 'active_record/oracle_enhanced/type/text'
1107
+ require "active_record/oracle_enhanced/type/text"
1341
1108
 
1342
1109
  # Add OracleEnhanced::Type::Boolean
1343
- require 'active_record/oracle_enhanced/type/boolean'
1110
+ require "active_record/oracle_enhanced/type/boolean"
1111
+
1112
+ # To use :boolean type for Attribute API, each type needs registered explicitly.
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"