activerecord-jdbc-adapter 61.2-java → 70.0-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aa4df302770068a233f5d07c6af210f49bddca54244ab09ecc3419ba3128918d
4
- data.tar.gz: a1f4a473192ba55a305a8d62595fef416f00471a9d8957137966876325a25d03
3
+ metadata.gz: 79e198f6d1579290fb0eeb3597282367757655bcff41b3e848a788b557573706
4
+ data.tar.gz: 935a5c332bf06b2d77ca47ae6fc92128cbf450e1c50d64a293ef02ef2a04ad07
5
5
  SHA512:
6
- metadata.gz: 6d6d41aa2bcbb0e9583e2c09c7b8b46357910def331a5bf9869f1eaf95199c6797f012ac57ef58dd2d144f4c6d7d46a86f52f87e55e24d7bf5166105355f760d
7
- data.tar.gz: 66ccf4e7075f94b6505669052f93bad576f4a6cb49ace225c049ce68a9d4302d2114352737f43bf0d8392de8c2a8ee1b28387caa2dda3e849880a7c8b82f42d6
6
+ metadata.gz: b124009ca502a4e24c88a5fc1ff0a8a307e1850db491ae0cf12f0388753cccb575fff87f2421ec725dc9a945e335d2f6f8de1c7734ee6887f887d380e6726a68
7
+ data.tar.gz: 82faa67a43955a2ff946510c3a77826365eb6dbd3adc7e7c81eecd83da03ce10ca37f0100a32b7089a3ef88014797a2960561851c701d695fe943f11f2712aae
@@ -1,10 +1,17 @@
1
- name: Run ARJDBC and Rails tests
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
2
9
 
3
10
  on:
4
11
  push:
5
- branches: [ 61-stable, master ]
12
+ branches: [ master ]
6
13
  pull_request:
7
- branches: [ 61-stable, master ]
14
+ branches: [ master ]
8
15
 
9
16
  permissions:
10
17
  contents: read
@@ -17,10 +24,10 @@ jobs:
17
24
  strategy:
18
25
  fail-fast: false
19
26
  matrix:
20
- ruby-version: ['jruby-9.2.20.1']
27
+ ruby-version: ['jruby-head']
21
28
  db: ['mysql2']
22
29
  test_targets: ["rails:test_mysql2"]
23
- ar_version: ["6-1-stable"]
30
+ ar_version: ["7-0-stable"]
24
31
  prepared_statements: ['false', 'true']
25
32
  driver: ['MySQL']
26
33
 
@@ -69,10 +76,10 @@ jobs:
69
76
  strategy:
70
77
  fail-fast: false
71
78
  matrix:
72
- ruby-version: [ 'jruby-9.2.20.1' ]
79
+ ruby-version: [ 'jruby-head' ]
73
80
  db: [ 'postgresql' ]
74
81
  test_targets: [ "rails:test_postgresql" ]
75
- ar_version: ["6-1-stable"]
82
+ ar_version: ["7-0-stable"]
76
83
  prepared_statements: [ 'false', 'true' ]
77
84
 
78
85
  services:
@@ -119,10 +126,10 @@ jobs:
119
126
  strategy:
120
127
  fail-fast: false
121
128
  matrix:
122
- ruby-version: ['jruby-9.2.20.1']
129
+ ruby-version: ['jruby-head']
123
130
  db: ['sqlite3']
124
131
  test_targets: ["rails:test_sqlite3"]
125
- ar_version: ["6-1-stable"]
132
+ ar_version: ["7-0-stable"]
126
133
 
127
134
  env:
128
135
  DB: ${{ matrix.db }}
@@ -151,7 +158,7 @@ jobs:
151
158
  strategy:
152
159
  fail-fast: false
153
160
  matrix:
154
- ruby-version: ['jruby-9.2.20.1']
161
+ ruby-version: ['jruby-head']
155
162
  db: ['mysql2']
156
163
  test_targets: ["db:mysql test_mysql2"]
157
164
  prepared_statements: ['false', 'true']
@@ -196,7 +203,7 @@ jobs:
196
203
  strategy:
197
204
  fail-fast: false
198
205
  matrix:
199
- ruby-version: ['jruby-9.2.20.1']
206
+ ruby-version: ['jruby-head']
200
207
  db: ['postgresql']
201
208
  test_targets: ["db:postgresql test_postgresql"]
202
209
  prepared_statements: ['false', 'true']
@@ -243,7 +250,7 @@ jobs:
243
250
  strategy:
244
251
  fail-fast: false
245
252
  matrix:
246
- ruby-version: ['jruby-9.2.20.1']
253
+ ruby-version: ['jruby-head']
247
254
  db: ['sqlite3']
248
255
  test_targets: ['test_sqlite3']
249
256
 
data/.travis.yml CHANGED
@@ -9,14 +9,13 @@ before_install:
9
9
  - rvm @default,@global do gem uninstall bundler -a -x -I || true
10
10
  - gem install bundler -v "~>1.17.3"
11
11
  install:
12
- - bundle config set --local without 'development'
13
- - bundle install
12
+ - bundle install --retry 3 --without development
14
13
  # to fix this issue: https://travis-ci.community/t/mariadb-10-1-fails-to-install-on-xenial/3151/3
15
14
  - mysql -u root -e 'CREATE USER IF NOT EXISTS travis@localhost; GRANT ALL ON *.* TO travis@localhost;' || true
16
15
 
17
16
  language: ruby
18
17
  rvm:
19
- - jruby-9.2.19.0
18
+ - jruby-9.2.14.0
20
19
  jdk:
21
20
  - openjdk8
22
21
 
@@ -49,7 +48,7 @@ before_script:
49
48
 
50
49
  env:
51
50
  global:
52
- - AR_VERSION="6-1-stable"
51
+ - AR_VERSION="master"
53
52
  matrix:
54
53
  allow_failures:
55
54
  - rvm: jruby-head
data/Gemfile CHANGED
@@ -47,11 +47,11 @@ else
47
47
  gemspec name: 'activerecord-jdbc-adapter' # Use versiom from .gemspec
48
48
  end
49
49
 
50
- gem 'rake', '>= 11.1', require: nil
50
+ gem 'rake', require: nil
51
51
 
52
52
  group :test do
53
- gem 'test-unit', '~> 2.5.4', require: nil
54
- gem 'test-unit-context', '>= 0.4.0', require: nil
53
+ gem 'test-unit', require: nil
54
+ gem 'test-unit-context', require: nil
55
55
  gem 'mocha', '~> 1.2', require: false # Rails has '~> 0.14'
56
56
 
57
57
  gem 'bcrypt', '~> 3.1.11', require: false
@@ -59,8 +59,8 @@ end
59
59
 
60
60
  group :rails do
61
61
  group :test do
62
- gem 'minitest', '~> 5.12.2', require: nil
63
- gem 'minitest-excludes', '~> 2.0.1', require: nil
62
+ gem 'minitest', require: nil
63
+ gem 'minitest-excludes', require: nil
64
64
  gem 'minitest-rg', require: nil
65
65
 
66
66
  gem 'benchmark-ips', require: nil
@@ -72,6 +72,8 @@ group :rails do
72
72
  gem 'erubis', require: nil # "~> 2.7.0"
73
73
  # NOTE: due rails/activerecord/test/cases/connection_management_test.rb
74
74
  gem 'rack', require: nil
75
+
76
+ gem 'zeitwerk'
75
77
  end
76
78
 
77
79
  group :development do
@@ -41,7 +41,7 @@ Gem::Specification.new do |gem|
41
41
  gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
42
42
  gem.test_files = gem.files.grep(%r{^test/})
43
43
 
44
- gem.add_dependency 'activerecord', '~> 6.1.0'
44
+ gem.add_dependency 'activerecord', '~> 7.0'
45
45
 
46
46
  #gem.add_development_dependency 'test-unit', '2.5.4'
47
47
  #gem.add_development_dependency 'test-unit-context', '>= 0.3.0'
@@ -34,7 +34,7 @@ module ArJdbc
34
34
  raw_connection.jdbc_connection(unwrap)
35
35
  end
36
36
 
37
- protected
37
+ private
38
38
 
39
39
  def translate_exception_class(e, sql, binds)
40
40
  message = "#{e.class.name}: #{e.message}"
@@ -42,16 +42,19 @@ module ArJdbc
42
42
  exception = translate_exception(
43
43
  e, message: message, sql: sql, binds: binds
44
44
  )
45
- exception.set_backtrace e.backtrace
45
+ exception.set_backtrace e.backtrace unless exception.equal?(e)
46
46
  exception
47
47
  end
48
48
 
49
+ Throwable = java.lang.Throwable
50
+ private_constant :Throwable
51
+
49
52
  def translate_exception(exception, message:, sql:, binds:)
50
53
  # override in derived class
51
54
 
52
55
  # we shall not translate native "Java" exceptions as they might
53
56
  # swallow an ArJdbc / driver bug into an AR::StatementInvalid !
54
- return exception if exception.is_a?(Java::JavaLang::Throwable)
57
+ return exception if exception.is_a?(Throwable)
55
58
 
56
59
  case exception
57
60
  when SystemExit, SignalException, NoMemoryError then exception
@@ -61,14 +64,10 @@ module ArJdbc
61
64
  end
62
65
  end
63
66
 
64
- def extract_raw_bind_values(binds)
65
- binds.map(&:value_for_database)
66
- end
67
-
68
67
  # this version of log() automatically fills type_casted_binds from binds if necessary
69
- def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil)
68
+ def log(sql, name = "SQL", binds = [], type_casted_binds = [], statement_name = nil, async: false)
70
69
  if binds.any? && (type_casted_binds.nil? || type_casted_binds.empty?)
71
- type_casted_binds = ->{ extract_raw_bind_values(binds) }
70
+ type_casted_binds = ->{ binds.map(&:value_for_database) } # extract_raw_bind_values
72
71
  end
73
72
  super
74
73
  end
@@ -30,7 +30,7 @@ module ArJdbc
30
30
 
31
31
  # It appears that at this point (AR 5.0) "prepare" should only ever be true
32
32
  # if prepared statements are enabled
33
- def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false)
33
+ def exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false)
34
34
  if preventing_writes? && write_query?(sql)
35
35
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
36
36
  end
@@ -69,7 +69,7 @@ module ArJdbc
69
69
  end
70
70
  alias :exec_delete :exec_update
71
71
 
72
- def execute(sql, name = nil)
72
+ def execute(sql, name = nil, async: false)
73
73
  if preventing_writes? && write_query?(sql)
74
74
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
75
75
  end
@@ -77,11 +77,11 @@ module ArJdbc
77
77
  materialize_transactions
78
78
  mark_transaction_written_if_write(sql)
79
79
 
80
- log(sql, name) { @connection.execute(sql) }
80
+ log(sql, name, async: async) { @connection.execute(sql) }
81
81
  end
82
82
 
83
83
  # overridden to support legacy binds
84
- def select_all(arel, name = nil, binds = NO_BINDS, preparable: nil)
84
+ def select_all(arel, name = nil, binds = NO_BINDS, preparable: nil, async: false)
85
85
  binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
86
86
  super
87
87
  end
@@ -100,7 +100,7 @@ module ArJdbc
100
100
  return if @@_initialized; @@_initialized = true
101
101
 
102
102
  require 'arjdbc/util/serialized_attributes'
103
- Util::SerializedAttributes.setup /blob|clob/i, 'after_save_with_db2_lob'
103
+ Util::SerializedAttributes.setup %r{blob|clob}i, 'after_save_with_db2_lob'
104
104
  end
105
105
 
106
106
  # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
@@ -422,7 +422,7 @@ module ArJdbc
422
422
  def quoted_date(value)
423
423
  if value.acts_like?(:time) && value.respond_to?(:usec)
424
424
  usec = sprintf("%06d", value.usec)
425
- value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
425
+ value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
426
426
  "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
427
427
  else
428
428
  super
@@ -430,7 +430,7 @@ module ArJdbc
430
430
  end if ::ActiveRecord::VERSION::MAJOR >= 3
431
431
 
432
432
  def quote_time(value)
433
- value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
433
+ value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
434
434
  # AS400 doesn't support date in time column
435
435
  "'#{value.strftime("%H:%M:%S")}'"
436
436
  end
@@ -34,7 +34,7 @@ module ArJdbc
34
34
  return nil unless time
35
35
  time_array = [time.year, time.month, time.day, time.hour, time.min, time.sec]
36
36
  time_array[0] ||= 2000; time_array[1] ||= 1; time_array[2] ||= 1;
37
- Time.send(ActiveRecord::Base.default_timezone, *time_array) rescue nil
37
+ Time.send(ActiveRecord.default_timezone, *time_array) rescue nil
38
38
  end
39
39
 
40
40
  # @deprecated
@@ -197,7 +197,7 @@ module ArJdbc
197
197
  def quoted_date(value)
198
198
  if value.acts_like?(:time) && value.respond_to?(:usec)
199
199
  usec = sprintf("%06d", value.usec)
200
- value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
200
+ value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
201
201
  "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
202
202
  else
203
203
  super
@@ -16,7 +16,7 @@ module ArJdbc
16
16
  return if @@_initialized; @@_initialized = true
17
17
 
18
18
  require 'arjdbc/util/serialized_attributes'
19
- Util::SerializedAttributes.setup /blob/i
19
+ Util::SerializedAttributes.setup %r{blob}i
20
20
  end
21
21
 
22
22
  # @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
@@ -339,7 +339,7 @@ module ArJdbc
339
339
  def quoted_date(value)
340
340
  if value.acts_like?(:time) && value.respond_to?(:usec)
341
341
  usec = sprintf "%04d", (value.usec / 100.0).round
342
- value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
342
+ value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
343
343
  "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
344
344
  else
345
345
  super
@@ -111,7 +111,7 @@ module ArJdbc
111
111
  if column_type == :time
112
112
  "'#{value.strftime("%H:%M:%S")}'"
113
113
  #elsif column_type == :timestamp # || column_type == :datetime
114
- #value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
114
+ #value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
115
115
  #"'#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{sprintf("%06d", value.usec)}'"
116
116
  else
117
117
  super
@@ -127,7 +127,7 @@ module ArJdbc
127
127
  def quoted_date(value)
128
128
  if value.acts_like?(:time) && value.respond_to?(:usec)
129
129
  usec = sprintf("%06d", value.usec)
130
- value = ::ActiveRecord::Base.default_timezone == :utc ? value.getutc : value.getlocal
130
+ value = ::ActiveRecord.default_timezone == :utc ? value.getutc : value.getlocal
131
131
  "#{value.strftime("%Y-%m-%d %H:%M:%S")}.#{usec}"
132
132
  else
133
133
  super
@@ -431,12 +431,12 @@ module ActiveRecord
431
431
  private
432
432
 
433
433
  # Helper useful during {#quote} since AREL might pass in it's literals
434
- # to be quoted, fixed since AREL 4.0.0.beta1 : http://git.io/7gyTig
434
+ # to be quoted, fixed since AREL 4.0.0.beta1 : https://github.com/rails/arel/commit/9c514f3
435
435
  def sql_literal?(value); ::Arel::Nodes::SqlLiteral === value; end
436
436
 
437
- # Helper to get local/UTC time (based on `ActiveRecord::Base.default_timezone`).
437
+ # Helper to get local/UTC time (based on `ActiveRecord::default_timezone`).
438
438
  def get_time(value)
439
- get = ::ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
439
+ get = ::ActiveRecord.default_timezone == :utc ? :getutc : :getlocal
440
440
  value.respond_to?(get) ? value.send(get) : value
441
441
  end
442
442
 
Binary file
@@ -130,9 +130,9 @@ module ActiveRecord::ConnectionAdapters
130
130
  return nil unless time
131
131
 
132
132
  time -= offset
133
- ActiveRecord::Base.default_timezone == :utc ? time : time.getlocal
133
+ ActiveRecord.default_timezone == :utc ? time : time.getlocal
134
134
  else
135
- timezone = ActiveRecord::Base.default_timezone
135
+ timezone = ActiveRecord.default_timezone
136
136
  Time.public_send(timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
137
137
  end
138
138
  end
@@ -107,7 +107,8 @@ module ActiveRecord
107
107
 
108
108
  # Reloading the type map in abstract/statement_cache.rb blows up postgres
109
109
  def clear_cache!
110
- reload_type_map
110
+ # FIXME: This seems to have disappeared in Rails 7?
111
+ # reload_type_map
111
112
  super
112
113
  end
113
114
 
@@ -40,7 +40,7 @@ module ArJdbc
40
40
  return if @@_initialized; @@_initialized = true
41
41
 
42
42
  require 'arjdbc/util/serialized_attributes'
43
- Util::SerializedAttributes.setup /LOB\(|LOB$/i, 'after_save_with_oracle_lob'
43
+ Util::SerializedAttributes.setup %r{LOB\(|LOB$}i, 'after_save_with_oracle_lob'
44
44
 
45
45
  unless ActiveRecord::ConnectionAdapters::AbstractAdapter.
46
46
  instance_methods(false).detect { |m| m.to_s == "prefetch_primary_key?" }
@@ -81,7 +81,7 @@ module ArJdbc
81
81
  # If using Active Record's time zone support configure the connection to return
82
82
  # TIMESTAMP WITH ZONE types in UTC.
83
83
  # (SET TIME ZONE does not use an equals sign like other SET variables)
84
- if ActiveRecord::Base.default_timezone == :utc
84
+ if ActiveRecord.default_timezone == :utc
85
85
  execute("SET time zone 'UTC'", 'SCHEMA')
86
86
  elsif tz = local_tz
87
87
  execute("SET time zone '#{tz}'", 'SCHEMA')
@@ -10,6 +10,7 @@ require "active_record/connection_adapters/abstract_adapter"
10
10
  require "active_record/connection_adapters/statement_pool"
11
11
  require "active_record/connection_adapters/sqlite3/explain_pretty_printer"
12
12
  require "active_record/connection_adapters/sqlite3/quoting"
13
+ require "active_record/connection_adapters/sqlite3/database_statements"
13
14
  require "active_record/connection_adapters/sqlite3/schema_creation"
14
15
  require "active_record/connection_adapters/sqlite3/schema_definitions"
15
16
  require "active_record/connection_adapters/sqlite3/schema_dumper"
@@ -64,6 +65,7 @@ module ArJdbc
64
65
  # DIFFERENCE: FQN
65
66
  include ::ActiveRecord::ConnectionAdapters::SQLite3::Quoting
66
67
  include ::ActiveRecord::ConnectionAdapters::SQLite3::SchemaStatements
68
+ include ::ActiveRecord::ConnectionAdapters::SQLite3::DatabaseStatements
67
69
 
68
70
  NATIVE_DATABASE_TYPES = {
69
71
  primary_key: "integer PRIMARY KEY AUTOINCREMENT NOT NULL",
@@ -79,15 +81,30 @@ module ArJdbc
79
81
  boolean: { name: "boolean" },
80
82
  json: { name: "json" },
81
83
  }
82
-
83
- # DIFFERENCE: class_attribute in original adapter is moved down to our section which is a class
84
- # since we cannot define it here in the module (original source this is a class).
84
+
85
+ class StatementPool < ConnectionAdapters::StatementPool # :nodoc:
86
+ private
87
+ def dealloc(stmt)
88
+ stmt.close unless stmt.closed?
89
+ end
90
+ end
85
91
 
86
92
  def initialize(connection, logger, connection_options, config)
93
+ @memory_database = config[:database] == ":memory:"
87
94
  super(connection, logger, config)
88
95
  configure_connection
89
96
  end
90
97
 
98
+ def self.database_exists?(config)
99
+ config = config.symbolize_keys
100
+ if config[:database] == ":memory:"
101
+ true
102
+ else
103
+ database_file = defined?(Rails.root) ? File.expand_path(config[:database], Rails.root) : config[:database]
104
+ File.exist?(database_file)
105
+ end
106
+ end
107
+
91
108
  def supports_ddl_transactions?
92
109
  true
93
110
  end
@@ -101,7 +118,7 @@ module ArJdbc
101
118
  end
102
119
 
103
120
  def supports_partial_index?
104
- database_version >= "3.9.0"
121
+ true
105
122
  end
106
123
 
107
124
  def supports_expression_index?
@@ -144,6 +161,25 @@ module ArJdbc
144
161
  alias supports_insert_conflict_target? supports_insert_on_conflict?
145
162
 
146
163
  # DIFFERENCE: active?, reconnect!, disconnect! handles by arjdbc core
164
+ def supports_concurrent_connections?
165
+ !@memory_database
166
+ end
167
+
168
+ def active?
169
+ !@raw_connection.closed?
170
+ end
171
+
172
+ def reconnect!
173
+ super
174
+ connect if @connection.closed?
175
+ end
176
+
177
+ # Disconnects from the database if already connected. Otherwise, this
178
+ # method does nothing.
179
+ def disconnect!
180
+ super
181
+ @connection.close rescue nil
182
+ end
147
183
 
148
184
  def supports_index_sort_order?
149
185
  true
@@ -182,48 +218,8 @@ module ArJdbc
182
218
  end
183
219
  end
184
220
 
185
- #--
186
- # DATABASE STATEMENTS ======================================
187
- #++
188
-
189
- READ_QUERY = ActiveRecord::ConnectionAdapters::AbstractAdapter.build_read_query_regexp(
190
- :pragma
191
- ) # :nodoc:
192
- private_constant :READ_QUERY
193
-
194
- def write_query?(sql) # :nodoc:
195
- !READ_QUERY.match?(sql)
196
- end
197
-
198
- def explain(arel, binds = [])
199
- sql = "EXPLAIN QUERY PLAN #{to_sql(arel, binds)}"
200
- # DIFFERENCE: FQN
201
- ::ActiveRecord::ConnectionAdapters::SQLite3::ExplainPrettyPrinter.new.pp(exec_query(sql, "EXPLAIN", []))
202
- end
203
-
204
- # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
205
- #def exec_query(sql, name = nil, binds = [], prepare: false)
206
-
207
- # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
208
- #def exec_delete(sql, name = "SQL", binds = [])
209
-
210
- def last_inserted_id(result)
211
- @connection.last_insert_row_id
212
- end
213
-
214
- # DIFFERENCE: implemented in ArJdbc::Abstract::DatabaseStatements
215
- #def execute(sql, name = nil) #:nodoc:
216
-
217
- def begin_db_transaction #:nodoc:
218
- log("begin transaction", 'TRANSACTION') { @connection.transaction }
219
- end
220
-
221
- def commit_db_transaction #:nodoc:
222
- log("commit transaction", 'TRANSACTION') { @connection.commit }
223
- end
224
-
225
- def exec_rollback_db_transaction #:nodoc:
226
- log("rollback transaction", 'TRANSACTION') { @connection.rollback }
221
+ def all_foreign_keys_valid? # :nodoc:
222
+ execute("PRAGMA foreign_key_check").blank?
227
223
  end
228
224
 
229
225
  # SCHEMA STATEMENTS ========================================
@@ -233,14 +229,15 @@ module ArJdbc
233
229
  pks.sort_by { |f| f["pk"] }.map { |f| f["name"] }
234
230
  end
235
231
 
236
- def remove_index(table_name, column_name = nil, **options) # :nodoc:
237
- return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
232
+ def remove_index(table_name, column_name = nil, **options) # :nodoc:
233
+ return if options[:if_exists] && !index_exists?(table_name, column_name, **options)
238
234
 
239
235
  index_name = index_name_for_remove(table_name, column_name, options)
240
236
 
241
237
  exec_query "DROP INDEX #{quote_column_name(index_name)}"
242
238
  end
243
239
 
240
+
244
241
  # Renames a table.
245
242
  #
246
243
  # Example:
@@ -265,9 +262,17 @@ module ArJdbc
265
262
  def remove_column(table_name, column_name, type = nil, **options) #:nodoc:
266
263
  alter_table(table_name) do |definition|
267
264
  definition.remove_column column_name
268
- definition.foreign_keys.delete_if do |_, fk_options|
269
- fk_options[:column] == column_name.to_s
265
+ definition.foreign_keys.delete_if { |fk| fk.column == column_name.to_s }
266
+ end
267
+ end
268
+
269
+ def remove_columns(table_name, *column_names, type: nil, **options) # :nodoc:
270
+ alter_table(table_name) do |definition|
271
+ column_names.each do |column_name|
272
+ definition.remove_column column_name
270
273
  end
274
+ column_names = column_names.map(&:to_s)
275
+ definition.foreign_keys.delete_if { |fk| column_names.include?(fk.column) }
271
276
  end
272
277
  end
273
278
 
@@ -291,8 +296,8 @@ module ArJdbc
291
296
  def change_column(table_name, column_name, type, **options) #:nodoc:
292
297
  alter_table(table_name) do |definition|
293
298
  definition[column_name].instance_eval do
294
- self.type = type
295
- self.options.merge!(options)
299
+ self.type = aliased_types(type.to_s, type)
300
+ self.options.merge!(options)
296
301
  end
297
302
  end
298
303
  end
@@ -322,18 +327,6 @@ module ArJdbc
322
327
  end
323
328
  end
324
329
 
325
- def insert_fixtures_set(fixture_set, tables_to_delete = [])
326
- disable_referential_integrity do
327
- transaction(requires_new: true) do
328
- tables_to_delete.each { |table| delete "DELETE FROM #{quote_table_name(table)}", "Fixture Delete" }
329
-
330
- fixture_set.each do |table_name, rows|
331
- rows.each { |row| insert_fixture(row, table_name) }
332
- end
333
- end
334
- end
335
- end
336
-
337
330
  def build_insert_sql(insert) # :nodoc:
338
331
  sql = +"INSERT #{insert.into} #{insert.values_list}"
339
332
 
@@ -341,23 +334,23 @@ module ArJdbc
341
334
  sql << " ON CONFLICT #{insert.conflict_target} DO NOTHING"
342
335
  elsif insert.update_duplicates?
343
336
  sql << " ON CONFLICT #{insert.conflict_target} DO UPDATE SET "
344
- sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
345
- sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
337
+ if insert.raw_update_sql?
338
+ sql << insert.raw_update_sql
339
+ else
340
+ sql << insert.touch_model_timestamps_unless { |column| "#{column} IS excluded.#{column}" }
341
+ sql << insert.updatable_columns.map { |column| "#{column}=excluded.#{column}" }.join(",")
342
+ end
346
343
  end
347
344
 
348
345
  sql
349
346
  end
350
347
 
351
- def shared_cache?
352
- config[:properties] && config[:properties][:shared_cache] == true
348
+ def shared_cache? # :nodoc:
349
+ @config.fetch(:flags, 0).anybits?(::SQLite3::Constants::Open::SHAREDCACHE)
353
350
  end
354
351
 
355
352
  def get_database_version # :nodoc:
356
- SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)"))
357
- end
358
-
359
- def build_truncate_statement(table_name)
360
- "DELETE FROM #{quote_table_name(table_name)}"
353
+ SQLite3Adapter::Version.new(query_value("SELECT sqlite_version(*)", "SCHEMA"))
361
354
  end
362
355
 
363
356
  def check_version
@@ -380,6 +373,34 @@ module ArJdbc
380
373
  end
381
374
  alias column_definitions table_structure
382
375
 
376
+ def extract_value_from_default(default)
377
+ case default
378
+ when /^null$/i
379
+ nil
380
+ # Quoted types
381
+ when /^'(.*)'$/m
382
+ $1.gsub("''", "'")
383
+ # Quoted types
384
+ when /^"(.*)"$/m
385
+ $1.gsub('""', '"')
386
+ # Numeric types
387
+ when /\A-?\d+(\.\d*)?\z/
388
+ $&
389
+ else
390
+ # Anything else is blank or some function
391
+ # and we can't know the value of that, so return nil.
392
+ nil
393
+ end
394
+ end
395
+
396
+ def extract_default_function(default_value, default)
397
+ default if has_default_function?(default_value, default)
398
+ end
399
+
400
+ def has_default_function?(default_value, default)
401
+ !default_value && %r{\w+\(.*\)|CURRENT_TIME|CURRENT_DATE|CURRENT_TIMESTAMP}.match?(default)
402
+ end
403
+
383
404
  # See: https://www.sqlite.org/lang_altertable.html
384
405
  # SQLite has an additional restriction on the ALTER TABLE statement
385
406
  def invalid_alter_table_type?(type, options)
@@ -440,8 +461,13 @@ module ArJdbc
440
461
  options[:rename][column.name.to_sym] ||
441
462
  column.name) : column.name
442
463
 
464
+ if column.has_default?
465
+ type = lookup_cast_type_from_column(column)
466
+ default = type.deserialize(column.default)
467
+ end
468
+
443
469
  @definition.column(column_name, column.type,
444
- limit: column.limit, default: column.default,
470
+ limit: column.limit, default: default,
445
471
  precision: column.precision, scale: column.scale,
446
472
  null: column.null, collation: column.collation,
447
473
  primary_key: column_name == from_primary_key
@@ -459,9 +485,6 @@ module ArJdbc
459
485
  def copy_table_indexes(from, to, rename = {})
460
486
  indexes(from).each do |index|
461
487
  name = index.name
462
- # indexes sqlite creates for internal use start with `sqlite_` and
463
- # don't need to be copied
464
- next if name.start_with?("sqlite_")
465
488
  if to == "a#{from}"
466
489
  name = "t#{name}"
467
490
  elsif from == "a#{to}"
@@ -481,6 +504,7 @@ module ArJdbc
481
504
  options = { name: name.gsub(/(^|_)(#{from})_/, "\\1#{to}_"), internal: true }
482
505
  options[:unique] = true if index.unique
483
506
  options[:where] = index.where if index.where
507
+ options[:order] = index.orders if index.orders
484
508
  add_index(to, columns, **options)
485
509
  end
486
510
  end
@@ -500,20 +524,22 @@ module ArJdbc
500
524
  end
501
525
 
502
526
  def translate_exception(exception, message:, sql:, binds:)
503
- case exception.message
504
527
  # SQLite 3.8.2 returns a newly formatted error message:
505
528
  # UNIQUE constraint failed: *table_name*.*column_name*
506
529
  # Older versions of SQLite return:
507
530
  # column *column_name* is not unique
508
- when /column(s)? .* (is|are) not unique/, /UNIQUE constraint failed: .*/
531
+ if exception.message.match?(/(column(s)? .* (is|are) not unique|UNIQUE constraint failed: .*)/i)
509
532
  # DIFFERENCE: FQN
510
533
  ::ActiveRecord::RecordNotUnique.new(message, sql: sql, binds: binds)
511
- when /.* may not be NULL/, /NOT NULL constraint failed: .*/
534
+ elsif exception.message.match?(/(.* may not be NULL|NOT NULL constraint failed: .*)/i)
512
535
  # DIFFERENCE: FQN
513
536
  ::ActiveRecord::NotNullViolation.new(message, sql: sql, binds: binds)
514
- when /FOREIGN KEY constraint failed/i
537
+ elsif exception.message.match?(/FOREIGN KEY constraint failed/i)
515
538
  # DIFFERENCE: FQN
516
539
  ::ActiveRecord::InvalidForeignKey.new(message, sql: sql, binds: binds)
540
+ elsif exception.message.match?(/called on a closed database/i)
541
+ # DIFFERENCE: FQN
542
+ ::ActiveRecord::ConnectionNotEstablished.new(exception)
517
543
  else
518
544
  super
519
545
  end
@@ -533,12 +559,12 @@ module ArJdbc
533
559
  # Result will have following sample string
534
560
  # CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
535
561
  # "password_digest" varchar COLLATE "NOCASE");
536
- result = exec_query(sql, "SCHEMA").first
562
+ result = query_value(sql, "SCHEMA")
537
563
 
538
564
  if result
539
565
  # Splitting with left parentheses and discarding the first part will return all
540
566
  # columns separated with comma(,).
541
- columns_string = result["sql"].split("(", 2).last
567
+ columns_string = result.split("(", 2).last
542
568
 
543
569
  columns_string.split(",").each do |column_string|
544
570
  # This regex will match the column name and collation type and will save
@@ -564,7 +590,21 @@ module ArJdbc
564
590
  Arel::Visitors::SQLite.new(self)
565
591
  end
566
592
 
593
+ def build_statement_pool
594
+ StatementPool.new(self.class.type_cast_config_to_integer(@config[:statement_limit]))
595
+ end
596
+
597
+ def connect
598
+ @connection = ::SQLite3::Database.new(
599
+ @config[:database].to_s,
600
+ @config.merge(results_as_hash: true)
601
+ )
602
+ end
603
+
567
604
  def configure_connection
605
+ # FIXME: missing from adapter
606
+ # @connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout])) if @config[:timeout]
607
+
568
608
  execute("PRAGMA foreign_keys = ON", "SCHEMA")
569
609
  end
570
610
 
@@ -720,11 +760,15 @@ module ActiveRecord::ConnectionAdapters
720
760
 
721
761
  # because the JDBC driver doesn't like multiple SQL statements in one JDBC statement
722
762
  def combine_multi_statements(total_sql)
723
- if total_sql.length == 1
724
- total_sql.first
725
- else
726
- total_sql
727
- end
763
+ total_sql
764
+ end
765
+
766
+ # combine
767
+ def write_query?(sql) # :nodoc:
768
+ return sql.any? { |stmt| super(stmt) } if sql.kind_of? Array
769
+ !READ_QUERY.match?(sql)
770
+ rescue ArgumentError # Invalid encoding
771
+ !READ_QUERY.match?(sql.b)
728
772
  end
729
773
 
730
774
  def initialize_type_map(m = type_map)
@@ -4,7 +4,8 @@ module ArJdbc
4
4
  module Util
5
5
  module TableCopier
6
6
 
7
- # taken from SQLite adapter, code loosely based on http://git.io/P7tFQA
7
+ # taken from SQLite adapter, code loosely based on
8
+ # https://github.com/rails/rails/blob/d3e5118/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb
8
9
 
9
10
  # Performs changes for table by first copying (and preserving contents)
10
11
  # into another (temporary) table, than alters and copies all data back.
@@ -1,3 +1,3 @@
1
1
  module ArJdbc
2
- VERSION = '61.2'
2
+ VERSION = '70.0'
3
3
  end
@@ -720,6 +720,21 @@ public class RubyJdbcConnection extends RubyObject {
720
720
  }
721
721
  }
722
722
 
723
+ @JRubyMethod(name = "closed?")
724
+ public IRubyObject closed_p(ThreadContext context) {
725
+ try {
726
+ final Connection connection = getConnectionInternal(false);
727
+
728
+ if (connection == null) return context.fals;
729
+
730
+ // NOTE: isClosed method generally cannot be called to determine
731
+ // whether a connection to a database is valid or invalid ...
732
+ return context.runtime.newBoolean(connection.isClosed());
733
+ } catch (SQLException e) {
734
+ return handleException(context, e);
735
+ }
736
+ }
737
+
723
738
  @JRubyMethod(name = "close")
724
739
  public IRubyObject close(final ThreadContext context) {
725
740
  final Connection connection = getConnection(false);
@@ -2633,8 +2648,8 @@ public class RubyJdbcConnection extends RubyObject {
2633
2648
  }
2634
2649
 
2635
2650
  private String default_timezone(final ThreadContext context) {
2636
- final RubyClass base = getBase(context.runtime);
2637
- return default_timezone.call(context, base, base).asJavaString(); // :utc (or :local)
2651
+ final RubyModule activeRecord = ActiveRecord(context);
2652
+ return default_timezone.call(context, activeRecord, activeRecord).asJavaString(); // :utc (or :local)
2638
2653
  }
2639
2654
 
2640
2655
  // ActiveRecord::Base.default_timezone
@@ -402,6 +402,11 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
402
402
  finally { close(statement); }
403
403
  }
404
404
 
405
+ @JRubyMethod
406
+ public IRubyObject filename(ThreadContext context) {
407
+ return getConfigValue(context, "database");
408
+ }
409
+
405
410
  @Override
406
411
  @JRubyMethod(name = "rollback_savepoint", required = 1)
407
412
  public IRubyObject rollback_savepoint(final ThreadContext context, final IRubyObject name) {
@@ -460,6 +465,34 @@ public class SQLite3RubyJdbcConnection extends RubyJdbcConnection {
460
465
  return context.runtime.newBoolean(connection.isReadOnly());
461
466
  }
462
467
 
468
+ // note: sqlite3 cext uses this same method but we do not combine all our statements
469
+ // into a single ; delimited string but leave it as an array of statements. This is
470
+ // because the JDBC way of handling batches is to use addBatch().
471
+ @JRubyMethod(name = "execute_batch2")
472
+ public IRubyObject execute_batch2(ThreadContext context, IRubyObject statementsArg) {
473
+ // Assume we will only call this with an array.
474
+ final RubyArray statements = (RubyArray) statementsArg;
475
+ return withConnection(context, connection -> {
476
+ Statement statement = null;
477
+ try {
478
+ statement = createStatement(context, connection);
479
+
480
+ int length = statements.getLength();
481
+ for (int i = 0; i < length; i++) {
482
+ statement.addBatch(sqlString(statements.eltOk(i)));
483
+ }
484
+ statement.executeBatch();
485
+ return context.nil;
486
+ } catch (final SQLException e) {
487
+ // Generate list semicolon list of statements which should match AR error formatting more.
488
+ debugErrorSQL(context, sqlString(statements.join(context, context.runtime.newString(";\n"))));
489
+ throw e;
490
+ } finally {
491
+ close(statement);
492
+ }
493
+ });
494
+ }
495
+
463
496
  @Override
464
497
  protected void setDecimalParameter(final ThreadContext context,
465
498
  final Connection connection, final PreparedStatement statement,
metadata CHANGED
@@ -1,21 +1,21 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-jdbc-adapter
3
3
  version: !ruby/object:Gem::Version
4
- version: '61.2'
4
+ version: '70.0'
5
5
  platform: java
6
6
  authors:
7
7
  - Nick Sieger, Ola Bini, Karol Bucek and JRuby contributors
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-04-29 00:00:00.000000000 Z
11
+ date: 2022-11-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 6.1.0
18
+ version: '7.0'
19
19
  name: activerecord
20
20
  prerelease: false
21
21
  type: :runtime
@@ -23,7 +23,7 @@ dependencies:
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 6.1.0
26
+ version: '7.0'
27
27
  description: 'AR-JDBC is a database adapter for Rails'' ActiveRecord component designed
28
28
  to be used with JRuby built upon Java''s JDBC API for database access. Provides
29
29
  (ActiveRecord) built-in adapters: MySQL, PostgreSQL, SQLite3, and SQLServer.'
@@ -231,7 +231,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
231
231
  - !ruby/object:Gem::Version
232
232
  version: '0'
233
233
  requirements: []
234
- rubygems_version: 3.2.29
234
+ rubygems_version: 3.3.25
235
235
  signing_key:
236
236
  specification_version: 4
237
237
  summary: JDBC adapter for ActiveRecord, for use within JRuby on Rails.