activerecord-jdbc-adapter 60.0-java → 61.0-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,7 +48,7 @@ module ArJdbc
48
48
  end
49
49
 
50
50
  def has_default_function?(default_value, default)
51
- !default_value && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
51
+ !default_value && default && %r{\w+\(.*\)|\(.*\)::\w+|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
52
52
  end
53
53
  end
54
54
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  ArJdbc::ConnectionMethods.module_eval do
3
3
  def postgresql_connection(config)
4
+ config = config.deep_dup
4
5
  # NOTE: this isn't "really" necessary but Rails (in tests) assumes being able to :
5
6
  # ActiveRecord::Base.postgresql_connection ActiveRecord::Base.configurations['arunit'].merge(:insert_returning => false)
6
7
  # ... while using symbols by default but than configurations returning string keys ;(
@@ -145,7 +145,7 @@ module ArJdbc
145
145
  m.register_type 'uuid', OID::Uuid.new
146
146
  m.register_type 'xml', OID::Xml.new
147
147
  m.register_type 'tsvector', OID::SpecializedString.new(:tsvector)
148
- m.register_type 'macaddr', OID::SpecializedString.new(:macaddr)
148
+ m.register_type 'macaddr', OID::Macaddr.new
149
149
  m.register_type 'citext', OID::SpecializedString.new(:citext)
150
150
  m.register_type 'ltree', OID::SpecializedString.new(:ltree)
151
151
  m.register_type 'line', OID::SpecializedString.new(:line)
@@ -155,9 +155,9 @@ module ArJdbc
155
155
  m.register_type 'polygon', OID::SpecializedString.new(:polygon)
156
156
  m.register_type 'circle', OID::SpecializedString.new(:circle)
157
157
 
158
- m.register_type 'interval' do |_, _, sql_type|
158
+ m.register_type 'interval' do |*args, sql_type|
159
159
  precision = extract_precision(sql_type)
160
- OID::SpecializedString.new(:interval, precision: precision)
160
+ OID::Interval.new(precision: precision)
161
161
  end
162
162
 
163
163
  register_class_with_precision m, 'time', Type::Time
@@ -213,7 +213,7 @@ module ArJdbc
213
213
  if oid
214
214
  if oid.is_a? Numeric || oid.match(/^\d+$/)
215
215
  # numeric OID
216
- query += "WHERE t.oid::integer = %s" % oid
216
+ query += "WHERE t.oid = %s" % oid
217
217
 
218
218
  elsif m = oid.match(/"?(\w+)"?\."?(\w+)"?/)
219
219
  # namespace and type name
@@ -244,6 +244,7 @@ module ArJdbc
244
244
  ActiveRecord::Type.register(:enum, OID::Enum, adapter: :postgresql)
245
245
  ActiveRecord::Type.register(:hstore, OID::Hstore, adapter: :postgresql)
246
246
  ActiveRecord::Type.register(:inet, OID::Inet, adapter: :postgresql)
247
+ ActiveRecord::Type.register(:interval, OID::Interval, adapter: :postgresql)
247
248
  ActiveRecord::Type.register(:json, Type::Json, adapter: :postgresql)
248
249
  ActiveRecord::Type.register(:jsonb, OID::Jsonb, adapter: :postgresql)
249
250
  ActiveRecord::Type.register(:money, OID::Money, adapter: :postgresql)
@@ -16,6 +16,33 @@ require "active_record/connection_adapters/sqlite3/schema_dumper"
16
16
  require "active_record/connection_adapters/sqlite3/schema_statements"
17
17
  require "active_support/core_ext/class/attribute"
18
18
 
19
+ module SQLite3
20
+ module Constants
21
+ module Open
22
+ READONLY = 0x00000001
23
+ READWRITE = 0x00000002
24
+ CREATE = 0x00000004
25
+ DELETEONCLOSE = 0x00000008
26
+ EXCLUSIVE = 0x00000010
27
+ AUTOPROXY = 0x00000020
28
+ URI = 0x00000040
29
+ MEMORY = 0x00000080
30
+ MAIN_DB = 0x00000100
31
+ TEMP_DB = 0x00000200
32
+ TRANSIENT_DB = 0x00000400
33
+ MAIN_JOURNAL = 0x00000800
34
+ TEMP_JOURNAL = 0x00001000
35
+ SUBJOURNAL = 0x00002000
36
+ MASTER_JOURNAL = 0x00004000
37
+ NOMUTEX = 0x00008000
38
+ FULLMUTEX = 0x00010000
39
+ SHAREDCACHE = 0x00020000
40
+ PRIVATECACHE = 0x00040000
41
+ WAL = 0x00080000
42
+ end
43
+ end
44
+ end
45
+
19
46
  module ArJdbc
20
47
  # All the code in this module is a copy of ConnectionAdapters::SQLite3Adapter from active_record 5.
21
48
  # The constants at the front of this file are to allow the rest of the file to remain with no modifications
@@ -69,6 +96,10 @@ module ArJdbc
69
96
  true
70
97
  end
71
98
 
99
+ def supports_transaction_isolation?
100
+ true
101
+ end
102
+
72
103
  def supports_partial_index?
73
104
  database_version >= "3.9.0"
74
105
  end
@@ -85,6 +116,10 @@ module ArJdbc
85
116
  true
86
117
  end
87
118
 
119
+ def supports_check_constraints?
120
+ true
121
+ end
122
+
88
123
  def supports_views?
89
124
  true
90
125
  end
@@ -97,6 +132,10 @@ module ArJdbc
97
132
  true
98
133
  end
99
134
 
135
+ def supports_common_table_expressions?
136
+ database_version >= "3.8.3"
137
+ end
138
+
100
139
  def supports_insert_on_conflict?
101
140
  database_version >= "3.24.0"
102
141
  end
@@ -110,13 +149,6 @@ module ArJdbc
110
149
  true
111
150
  end
112
151
 
113
- # Returns 62. SQLite supports index names up to 64
114
- # characters. The rest is used by Rails internally to perform
115
- # temporary rename operations
116
- def allowed_index_name_length
117
- index_name_length - 2
118
- end
119
-
120
152
  def native_database_types #:nodoc:
121
153
  NATIVE_DATABASE_TYPES
122
154
  end
@@ -154,7 +186,9 @@ module ArJdbc
154
186
  # DATABASE STATEMENTS ======================================
155
187
  #++
156
188
 
157
- READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(:begin, :commit, :explain, :select, :pragma, :release, :savepoint, :rollback) # :nodoc:
189
+ READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
190
+ :pragma
191
+ ) # :nodoc:
158
192
  private_constant :READ_QUERY
159
193
 
160
194
  def write_query?(sql) # :nodoc:
@@ -181,15 +215,15 @@ module ArJdbc
181
215
  #def execute(sql, name = nil) #:nodoc:
182
216
 
183
217
  def begin_db_transaction #:nodoc:
184
- log("begin transaction", nil) { @connection.transaction }
218
+ log("begin transaction", 'TRANSACTION') { @connection.transaction }
185
219
  end
186
220
 
187
221
  def commit_db_transaction #:nodoc:
188
- log("commit transaction", nil) { @connection.commit }
222
+ log("commit transaction", 'TRANSACTION') { @connection.commit }
189
223
  end
190
224
 
191
225
  def exec_rollback_db_transaction #:nodoc:
192
- log("rollback transaction", nil) { @connection.rollback }
226
+ log("rollback transaction", 'TRANSACTION') { @connection.rollback }
193
227
  end
194
228
 
195
229
  # SCHEMA STATEMENTS ========================================
@@ -199,8 +233,11 @@ module ArJdbc
199
233
  pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
200
234
  end
201
235
 
202
- def remove_index(table_name, options = {}) #:nodoc:
203
- index_name = index_name_for_remove(table_name, options)
236
+ def remove_index(table_name, column_name = nil, **options) # :nodoc:
237
+ return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
238
+
239
+ index_name = index_name_for_remove(table_name, column_name, options)
240
+
204
241
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
205
242
  end
206
243
 
@@ -209,21 +246,23 @@ module ArJdbc
209
246
  # Example:
210
247
  # rename_table('octopuses', 'octopi')
211
248
  def rename_table(table_name, new_name)
249
+ schema_cache.clear_data_source_cache!(table_name.to_s)
250
+ schema_cache.clear_data_source_cache!(new_name.to_s)
212
251
  exec_query "ALTER TABLE #{quote_table_name(table_name)} RENAME TO #{quote_table_name(new_name)}"
213
252
  rename_table_indexes(table_name, new_name)
214
253
  end
215
254
 
216
- def add_column(table_name, column_name, type, options = {}) #:nodoc:
255
+ def add_column(table_name, column_name, type, **options) #:nodoc:
217
256
  if invalid_alter_table_type?(type, options)
218
257
  alter_table(table_name) do |definition|
219
- definition.column(column_name, type, options)
258
+ definition.column(column_name, type, **options)
220
259
  end
221
260
  else
222
261
  super
223
262
  end
224
263
  end
225
264
 
226
- def remove_column(table_name, column_name, type = nil, options = {}) #:nodoc:
265
+ def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
227
266
  alter_table(table_name) do |definition|
228
267
  definition.remove_column column_name
229
268
  definition.foreign_keys.delete_if do |_, fk_options|
@@ -249,16 +288,11 @@ module ArJdbc
249
288
  end
250
289
  end
251
290
 
252
- def change_column(table_name, column_name, type, options = {}) #:nodoc:
291
+ def change_column(table_name, column_name, type, **options) #:nodoc:
253
292
  alter_table(table_name) do |definition|
254
293
  definition[column_name].instance_eval do
255
294
  self.type = type
256
- self.limit = options[:limit] if options.include?(:limit)
257
- self.default = options[:default] if options.include?(:default)
258
- self.null = options[:null] if options.include?(:null)
259
- self.precision = options[:precision] if options.include?(:precision)
260
- self.scale = options[:scale] if options.include?(:scale)
261
- self.collation = options[:collation] if options.include?(:collation)
295
+ self.options.merge!(options)
262
296
  end
263
297
  end
264
298
  end
@@ -307,21 +341,23 @@ module ArJdbc
307
341
  sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
308
342
  elsif insert.update_duplicates?
309
343
  sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
344
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
310
345
  sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
311
346
  end
312
347
 
313
348
  sql
314
349
  end
315
350
 
351
+ def shared_cache?
352
+ config[:properties] && config[:properties][:shared_cache] == true
353
+ end
354
+
316
355
  def get_database_version # :nodoc:
317
356
  SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
318
357
  end
319
358
 
320
- def build_truncate_statements(*table_names)
321
- truncate_tables = table_names.map do |table_name|
322
- "DELETE FROM #{quote_table_name(table_name)}"
323
- end
324
- combine_multi_statements(truncate_tables)
359
+ def build_truncate_statement(table_name)
360
+ "DELETE FROM #{quote_table_name(table_name)}"
325
361
  end
326
362
 
327
363
  def check_version
@@ -337,11 +373,6 @@ module ArJdbc
337
373
  999
338
374
  end
339
375
 
340
- def initialize_type_map(m = type_map)
341
- super
342
- register_class_with_limit m, %r(int)i, SQLite3Integer
343
- end
344
-
345
376
  def table_structure(table_name)
346
377
  structure = exec_query("PRAGMA table_info(#{quote_table_name(table_name)})", "SCHEMA")
347
378
  raise(ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'") if structure.empty?
@@ -352,10 +383,16 @@ module ArJdbc
352
383
  # See: https://www.sqlite.org/lang_altertable.html
353
384
  # SQLite has an additional restriction on the ALTER TABLE statement
354
385
  def invalid_alter_table_type?(type, options)
355
- type.to_sym == :primary_key || options[:primary_key]
386
+ type.to_sym == :primary_key || options[:primary_key] ||
387
+ options[:null] == false && options[:default].nil?
356
388
  end
357
389
 
358
- def alter_table(table_name, foreign_keys = foreign_keys(table_name), **options)
390
+ def alter_table(
391
+ table_name,
392
+ foreign_keys = foreign_keys(table_name),
393
+ check_constraints = check_constraints(table_name),
394
+ **options
395
+ )
359
396
  altered_table_name = "a#{table_name}"
360
397
 
361
398
  caller = lambda do |definition|
@@ -365,7 +402,11 @@ module ArJdbc
365
402
  fk.options[:column] = column
366
403
  end
367
404
  to_table = strip_table_name_prefix_and_suffix(fk.to_table)
368
- definition.foreign_key(to_table, fk.options)
405
+ definition.foreign_key(to_table, **fk.options)
406
+ end
407
+
408
+ check_constraints.each do |chk|
409
+ definition.check_constraint(chk.expression, **chk.options)
369
410
  end
370
411
 
371
412
  yield definition if block_given?
@@ -387,11 +428,12 @@ module ArJdbc
387
428
  def copy_table(from, to, options = {})
388
429
  from_primary_key = primary_key(from)
389
430
  options[:id] = false
390
- create_table(to, options) do |definition|
431
+ create_table(to, **options) do |definition|
391
432
  @definition = definition
392
433
  if from_primary_key.is_a?(Array)
393
434
  @definition.primary_keys from_primary_key
394
435
  end
436
+
395
437
  columns(from).each do |column|
396
438
  column_name = options[:rename] ?
397
439
  (options[:rename][column.name] ||
@@ -419,7 +461,7 @@ module ArJdbc
419
461
  name = index.name
420
462
  # indexes sqlite creates for internal use start with `sqlite_` and
421
463
  # don't need to be copied
422
- next if name.starts_with?("sqlite_")
464
+ next if name.start_with?("sqlite_")
423
465
  if to == "a#{from}"
424
466
  name = "t#{name}"
425
467
  elsif from == "a#{to}"
@@ -436,10 +478,10 @@ module ArJdbc
436
478
 
437
479
  unless columns.empty?
438
480
  # index name can't be the same
439
- opts = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
440
- opts[:unique] = true if index.unique
441
- opts[:where] = index.where if index.where
442
- add_index(to, columns, opts)
481
+ options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
482
+ options[:unique] = true if index.unique
483
+ options[:where] = index.where if index.where
484
+ add_index(to, columns, **options)
443
485
  end
444
486
  end
445
487
  end
@@ -504,7 +546,7 @@ module ArJdbc
504
546
  collation_hash[$1] = $2 if COLLATE_REGEX =~ column_string
505
547
  end
506
548
 
507
- basic_structure.map! do |column|
549
+ basic_structure.map do |column|
508
550
  column_name = column["name"]
509
551
 
510
552
  if collation_hash.has_key? column_name
@@ -526,18 +568,6 @@ module ArJdbc
526
568
  execute("PRAGMA foreign_keys = ON", "SCHEMA")
527
569
  end
528
570
 
529
- # DIFFERENCE: FQN
530
- class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
531
- private
532
- def _limit
533
- # INTEGER storage class can be stored 8 bytes value.
534
- # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
535
- limit || 8
536
- end
537
- end
538
-
539
- # DIFFERENCE: FQN
540
- ::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
541
571
  end
542
572
  # DIFFERENCE: A registration here is moved down to concrete class so we are not registering part of an adapter.
543
573
  end
@@ -658,7 +688,9 @@ module ActiveRecord::ConnectionAdapters
658
688
  end
659
689
 
660
690
  def begin_isolated_db_transaction(isolation)
661
- raise ActiveRecord::TransactionIsolationError, 'adapter does not support setting transaction isolation'
691
+ raise ActiveRecord::TransactionIsolationError, "SQLite3 only supports the `read_uncommitted` transaction isolation level" if isolation != :read_uncommitted
692
+ raise StandardError, "You need to enable the shared-cache mode in SQLite mode before attempting to change the transaction isolation level" unless shared_cache?
693
+ super
662
694
  end
663
695
 
664
696
  # SQLite driver doesn't support all types of insert statements with executeUpdate so
@@ -694,5 +726,23 @@ module ActiveRecord::ConnectionAdapters
694
726
  total_sql
695
727
  end
696
728
  end
729
+
730
+ def initialize_type_map(m = type_map)
731
+ super
732
+ register_class_with_limit m, %r(int)i, SQLite3Integer
733
+ end
734
+
735
+ # DIFFERENCE: FQN
736
+ class SQLite3Integer < ::ActiveRecord::Type::Integer # :nodoc:
737
+ private
738
+ def _limit
739
+ # INTEGER storage class can be stored 8 bytes value.
740
+ # See https://www.sqlite.org/datatype3.html#storage_classes_and_datatypes
741
+ limit || 8
742
+ end
743
+ end
744
+
745
+ # DIFFERENCE: FQN
746
+ ::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
697
747
  end
698
748
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
  ArJdbc::ConnectionMethods.module_eval do
3
3
  def sqlite3_connection(config)
4
+ config = config.deep_dup
4
5
  config[:adapter_spec] ||= ::ArJdbc::SQLite3
5
6
  config[:adapter_class] = ActiveRecord::ConnectionAdapters::SQLite3Adapter unless config.key?(:adapter_class)
6
7
 
@@ -34,7 +35,17 @@ ArJdbc::ConnectionMethods.module_eval do
34
35
  # * http://sqlite.org/c3ref/open.html
35
36
  # * http://sqlite.org/c3ref/c_open_autoproxy.html
36
37
  # => 0x01 = readonly, 0x40 = uri (default in JDBC)
37
- config[:properties][:open_mode] = 0x01 | 0x40
38
+ config[:properties][:open_mode] = ::SQLite3::Constants::Open::READONLY | ::SQLite3::Constants::Open::URI
39
+ end
40
+
41
+ if config[:flags]
42
+ config[:properties][:open_mode] ||= 0
43
+ config[:properties][:open_mode] |= config[:flags]
44
+
45
+ # JDBC driver has an extra flag for it
46
+ if config[:flags] & ::SQLite3::Constants::Open::SHAREDCACHE != 0
47
+ config[:properties][:shared_cache] = true
48
+ end
38
49
  end
39
50
 
40
51
  timeout = config[:timeout]
@@ -5,15 +5,17 @@ module ActiveRecord::Tasks
5
5
  DatabaseTasks.module_eval do
6
6
 
7
7
  # @override patched to adapt jdbc configuration
8
- def each_current_configuration(environment, spec_name = nil)
8
+ def each_current_configuration(environment, name = nil)
9
9
  environments = [environment]
10
10
  environments << 'test' if environment == 'development'
11
11
 
12
12
  environments.each do |env|
13
13
  ActiveRecord::Base.configurations.configs_for(env_name: env).each do |db_config|
14
- next if spec_name && spec_name != db_config.spec_name
14
+ next if name && name != db_config.name
15
15
 
16
- yield adapt_jdbc_config(db_config.config), db_config.spec_name, env unless db_config.config['database'].blank?
16
+ if db_config.database
17
+ yield adapt_jdbc_config(db_config), db_config.name, env
18
+ end
17
19
  end
18
20
  end
19
21
  end
@@ -21,21 +23,24 @@ module ActiveRecord::Tasks
21
23
  # @override patched to adapt jdbc configuration
22
24
  def each_local_configuration
23
25
  ActiveRecord::Base.configurations.configs_for.each do |db_config|
24
- next unless db_config.config['database']
26
+ next unless db_config.database
25
27
 
26
- if local_database?(db_config.config)
27
- yield adapt_jdbc_config(db_config.config)
28
+ if local_database?(db_config)
29
+ yield adapt_jdbc_config(db_config)
28
30
  else
29
- $stderr.puts "This task only modifies local databases. #{db_config.config['database']} is on a remote host."
31
+ $stderr.puts "This task only modifies local databases. #{db_config.database} is on a remote host."
30
32
  end
31
33
  end
32
34
  end
33
35
 
34
36
  private
35
37
 
36
- def adapt_jdbc_config(config)
37
- return config unless config['adapter']
38
- config.merge 'adapter' => config['adapter'].sub(/^jdbc/, '')
38
+ def adapt_jdbc_config(db_config)
39
+ if db_config.adapter.start_with? 'jdbc'
40
+ config = db_config.configuration_hash.merge(adapter: db_config.adapter.sub(/^jdbc/, ''))
41
+ db_config = ActiveRecord::DatabaseConfigurations::HashConfig.new(db_config.env_name, db_config.name, config)
42
+ end
43
+ db_config
39
44
  end
40
45
 
41
46
  end