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 +4 -4
- data/.github/workflows/ruby.yml +19 -12
- data/.travis.yml +3 -4
- data/Gemfile +7 -5
- data/activerecord-jdbc-adapter.gemspec +1 -1
- data/lib/arjdbc/abstract/core.rb +8 -9
- data/lib/arjdbc/abstract/database_statements.rb +4 -4
- data/lib/arjdbc/db2/adapter.rb +3 -3
- data/lib/arjdbc/db2/column.rb +1 -1
- data/lib/arjdbc/derby/adapter.rb +1 -1
- data/lib/arjdbc/firebird/adapter.rb +2 -2
- data/lib/arjdbc/hsqldb/adapter.rb +2 -2
- data/lib/arjdbc/jdbc/adapter.rb +3 -3
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/type_cast.rb +2 -2
- data/lib/arjdbc/mysql/adapter.rb +2 -1
- data/lib/arjdbc/oracle/adapter.rb +1 -1
- data/lib/arjdbc/postgresql/adapter.rb +1 -1
- data/lib/arjdbc/sqlite3/adapter.rb +132 -88
- data/lib/arjdbc/util/table_copier.rb +2 -1
- data/lib/arjdbc/version.rb +1 -1
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +17 -2
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +33 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79e198f6d1579290fb0eeb3597282367757655bcff41b3e848a788b557573706
|
4
|
+
data.tar.gz: 935a5c332bf06b2d77ca47ae6fc92128cbf450e1c50d64a293ef02ef2a04ad07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b124009ca502a4e24c88a5fc1ff0a8a307e1850db491ae0cf12f0388753cccb575fff87f2421ec725dc9a945e335d2f6f8de1c7734ee6887f887d380e6726a68
|
7
|
+
data.tar.gz: 82faa67a43955a2ff946510c3a77826365eb6dbd3adc7e7c81eecd83da03ce10ca37f0100a32b7089a3ef88014797a2960561851c701d695fe943f11f2712aae
|
data/.github/workflows/ruby.yml
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
-
|
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: [
|
12
|
+
branches: [ master ]
|
6
13
|
pull_request:
|
7
|
-
branches: [
|
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-
|
27
|
+
ruby-version: ['jruby-head']
|
21
28
|
db: ['mysql2']
|
22
29
|
test_targets: ["rails:test_mysql2"]
|
23
|
-
ar_version: ["
|
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-
|
79
|
+
ruby-version: [ 'jruby-head' ]
|
73
80
|
db: [ 'postgresql' ]
|
74
81
|
test_targets: [ "rails:test_postgresql" ]
|
75
|
-
ar_version: ["
|
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-
|
129
|
+
ruby-version: ['jruby-head']
|
123
130
|
db: ['sqlite3']
|
124
131
|
test_targets: ["rails:test_sqlite3"]
|
125
|
-
ar_version: ["
|
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-
|
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-
|
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-
|
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
|
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.
|
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="
|
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',
|
50
|
+
gem 'rake', require: nil
|
51
51
|
|
52
52
|
group :test do
|
53
|
-
gem 'test-unit',
|
54
|
-
gem 'test-unit-context',
|
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',
|
63
|
-
gem 'minitest-excludes',
|
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', '~>
|
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'
|
data/lib/arjdbc/abstract/core.rb
CHANGED
@@ -34,7 +34,7 @@ module ArJdbc
|
|
34
34
|
raw_connection.jdbc_connection(unwrap)
|
35
35
|
end
|
36
36
|
|
37
|
-
|
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?(
|
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 = ->{
|
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
|
data/lib/arjdbc/db2/adapter.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
data/lib/arjdbc/db2/column.rb
CHANGED
@@ -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
|
37
|
+
Time.send(ActiveRecord.default_timezone, *time_array) rescue nil
|
38
38
|
end
|
39
39
|
|
40
40
|
# @deprecated
|
data/lib/arjdbc/derby/adapter.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
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
|
data/lib/arjdbc/jdbc/adapter.rb
CHANGED
@@ -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 :
|
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::
|
437
|
+
# Helper to get local/UTC time (based on `ActiveRecord::default_timezone`).
|
438
438
|
def get_time(value)
|
439
|
-
get = ::ActiveRecord
|
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
|
133
|
+
ActiveRecord.default_timezone == :utc ? time : time.getlocal
|
134
134
|
else
|
135
|
-
timezone = ActiveRecord
|
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
|
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -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
|
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
|
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
|
-
|
84
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
237
|
-
|
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
|
269
|
-
|
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
|
295
|
-
|
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
|
-
|
345
|
-
|
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
|
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:
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
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
|
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
|
-
|
724
|
-
|
725
|
-
|
726
|
-
|
727
|
-
|
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
|
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.
|
data/lib/arjdbc/version.rb
CHANGED
@@ -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
|
2637
|
-
return default_timezone.call(context,
|
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: '
|
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-
|
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:
|
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:
|
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.
|
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.
|