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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +225 -0
  3. data/README.md +14 -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 +58 -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 +51 -79
  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 +112 -132
  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 +292 -539
  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 +2 -3
  35. data/spec/active_record/connection_adapters/oracle_enhanced_adapter_spec.rb +82 -162
  36. data/spec/active_record/connection_adapters/oracle_enhanced_connection_spec.rb +35 -35
  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 +270 -365
  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 +73 -77
  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 +263 -329
  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 -83
  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,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
- include Enumerable
216
+ class StatementPool < ConnectionAdapters::StatementPool
217
+ private
406
218
 
407
- def initialize(connection, max = 300)
408
- @connection = connection
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
- @quoted_column_names, @quoted_table_names = {}, {}
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 = 'OracleEnhanced'.freeze
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? && !use_old_oracle_visitor
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 == [12,1]
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
- #TODO: Needs to consider to return false to keep old behaviour
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
- false
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
- :nls_calendar => nil,
504
- :nls_comp => nil,
505
- :nls_currency => nil,
506
- :nls_date_format => 'YYYY-MM-DD HH24:MI:SS',
507
- :nls_date_language => nil,
508
- :nls_dual_currency => nil,
509
- :nls_iso_currency => nil,
510
- :nls_language => nil,
511
- :nls_length_semantics => 'CHAR',
512
- :nls_nchar_conv_excp => nil,
513
- :nls_numeric_characters => nil,
514
- :nls_sort => nil,
515
- :nls_territory => nil,
516
- :nls_timestamp_format => 'YYYY-MM-DD HH24:MI:SS:FF6',
517
- :nls_timestamp_tz_format => nil,
518
- :nls_time_format => nil,
519
- :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
520
333
  }
521
334
 
522
335
  #:stopdoc:
523
336
  NATIVE_DATABASE_TYPES = {
524
- :primary_key => "NUMBER(38) NOT NULL PRIMARY KEY",
525
- :string => { :name => "VARCHAR2", :limit => 255 },
526
- :text => { :name => "CLOB" },
527
- :integer => { :name => "NUMBER", :limit => 38 },
528
- :float => { :name => "BINARY_FLOAT" },
529
- :decimal => { :name => "DECIMAL" },
530
- :datetime => { :name => "TIMESTAMP" },
531
- :timestamp => { :name => "TIMESTAMP" },
532
- :time => { :name => "TIMESTAMP" },
533
- :date => { :name => "DATE" },
534
- :binary => { :name => "BLOB" },
535
- :boolean => { :name => "NUMBER", :limit => 1 },
536
- :raw => { :name => "RAW", :limit => 2000 },
537
- :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 }
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
- :boolean => { :name => "VARCHAR2", :limit => 1 }
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 = 'autogenerated'.freeze
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 and sequence_name
680
- # *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.
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
- # is class with composite primary key>
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 = is_with_cpk ? "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{klass.composite_where_clause(id)} FOR UPDATE" :
724
- "SELECT #{quote_column_name(col.name)} FROM #{quote_table_name(table_name)} WHERE #{quote_column_name(klass.primary_key)} = #{id} FOR UPDATE"
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(name = nil) #:nodoc:
755
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
756
- #tables currently returns both tables and views.
757
- This behavior is deprecated and will be changed with Rails 5.1 to only return tables.
758
- Use #data_sources instead.
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
- select_values(
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
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
779
- #table_exists? currently checks both tables and views.
780
- This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
781
- Use #data_source_exists? instead.
782
- MSG
783
-
784
- 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
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', 'session_user')")
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['index_name']
644
+ if current_index != row["index_name"]
838
645
  statement_parameters = nil
839
- if row['index_type'] == 'DOMAIN' && row['ityp_owner'] == 'CTXSYS' && row['ityp_name'] == 'CONTEXT'
840
- 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"])
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['table_name'],
854
- row['index_name'],
855
- row['uniqueness'] == "UNIQUE",
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['index_type'] == 'DOMAIN' ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
667
+ row["index_type"] == "DOMAIN" ? "#{row['ityp_owner']}.#{row['ityp_name']}" : nil,
861
668
  nil,
862
- row['parameters'],
669
+ row["parameters"],
863
670
  statement_parameters,
864
- row['tablespace_name'] == default_tablespace_name ? nil : row['tablespace_name'])
865
- current_index = row['index_name']
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['column_expression'] && row['virtual_column'] != 'YES'
873
- 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"]
874
681
  else
875
- all_schema_indexes.last.columns << row['column_name'].downcase
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, 'Primary Key Trigger') ? true : false
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 = '#{desc_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.delete_if do |row|
1001
- ignored_columns && ignored_columns.include?(row['name'].downcase)
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['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})" : ")")
1006
763
  end
1007
764
 
1008
- if row['sql_type_owner']
1009
- 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"]
1010
767
  end
1011
768
 
1012
- is_virtual = row['virtual_column']=='YES'
769
+ is_virtual = row["virtual_column"] == "YES"
1013
770
 
1014
771
  # clean up odd default spacing from Oracle
1015
- if row['data_default'] && !is_virtual
1016
- row['data_default'].sub!(/^(.*?)\s*$/, '\1')
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['data_default'].sub!(/^'(.*)'$/m, '\1')
1021
- 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
1022
779
  # TODO: Needs better fix to fallback "N" to false
1023
- 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)
1024
781
  end
1025
782
 
1026
- type_metadata = fetch_type_metadata(row['sql_type'])
1027
- new_column(oracle_downcase(row['name']),
1028
- row['data_default'],
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['nullable'] == 'Y',
787
+ row["nullable"] == "Y",
1031
788
  table_name,
1032
789
  is_virtual,
1033
790
  false,
1034
- row['column_comment']
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+/, ' '), 'Sequence')
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 = '#{desc_table_name}_SEQ'
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+/, ' '), 'Primary Key')
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 = '#{desc_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, 'Primary Keys')
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
- s = s.to_sql unless s.is_a?(String)
1146
- # remove any ASC/DESC modifiers
1147
- s.gsub(/\s+(ASC|DESC)\s*?/i, '')
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
- [super, *order_columns].join(', ')
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')") == 'Y'
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 == 'jruby' && !supports_fetch_first_n_rows_and_offset? && offset && limit
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
- def initialize_type_map(m)
1197
- super
1198
- # oracle
1199
- register_class_with_limit m, %r(raw)i, ActiveRecord::OracleEnhanced::Type::Raw
1200
- register_class_with_limit m, %r(char)i, ActiveRecord::OracleEnhanced::Type::String
1201
- register_class_with_limit m, %r(clob)i, ActiveRecord::OracleEnhanced::Type::Text
1202
-
1203
- m.register_type 'NCHAR', ActiveRecord::OracleEnhanced::Type::NationalCharacterString.new
1204
- m.alias_type %r(NVARCHAR2)i, 'NCHAR'
1205
-
1206
- m.register_type(%r(NUMBER)i) do |sql_type|
1207
- scale = extract_scale(sql_type)
1208
- precision = extract_precision(sql_type)
1209
- limit = extract_limit(sql_type)
1210
- if scale == 0
1211
- ActiveRecord::OracleEnhanced::Type::Integer.new(precision: precision, limit: limit)
1212
- else
1213
- 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
1214
961
  end
1215
- end
1216
962
 
1217
- if OracleEnhancedAdapter.emulate_booleans
1218
- if OracleEnhancedAdapter.emulate_booleans_from_strings
1219
- m.register_type %r(^VARCHAR2\(1\))i, ActiveRecord::OracleEnhanced::Type::Boolean.new
1220
- else
1221
- 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
1222
969
  end
1223
970
  end
1224
- end
1225
971
 
1226
- def extract_limit(sql_type) #:nodoc:
1227
- case sql_type
1228
- when /^bigint/i
1229
- 19
1230
- when /\((.*)\)/
1231
- $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
1232
979
  end
1233
- end
1234
980
 
1235
- def translate_exception(exception, message) #:nodoc:
1236
- case @connection.error_code(exception)
1237
- when 1
1238
- RecordNotUnique.new(message)
1239
- when 2291
1240
- InvalidForeignKey.new(message)
1241
- when 12899
1242
- ValueTooLong.new(message)
1243
- else
1244
- 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
1245
996
  end
1246
- end
1247
997
 
1248
998
  private
1249
999
 
1250
- def oracle_downcase(column_name)
1251
- @connection.oracle_downcase(column_name)
1252
- end
1000
+ def oracle_downcase(column_name)
1001
+ @connection.oracle_downcase(column_name)
1002
+ end
1253
1003
 
1254
- def compress_lines(string, join_with = "\n")
1255
- string.split($/).map { |line| line.strip }.join(join_with)
1256
- end
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
- def log(sql, name = "SQL", binds = [], statement_name = nil) #:nodoc:
1287
- super
1288
- ensure
1289
- log_dbms_output if dbms_output_enabled?
1290
- 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
1291
1041
 
1292
1042
  private
1293
1043
 
1294
- def set_dbms_output_plsql_connection
1295
- raise OracleEnhancedConnectionException, "ruby-plsql gem is required for logging DBMS output" unless self.respond_to?(:plsql)
1296
- # do not reset plsql connection if it is the same (as resetting will clear PL/SQL metadata cache)
1297
- unless plsql(:dbms_output).connection && plsql(:dbms_output).connection.raw_connection == raw_connection
1298
- 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
1299
1050
  end
1300
- end
1301
1051
 
1302
- def log_dbms_output
1303
- while true do
1304
- result = plsql(:dbms_output).sys.dbms_output.get_line(:line => '', :status => 0)
1305
- break unless result[:status] == 0
1306
- @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
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 'active_record/connection_adapters/oracle_enhanced/schema_statements'
1316
- 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"
1317
1066
 
1318
1067
  # Extensions for schema definition
1319
- require 'active_record/connection_adapters/oracle_enhanced/schema_definitions'
1068
+ require "active_record/connection_adapters/oracle_enhanced/schema_definitions"
1320
1069
 
1321
1070
  # Extensions for context index definition
1322
- require 'active_record/connection_adapters/oracle_enhanced/context_index'
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 'active_record/connection_adapters/oracle_enhanced/schema_dumper'
1074
+ require "active_record/connection_adapters/oracle_enhanced/schema_dumper"
1329
1075
 
1330
1076
  # Implementation of structure dump
1331
- require 'active_record/connection_adapters/oracle_enhanced/structure_dump'
1077
+ require "active_record/connection_adapters/oracle_enhanced/structure_dump"
1332
1078
 
1333
- require 'active_record/connection_adapters/oracle_enhanced/version'
1079
+ require "active_record/connection_adapters/oracle_enhanced/version"
1334
1080
 
1335
1081
  module ActiveRecord
1336
- autoload :OracleEnhancedProcedures, 'active_record/connection_adapters/oracle_enhanced/procedures'
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 'active_record/connection_adapters/oracle_enhanced/column_dumper'
1086
+ require "active_record/connection_adapters/oracle_enhanced/column_dumper"
1341
1087
 
1342
1088
  # Moved SchemaCreation class
1343
- require 'active_record/connection_adapters/oracle_enhanced/schema_creation'
1089
+ require "active_record/connection_adapters/oracle_enhanced/schema_creation"
1344
1090
 
1345
1091
  # Moved DatabaseStetements
1346
- require 'active_record/connection_adapters/oracle_enhanced/database_statements'
1092
+ require "active_record/connection_adapters/oracle_enhanced/database_statements"
1347
1093
 
1348
1094
  # Add Type:Raw
1349
- require 'active_record/oracle_enhanced/type/raw'
1095
+ require "active_record/oracle_enhanced/type/raw"
1350
1096
 
1351
1097
  # Add OracleEnhanced::Type::Integer
1352
- require 'active_record/oracle_enhanced/type/integer'
1098
+ require "active_record/oracle_enhanced/type/integer"
1353
1099
 
1354
1100
  # Add OracleEnhanced::Type::String
1355
- require 'active_record/oracle_enhanced/type/string'
1101
+ require "active_record/oracle_enhanced/type/string"
1356
1102
 
1357
1103
  # Add OracleEnhanced::Type::NationalCharacterString
1358
- require 'active_record/oracle_enhanced/type/national_character_string'
1104
+ require "active_record/oracle_enhanced/type/national_character_string"
1359
1105
 
1360
1106
  # Add OracleEnhanced::Type::Text
1361
- require 'active_record/oracle_enhanced/type/text'
1107
+ require "active_record/oracle_enhanced/type/text"
1362
1108
 
1363
1109
  # Add OracleEnhanced::Type::Boolean
1364
- require 'active_record/oracle_enhanced/type/boolean'
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"