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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +135 -21
- data/.github/workflows/ruby.yml +10 -10
- data/.gitignore +1 -0
- data/.solargraph.yml +15 -0
- data/Gemfile +17 -4
- data/README.md +7 -3
- data/RUNNING_TESTS.md +36 -0
- data/activerecord-jdbc-adapter.gemspec +2 -2
- data/activerecord-jdbc-alt-adapter.gemspec +1 -1
- data/lib/arel/visitors/sqlserver.rb +10 -0
- data/lib/arjdbc/abstract/connection_management.rb +23 -10
- data/lib/arjdbc/abstract/core.rb +5 -6
- data/lib/arjdbc/abstract/database_statements.rb +35 -25
- data/lib/arjdbc/abstract/statement_cache.rb +1 -6
- data/lib/arjdbc/abstract/transaction_support.rb +37 -9
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/column.rb +0 -34
- data/lib/arjdbc/jdbc/connection_methods.rb +1 -1
- data/lib/arjdbc/mssql/adapter.rb +93 -80
- data/lib/arjdbc/mssql/column.rb +1 -0
- data/lib/arjdbc/mssql/connection_methods.rb +7 -55
- data/lib/arjdbc/mssql/database_statements.rb +182 -71
- data/lib/arjdbc/mssql/explain_support.rb +8 -5
- data/lib/arjdbc/mssql/schema_creation.rb +1 -1
- data/lib/arjdbc/mssql/schema_definitions.rb +10 -0
- data/lib/arjdbc/mssql/schema_statements.rb +19 -11
- data/lib/arjdbc/mssql/server_version.rb +56 -0
- data/lib/arjdbc/mssql/utils.rb +23 -9
- data/lib/arjdbc/mysql/adapter.rb +64 -22
- data/lib/arjdbc/mysql/connection_methods.rb +43 -42
- data/lib/arjdbc/sqlite3/adapter.rb +218 -135
- data/lib/arjdbc/sqlite3/column.rb +103 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +7 -2
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +9 -5
- data/lib/arjdbc/version.rb +1 -1
- data/rakelib/02-test.rake +1 -1
- data/rakelib/rails.rake +2 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +4 -2
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +2 -1
- metadata +11 -14
- data/lib/arel/visitors/sql_server/ng42.rb +0 -294
- data/lib/arel/visitors/sql_server.rb +0 -124
- data/lib/arjdbc/mssql/limit_helpers.rb +0 -231
- data/lib/arjdbc/mssql/lock_methods.rb +0 -77
- data/lib/arjdbc/mssql/old_adapter.rb +0 -804
- 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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
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
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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 =
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
-
|
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)] ||= @
|
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
|
-
@
|
15
|
+
@raw_connection.supports_savepoints?
|
16
16
|
end
|
17
17
|
|
18
18
|
def supports_transaction_isolation?
|
19
|
-
@
|
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')
|
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')
|
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')
|
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')
|
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')
|
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')
|
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')
|
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
|
data/lib/arjdbc/jdbc/column.rb
CHANGED
@@ -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(
|
10
|
+
adapter_class.new(config)
|
11
11
|
end
|
12
12
|
|
13
13
|
def jndi_connection(config); jdbc_connection(config) end
|
data/lib/arjdbc/mssql/adapter.rb
CHANGED
@@ -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
|
-
|
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(
|
78
|
+
def initialize(...)
|
69
79
|
# configure_connection happens in super
|
70
|
-
super
|
80
|
+
super
|
71
81
|
|
72
|
-
|
73
|
-
|
74
|
-
|
82
|
+
conn_params = @config.compact
|
83
|
+
|
84
|
+
@raw_connection = nil
|
85
|
+
|
86
|
+
@connection_parameters = conn_params
|
75
87
|
end
|
76
88
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
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
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
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
|
-
|
182
|
-
|
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
|
-
|
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
|
-
|
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 ||=
|
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 ||=
|
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
|
-
|
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
|
286
|
-
|
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
|
296
|
-
return
|
301
|
+
def check_version # :nodoc:
|
302
|
+
return unless database_version.to_s <= mssql_version.min_major
|
297
303
|
|
298
|
-
|
304
|
+
raise "Your #{mssql_version.product_name} is too old. #{mssql_version.support_message}"
|
299
305
|
end
|
300
306
|
|
301
|
-
def
|
302
|
-
return @
|
307
|
+
def mssql_version
|
308
|
+
return @mssql_version if defined? @mssql_version
|
303
309
|
|
304
|
-
|
305
|
-
end
|
310
|
+
result = internal_execute("SELECT #{mssql_version_properties.join(', ')}").rows
|
306
311
|
|
307
|
-
|
308
|
-
MSSQLAdapter::Version.new(mssql_product_version)
|
312
|
+
@mssql_version = MSSQL::Version.new(result.flatten)
|
309
313
|
end
|
310
314
|
|
311
|
-
def
|
312
|
-
|
313
|
-
|
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
|
-
|
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
|