activerecord-jdbc-alt-adapter 70.1.0-java → 71.0.0.alpha1-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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +135 -21
  3. data/.github/workflows/ruby.yml +10 -10
  4. data/.gitignore +1 -0
  5. data/.solargraph.yml +15 -0
  6. data/Gemfile +17 -4
  7. data/README.md +7 -3
  8. data/RUNNING_TESTS.md +36 -0
  9. data/activerecord-jdbc-adapter.gemspec +2 -2
  10. data/activerecord-jdbc-alt-adapter.gemspec +1 -1
  11. data/lib/arel/visitors/sqlserver.rb +10 -0
  12. data/lib/arjdbc/abstract/connection_management.rb +23 -10
  13. data/lib/arjdbc/abstract/core.rb +5 -6
  14. data/lib/arjdbc/abstract/database_statements.rb +35 -25
  15. data/lib/arjdbc/abstract/statement_cache.rb +1 -6
  16. data/lib/arjdbc/abstract/transaction_support.rb +37 -9
  17. data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
  18. data/lib/arjdbc/jdbc/column.rb +0 -34
  19. data/lib/arjdbc/jdbc/connection_methods.rb +1 -1
  20. data/lib/arjdbc/mssql/adapter.rb +93 -80
  21. data/lib/arjdbc/mssql/column.rb +1 -0
  22. data/lib/arjdbc/mssql/connection_methods.rb +7 -55
  23. data/lib/arjdbc/mssql/database_statements.rb +182 -71
  24. data/lib/arjdbc/mssql/explain_support.rb +8 -5
  25. data/lib/arjdbc/mssql/schema_creation.rb +1 -1
  26. data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
  27. data/lib/arjdbc/mssql/schema_statements.rb +19 -11
  28. data/lib/arjdbc/mssql/server_version.rb +56 -0
  29. data/lib/arjdbc/mssql/utils.rb +23 -9
  30. data/lib/arjdbc/mysql/adapter.rb +64 -22
  31. data/lib/arjdbc/mysql/connection_methods.rb +43 -42
  32. data/lib/arjdbc/sqlite3/adapter.rb +218 -135
  33. data/lib/arjdbc/sqlite3/column.rb +103 -0
  34. data/lib/arjdbc/sqlite3/connection_methods.rb +7 -2
  35. data/lib/arjdbc/tasks/mssql_database_tasks.rb +9 -5
  36. data/lib/arjdbc/version.rb +1 -1
  37. data/rakelib/02-test.rake +1 -1
  38. data/rakelib/rails.rake +2 -0
  39. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4 -2
  40. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +2 -1
  41. metadata +11 -14
  42. data/lib/arel/visitors/sql_server/ng42.rb +0 -294
  43. data/lib/arel/visitors/sql_server.rb +0 -124
  44. data/lib/arjdbc/mssql/limit_helpers.rb +0 -231
  45. data/lib/arjdbc/mssql/lock_methods.rb +0 -77
  46. data/lib/arjdbc/mssql/old_adapter.rb +0 -804
  47. data/lib/arjdbc/mssql/old_column.rb +0 -200
@@ -9,83 +9,85 @@ module ArJdbc
9
9
 
10
10
  NO_BINDS = [].freeze
11
11
 
12
- def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil)
12
+ def exec_insert(sql, name = nil, binds = NO_BINDS, pk = nil, sequence_name = nil, returning: nil)
13
13
  sql = transform_query(sql)
14
14
 
15
15
  if preventing_writes?
16
16
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
17
17
  end
18
18
 
19
- materialize_transactions
20
19
  mark_transaction_written_if_write(sql)
21
20
 
22
21
  binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
23
22
 
24
- if without_prepared_statement?(binds)
25
- log(sql, name) { @connection.execute_insert_pk(sql, pk) }
26
- else
27
- log(sql, name, binds) do
28
- @connection.execute_insert_pk(sql, binds, pk)
23
+ with_raw_connection do |conn|
24
+ if without_prepared_statement?(binds)
25
+ log(sql, name) { conn.execute_insert_pk(sql, pk) }
26
+ else
27
+ log(sql, name, binds) do
28
+ conn.execute_insert_pk(sql, binds, pk)
29
+ end
29
30
  end
30
31
  end
31
32
  end
32
33
 
33
34
  # It appears that at this point (AR 5.0) "prepare" should only ever be true
34
35
  # if prepared statements are enabled
35
- def 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)
36
37
  sql = transform_query(sql)
37
38
 
38
39
  if preventing_writes? && write_query?(sql)
39
40
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
40
41
  end
41
42
 
42
- materialize_transactions
43
43
  mark_transaction_written_if_write(sql)
44
44
 
45
45
  binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
46
46
 
47
- if without_prepared_statement?(binds)
48
- log(sql, name) { @connection.execute_query(sql) }
49
- else
50
- log(sql, name, binds) do
51
- # this is different from normal AR that always caches
52
- cached_statement = fetch_cached_statement(sql) if prepare && @jdbc_statement_cache_enabled
53
- @connection.execute_prepared_query(sql, binds, cached_statement)
47
+ with_raw_connection do |conn|
48
+ if without_prepared_statement?(binds)
49
+ log(sql, name, async: async) { conn.execute_query(sql) }
50
+ else
51
+ log(sql, name, binds, async: async) do
52
+ # this is different from normal AR that always caches
53
+ cached_statement = fetch_cached_statement(sql) if prepare && @jdbc_statement_cache_enabled
54
+ conn.execute_prepared_query(sql, binds, cached_statement)
55
+ end
54
56
  end
55
57
  end
56
58
  end
57
59
 
58
- def exec_update(sql, name = nil, binds = NO_BINDS)
60
+ def exec_update(sql, name = 'SQL', binds = NO_BINDS)
59
61
  sql = transform_query(sql)
60
62
 
61
63
  if preventing_writes?
62
64
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
63
65
  end
64
66
 
65
- materialize_transactions
66
67
  mark_transaction_written_if_write(sql)
67
68
 
68
69
  binds = convert_legacy_binds_to_attributes(binds) if binds.first.is_a?(Array)
69
70
 
70
- if without_prepared_statement?(binds)
71
- log(sql, name) { @connection.execute_update(sql) }
72
- else
73
- log(sql, name, binds) { @connection.execute_prepared_update(sql, binds) }
71
+ with_raw_connection do |conn|
72
+ if without_prepared_statement?(binds)
73
+ log(sql, name) { conn.execute_update(sql) }
74
+ else
75
+ log(sql, name, binds) { conn.execute_prepared_update(sql, binds) }
76
+ end
74
77
  end
75
78
  end
76
79
  alias :exec_delete :exec_update
77
80
 
78
- def execute(sql, name = nil, async: false)
81
+ def execute(sql, name = nil, async: false, allow_retry: false, materialize_transactions: true)
79
82
  sql = transform_query(sql)
80
83
 
81
84
  if preventing_writes? && write_query?(sql)
82
85
  raise ActiveRecord::ReadOnlyError, "Write query attempted while in readonly mode: #{sql}"
83
86
  end
84
87
 
85
- materialize_transactions
86
88
  mark_transaction_written_if_write(sql)
87
89
 
88
- log(sql, name, async: async) { @connection.execute(sql) }
90
+ raw_execute(sql, name, async: async, allow_retry: allow_retry, materialize_transactions: materialize_transactions)
89
91
  end
90
92
 
91
93
  # overridden to support legacy binds
@@ -102,6 +104,14 @@ module ArJdbc
102
104
  end
103
105
  end
104
106
 
107
+ def raw_execute(sql, name, async: false, allow_retry: false, materialize_transactions: false)
108
+ log(sql, name, async: async) do
109
+ with_raw_connection(allow_retry: allow_retry, materialize_transactions: materialize_transactions) do |conn|
110
+ conn.execute(sql)
111
+ end
112
+ end
113
+ end
114
+
105
115
  end
106
116
  end
107
117
  end
@@ -30,17 +30,12 @@ module ArJdbc
30
30
  @statements = StatementPool.new(statement_limit) # AR (5.0) expects this to be stored as @statements
31
31
  end
32
32
 
33
- # Clears the prepared statements cache.
34
- def clear_cache!
35
- @statements.clear
36
- end
37
-
38
33
  def delete_cached_statement(sql)
39
34
  @statements.delete(sql_key(sql))
40
35
  end
41
36
 
42
37
  def fetch_cached_statement(sql)
43
- @statements[sql_key(sql)] ||= @connection.prepare_statement(sql)
38
+ @statements[sql_key(sql)] ||= @raw_connection.prepare_statement(sql)
44
39
  end
45
40
 
46
41
  private
@@ -12,11 +12,11 @@ module ArJdbc
12
12
  # @since 1.3.0
13
13
  # @override
14
14
  def supports_savepoints?
15
- @connection.supports_savepoints?
15
+ @raw_connection.supports_savepoints?
16
16
  end
17
17
 
18
18
  def supports_transaction_isolation?
19
- @connection.supports_transaction_isolation?
19
+ @raw_connection.supports_transaction_isolation?
20
20
  end
21
21
 
22
22
  ########################## Transaction Interface ##########################
@@ -24,26 +24,42 @@ module ArJdbc
24
24
  # Starts a database transaction.
25
25
  # @override
26
26
  def begin_db_transaction
27
- log('BEGIN', 'TRANSACTION') { @connection.begin }
27
+ log('BEGIN', 'TRANSACTION') do
28
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
29
+ conn.begin
30
+ end
31
+ end
28
32
  end
29
33
 
30
34
  # Starts a database transaction.
31
35
  # @param isolation the transaction isolation to use
32
36
  def begin_isolated_db_transaction(isolation)
33
- log("BEGIN ISOLATED - #{isolation}", 'TRANSACTION') { @connection.begin(isolation) }
37
+ log("BEGIN ISOLATED - #{isolation}", 'TRANSACTION') do
38
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
39
+ conn.begin(isolation)
40
+ end
41
+ end
34
42
  end
35
43
 
36
44
  # Commits the current database transaction.
37
45
  # @override
38
46
  def commit_db_transaction
39
- log('COMMIT', 'TRANSACTION') { @connection.commit }
47
+ log('COMMIT', 'TRANSACTION') do
48
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
49
+ conn.commit
50
+ end
51
+ end
40
52
  end
41
53
 
42
54
  # Rolls back the current database transaction.
43
55
  # Called from 'rollback_db_transaction' in the AbstractAdapter
44
56
  # @override
45
57
  def exec_rollback_db_transaction
46
- log('ROLLBACK', 'TRANSACTION') { @connection.rollback }
58
+ log('ROLLBACK', 'TRANSACTION') do
59
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
60
+ conn.rollback
61
+ end
62
+ end
47
63
  end
48
64
 
49
65
  ########################## Savepoint Interface ############################
@@ -55,7 +71,11 @@ module ArJdbc
55
71
  # @since 1.3.0
56
72
  # @extension added optional name parameter
57
73
  def create_savepoint(name = current_savepoint_name)
58
- log("SAVEPOINT #{name}", 'TRANSACTION') { @connection.create_savepoint(name) }
74
+ log("SAVEPOINT #{name}", 'TRANSACTION') do
75
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
76
+ conn.create_savepoint(name)
77
+ end
78
+ end
59
79
  end
60
80
 
61
81
  # Transaction rollback to a given (previously created) save-point.
@@ -64,7 +84,11 @@ module ArJdbc
64
84
  # @param name the save-point name
65
85
  # @extension added optional name parameter
66
86
  def exec_rollback_to_savepoint(name = current_savepoint_name)
67
- log("ROLLBACK TO SAVEPOINT #{name}", 'TRANSACTION') { @connection.rollback_savepoint(name) }
87
+ log("ROLLBACK TO SAVEPOINT #{name}", 'TRANSACTION') do
88
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
89
+ conn.rollback_savepoint(name)
90
+ end
91
+ end
68
92
  end
69
93
 
70
94
  # Release a previously created save-point.
@@ -73,7 +97,11 @@ module ArJdbc
73
97
  # @param name the save-point name
74
98
  # @extension added optional name parameter
75
99
  def release_savepoint(name = current_savepoint_name)
76
- log("RELEASE SAVEPOINT #{name}", 'TRANSACTION') { @connection.release_savepoint(name) }
100
+ log("RELEASE SAVEPOINT #{name}", 'TRANSACTION') do
101
+ with_raw_connection(allow_retry: true, materialize_transactions: false) do |conn|
102
+ conn.release_savepoint(name)
103
+ end
104
+ end
77
105
  end
78
106
 
79
107
  end
Binary file
@@ -12,45 +12,11 @@ module ActiveRecord
12
12
  # specific type.
13
13
  # @see JdbcAdapter#jdbc_column_class
14
14
  class JdbcColumn < Column
15
- # @deprecated attribute writers will be removed in 1.4
16
- attr_writer :limit, :precision # unless ArJdbc::AR42
17
-
18
- def initialize(config, name, *args)
19
- if self.class == JdbcColumn
20
- # NOTE: extending classes do not want this if they do they shall call
21
- call_discovered_column_callbacks(config) if config
22
- default = args.shift
23
- else # for extending classes allow ignoring first argument :
24
- if ! config.nil? && ! config.is_a?(Hash)
25
- default = name; name = config # initialize(name, default, *args)
26
- else
27
- default = args.shift
28
- end
29
- end
30
-
31
- super(name, default, *args)
32
- init_column(name, default, *args)
33
- end
34
-
35
- # Additional column initialization for sub-classes.
36
- def init_column(*args); end
37
15
 
38
16
  # Similar to `ActiveRecord`'s `extract_value_from_default(default)`.
39
17
  # @return default value for a column (possibly extracted from driver value)
40
18
  def default_value(value); value; end
41
19
 
42
- protected
43
-
44
- # @private
45
- def call_discovered_column_callbacks(config)
46
- dialect = (config[:dialect] || config[:driver]).to_s
47
- for matcher, block in self.class.column_types
48
- block.call(config, self) if matcher === dialect
49
- end
50
- end
51
-
52
- public
53
-
54
20
  # Returns the available column types
55
21
  # @return [Hash] of (matcher, block) pairs
56
22
  def self.column_types
@@ -7,7 +7,7 @@ module ArJdbc
7
7
 
8
8
  def jdbc_connection(config)
9
9
  adapter_class = config[:adapter_class] || ::ActiveRecord::ConnectionAdapters::JdbcAdapter
10
- adapter_class.new(nil, logger, nil, config)
10
+ adapter_class.new(config)
11
11
  end
12
12
 
13
13
  def jndi_connection(config); jdbc_connection(config) end
@@ -15,6 +15,8 @@ require 'arjdbc/abstract/database_statements'
15
15
  require 'arjdbc/abstract/statement_cache'
16
16
  require 'arjdbc/abstract/transaction_support'
17
17
 
18
+ require 'arjdbc/mssql/utils'
19
+ require 'arjdbc/mssql/server_version'
18
20
  require 'arjdbc/mssql/column'
19
21
  require 'arjdbc/mssql/types'
20
22
  require 'arjdbc/mssql/quoting'
@@ -34,23 +36,11 @@ module ActiveRecord
34
36
  class MSSQLAdapter < AbstractAdapter
35
37
  ADAPTER_NAME = 'MSSQL'.freeze
36
38
 
37
- MSSQL_VERSION_YEAR = {
38
- 8 => '2000',
39
- 9 => '2005',
40
- 10 => '2008',
41
- 11 => '2012',
42
- 12 => '2014',
43
- 13 => '2016',
44
- 14 => '2017',
45
- 15 => '2019',
46
- 16 => '2022'
47
- }.freeze
48
-
49
- include Jdbc::ConnectionPoolCallbacks
39
+ # include Jdbc::ConnectionPoolCallbacks
50
40
  include ArJdbc::Abstract::Core
51
- include ArJdbc::Abstract::ConnectionManagement
52
- include ArJdbc::Abstract::DatabaseStatements
53
- include ArJdbc::Abstract::StatementCache
41
+ # include ArJdbc::Abstract::ConnectionManagement
42
+ # include ArJdbc::Abstract::DatabaseStatements
43
+ # include ArJdbc::Abstract::StatementCache
54
44
  include ArJdbc::Abstract::TransactionSupport
55
45
 
56
46
  include MSSQL::Quoting
@@ -63,32 +53,50 @@ module ActiveRecord
63
53
 
64
54
  class << self
65
55
  attr_accessor :cs_equality_operator
56
+
57
+ # Returns the (JDBC) connection class to be used for this adapter.
58
+ # The class is defined in the java part
59
+ def jdbc_connection_class
60
+ ::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
61
+ end
62
+
63
+ def new_client(conn_params, adapter_instance)
64
+ jdbc_connection_class.new(conn_params, adapter_instance)
65
+ rescue ActiveRecord::JDBCError => error
66
+ if conn_params && conn_params[:database] && error.message.include?(conn_params[:database])
67
+ raise ActiveRecord::NoDatabaseError.db_error(conn_params[:database])
68
+ elsif conn_params && conn_params[:username] && error.message.include?(conn_params[:username])
69
+ raise ActiveRecord::DatabaseConnectionError.username_error(conn_params[:username])
70
+ elsif conn_params && conn_params[:host] && error.message.include?(conn_params[:host])
71
+ raise ActiveRecord::DatabaseConnectionError.hostname_error(conn_params[:host])
72
+ else
73
+ raise ActiveRecord::ConnectionNotEstablished, error.message
74
+ end
75
+ end
66
76
  end
67
77
 
68
- def initialize(connection, logger, _connection_parameters, config = {})
78
+ def initialize(...)
69
79
  # configure_connection happens in super
70
- super(connection, logger, config)
80
+ super
71
81
 
72
- if database_version < '11'
73
- raise "Your #{mssql_product_name} #{mssql_version_year} is too old. This adapter supports #{mssql_product_name} >= 2012."
74
- end
82
+ conn_params = @config.compact
83
+
84
+ @raw_connection = nil
85
+
86
+ @connection_parameters = conn_params
75
87
  end
76
88
 
77
- def self.database_exists?(config)
78
- !!ActiveRecord::Base.sqlserver_connection(config)
79
- rescue ActiveRecord::JDBCError => e
80
- case e.message
81
- when /Cannot open database .* requested by the login/
82
- false
83
- else
84
- raise
85
- end
89
+ # @override
90
+ def active?
91
+ return false unless @raw_connection
92
+
93
+ @raw_connection.active?
86
94
  end
87
95
 
88
- # Returns the (JDBC) connection class to be used for this adapter.
89
- # The class is defined in the java part
90
- def jdbc_connection_class(_spec)
91
- ::ActiveRecord::ConnectionAdapters::MSSQLJdbcConnection
96
+ # @override
97
+ def disconnect!
98
+ super # clear_cache! && reset_transaction
99
+ @raw_connection&.disconnect!
92
100
  end
93
101
 
94
102
  # Returns the (JDBC) `ActiveRecord` column class for this adapter.
@@ -177,10 +185,10 @@ module ActiveRecord
177
185
  !native_database_types[type].nil?
178
186
  end
179
187
 
180
- def clear_cache!
181
- # reload_type_map
182
- super
183
- end
188
+ # def clear_cache!
189
+ # # reload_type_map
190
+ # super
191
+ # end
184
192
 
185
193
  def reset!
186
194
  # execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
@@ -193,12 +201,12 @@ module ActiveRecord
193
201
  tables = tables_with_referential_integrity
194
202
 
195
203
  tables.each do |table_name|
196
- execute "ALTER TABLE #{table_name} NOCHECK CONSTRAINT ALL"
204
+ internal_execute("ALTER TABLE #{table_name} NOCHECK CONSTRAINT ALL")
197
205
  end
198
206
  yield
199
207
  ensure
200
208
  tables.each do |table_name|
201
- execute "ALTER TABLE #{table_name} CHECK CONSTRAINT ALL"
209
+ internal_execute("ALTER TABLE #{table_name} CHECK CONSTRAINT ALL")
202
210
  end
203
211
  end
204
212
 
@@ -222,13 +230,17 @@ module ActiveRecord
222
230
 
223
231
  # Returns the name of the current security context
224
232
  def current_user
225
- @current_user ||= select_value('SELECT CURRENT_USER')
233
+ @current_user ||= internal_execute('SELECT CURRENT_USER').rows.flatten.first
226
234
  end
227
235
 
228
236
  # Returns the default schema (to be used for table resolution)
229
237
  # used for the {#current_user}.
230
238
  def default_schema
231
- @default_schema ||= select_value('SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER')
239
+ @default_schema ||= internal_execute(default_schema_query).rows.flatten.first
240
+ end
241
+
242
+ def default_schema_query
243
+ 'SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER'
232
244
  end
233
245
 
234
246
  alias_method :current_schema, :default_schema
@@ -236,7 +248,7 @@ module ActiveRecord
236
248
  # Allows for changing of the default schema.
237
249
  # (to be used during unqualified table name resolution).
238
250
  def default_schema=(default_schema)
239
- execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
251
+ internal_execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
240
252
  @default_schema = nil if defined?(@default_schema)
241
253
  end
242
254
 
@@ -273,7 +285,7 @@ module ActiveRecord
273
285
  end
274
286
 
275
287
  def set_session_transaction_isolation
276
- isolation_level = config[:transaction_isolation]
288
+ isolation_level = @config[:transaction_isolation]
277
289
 
278
290
  self.transaction_isolation = isolation_level if isolation_level
279
291
  end
@@ -282,35 +294,31 @@ module ActiveRecord
282
294
  true
283
295
  end
284
296
 
285
- def mssql_major_version
286
- return @mssql_major_version if defined? @mssql_major_version
287
-
288
- @mssql_major_version = @connection.database_major_version
289
- end
290
-
291
- def mssql_version_year
292
- MSSQL_VERSION_YEAR[mssql_major_version.to_i]
297
+ def get_database_version # :nodoc:
298
+ MSSQLAdapter::Version.new(mssql_version.major, mssql_version.complete)
293
299
  end
294
300
 
295
- def mssql_product_version
296
- return @mssql_product_version if defined? @mssql_product_version
301
+ def check_version # :nodoc:
302
+ return unless database_version.to_s <= mssql_version.min_major
297
303
 
298
- @mssql_product_version = @connection.database_product_version
304
+ raise "Your #{mssql_version.product_name} is too old. #{mssql_version.support_message}"
299
305
  end
300
306
 
301
- def mssql_product_name
302
- return @mssql_product_name if defined? @mssql_product_name
307
+ def mssql_version
308
+ return @mssql_version if defined? @mssql_version
303
309
 
304
- @mssql_product_name = @connection.database_product_name
305
- end
310
+ result = internal_execute("SELECT #{mssql_version_properties.join(', ')}").rows
306
311
 
307
- def get_database_version # :nodoc:
308
- MSSQLAdapter::Version.new(mssql_product_version)
312
+ @mssql_version = MSSQL::Version.new(result.flatten)
309
313
  end
310
314
 
311
- def check_version # :nodoc:
312
- # NOTE: hitting the database from here causes trouble when adapter
313
- # uses JNDI or Data Source setup.
315
+ def mssql_version_properties
316
+ [
317
+ "SERVERPROPERTY('productVersion')",
318
+ "SERVERPROPERTY('productMajorVersion')",
319
+ "SERVERPROPERTY('productLevel')",
320
+ "SERVERPROPERTY('edition')"
321
+ ]
314
322
  end
315
323
 
316
324
  def tables_with_referential_integrity
@@ -404,6 +412,8 @@ module ActiveRecord
404
412
  register_class_with_precision map, %r{\Adatetime2\(\d+\)}i, MSSQL::Type::DateTime2
405
413
  # map.register_type 'datetime2(7)', MSSQL::Type::DateTime2.new
406
414
 
415
+ # map.register_type %r(^json)i, Type::Json.new
416
+
407
417
  # TODO: we should have identity separated from the sql_type
408
418
  # let's say in another attribute (this will help to pass more AR tests),
409
419
  # also we add collation attribute per column.
@@ -440,6 +450,20 @@ module ActiveRecord
440
450
 
441
451
  private
442
452
 
453
+ def connect
454
+ @raw_connection = self.class.new_client(@connection_parameters, self)
455
+ rescue ConnectionNotEstablished => ex
456
+ raise ex.set_pool(@pool)
457
+ end
458
+
459
+ def reconnect
460
+ @raw_connection&.disconnect!
461
+
462
+ @raw_connection = nil
463
+
464
+ connect
465
+ end
466
+
443
467
  def type_map
444
468
  TYPE_MAP
445
469
  end
@@ -454,6 +478,8 @@ module ActiveRecord
454
478
  LockTimeout.new(message, sql: sql, binds: binds)
455
479
  when /The .* statement conflicted with the FOREIGN KEY constraint/
456
480
  InvalidForeignKey.new(message, sql: sql, binds: binds)
481
+ when /Could not drop object .* because it is referenced by a FOREIGN KEY constraint/
482
+ StatementInvalid.new(message, sql: sql, binds: binds)
457
483
  when /The .* statement conflicted with the REFERENCE constraint/
458
484
  InvalidForeignKey.new(message, sql: sql, binds: binds)
459
485
  when /(String or binary data would be truncated)/i
@@ -462,6 +488,8 @@ module ActiveRecord
462
488
  NotNullViolation.new(message, sql: sql, binds: binds)
463
489
  when /Arithmetic overflow error converting expression/
464
490
  RangeError.new(message, sql: sql, binds: binds)
491
+ when /Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation/
492
+ StatementInvalid.new(message, sql: sql, binds: binds)
465
493
  else
466
494
  super
467
495
  end
@@ -472,13 +500,11 @@ module ActiveRecord
472
500
  # NOTE: This is ready, all implemented in the java part of adapter,
473
501
  # it uses MSSQLColumn, SqlTypeMetadata, etc.
474
502
  def column_definitions(table_name)
475
- log('JDBC: GETCOLUMNS', 'SCHEMA') { @connection.columns(table_name, nil, default_schema) }
476
- rescue => e
503
+ log('JDBC: GETCOLUMNS', 'SCHEMA') { valid_raw_connection.columns(table_name, nil, default_schema) }
477
504
  # raise translate_exception_class(e, nil)
478
505
  # FIXME: this breaks one arjdbc test but fixes activerecord tests
479
506
  # (table name alias). Also it behaves similarly to the CRuby adapter
480
507
  # which returns an empty array too. (postgres throws a exception)
481
- []
482
508
  end
483
509
 
484
510
  def arel_visitor # :nodoc:
@@ -491,16 +517,3 @@ module ActiveRecord
491
517
  end
492
518
  end
493
519
  end
494
-
495
- # FIXME: this is not used by the adapter anymore, it is here because
496
- # it is a dependency of old tests that needs to be reviewed
497
- module ArJdbc
498
- module MSSQL
499
- require 'arjdbc/mssql/utils'
500
- require 'arjdbc/mssql/limit_helpers'
501
- require 'arjdbc/mssql/lock_methods'
502
-
503
- include LimitHelpers
504
- include Utils
505
- end
506
- end
@@ -29,6 +29,7 @@ module ActiveRecord
29
29
  def identity?
30
30
  sql_type.downcase.include? 'identity'
31
31
  end
32
+ alias_method :auto_incremented_by_db?, :identity?
32
33
 
33
34
  def ==(other)
34
35
  other.is_a?(MSSQLColumn) &&