activerecord-jdbc-alt-adapter 71.0.0.alpha1-java → 71.0.0.alpha2-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: 3a773766cbb0e3ea279a04ab67b60c578382c604214c0a3dd5e54b7f419f4b96
4
- data.tar.gz: d0f347ef628b4b791d81ad46a34d20f8ea3acb75cee3a473b2dbd8784769e897
3
+ metadata.gz: 6590c4d705c35e5a4849e4ef0bb076efba93509b8bcd8b4c2db49a4bc84b0f31
4
+ data.tar.gz: cb87d9f9f2763b178f990359efecb6b1199cbe15866460bb837232fcdd8b75e1
5
5
  SHA512:
6
- metadata.gz: 7c08cd49b3245c655a4c51d5c0d327cf7f058a7c2c98cedf7a59f00f60d14e7d79b1d9c2eef614712cee71b684f717fd6edd7c122fd0349d775a7e4fb2a48150
7
- data.tar.gz: b1a059930367508754dc54ff2b8b76434991ac2897ea4ff4917a7ef540d25c28272c4c5cbe13f5b5215eded00940c9beece3f2415860a69b4621a7c62664fa02
6
+ metadata.gz: 511e55410d149724a0765b5494a15ca4fe493bbd36b969a587d7bab23458cb32a45d34c01f79ca8b170b7f1e86fdf58e81bc4ba3ea15d464fe954a8266c41743
7
+ data.tar.gz: 9fdfe69ab63373f8e31cd2d60f5ae88fd3f4499250010aab4ffbeabb9c9345f017bb012932598a84297bd63d8b28f5bc38d18213f95b19b3307a93f38ecfc775
@@ -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-latest
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:10
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-latest
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:10
249
+ image: postgres:11
247
250
  env:
248
251
  POSTGRES_PASSWORD: postgres
249
252
  POSTGRES_HOST_AUTH_METHOD: trust
@@ -84,7 +84,7 @@ jobs:
84
84
 
85
85
  services:
86
86
  postgres:
87
- image: postgres:10
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:10
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
- pik.sh
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.0'
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 = jdbc_connection_class(@config[:adapter_spec]).new(@config, self)
42
- @raw_connection.configure_connection
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
@@ -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
- attr_reader :config
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: false)
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
@@ -88,15 +88,20 @@ module ActiveRecord
88
88
 
89
89
  # @override
90
90
  def active?
91
- return false unless @raw_connection
91
+ @lock.synchronize do
92
+ return false unless @raw_connection
92
93
 
93
- @raw_connection.active?
94
+ @raw_connection.active?
95
+ end
94
96
  end
95
97
 
96
98
  # @override
97
99
  def disconnect!
98
- super # clear_cache! && reset_transaction
99
- @raw_connection&.disconnect!
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, new_table_name)
178
- execute "EXEC sp_rename '#{table_name}', '#{new_table_name}'"
179
- rename_table_indexes(table_name, new_table_name)
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
@@ -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?) && @lock.synchronize { @raw_connection&.execute_query("/* ping */ SELECT 1") } || false
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 ( redshift = config[:redshift] ).nil?
56
- redshift = !! (@connection.database_product || '').index('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
- exec_query("CREATE EXTENSION IF NOT EXISTS \"#{name}\"").tap {
302
- reload_type_map
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
- def disable_extension(name)
307
- exec_query("DROP EXTENSION IF EXISTS \"#{name}\" CASCADE").tap {
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
- exec_query("SELECT extname FROM pg_extension", "SCHEMA").cast_values
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 = @connection.database_product
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
- super
469
- # Make sure all query plans are *really* gone
470
- @connection.execute 'DEALLOCATE ALL' if active?
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
- clear_cache!
475
- reset_transaction
476
- @connection.rollback # Have to deal with rollbacks differently than the AR adapter
477
- @connection.execute 'DISCARD ALL'
478
- @connection.configure_connection
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
- def initialize(connection, logger = nil, connection_parameters = nil, config = {})
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
- ActiveSupport::Dependencies.interlock.permit_concurrent_loads do
833
- @connection.exec_params(sql, type_casted_binds)
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
- type_map.clear
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
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArJdbc
4
- VERSION = '71.0.0.alpha1'
4
+ VERSION = '71.0.0.alpha2'
5
5
  end
@@ -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
- //result = mapExecuteResult(context, connection, resultSet);
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.alpha1
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-07-24 00:00:00.000000000 Z
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