activerecord-jdbc-alt-adapter 71.0.0.alpha1-java → 71.0.0.alpha2-java
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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +7 -4
- data/.github/workflows/ruby.yml +2 -2
- data/.gitignore +6 -3
- data/activerecord-jdbc-adapter.gemspec +1 -1
- data/lib/arjdbc/abstract/connection_management.rb +5 -2
- data/lib/arjdbc/abstract/core.rb +2 -8
- data/lib/arjdbc/abstract/database_statements.rb +2 -2
- data/lib/arjdbc/abstract/statement_cache.rb +1 -1
- data/lib/arjdbc/abstract/transaction_support.rb +0 -13
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/mssql/adapter.rb +13 -4
- data/lib/arjdbc/mssql/schema_statements.rb +6 -3
- data/lib/arjdbc/mysql/adapter.rb +41 -6
- data/lib/arjdbc/postgresql/adapter.rb +71 -44
- data/lib/arjdbc/postgresql/oid_types.rb +8 -27
- data/lib/arjdbc/postgresql/schema_statements.rb +57 -0
- data/lib/arjdbc/sqlite3/adapter.rb +22 -47
- data/lib/arjdbc/version.rb +1 -1
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +2 -2
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +11 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6590c4d705c35e5a4849e4ef0bb076efba93509b8bcd8b4c2db49a4bc84b0f31
|
4
|
+
data.tar.gz: cb87d9f9f2763b178f990359efecb6b1199cbe15866460bb837232fcdd8b75e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 511e55410d149724a0765b5494a15ca4fe493bbd36b969a587d7bab23458cb32a45d34c01f79ca8b170b7f1e86fdf58e81bc4ba3ea15d464fe954a8266c41743
|
7
|
+
data.tar.gz: 9fdfe69ab63373f8e31cd2d60f5ae88fd3f4499250010aab4ffbeabb9c9345f017bb012932598a84297bd63d8b28f5bc38d18213f95b19b3307a93f38ecfc775
|
data/.github/workflows/main.yml
CHANGED
@@ -31,9 +31,12 @@ jobs:
|
|
31
31
|
db: ['mssql']
|
32
32
|
test_targets: ['test_mssql']
|
33
33
|
|
34
|
+
# NOTE: using a specific tag, it fails with 2019-latest.
|
35
|
+
# it seems the issue is related to some changes in mssql tools
|
36
|
+
# https://learn.microsoft.com/en-au/answers/questions/1853144/error-failed-to-initialize-container-mcr-microsoft
|
34
37
|
services:
|
35
38
|
mssql:
|
36
|
-
image: mcr.microsoft.com/mssql/server:2019-
|
39
|
+
image: mcr.microsoft.com/mssql/server:2019-CU27-ubuntu-20.04
|
37
40
|
env:
|
38
41
|
ACCEPT_EULA: Y
|
39
42
|
MSSQL_SA_PASSWORD: Password12!
|
@@ -112,7 +115,7 @@ jobs:
|
|
112
115
|
|
113
116
|
services:
|
114
117
|
postgres:
|
115
|
-
image: postgres:
|
118
|
+
image: postgres:11
|
116
119
|
env:
|
117
120
|
POSTGRES_PASSWORD: postgres
|
118
121
|
POSTGRES_HOST_AUTH_METHOD: trust
|
@@ -157,7 +160,7 @@ jobs:
|
|
157
160
|
|
158
161
|
services:
|
159
162
|
mssql:
|
160
|
-
image: mcr.microsoft.com/mssql/server:2019-
|
163
|
+
image: mcr.microsoft.com/mssql/server:2019-CU27-ubuntu-20.04
|
161
164
|
env:
|
162
165
|
ACCEPT_EULA: Y
|
163
166
|
MSSQL_SA_PASSWORD: Password12!
|
@@ -243,7 +246,7 @@ jobs:
|
|
243
246
|
|
244
247
|
services:
|
245
248
|
postgres:
|
246
|
-
image: postgres:
|
249
|
+
image: postgres:11
|
247
250
|
env:
|
248
251
|
POSTGRES_PASSWORD: postgres
|
249
252
|
POSTGRES_HOST_AUTH_METHOD: trust
|
data/.github/workflows/ruby.yml
CHANGED
@@ -84,7 +84,7 @@ jobs:
|
|
84
84
|
|
85
85
|
services:
|
86
86
|
postgres:
|
87
|
-
image: postgres:
|
87
|
+
image: postgres:11
|
88
88
|
env:
|
89
89
|
POSTGRES_PASSWORD: postgres
|
90
90
|
POSTGRES_HOST_AUTH_METHOD: trust
|
@@ -211,7 +211,7 @@ jobs:
|
|
211
211
|
|
212
212
|
services:
|
213
213
|
postgres:
|
214
|
-
image: postgres:
|
214
|
+
image: postgres:11
|
215
215
|
env:
|
216
216
|
POSTGRES_PASSWORD: postgres
|
217
217
|
POSTGRES_HOST_AUTH_METHOD: trust
|
data/.gitignore
CHANGED
@@ -19,6 +19,8 @@ nbproject
|
|
19
19
|
.project
|
20
20
|
*.sqlite
|
21
21
|
*.sqlite3
|
22
|
+
*.sqlite3-shm
|
23
|
+
*.sqlite3-wal
|
22
24
|
*.derby
|
23
25
|
derby.log
|
24
26
|
test.hsqldb*
|
@@ -33,8 +35,9 @@ Gemfile.lock
|
|
33
35
|
.settings
|
34
36
|
activerecord-jdbc.iml
|
35
37
|
lib/arjdbc/jdbc/adapter_java.jar
|
36
|
-
.jrubyrc
|
37
38
|
tags
|
38
|
-
|
39
|
-
.ruby-version
|
39
|
+
.jrubyrc
|
40
40
|
.rubocop.yml
|
41
|
+
.solargraph.yml
|
42
|
+
pik.sh
|
43
|
+
.tool-versions
|
@@ -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', '~> 7.1.
|
44
|
+
gem.add_dependency 'activerecord', '~> 7.1.3'
|
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'
|
@@ -36,10 +36,13 @@ module ArJdbc
|
|
36
36
|
# end
|
37
37
|
# end
|
38
38
|
|
39
|
+
private
|
40
|
+
|
39
41
|
# DIFFERENCE: we delve into jdbc shared code and this does self.class.new_client.
|
40
42
|
def connect
|
41
|
-
@raw_connection =
|
42
|
-
|
43
|
+
@raw_connection = self.class.new_client(@connection_parameters, self)
|
44
|
+
rescue ActiveRecord::ConnectionNotEstablished => ex
|
45
|
+
raise ex.set_pool(@pool)
|
43
46
|
end
|
44
47
|
|
45
48
|
def reconnect
|
data/lib/arjdbc/abstract/core.rb
CHANGED
@@ -2,23 +2,17 @@
|
|
2
2
|
|
3
3
|
module ArJdbc
|
4
4
|
module Abstract
|
5
|
-
|
6
5
|
# This is minimum amount of code needed from base JDBC Adapter class to make common adapters
|
7
6
|
# work. This replaces using jdbc/adapter as a base class for all adapters.
|
8
7
|
module Core
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(config)
|
13
|
-
@config = config
|
8
|
+
def initialize(...)
|
9
|
+
super
|
14
10
|
|
15
11
|
if self.class.equal? ActiveRecord::ConnectionAdapters::JdbcAdapter
|
16
12
|
spec = @config.key?(:adapter_spec) ? @config[:adapter_spec] :
|
17
13
|
( @config[:adapter_spec] = adapter_spec(@config) ) # due resolving visitor
|
18
14
|
extend spec if spec
|
19
15
|
end
|
20
|
-
|
21
|
-
super(config) # AbstractAdapter
|
22
16
|
end
|
23
17
|
|
24
18
|
# Retrieve the raw `java.sql.Connection` object.
|
@@ -33,7 +33,7 @@ module ArJdbc
|
|
33
33
|
|
34
34
|
# It appears that at this point (AR 5.0) "prepare" should only ever be true
|
35
35
|
# if prepared statements are enabled
|
36
|
-
def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false)
|
36
|
+
def internal_exec_query(sql, name = nil, binds = NO_BINDS, prepare: false, async: false, allow_retry: false, materialize_transactions: true)
|
37
37
|
sql = transform_query(sql)
|
38
38
|
|
39
39
|
if preventing_writes? && write_query?(sql)
|
@@ -104,7 +104,7 @@ module ArJdbc
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions:
|
107
|
+
def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: true)
|
108
108
|
log(sql, name, async: async) do
|
109
109
|
with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
|
110
110
|
conn.execute(sql)
|
@@ -24,7 +24,7 @@ module ArJdbc
|
|
24
24
|
|
25
25
|
# Only say we support the statement cache if we are using prepared statements
|
26
26
|
# and have a max number of statements defined
|
27
|
-
statement_limit = self.class.type_cast_config_to_integer(config[:statement_limit])
|
27
|
+
statement_limit = self.class.type_cast_config_to_integer(@config[:statement_limit])
|
28
28
|
@jdbc_statement_cache_enabled = prepared_statements && (statement_limit.nil? || statement_limit > 0)
|
29
29
|
|
30
30
|
@statements = StatementPool.new(statement_limit) # AR (5.0) expects this to be stored as @statements
|
@@ -107,16 +107,3 @@ module ArJdbc
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
end
|
110
|
-
|
111
|
-
# patch to avoid the usage of WeakMap
|
112
|
-
require 'active_record/connection_adapters/abstract/transaction'
|
113
|
-
module ActiveRecord
|
114
|
-
module ConnectionAdapters
|
115
|
-
class Transaction
|
116
|
-
def add_record(record, ensure_finalize = true)
|
117
|
-
@records ||= []
|
118
|
-
@records << record
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
Binary file
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
@@ -88,15 +88,20 @@ module ActiveRecord
|
|
88
88
|
|
89
89
|
# @override
|
90
90
|
def active?
|
91
|
-
|
91
|
+
@lock.synchronize do
|
92
|
+
return false unless @raw_connection
|
92
93
|
|
93
|
-
|
94
|
+
@raw_connection.active?
|
95
|
+
end
|
94
96
|
end
|
95
97
|
|
96
98
|
# @override
|
97
99
|
def disconnect!
|
98
|
-
|
99
|
-
|
100
|
+
@lock.synchronize do
|
101
|
+
super # clear_cache! && reset_transaction
|
102
|
+
@raw_connection&.disconnect!
|
103
|
+
@raw_connection = nil
|
104
|
+
end
|
100
105
|
end
|
101
106
|
|
102
107
|
# Returns the (JDBC) `ActiveRecord` column class for this adapter.
|
@@ -490,6 +495,10 @@ module ActiveRecord
|
|
490
495
|
RangeError.new(message, sql: sql, binds: binds)
|
491
496
|
when /Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation/
|
492
497
|
StatementInvalid.new(message, sql: sql, binds: binds)
|
498
|
+
when /Incorrect syntax near the keyword .*/
|
499
|
+
StatementInvalid.new(message, sql: sql, binds: binds)
|
500
|
+
when /Could not find stored procedure .*/
|
501
|
+
StatementInvalid.new(message, sql: sql, binds: binds)
|
493
502
|
else
|
494
503
|
super
|
495
504
|
end
|
@@ -174,9 +174,12 @@ module ActiveRecord
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
177
|
-
def rename_table(table_name,
|
178
|
-
|
179
|
-
|
177
|
+
def rename_table(table_name, new_name, **options)
|
178
|
+
validate_table_length!(new_name) unless options[:_uses_legacy_table_name]
|
179
|
+
schema_cache.clear_data_source_cache!(table_name.to_s)
|
180
|
+
schema_cache.clear_data_source_cache!(new_name.to_s)
|
181
|
+
execute "EXEC sp_rename '#{table_name}', '#{new_name}'"
|
182
|
+
rename_table_indexes(table_name, new_name)
|
180
183
|
end
|
181
184
|
|
182
185
|
# This is the same as the abstract method
|
data/lib/arjdbc/mysql/adapter.rb
CHANGED
@@ -23,7 +23,7 @@ module ActiveRecord
|
|
23
23
|
class Mysql2Adapter < AbstractMysqlAdapter
|
24
24
|
ADAPTER_NAME = 'Mysql2'
|
25
25
|
|
26
|
-
include Jdbc::ConnectionPoolCallbacks
|
26
|
+
# include Jdbc::ConnectionPoolCallbacks
|
27
27
|
|
28
28
|
include ArJdbc::Abstract::ConnectionManagement
|
29
29
|
include ArJdbc::Abstract::DatabaseStatements
|
@@ -33,6 +33,34 @@ module ActiveRecord
|
|
33
33
|
|
34
34
|
include ArJdbc::MySQL
|
35
35
|
|
36
|
+
class << self
|
37
|
+
def jdbc_connection_class
|
38
|
+
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_client(conn_params, adapter_instance)
|
42
|
+
jdbc_connection_class.new(conn_params, adapter_instance)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def initialize_type_map(m)
|
47
|
+
super
|
48
|
+
|
49
|
+
m.register_type(%r(char)i) do |sql_type|
|
50
|
+
limit = extract_limit(sql_type)
|
51
|
+
Type.lookup(:string, adapter: :mysql2, limit: limit)
|
52
|
+
end
|
53
|
+
|
54
|
+
m.register_type %r(^enum)i, Type.lookup(:string, adapter: :mysql2)
|
55
|
+
m.register_type %r(^set)i, Type.lookup(:string, adapter: :mysql2)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# NOTE: redefines constant defined in abstract class however this time
|
60
|
+
# will use methods defined in the mysql abstract class and map properly
|
61
|
+
# mysql types.
|
62
|
+
TYPE_MAP = Type::TypeMap.new.tap { |m| initialize_type_map(m) }
|
63
|
+
|
36
64
|
def initialize(...)
|
37
65
|
super
|
38
66
|
|
@@ -171,7 +199,7 @@ module ActiveRecord
|
|
171
199
|
#++
|
172
200
|
|
173
201
|
def active?
|
174
|
-
!(@raw_connection.nil? || @raw_connection.closed?)
|
202
|
+
!(@raw_connection.nil? || @raw_connection.closed?) && @lock.synchronize { @raw_connection&.ping } || false
|
175
203
|
end
|
176
204
|
|
177
205
|
alias :reset! :reconnect!
|
@@ -221,14 +249,21 @@ module ActiveRecord
|
|
221
249
|
@full_version ||= any_raw_connection.full_version
|
222
250
|
end
|
223
251
|
|
224
|
-
def jdbc_connection_class(spec)
|
225
|
-
::ActiveRecord::ConnectionAdapters::MySQLJdbcConnection
|
226
|
-
end
|
227
|
-
|
228
252
|
def jdbc_column_class
|
229
253
|
::ActiveRecord::ConnectionAdapters::MySQL::Column
|
230
254
|
end
|
231
255
|
|
256
|
+
def translate_exception(exception, message:, sql:, binds:)
|
257
|
+
case message
|
258
|
+
when /Table .* doesn't exist/i
|
259
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
260
|
+
when /BLOB, TEXT, GEOMETRY or JSON column .* can't have a default value/i
|
261
|
+
StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
262
|
+
else
|
263
|
+
super
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
232
267
|
# defined in MySQL::DatabaseStatements which is not included
|
233
268
|
def default_insert_value(column)
|
234
269
|
super unless column.auto_increment?
|
@@ -13,6 +13,7 @@ require 'active_record/connection_adapters/postgresql/schema_dumper'
|
|
13
13
|
require 'active_record/connection_adapters/postgresql/schema_statements'
|
14
14
|
require 'active_record/connection_adapters/postgresql/type_metadata'
|
15
15
|
require 'active_record/connection_adapters/postgresql/utils'
|
16
|
+
|
16
17
|
require 'arjdbc/abstract/core'
|
17
18
|
require 'arjdbc/abstract/connection_management'
|
18
19
|
require 'arjdbc/abstract/database_statements'
|
@@ -21,6 +22,8 @@ require 'arjdbc/abstract/transaction_support'
|
|
21
22
|
require 'arjdbc/postgresql/base/array_decoder'
|
22
23
|
require 'arjdbc/postgresql/base/array_encoder'
|
23
24
|
require 'arjdbc/postgresql/name'
|
25
|
+
require 'arjdbc/postgresql/schema_statements'
|
26
|
+
|
24
27
|
require 'active_model'
|
25
28
|
|
26
29
|
module ArJdbc
|
@@ -35,11 +38,6 @@ module ArJdbc
|
|
35
38
|
# @private
|
36
39
|
Type = ::ActiveRecord::Type
|
37
40
|
|
38
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
39
|
-
def self.jdbc_connection_class
|
40
|
-
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
41
|
-
end
|
42
|
-
|
43
41
|
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_column_class
|
44
42
|
def jdbc_column_class; ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn end
|
45
43
|
|
@@ -52,8 +50,8 @@ module ArJdbc
|
|
52
50
|
def redshift?
|
53
51
|
# SELECT version() :
|
54
52
|
# PostgreSQL 8.0.2 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 3.4.2 20041017 (Red Hat 3.4.2-6.fc3), Redshift 1.0.647
|
55
|
-
if (
|
56
|
-
redshift = !! (
|
53
|
+
if (redshift = @config[:redshift]).nil?
|
54
|
+
redshift = !! (valid_raw_connection.database_product || '').index('Redshift')
|
57
55
|
end
|
58
56
|
redshift
|
59
57
|
end
|
@@ -73,8 +71,8 @@ module ArJdbc
|
|
73
71
|
# see http://jdbc.postgresql.org/documentation/91/connect.html
|
74
72
|
# self.set_client_encoding(encoding)
|
75
73
|
#end
|
76
|
-
self.client_min_messages = config[:min_messages] || 'warning'
|
77
|
-
self.schema_search_path = config[:schema_search_path] || config[:schema_order]
|
74
|
+
self.client_min_messages = @config[:min_messages] || 'warning'
|
75
|
+
self.schema_search_path = @config[:schema_search_path] || @config[:schema_order]
|
78
76
|
|
79
77
|
# Use standard-conforming strings if available so we don't have to do the E'...' dance.
|
80
78
|
set_standard_conforming_strings
|
@@ -93,7 +91,7 @@ module ArJdbc
|
|
93
91
|
|
94
92
|
# SET statements from :variables config hash
|
95
93
|
# http://www.postgresql.org/docs/8.3/static/sql-set.html
|
96
|
-
(config[:variables] || {}).map do |k, v|
|
94
|
+
(@config[:variables] || {}).map do |k, v|
|
97
95
|
if v == ':default' || v == :default
|
98
96
|
# Sets the value to the global or compile default
|
99
97
|
execute("SET SESSION #{k} TO DEFAULT", 'SCHEMA')
|
@@ -101,6 +99,8 @@ module ArJdbc
|
|
101
99
|
execute("SET SESSION #{k} TO #{quote(v)}", 'SCHEMA')
|
102
100
|
end
|
103
101
|
end
|
102
|
+
|
103
|
+
reload_type_map
|
104
104
|
end
|
105
105
|
|
106
106
|
# @private
|
@@ -127,7 +127,7 @@ module ArJdbc
|
|
127
127
|
inet: { name: 'inet' },
|
128
128
|
int4range: { name: 'int4range' },
|
129
129
|
int8range: { name: 'int8range' },
|
130
|
-
integer: { name: 'integer' },
|
130
|
+
integer: { name: 'integer', limit: 4 },
|
131
131
|
interval: { name: 'interval' },
|
132
132
|
json: { name: 'json' },
|
133
133
|
jsonb: { name: 'jsonb' },
|
@@ -232,6 +232,10 @@ module ArJdbc
|
|
232
232
|
alias supports_insert_on_duplicate_update? supports_insert_on_conflict?
|
233
233
|
alias supports_insert_conflict_target? supports_insert_on_conflict?
|
234
234
|
|
235
|
+
def supports_identity_columns? # :nodoc:
|
236
|
+
database_version >= 10_00_00 # >= 10.0
|
237
|
+
end
|
238
|
+
|
235
239
|
def index_algorithms
|
236
240
|
{ concurrently: 'CONCURRENTLY' }
|
237
241
|
end
|
@@ -297,14 +301,21 @@ module ArJdbc
|
|
297
301
|
query_value("SELECT pg_advisory_unlock(#{lock_id})")
|
298
302
|
end
|
299
303
|
|
300
|
-
def enable_extension(name)
|
301
|
-
|
302
|
-
|
303
|
-
}
|
304
|
+
def enable_extension(name, **)
|
305
|
+
schema, name = name.to_s.split(".").values_at(-2, -1)
|
306
|
+
sql = +"CREATE EXTENSION IF NOT EXISTS \"#{name}\""
|
307
|
+
sql << " SCHEMA #{schema}" if schema
|
308
|
+
|
309
|
+
internal_exec_query(sql).tap { reload_type_map }
|
304
310
|
end
|
305
311
|
|
306
|
-
|
307
|
-
|
312
|
+
# Removes an extension from the database.
|
313
|
+
#
|
314
|
+
# [<tt>:force</tt>]
|
315
|
+
# Set to +:cascade+ to drop dependent objects as well.
|
316
|
+
# Defaults to false.
|
317
|
+
def disable_extension(name, force: false)
|
318
|
+
internal_exec_query("DROP EXTENSION IF EXISTS \"#{name}\"#{' CASCADE' if force == :cascade}").tap {
|
308
319
|
reload_type_map
|
309
320
|
}
|
310
321
|
end
|
@@ -318,7 +329,7 @@ module ArJdbc
|
|
318
329
|
end
|
319
330
|
|
320
331
|
def extensions
|
321
|
-
|
332
|
+
internal_exec_query("SELECT extname FROM pg_extension", "SCHEMA", allow_retry: true, materialize_transactions: false).cast_values
|
322
333
|
end
|
323
334
|
|
324
335
|
# Returns a list of defined enum types, and their values.
|
@@ -370,7 +381,7 @@ module ArJdbc
|
|
370
381
|
|
371
382
|
def get_database_version # :nodoc:
|
372
383
|
begin
|
373
|
-
version =
|
384
|
+
version = valid_raw_connection.database_product
|
374
385
|
if match = version.match(/([\d\.]*\d).*?/)
|
375
386
|
version = match[1].split('.').map(&:to_i)
|
376
387
|
# PostgreSQL version representation does not have more than 4 digits
|
@@ -426,8 +437,7 @@ module ArJdbc
|
|
426
437
|
end
|
427
438
|
end
|
428
439
|
|
429
|
-
|
430
|
-
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil)
|
440
|
+
def exec_insert(sql, name = nil, binds = [], pk = nil, sequence_name = nil, returning: nil) # :nodoc:
|
431
441
|
val = super
|
432
442
|
if !use_insert_returning? && pk
|
433
443
|
unless sequence_name
|
@@ -464,18 +474,23 @@ module ArJdbc
|
|
464
474
|
# since apparently calling close on the statement object
|
465
475
|
# doesn't always free the server resources and calling
|
466
476
|
# 'DISCARD ALL' fails if we are inside a transaction
|
467
|
-
def clear_cache!
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
end
|
477
|
+
# def clear_cache!
|
478
|
+
# super
|
479
|
+
# # Make sure all query plans are *really* gone
|
480
|
+
# @connection.execute 'DEALLOCATE ALL' if active?
|
481
|
+
# end
|
472
482
|
|
473
483
|
def reset!
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
484
|
+
@lock.synchronize do
|
485
|
+
return connect! unless @raw_connection
|
486
|
+
|
487
|
+
# Have to deal with rollbacks differently than the AR adapter
|
488
|
+
@raw_connection.rollback
|
489
|
+
|
490
|
+
@raw_connection.execute("DISCARD ALL")
|
491
|
+
|
492
|
+
super
|
493
|
+
end
|
479
494
|
end
|
480
495
|
|
481
496
|
def default_sequence_name(table_name, pk = "id") #:nodoc:
|
@@ -660,6 +675,8 @@ module ArJdbc
|
|
660
675
|
::ActiveRecord::LockWaitTimeout.new(message, sql: sql, binds: binds)
|
661
676
|
when /canceling statement/ # This needs to come after lock timeout because the lock timeout message also contains "canceling statement"
|
662
677
|
::ActiveRecord::QueryCanceled.new(message, sql: sql, binds: binds)
|
678
|
+
when /relation "animals" does not exist/i
|
679
|
+
::ActiveRecord::StatementInvalid.new(message, sql: sql, binds: binds, connection_pool: @pool)
|
663
680
|
else
|
664
681
|
super
|
665
682
|
end
|
@@ -742,7 +759,7 @@ module ActiveRecord::ConnectionAdapters
|
|
742
759
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaStatements
|
743
760
|
include ActiveRecord::ConnectionAdapters::PostgreSQL::Quoting
|
744
761
|
|
745
|
-
include Jdbc::ConnectionPoolCallbacks
|
762
|
+
# include Jdbc::ConnectionPoolCallbacks
|
746
763
|
|
747
764
|
include ArJdbc::Abstract::Core
|
748
765
|
include ArJdbc::Abstract::ConnectionManagement
|
@@ -753,6 +770,7 @@ module ActiveRecord::ConnectionAdapters
|
|
753
770
|
|
754
771
|
require 'arjdbc/postgresql/oid_types'
|
755
772
|
include ::ArJdbc::PostgreSQL::OIDTypes
|
773
|
+
include ::ArJdbc::PostgreSQL::SchemaStatements
|
756
774
|
|
757
775
|
include ::ArJdbc::PostgreSQL::ColumnHelpers
|
758
776
|
|
@@ -761,16 +779,27 @@ module ActiveRecord::ConnectionAdapters
|
|
761
779
|
# AR expects OID to be available on the adapter
|
762
780
|
OID = ActiveRecord::ConnectionAdapters::PostgreSQL::OID
|
763
781
|
|
764
|
-
|
782
|
+
class << self
|
783
|
+
def jdbc_connection_class
|
784
|
+
::ActiveRecord::ConnectionAdapters::PostgreSQLJdbcConnection
|
785
|
+
end
|
786
|
+
|
787
|
+
def new_client(conn_params, adapter_instance)
|
788
|
+
jdbc_connection_class.new(conn_params, adapter_instance)
|
789
|
+
end
|
790
|
+
end
|
791
|
+
|
792
|
+
def initialize(...)
|
793
|
+
super
|
794
|
+
|
795
|
+
conn_params = @config.compact
|
796
|
+
|
797
|
+
@connection_parameters = conn_params
|
798
|
+
|
765
799
|
# @local_tz is initialized as nil to avoid warnings when connect tries to use it
|
766
800
|
@local_tz = nil
|
767
801
|
@max_identifier_length = nil
|
768
802
|
|
769
|
-
super(connection, logger, config) # configure_connection happens in super
|
770
|
-
|
771
|
-
@type_map = Type::HashLookupTypeMap.new
|
772
|
-
initialize_type_map
|
773
|
-
|
774
803
|
@use_insert_returning = @config.key?(:insert_returning) ?
|
775
804
|
self.class.type_cast_config_to_boolean(@config[:insert_returning]) : true
|
776
805
|
end
|
@@ -793,10 +822,6 @@ module ActiveRecord::ConnectionAdapters
|
|
793
822
|
public :sql_for_insert
|
794
823
|
alias :postgresql_version :database_version
|
795
824
|
|
796
|
-
def jdbc_connection_class(spec)
|
797
|
-
::ArJdbc::PostgreSQL.jdbc_connection_class
|
798
|
-
end
|
799
|
-
|
800
825
|
private
|
801
826
|
|
802
827
|
FEATURE_NOT_SUPPORTED = "0A000" # :nodoc:
|
@@ -829,8 +854,10 @@ module ActiveRecord::ConnectionAdapters
|
|
829
854
|
|
830
855
|
type_casted_binds = type_casted_binds(binds)
|
831
856
|
log(sql, name, binds, type_casted_binds, async: async) do
|
832
|
-
|
833
|
-
|
857
|
+
with_raw_connection do |conn|
|
858
|
+
result = conn.exec_params(sql, type_casted_binds)
|
859
|
+
verified!
|
860
|
+
result
|
834
861
|
end
|
835
862
|
end
|
836
863
|
end
|
@@ -67,28 +67,6 @@ module ArJdbc
|
|
67
67
|
|
68
68
|
# @private
|
69
69
|
module OIDTypes
|
70
|
-
|
71
|
-
# @override
|
72
|
-
def enable_extension(name)
|
73
|
-
result = super(name)
|
74
|
-
@extensions = nil
|
75
|
-
reload_type_map
|
76
|
-
result
|
77
|
-
end
|
78
|
-
|
79
|
-
# @override
|
80
|
-
def disable_extension(name)
|
81
|
-
result = super(name)
|
82
|
-
@extensions = nil
|
83
|
-
reload_type_map
|
84
|
-
result
|
85
|
-
end
|
86
|
-
|
87
|
-
# @override
|
88
|
-
def extensions
|
89
|
-
@extensions ||= super
|
90
|
-
end
|
91
|
-
|
92
70
|
def get_oid_type(oid, fmod, column_name, sql_type = '') # :nodoc:
|
93
71
|
# Note: type_map is storing a bunch of oid type prefixed with a namespace even
|
94
72
|
# if they are not namespaced (e.g. ""."oidvector"). builtin types which are
|
@@ -118,8 +96,15 @@ module ArJdbc
|
|
118
96
|
end
|
119
97
|
|
120
98
|
def reload_type_map
|
121
|
-
|
99
|
+
@lock.synchronize do
|
100
|
+
if @type_map
|
101
|
+
type_map.clear
|
102
|
+
else
|
103
|
+
@type_map = Type::HashLookupTypeMap.new
|
104
|
+
end
|
105
|
+
|
122
106
|
initialize_type_map
|
107
|
+
end
|
123
108
|
end
|
124
109
|
|
125
110
|
def initialize_type_map_inner(m)
|
@@ -274,10 +259,6 @@ module ArJdbc
|
|
274
259
|
$1.to_i if sql_type =~ /\((\d+)(,\d+)?\)/
|
275
260
|
end
|
276
261
|
|
277
|
-
def extract_limit(sql_type)
|
278
|
-
$1.to_i if sql_type =~ /\((.*)\)/
|
279
|
-
end
|
280
|
-
|
281
262
|
# Support arrays/ranges for defining attributes that don't exist in the db
|
282
263
|
ActiveRecord::Type.add_modifier({ array: true }, OID::Array, adapter: :postgresql)
|
283
264
|
ActiveRecord::Type.add_modifier({ range: true }, OID::Range, adapter: :postgresql)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ArJdbc
|
4
|
+
module PostgreSQL
|
5
|
+
module SchemaStatements
|
6
|
+
ForeignKeyDefinition = ActiveRecord::ConnectionAdapters::ForeignKeyDefinition
|
7
|
+
Utils = ActiveRecord::ConnectionAdapters::PostgreSQL::Utils
|
8
|
+
|
9
|
+
def foreign_keys(table_name)
|
10
|
+
scope = quoted_scope(table_name)
|
11
|
+
fk_info = internal_exec_query(<<~SQL, "SCHEMA", allow_retry: true, materialize_transactions: false)
|
12
|
+
SELECT t2.oid::regclass::text AS to_table, a1.attname AS column, a2.attname AS primary_key, c.conname AS name, c.confupdtype AS on_update, c.confdeltype AS on_delete, c.convalidated AS valid, c.condeferrable AS deferrable, c.condeferred AS deferred, c.conkey, c.confkey, c.conrelid, c.confrelid
|
13
|
+
FROM pg_constraint c
|
14
|
+
JOIN pg_class t1 ON c.conrelid = t1.oid
|
15
|
+
JOIN pg_class t2 ON c.confrelid = t2.oid
|
16
|
+
JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
|
17
|
+
JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
|
18
|
+
JOIN pg_namespace t3 ON c.connamespace = t3.oid
|
19
|
+
WHERE c.contype = 'f'
|
20
|
+
AND t1.relname = #{scope[:name]}
|
21
|
+
AND t3.nspname = #{scope[:schema]}
|
22
|
+
ORDER BY c.conname
|
23
|
+
SQL
|
24
|
+
|
25
|
+
fk_info.map do |row|
|
26
|
+
to_table = Utils.unquote_identifier(row["to_table"])
|
27
|
+
# conkey = row["conkey"].scan(/\d+/).map(&:to_i)
|
28
|
+
# confkey = row["confkey"].scan(/\d+/).map(&:to_i)
|
29
|
+
conkey = row["conkey"]
|
30
|
+
confkey = row["confkey"]
|
31
|
+
|
32
|
+
if conkey.size > 1
|
33
|
+
column = column_names_from_column_numbers(row["conrelid"], conkey)
|
34
|
+
primary_key = column_names_from_column_numbers(row["confrelid"], confkey)
|
35
|
+
else
|
36
|
+
column = Utils.unquote_identifier(row["column"])
|
37
|
+
primary_key = row["primary_key"]
|
38
|
+
end
|
39
|
+
|
40
|
+
options = {
|
41
|
+
column: column,
|
42
|
+
name: row["name"],
|
43
|
+
primary_key: primary_key
|
44
|
+
}
|
45
|
+
|
46
|
+
options[:on_delete] = extract_foreign_key_action(row["on_delete"])
|
47
|
+
options[:on_update] = extract_foreign_key_action(row["on_update"])
|
48
|
+
options[:deferrable] = extract_constraint_deferrable(row["deferrable"], row["deferred"])
|
49
|
+
|
50
|
+
options[:validate] = row["valid"]
|
51
|
+
|
52
|
+
ForeignKeyDefinition.new(table_name, to_table, options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -706,44 +706,6 @@ module ArJdbc
|
|
706
706
|
# https://www.sqlite.org/pragma.html#pragma_cache_size
|
707
707
|
raw_execute("PRAGMA cache_size = 2000", "SCHEMA")
|
708
708
|
end
|
709
|
-
|
710
|
-
def configure_connection
|
711
|
-
if @config[:timeout] && @config[:retries]
|
712
|
-
raise ArgumentError, "Cannot specify both timeout and retries arguments"
|
713
|
-
elsif @config[:timeout]
|
714
|
-
# FIXME:
|
715
|
-
# @raw_connection.busy_timeout(self.class.type_cast_config_to_integer(@config[:timeout]))
|
716
|
-
elsif @config[:retries]
|
717
|
-
retries = self.class.type_cast_config_to_integer(@config[:retries])
|
718
|
-
raw_connection.busy_handler do |count|
|
719
|
-
count <= retries
|
720
|
-
end
|
721
|
-
end
|
722
|
-
|
723
|
-
# Enforce foreign key constraints
|
724
|
-
# https://www.sqlite.org/pragma.html#pragma_foreign_keys
|
725
|
-
# https://www.sqlite.org/foreignkeys.html
|
726
|
-
raw_execute("PRAGMA foreign_keys = ON", "SCHEMA")
|
727
|
-
unless @memory_database
|
728
|
-
# Journal mode WAL allows for greater concurrency (many readers + one writer)
|
729
|
-
# https://www.sqlite.org/pragma.html#pragma_journal_mode
|
730
|
-
raw_execute("PRAGMA journal_mode = WAL", "SCHEMA")
|
731
|
-
# Set more relaxed level of database durability
|
732
|
-
# 2 = "FULL" (sync on every write), 1 = "NORMAL" (sync every 1000 written pages) and 0 = "NONE"
|
733
|
-
# https://www.sqlite.org/pragma.html#pragma_synchronous
|
734
|
-
raw_execute("PRAGMA synchronous = NORMAL", "SCHEMA")
|
735
|
-
# Set the global memory map so all processes can share some data
|
736
|
-
# https://www.sqlite.org/pragma.html#pragma_mmap_size
|
737
|
-
# https://www.sqlite.org/mmap.html
|
738
|
-
raw_execute("PRAGMA mmap_size = #{128.megabytes}", "SCHEMA")
|
739
|
-
end
|
740
|
-
# Impose a limit on the WAL file to prevent unlimited growth
|
741
|
-
# https://www.sqlite.org/pragma.html#pragma_journal_size_limit
|
742
|
-
raw_execute("PRAGMA journal_size_limit = #{64.megabytes}", "SCHEMA")
|
743
|
-
# Set the local connection cache to 2000 pages
|
744
|
-
# https://www.sqlite.org/pragma.html#pragma_cache_size
|
745
|
-
raw_execute("PRAGMA cache_size = 2000", "SCHEMA")
|
746
|
-
end
|
747
709
|
end
|
748
710
|
# DIFFERENCE: A registration here is moved down to concrete class so we are not registering part of an adapter.
|
749
711
|
end
|
@@ -774,6 +736,20 @@ module ActiveRecord::ConnectionAdapters
|
|
774
736
|
# config.active_record.sqlite3_adapter_strict_strings_by_default = true
|
775
737
|
class_attribute :strict_strings_by_default, default: false # Does not actually do anything right now
|
776
738
|
|
739
|
+
def initialize(...)
|
740
|
+
super
|
741
|
+
|
742
|
+
conn_params = @config.compact
|
743
|
+
|
744
|
+
# NOTE: strict strings is not supported by the jdbc driver yet,
|
745
|
+
# hope it will supported soon, I open a issue in their repository.
|
746
|
+
# https://github.com/xerial/sqlite-jdbc/issues/1153
|
747
|
+
#
|
748
|
+
# @config[:strict] = ConnectionAdapters::SQLite3Adapter.strict_strings_by_default unless @config.key?(:strict)
|
749
|
+
|
750
|
+
@connection_parameters = conn_params
|
751
|
+
end
|
752
|
+
|
777
753
|
def self.represent_boolean_as_integer=(value) # :nodoc:
|
778
754
|
if value == false
|
779
755
|
raise "`.represent_boolean_as_integer=` is now always true, so make sure your application can work with it and remove this settings."
|
@@ -817,15 +793,6 @@ module ActiveRecord::ConnectionAdapters
|
|
817
793
|
::ActiveRecord::ConnectionAdapters::SQLite3Column
|
818
794
|
end
|
819
795
|
|
820
|
-
def jdbc_connection_class(spec)
|
821
|
-
self.class.jdbc_connection_class
|
822
|
-
end
|
823
|
-
|
824
|
-
# @see ActiveRecord::ConnectionAdapters::JdbcAdapter#jdbc_connection_class
|
825
|
-
def self.jdbc_connection_class
|
826
|
-
::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
|
827
|
-
end
|
828
|
-
|
829
796
|
# Note: This is not an override of ours but a moved line from AR Sqlite3Adapter to register ours vs our copied module (which would be their class).
|
830
797
|
# ActiveSupport.run_load_hooks(:active_record_sqlite3adapter, SQLite3Adapter)
|
831
798
|
|
@@ -843,6 +810,14 @@ module ActiveRecord::ConnectionAdapters
|
|
843
810
|
::ActiveRecord::Type.register(:integer, SQLite3Integer, adapter: :sqlite3)
|
844
811
|
|
845
812
|
class << self
|
813
|
+
def jdbc_connection_class
|
814
|
+
::ActiveRecord::ConnectionAdapters::SQLite3JdbcConnection
|
815
|
+
end
|
816
|
+
|
817
|
+
def new_client(conn_params, adapter_instance)
|
818
|
+
jdbc_connection_class.new(conn_params, adapter_instance)
|
819
|
+
end
|
820
|
+
|
846
821
|
def dbconsole(config, options = {})
|
847
822
|
args = []
|
848
823
|
|
data/lib/arjdbc/version.rb
CHANGED
@@ -793,8 +793,8 @@ public class RubyJdbcConnection extends RubyObject {
|
|
793
793
|
// Unfortunately the result set gets closed when getMoreResults()
|
794
794
|
// is called, so we have to process the result sets as we get them
|
795
795
|
// this shouldn't be an issue in most cases since we're only getting 1 result set anyways
|
796
|
-
|
797
|
-
result = mapToRawResult(context, connection, resultSet, false);
|
796
|
+
result = mapExecuteResult(context, connection, resultSet);
|
797
|
+
// result = mapToRawResult(context, connection, resultSet, false);
|
798
798
|
resultSet.close();
|
799
799
|
} else {
|
800
800
|
result = context.runtime.newFixnum(updateCount);
|
@@ -119,6 +119,17 @@ public class MySQLRubyJdbcConnection extends RubyJdbcConnection {
|
|
119
119
|
return driverWrapper;
|
120
120
|
}
|
121
121
|
|
122
|
+
@JRubyMethod(name = "ping")
|
123
|
+
public RubyBoolean db_ping(final ThreadContext context) {
|
124
|
+
final Connection connection = getConnection(true);
|
125
|
+
if (connection == null) return context.fals;
|
126
|
+
|
127
|
+
// NOTE: It seems only `connection.isValid(aliveTimeout)` is needed
|
128
|
+
// for JDBC 4.0 and up. https://jira.mariadb.org/browse/CONJ-51
|
129
|
+
|
130
|
+
return context.runtime.newBoolean(isConnectionValid(context, connection));
|
131
|
+
}
|
132
|
+
|
122
133
|
private static transient Class MYSQL_CONNECTION;
|
123
134
|
private static transient Boolean MYSQL_CONNECTION_FOUND;
|
124
135
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-jdbc-alt-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 71.0.0.
|
4
|
+
version: 71.0.0.alpha2
|
5
5
|
platform: java
|
6
6
|
authors:
|
7
7
|
- Nick Sieger, Ola Bini, Karol Bucek, Jesse Chavez, and JRuby contributors
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +145,7 @@ files:
|
|
145
145
|
- lib/arjdbc/postgresql/connection_methods.rb
|
146
146
|
- lib/arjdbc/postgresql/name.rb
|
147
147
|
- lib/arjdbc/postgresql/oid_types.rb
|
148
|
+
- lib/arjdbc/postgresql/schema_statements.rb
|
148
149
|
- lib/arjdbc/railtie.rb
|
149
150
|
- lib/arjdbc/sqlite3.rb
|
150
151
|
- lib/arjdbc/sqlite3/adapter.rb
|