activerecord-sqlserver-adapter 2.3.7 → 3.2.18
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG +385 -61
- data/MIT-LICENSE +1 -1
- data/VERSION +1 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +42 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/database_statements.rb +97 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +41 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +26 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +38 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/relation.rb +19 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +458 -0
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +113 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +85 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +376 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +69 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +25 -0
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +67 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +32 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +344 -1055
- data/lib/arel/visitors/sqlserver.rb +389 -0
- metadata +60 -83
- data/README.rdoc +0 -190
- data/RUNNING_UNIT_TESTS +0 -65
- data/Rakefile +0 -41
- data/autotest/discover.rb +0 -4
- data/autotest/railssqlserver.rb +0 -16
- data/autotest/sqlserver.rb +0 -54
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/active_record.rb +0 -151
- data/lib/active_record/connection_adapters/sqlserver_adapter/core_ext/odbc.rb +0 -40
- data/test/cases/aaaa_create_tables_test_sqlserver.rb +0 -19
- data/test/cases/adapter_test_sqlserver.rb +0 -756
- data/test/cases/attribute_methods_test_sqlserver.rb +0 -33
- data/test/cases/basics_test_sqlserver.rb +0 -21
- data/test/cases/calculations_test_sqlserver.rb +0 -20
- data/test/cases/column_test_sqlserver.rb +0 -285
- data/test/cases/connection_test_sqlserver.rb +0 -146
- data/test/cases/eager_association_test_sqlserver.rb +0 -42
- data/test/cases/execute_procedure_test_sqlserver.rb +0 -44
- data/test/cases/inheritance_test_sqlserver.rb +0 -28
- data/test/cases/method_scoping_test_sqlserver.rb +0 -28
- data/test/cases/migration_test_sqlserver.rb +0 -123
- data/test/cases/named_scope_test_sqlserver.rb +0 -21
- data/test/cases/offset_and_limit_test_sqlserver.rb +0 -108
- data/test/cases/pessimistic_locking_test_sqlserver.rb +0 -125
- data/test/cases/query_cache_test_sqlserver.rb +0 -24
- data/test/cases/schema_dumper_test_sqlserver.rb +0 -72
- data/test/cases/specific_schema_test_sqlserver.rb +0 -97
- data/test/cases/sqlserver_helper.rb +0 -127
- data/test/cases/table_name_test_sqlserver.rb +0 -38
- data/test/cases/transaction_test_sqlserver.rb +0 -93
- data/test/cases/unicode_test_sqlserver.rb +0 -50
- data/test/cases/validations_test_sqlserver.rb +0 -35
- data/test/connections/native_sqlserver/connection.rb +0 -25
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -27
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +0 -11
- data/test/schema/sqlserver_specific_schema.rb +0 -94
@@ -0,0 +1,97 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module DatabaseStatements
|
6
|
+
|
7
|
+
# This is a copy of the current (3.1.3) ActiveRecord's transaction method. We should propose
|
8
|
+
# a patch to the default transaction method to make it more callback for adapters that want to
|
9
|
+
# do deadlock retry logic. Because this is a copy, we really need to keep an eye out on this when
|
10
|
+
# upgradding the adapter.
|
11
|
+
def transaction_with_retry_deadlock_victim(options = {})
|
12
|
+
options.assert_valid_keys :requires_new, :joinable
|
13
|
+
|
14
|
+
last_transaction_joinable = defined?(@transaction_joinable) ? @transaction_joinable : nil
|
15
|
+
if options.has_key?(:joinable)
|
16
|
+
@transaction_joinable = options[:joinable]
|
17
|
+
else
|
18
|
+
@transaction_joinable = true
|
19
|
+
end
|
20
|
+
requires_new = options[:requires_new] || !last_transaction_joinable
|
21
|
+
|
22
|
+
transaction_open = false
|
23
|
+
@_current_transaction_records ||= []
|
24
|
+
|
25
|
+
begin
|
26
|
+
if block_given?
|
27
|
+
if requires_new || open_transactions == 0
|
28
|
+
if open_transactions == 0
|
29
|
+
begin_db_transaction
|
30
|
+
elsif requires_new
|
31
|
+
create_savepoint
|
32
|
+
end
|
33
|
+
increment_open_transactions
|
34
|
+
transaction_open = true
|
35
|
+
@_current_transaction_records.push([])
|
36
|
+
end
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
rescue Exception => database_transaction_rollback
|
40
|
+
if transaction_open && !outside_transaction?
|
41
|
+
transaction_open = false
|
42
|
+
decrement_open_transactions
|
43
|
+
# handle deadlock victim retries at the outermost transaction
|
44
|
+
if open_transactions == 0
|
45
|
+
if database_transaction_rollback.is_a?(::ActiveRecord::DeadlockVictim)
|
46
|
+
# SQL Server has already rolled back, so rollback activerecord's history
|
47
|
+
rollback_transaction_records(true)
|
48
|
+
retry
|
49
|
+
else
|
50
|
+
rollback_db_transaction
|
51
|
+
rollback_transaction_records(true)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
rollback_to_savepoint
|
55
|
+
rollback_transaction_records(false)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
raise unless database_transaction_rollback.is_a?(::ActiveRecord::Rollback)
|
59
|
+
end
|
60
|
+
ensure
|
61
|
+
@transaction_joinable = last_transaction_joinable
|
62
|
+
|
63
|
+
if outside_transaction?
|
64
|
+
@open_transactions = 0
|
65
|
+
elsif transaction_open
|
66
|
+
decrement_open_transactions
|
67
|
+
begin
|
68
|
+
if open_transactions == 0
|
69
|
+
commit_db_transaction
|
70
|
+
commit_transaction_records
|
71
|
+
else
|
72
|
+
release_savepoint
|
73
|
+
save_point_records = @_current_transaction_records.pop
|
74
|
+
unless save_point_records.blank?
|
75
|
+
@_current_transaction_records.push([]) if @_current_transaction_records.empty?
|
76
|
+
@_current_transaction_records.last.concat(save_point_records)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
rescue Exception => database_transaction_rollback
|
80
|
+
if open_transactions == 0
|
81
|
+
rollback_db_transaction
|
82
|
+
rollback_transaction_records(true)
|
83
|
+
else
|
84
|
+
rollback_to_savepoint
|
85
|
+
rollback_transaction_records(false)
|
86
|
+
end
|
87
|
+
raise
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module Explain
|
6
|
+
|
7
|
+
SQLSERVER_STATEMENT_PREFIX = "EXEC sp_executesql "
|
8
|
+
SQLSERVER_PARAM_MATCHER = /@\d+ =/
|
9
|
+
|
10
|
+
def exec_explain(queries)
|
11
|
+
unprepared_queries = queries.map { |sql, bind| [unprepare_sqlserver_statement(sql), bind] }
|
12
|
+
super(unprepared_queries)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# This is somewhat hacky, but it should reliably reformat our prepared sql statment
|
18
|
+
# which uses sp_executesql to just the first argument, then unquote it. Likewise our
|
19
|
+
# do_exec_query method should substitude the @n args withe the quoted values.
|
20
|
+
def unprepare_sqlserver_statement(sql)
|
21
|
+
if sql.starts_with?(SQLSERVER_STATEMENT_PREFIX)
|
22
|
+
executesql = sql.from(SQLSERVER_STATEMENT_PREFIX.length)
|
23
|
+
executesql_args = executesql.split(', ')
|
24
|
+
found_args = executesql_args.reject! { |arg| arg =~ SQLSERVER_PARAM_MATCHER }
|
25
|
+
executesql_args.pop if found_args && executesql_args.many?
|
26
|
+
executesql = executesql_args.join(', ').strip.match(/N'(.*)'/m)[1]
|
27
|
+
Utils.unquote_string(executesql)
|
28
|
+
else
|
29
|
+
sql
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ActiveRecord::Base.extend ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::Explain
|
41
|
+
ActiveRecord::Relation.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::Explain
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
class ExplainSubscriber
|
6
|
+
def call(*args)
|
7
|
+
if queries = Thread.current[:available_queries_for_explain]
|
8
|
+
payload = args.last
|
9
|
+
queries << payload.values_at(:sql, :binds) unless ignore_sqlserver_payload?(payload)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
IGNORED_PAYLOADS = %w(SCHEMA EXPLAIN CACHE)
|
14
|
+
SQLSERVER_EXPLAINED_SQLS = /(select|update|delete|insert)/i
|
15
|
+
|
16
|
+
# Need to modify the regex for the TSQL generated by this adapter so we can explain the proper sql statements
|
17
|
+
def ignore_sqlserver_payload?(payload)
|
18
|
+
payload[:exception] || IGNORED_PAYLOADS.include?(payload[:name]) || payload[:sql] !~ SQLSERVER_EXPLAINED_SQLS
|
19
|
+
end
|
20
|
+
|
21
|
+
ActiveSupport::Notifications.subscribe("sql.active_record", new)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module ODBC
|
6
|
+
|
7
|
+
module Statement
|
8
|
+
|
9
|
+
def finished?
|
10
|
+
begin
|
11
|
+
connected?
|
12
|
+
false
|
13
|
+
rescue ::ODBC::Error
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
module Database
|
21
|
+
|
22
|
+
def run_block(*args)
|
23
|
+
yield sth = run(*args)
|
24
|
+
sth.drop
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
ODBC::Statement.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Statement
|
37
|
+
ODBC::Database.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::ODBC::Database
|
38
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module CoreExt
|
5
|
+
module Relation
|
6
|
+
|
7
|
+
private
|
8
|
+
|
9
|
+
def tables_in_string(string)
|
10
|
+
super - ['__rnt']
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
ActiveRecord::Relation.send :include, ActiveRecord::ConnectionAdapters::Sqlserver::CoreExt::Relation
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module Sqlserver
|
4
|
+
module DatabaseLimits
|
5
|
+
|
6
|
+
def table_alias_length
|
7
|
+
128
|
8
|
+
end
|
9
|
+
|
10
|
+
def column_name_length
|
11
|
+
128
|
12
|
+
end
|
13
|
+
|
14
|
+
def table_name_length
|
15
|
+
128
|
16
|
+
end
|
17
|
+
|
18
|
+
def index_name_length
|
19
|
+
128
|
20
|
+
end
|
21
|
+
|
22
|
+
def columns_per_table
|
23
|
+
1024
|
24
|
+
end
|
25
|
+
|
26
|
+
def indexes_per_table
|
27
|
+
999
|
28
|
+
end
|
29
|
+
|
30
|
+
def columns_per_multicolumn_index
|
31
|
+
16
|
32
|
+
end
|
33
|
+
|
34
|
+
def in_clause_length
|
35
|
+
65536
|
36
|
+
end
|
37
|
+
|
38
|
+
def sql_query_length
|
39
|
+
65536 * 4096
|
40
|
+
end
|
41
|
+
|
42
|
+
def joins_per_query
|
43
|
+
256
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|