activerecord-jdbc-alt-adapter 70.2.0-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 +141 -24
- data/.github/workflows/ruby.yml +12 -12
- data/.gitignore +7 -3
- 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/arjdbc/abstract/connection_management.rb +26 -10
- data/lib/arjdbc/abstract/core.rb +5 -12
- data/lib/arjdbc/abstract/database_statements.rb +35 -25
- data/lib/arjdbc/abstract/statement_cache.rb +2 -7
- data/lib/arjdbc/abstract/transaction_support.rb +37 -22
- 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 +101 -79
- 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 +25 -14
- data/lib/arjdbc/mssql/server_version.rb +56 -0
- data/lib/arjdbc/mssql/utils.rb +23 -9
- data/lib/arjdbc/mysql/adapter.rb +104 -27
- 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 +205 -147
- 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 +3 -1
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +11 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +2 -1
- metadata +10 -12
- 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, allow_retry: false, materialize_transactions: true)
|
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: true)
|
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
|
@@ -24,23 +24,18 @@ 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
|
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,22 +97,13 @@ 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
|
80
108
|
end
|
81
109
|
end
|
82
|
-
|
83
|
-
# patch to avoid the usage of WeakMap
|
84
|
-
require 'active_record/connection_adapters/abstract/transaction'
|
85
|
-
module ActiveRecord
|
86
|
-
module ConnectionAdapters
|
87
|
-
class Transaction
|
88
|
-
def add_record(record, ensure_finalize = true)
|
89
|
-
@records ||= []
|
90
|
-
@records << record
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
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,55 @@ 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
|
-
|
83
|
-
else
|
84
|
-
raise
|
89
|
+
# @override
|
90
|
+
def active?
|
91
|
+
@lock.synchronize do
|
92
|
+
return false unless @raw_connection
|
93
|
+
|
94
|
+
@raw_connection.active?
|
85
95
|
end
|
86
96
|
end
|
87
97
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
98
|
+
# @override
|
99
|
+
def disconnect!
|
100
|
+
@lock.synchronize do
|
101
|
+
super # clear_cache! && reset_transaction
|
102
|
+
@raw_connection&.disconnect!
|
103
|
+
@raw_connection = nil
|
104
|
+
end
|
92
105
|
end
|
93
106
|
|
94
107
|
# Returns the (JDBC) `ActiveRecord` column class for this adapter.
|
@@ -177,10 +190,10 @@ module ActiveRecord
|
|
177
190
|
!native_database_types[type].nil?
|
178
191
|
end
|
179
192
|
|
180
|
-
def clear_cache!
|
181
|
-
|
182
|
-
|
183
|
-
end
|
193
|
+
# def clear_cache!
|
194
|
+
# # reload_type_map
|
195
|
+
# super
|
196
|
+
# end
|
184
197
|
|
185
198
|
def reset!
|
186
199
|
# execute 'IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION'
|
@@ -193,12 +206,12 @@ module ActiveRecord
|
|
193
206
|
tables = tables_with_referential_integrity
|
194
207
|
|
195
208
|
tables.each do |table_name|
|
196
|
-
|
209
|
+
internal_execute("ALTER TABLE #{table_name} NOCHECK CONSTRAINT ALL")
|
197
210
|
end
|
198
211
|
yield
|
199
212
|
ensure
|
200
213
|
tables.each do |table_name|
|
201
|
-
|
214
|
+
internal_execute("ALTER TABLE #{table_name} CHECK CONSTRAINT ALL")
|
202
215
|
end
|
203
216
|
end
|
204
217
|
|
@@ -222,13 +235,17 @@ module ActiveRecord
|
|
222
235
|
|
223
236
|
# Returns the name of the current security context
|
224
237
|
def current_user
|
225
|
-
@current_user ||=
|
238
|
+
@current_user ||= internal_execute('SELECT CURRENT_USER').rows.flatten.first
|
226
239
|
end
|
227
240
|
|
228
241
|
# Returns the default schema (to be used for table resolution)
|
229
242
|
# used for the {#current_user}.
|
230
243
|
def default_schema
|
231
|
-
@default_schema ||=
|
244
|
+
@default_schema ||= internal_execute(default_schema_query).rows.flatten.first
|
245
|
+
end
|
246
|
+
|
247
|
+
def default_schema_query
|
248
|
+
'SELECT default_schema_name FROM sys.database_principals WHERE name = CURRENT_USER'
|
232
249
|
end
|
233
250
|
|
234
251
|
alias_method :current_schema, :default_schema
|
@@ -236,7 +253,7 @@ module ActiveRecord
|
|
236
253
|
# Allows for changing of the default schema.
|
237
254
|
# (to be used during unqualified table name resolution).
|
238
255
|
def default_schema=(default_schema)
|
239
|
-
|
256
|
+
internal_execute("ALTER #{current_user} WITH DEFAULT_SCHEMA=#{default_schema}")
|
240
257
|
@default_schema = nil if defined?(@default_schema)
|
241
258
|
end
|
242
259
|
|
@@ -273,7 +290,7 @@ module ActiveRecord
|
|
273
290
|
end
|
274
291
|
|
275
292
|
def set_session_transaction_isolation
|
276
|
-
isolation_level = config[:transaction_isolation]
|
293
|
+
isolation_level = @config[:transaction_isolation]
|
277
294
|
|
278
295
|
self.transaction_isolation = isolation_level if isolation_level
|
279
296
|
end
|
@@ -282,35 +299,31 @@ module ActiveRecord
|
|
282
299
|
true
|
283
300
|
end
|
284
301
|
|
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]
|
302
|
+
def get_database_version # :nodoc:
|
303
|
+
MSSQLAdapter::Version.new(mssql_version.major, mssql_version.complete)
|
293
304
|
end
|
294
305
|
|
295
|
-
def
|
296
|
-
return
|
306
|
+
def check_version # :nodoc:
|
307
|
+
return unless database_version.to_s <= mssql_version.min_major
|
297
308
|
|
298
|
-
|
309
|
+
raise "Your #{mssql_version.product_name} is too old. #{mssql_version.support_message}"
|
299
310
|
end
|
300
311
|
|
301
|
-
def
|
302
|
-
return @
|
312
|
+
def mssql_version
|
313
|
+
return @mssql_version if defined? @mssql_version
|
303
314
|
|
304
|
-
|
305
|
-
end
|
315
|
+
result = internal_execute("SELECT #{mssql_version_properties.join(', ')}").rows
|
306
316
|
|
307
|
-
|
308
|
-
MSSQLAdapter::Version.new(mssql_product_version)
|
317
|
+
@mssql_version = MSSQL::Version.new(result.flatten)
|
309
318
|
end
|
310
319
|
|
311
|
-
def
|
312
|
-
|
313
|
-
|
320
|
+
def mssql_version_properties
|
321
|
+
[
|
322
|
+
"SERVERPROPERTY('productVersion')",
|
323
|
+
"SERVERPROPERTY('productMajorVersion')",
|
324
|
+
"SERVERPROPERTY('productLevel')",
|
325
|
+
"SERVERPROPERTY('edition')"
|
326
|
+
]
|
314
327
|
end
|
315
328
|
|
316
329
|
def tables_with_referential_integrity
|
@@ -404,6 +417,8 @@ module ActiveRecord
|
|
404
417
|
register_class_with_precision map, %r{\Adatetime2\(\d+\)}i, MSSQL::Type::DateTime2
|
405
418
|
# map.register_type 'datetime2(7)', MSSQL::Type::DateTime2.new
|
406
419
|
|
420
|
+
# map.register_type %r(^json)i, Type::Json.new
|
421
|
+
|
407
422
|
# TODO: we should have identity separated from the sql_type
|
408
423
|
# let's say in another attribute (this will help to pass more AR tests),
|
409
424
|
# also we add collation attribute per column.
|
@@ -440,6 +455,20 @@ module ActiveRecord
|
|
440
455
|
|
441
456
|
private
|
442
457
|
|
458
|
+
def connect
|
459
|
+
@raw_connection = self.class.new_client(@connection_parameters, self)
|
460
|
+
rescue ConnectionNotEstablished => ex
|
461
|
+
raise ex.set_pool(@pool)
|
462
|
+
end
|
463
|
+
|
464
|
+
def reconnect
|
465
|
+
@raw_connection&.disconnect!
|
466
|
+
|
467
|
+
@raw_connection = nil
|
468
|
+
|
469
|
+
connect
|
470
|
+
end
|
471
|
+
|
443
472
|
def type_map
|
444
473
|
TYPE_MAP
|
445
474
|
end
|
@@ -454,6 +483,8 @@ module ActiveRecord
|
|
454
483
|
LockTimeout.new(message, sql: sql, binds: binds)
|
455
484
|
when /The .* statement conflicted with the FOREIGN KEY constraint/
|
456
485
|
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
486
|
+
when /Could not drop object .* because it is referenced by a FOREIGN KEY constraint/
|
487
|
+
StatementInvalid.new(message, sql: sql, binds: binds)
|
457
488
|
when /The .* statement conflicted with the REFERENCE constraint/
|
458
489
|
InvalidForeignKey.new(message, sql: sql, binds: binds)
|
459
490
|
when /(String or binary data would be truncated)/i
|
@@ -462,6 +493,12 @@ module ActiveRecord
|
|
462
493
|
NotNullViolation.new(message, sql: sql, binds: binds)
|
463
494
|
when /Arithmetic overflow error converting expression/
|
464
495
|
RangeError.new(message, sql: sql, binds: binds)
|
496
|
+
when /Snapshot isolation transaction aborted due to update conflict. You cannot use snapshot isolation/
|
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)
|
465
502
|
else
|
466
503
|
super
|
467
504
|
end
|
@@ -472,13 +509,11 @@ module ActiveRecord
|
|
472
509
|
# NOTE: This is ready, all implemented in the java part of adapter,
|
473
510
|
# it uses MSSQLColumn, SqlTypeMetadata, etc.
|
474
511
|
def column_definitions(table_name)
|
475
|
-
|
476
|
-
rescue => e
|
512
|
+
log('JDBC: GETCOLUMNS', 'SCHEMA') { valid_raw_connection.columns(table_name, nil, default_schema) }
|
477
513
|
# raise translate_exception_class(e, nil)
|
478
514
|
# FIXME: this breaks one arjdbc test but fixes activerecord tests
|
479
515
|
# (table name alias). Also it behaves similarly to the CRuby adapter
|
480
516
|
# which returns an empty array too. (postgres throws a exception)
|
481
|
-
[]
|
482
517
|
end
|
483
518
|
|
484
519
|
def arel_visitor # :nodoc:
|
@@ -491,16 +526,3 @@ module ActiveRecord
|
|
491
526
|
end
|
492
527
|
end
|
493
528
|
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
|