activerecord-sqlserver-adapter_new 4.2.15

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 (132) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/CHANGELOG.md +212 -0
  4. data/CODE_OF_CONDUCT.md +31 -0
  5. data/Gemfile +61 -0
  6. data/Guardfile +29 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +201 -0
  9. data/RUNNING_UNIT_TESTS.md +121 -0
  10. data/Rakefile +48 -0
  11. data/VERSION +1 -0
  12. data/activerecord-sqlserver-adapter_new.gemspec +20 -0
  13. data/appveyor.yml +39 -0
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +27 -0
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +25 -0
  16. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +40 -0
  17. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +4 -0
  18. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +34 -0
  19. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +49 -0
  20. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +386 -0
  21. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +68 -0
  22. data/lib/active_record/connection_adapters/sqlserver/errors.rb +7 -0
  23. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +69 -0
  24. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +114 -0
  25. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +52 -0
  26. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +473 -0
  27. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +66 -0
  28. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +66 -0
  29. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +22 -0
  30. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +76 -0
  31. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +57 -0
  32. data/lib/active_record/connection_adapters/sqlserver/type.rb +46 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +15 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +15 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +12 -0
  36. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +38 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +21 -0
  38. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +41 -0
  39. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +17 -0
  40. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +31 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +12 -0
  42. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +15 -0
  43. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +12 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +21 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +15 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +13 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +21 -0
  48. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +22 -0
  49. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +12 -0
  50. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +15 -0
  51. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +40 -0
  52. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +76 -0
  53. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +15 -0
  54. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +22 -0
  55. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +15 -0
  56. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +12 -0
  57. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +15 -0
  58. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +20 -0
  59. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +20 -0
  60. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +23 -0
  61. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +20 -0
  62. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +20 -0
  63. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +20 -0
  64. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +20 -0
  65. data/lib/active_record/connection_adapters/sqlserver/utils.rb +136 -0
  66. data/lib/active_record/connection_adapters/sqlserver/version.rb +11 -0
  67. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +405 -0
  68. data/lib/active_record/connection_adapters/sqlserver_column.rb +53 -0
  69. data/lib/active_record/sqlserver_base.rb +20 -0
  70. data/lib/active_record/tasks/sqlserver_database_tasks.rb +131 -0
  71. data/lib/activerecord-sqlserver-adapter.rb +1 -0
  72. data/lib/arel/visitors/sqlserver.rb +214 -0
  73. data/lib/arel_sqlserver.rb +3 -0
  74. data/test/appveyor/dbsetup.ps1 +27 -0
  75. data/test/appveyor/dbsetup.sql +11 -0
  76. data/test/cases/adapter_test_sqlserver.rb +444 -0
  77. data/test/cases/coerced_tests.rb +713 -0
  78. data/test/cases/column_test_sqlserver.rb +780 -0
  79. data/test/cases/connection_test_sqlserver.rb +142 -0
  80. data/test/cases/execute_procedure_test_sqlserver.rb +44 -0
  81. data/test/cases/fetch_test_sqlserver.rb +57 -0
  82. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +76 -0
  83. data/test/cases/helper_sqlserver.rb +54 -0
  84. data/test/cases/migration_test_sqlserver.rb +61 -0
  85. data/test/cases/order_test_sqlserver.rb +147 -0
  86. data/test/cases/pessimistic_locking_test_sqlserver.rb +90 -0
  87. data/test/cases/rake_test_sqlserver.rb +163 -0
  88. data/test/cases/schema_dumper_test_sqlserver.rb +198 -0
  89. data/test/cases/schema_test_sqlserver.rb +54 -0
  90. data/test/cases/scratchpad_test_sqlserver.rb +9 -0
  91. data/test/cases/showplan_test_sqlserver.rb +65 -0
  92. data/test/cases/specific_schema_test_sqlserver.rb +167 -0
  93. data/test/cases/transaction_test_sqlserver.rb +66 -0
  94. data/test/cases/utils_test_sqlserver.rb +129 -0
  95. data/test/cases/uuid_test_sqlserver.rb +48 -0
  96. data/test/config.yml +41 -0
  97. data/test/debug.rb +14 -0
  98. data/test/fixtures/1px.gif +0 -0
  99. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +11 -0
  100. data/test/models/sqlserver/booking.rb +3 -0
  101. data/test/models/sqlserver/customers_view.rb +3 -0
  102. data/test/models/sqlserver/datatype.rb +3 -0
  103. data/test/models/sqlserver/datatype_migration.rb +3 -0
  104. data/test/models/sqlserver/dollar_table_name.rb +3 -0
  105. data/test/models/sqlserver/dot_table_name.rb +3 -0
  106. data/test/models/sqlserver/edge_schema.rb +13 -0
  107. data/test/models/sqlserver/fk_has_fk.rb +3 -0
  108. data/test/models/sqlserver/fk_has_pk.rb +3 -0
  109. data/test/models/sqlserver/natural_pk_data.rb +4 -0
  110. data/test/models/sqlserver/natural_pk_int_data.rb +3 -0
  111. data/test/models/sqlserver/no_pk_data.rb +3 -0
  112. data/test/models/sqlserver/object_default.rb +3 -0
  113. data/test/models/sqlserver/quoted_table.rb +7 -0
  114. data/test/models/sqlserver/quoted_view_1.rb +3 -0
  115. data/test/models/sqlserver/quoted_view_2.rb +3 -0
  116. data/test/models/sqlserver/string_default.rb +3 -0
  117. data/test/models/sqlserver/string_defaults_big_view.rb +3 -0
  118. data/test/models/sqlserver/string_defaults_view.rb +3 -0
  119. data/test/models/sqlserver/tinyint_pk.rb +3 -0
  120. data/test/models/sqlserver/upper.rb +3 -0
  121. data/test/models/sqlserver/uppered.rb +3 -0
  122. data/test/models/sqlserver/uuid.rb +3 -0
  123. data/test/schema/datatypes/2012.sql +55 -0
  124. data/test/schema/sqlserver_specific_schema.rb +207 -0
  125. data/test/support/coerceable_test_sqlserver.rb +45 -0
  126. data/test/support/connection_reflection.rb +37 -0
  127. data/test/support/load_schema_sqlserver.rb +29 -0
  128. data/test/support/minitest_sqlserver.rb +1 -0
  129. data/test/support/paths_sqlserver.rb +50 -0
  130. data/test/support/rake_helpers.rb +41 -0
  131. data/test/support/sql_counter_sqlserver.rb +32 -0
  132. metadata +253 -0
@@ -0,0 +1,66 @@
1
+ require 'active_record/connection_adapters/sqlserver/showplan/printer_table'
2
+ require 'active_record/connection_adapters/sqlserver/showplan/printer_xml'
3
+
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ module SQLServer
7
+ module Showplan
8
+
9
+ OPTION_ALL = 'SHOWPLAN_ALL'
10
+ OPTION_TEXT = 'SHOWPLAN_TEXT'
11
+ OPTION_XML = 'SHOWPLAN_XML'
12
+ OPTIONS = [OPTION_ALL, OPTION_TEXT, OPTION_XML]
13
+
14
+ def explain(arel, binds = [])
15
+ sql = to_sql(arel)
16
+ result = with_showplan_on { sp_executesql(sql, 'EXPLAIN', binds) }
17
+ printer = showplan_printer.new(result)
18
+ printer.pp
19
+ end
20
+
21
+ protected
22
+
23
+ def with_showplan_on
24
+ set_showplan_option(true)
25
+ yield
26
+ ensure
27
+ set_showplan_option(false)
28
+ end
29
+
30
+ def set_showplan_option(enable = true)
31
+ sql = "SET #{option} #{enable ? 'ON' : 'OFF'}"
32
+ raw_connection_do(sql)
33
+ rescue Exception
34
+ raise ActiveRecordError, "#{option} could not be turned #{enable ? 'ON' : 'OFF'}, perhaps you do not have SHOWPLAN permissions?"
35
+ end
36
+
37
+ def option
38
+ (SQLServerAdapter.showplan_option || OPTION_ALL).tap do |opt|
39
+ raise(ArgumentError, "Unknown SHOWPLAN option #{opt.inspect} found.") if OPTIONS.exclude?(opt)
40
+ end
41
+ end
42
+
43
+ def showplan_all?
44
+ option == OPTION_ALL
45
+ end
46
+
47
+ def showplan_text?
48
+ option == OPTION_TEXT
49
+ end
50
+
51
+ def showplan_xml?
52
+ option == OPTION_XML
53
+ end
54
+
55
+ def showplan_printer
56
+ case option
57
+ when OPTION_XML then PrinterXml
58
+ when OPTION_ALL, OPTION_TEXT then PrinterTable
59
+ else PrinterTable
60
+ end
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,66 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Showplan
5
+ class PrinterTable
6
+ cattr_accessor :max_column_width, :cell_padding
7
+ self.max_column_width = 50
8
+ self.cell_padding = 1
9
+
10
+ attr_reader :result
11
+
12
+ def initialize(result)
13
+ @result = result
14
+ end
15
+
16
+ def pp
17
+ @widths = compute_column_widths
18
+ @separator = build_separator
19
+ pp = []
20
+ pp << @separator
21
+ pp << build_cells(result.columns)
22
+ pp << @separator
23
+ result.rows.each do |row|
24
+ pp << build_cells(row)
25
+ end
26
+ pp << @separator
27
+ pp.join("\n") + "\n"
28
+ end
29
+
30
+ private
31
+
32
+ def compute_column_widths
33
+ [].tap do |computed_widths|
34
+ result.columns.each_with_index do |column, i|
35
+ cells_in_column = [column] + result.rows.map { |r| cast_item(r[i]) }
36
+ computed_width = cells_in_column.map(&:length).max
37
+ final_width = computed_width > max_column_width ? max_column_width : computed_width
38
+ computed_widths << final_width
39
+ end
40
+ end
41
+ end
42
+
43
+ def build_separator
44
+ '+' + @widths.map { |w| '-' * (w + (cell_padding * 2)) }.join('+') + '+'
45
+ end
46
+
47
+ def build_cells(items)
48
+ cells = []
49
+ items.each_with_index do |item, i|
50
+ cells << cast_item(item).ljust(@widths[i])
51
+ end
52
+ "| #{cells.join(' | ')} |"
53
+ end
54
+
55
+ def cast_item(item)
56
+ case item
57
+ when NilClass then 'NULL'
58
+ when Float then item.to_s.to(9)
59
+ else item.to_s.truncate(max_column_width)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Showplan
5
+ class PrinterXml
6
+ def initialize(result)
7
+ @result = result
8
+ end
9
+
10
+ def pp
11
+ xml = @result.rows.first.first
12
+ if defined?(Nokogiri)
13
+ Nokogiri::XML(xml).to_xml indent: 2, encoding: 'UTF-8'
14
+ else
15
+ xml
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,76 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
5
+
6
+ def primary_key(name, type = :primary_key, options = {})
7
+ return super unless type == :uuid
8
+ options[:default] = options.fetch(:default, 'NEWID()')
9
+ options[:primary_key] = true
10
+ column name, type, options
11
+ end
12
+
13
+ def real(name, options = {})
14
+ column(name, :real, options)
15
+ end
16
+
17
+ def money(name, options = {})
18
+ column(name, :money, options)
19
+ end
20
+
21
+ def datetime2(name, options = {})
22
+ column(name, :datetime2, options)
23
+ end
24
+
25
+ def datetimeoffset(name, options = {})
26
+ column(name, :datetimeoffset, options)
27
+ end
28
+
29
+ def smallmoney(name, options = {})
30
+ column(name, :smallmoney, options)
31
+ end
32
+
33
+ def char(name, options = {})
34
+ column(name, :char, options)
35
+ end
36
+
37
+ def varchar(name, options = {})
38
+ column(name, :varchar, options)
39
+ end
40
+
41
+ def varchar_max(name, options = {})
42
+ column(name, :varchar_max, options)
43
+ end
44
+
45
+ def text_basic(name, options = {})
46
+ column(name, :text_basic, options)
47
+ end
48
+
49
+ def nchar(name, options = {})
50
+ column(name, :nchar, options)
51
+ end
52
+
53
+ def ntext(name, options = {})
54
+ column(name, :ntext, options)
55
+ end
56
+
57
+ def binary_basic(name, options = {})
58
+ column(name, :binary_basic, options)
59
+ end
60
+
61
+ def varbinary(name, options = {})
62
+ column(name, :varbinary, options)
63
+ end
64
+
65
+ def uuid(name, options = {})
66
+ column(name, :uniqueidentifier, options)
67
+ end
68
+
69
+ def ss_timestamp(name, options = {})
70
+ column(name, :ss_timestamp, options)
71
+ end
72
+
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,57 @@
1
+ require 'active_record/connection_adapters/abstract/transaction'
2
+
3
+ module ActiveRecord
4
+ module ConnectionAdapters
5
+
6
+ module SQLServerTransaction
7
+
8
+ private
9
+
10
+ def sqlserver?
11
+ connection.respond_to?(:sqlserver?) && connection.sqlserver?
12
+ end
13
+
14
+ def current_isolation_level
15
+ return unless sqlserver?
16
+ level = connection.user_options_isolation_level
17
+ level.blank? ? 'READ COMMITTED' : level.upcase
18
+ end
19
+
20
+ end
21
+
22
+ Transaction.send :include, SQLServerTransaction
23
+
24
+ module SQLServerRealTransaction
25
+
26
+ attr_reader :starting_isolation_level
27
+
28
+ def initialize(connection, options)
29
+ @connection = connection
30
+ @starting_isolation_level = current_isolation_level if options[:isolation]
31
+ super
32
+ end
33
+
34
+ def commit
35
+ super
36
+ reset_starting_isolation_level
37
+ end
38
+
39
+ def rollback
40
+ super
41
+ reset_starting_isolation_level
42
+ end
43
+
44
+ private
45
+
46
+ def reset_starting_isolation_level
47
+ if sqlserver? && starting_isolation_level
48
+ connection.set_transaction_isolation_level(starting_isolation_level)
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ RealTransaction.send :include, SQLServerRealTransaction
55
+
56
+ end
57
+ end
@@ -0,0 +1,46 @@
1
+ require 'active_record/type'
2
+ # Exact Numerics
3
+ require 'active_record/connection_adapters/sqlserver/type/integer.rb'
4
+ require 'active_record/connection_adapters/sqlserver/type/big_integer.rb'
5
+ require 'active_record/connection_adapters/sqlserver/type/small_integer.rb'
6
+ require 'active_record/connection_adapters/sqlserver/type/tiny_integer.rb'
7
+ require 'active_record/connection_adapters/sqlserver/type/boolean.rb'
8
+ require 'active_record/connection_adapters/sqlserver/type/decimal.rb'
9
+ require 'active_record/connection_adapters/sqlserver/type/money.rb'
10
+ require 'active_record/connection_adapters/sqlserver/type/small_money.rb'
11
+ # Approximate Numerics
12
+ require 'active_record/connection_adapters/sqlserver/type/float.rb'
13
+ require 'active_record/connection_adapters/sqlserver/type/real.rb'
14
+ # Date and Time
15
+ require 'active_record/connection_adapters/sqlserver/type/time_value_fractional.rb'
16
+ require 'active_record/connection_adapters/sqlserver/type/date.rb'
17
+ require 'active_record/connection_adapters/sqlserver/type/datetime.rb'
18
+ require 'active_record/connection_adapters/sqlserver/type/datetime2.rb'
19
+ require 'active_record/connection_adapters/sqlserver/type/datetimeoffset.rb'
20
+ require 'active_record/connection_adapters/sqlserver/type/smalldatetime.rb'
21
+ require 'active_record/connection_adapters/sqlserver/type/time.rb'
22
+ # Character Strings
23
+ require 'active_record/connection_adapters/sqlserver/type/string.rb'
24
+ require 'active_record/connection_adapters/sqlserver/type/char.rb'
25
+ require 'active_record/connection_adapters/sqlserver/type/varchar.rb'
26
+ require 'active_record/connection_adapters/sqlserver/type/varchar_max.rb'
27
+ require 'active_record/connection_adapters/sqlserver/type/text.rb'
28
+ # Unicode Character Strings
29
+ require 'active_record/connection_adapters/sqlserver/type/unicode_string.rb'
30
+ require 'active_record/connection_adapters/sqlserver/type/unicode_char.rb'
31
+ require 'active_record/connection_adapters/sqlserver/type/unicode_varchar.rb'
32
+ require 'active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb'
33
+ require 'active_record/connection_adapters/sqlserver/type/unicode_text.rb'
34
+ # Binary Strings
35
+ require 'active_record/connection_adapters/sqlserver/type/binary.rb'
36
+ require 'active_record/connection_adapters/sqlserver/type/varbinary.rb'
37
+ require 'active_record/connection_adapters/sqlserver/type/varbinary_max.rb'
38
+ # Other Data Types
39
+ require 'active_record/connection_adapters/sqlserver/type/uuid.rb'
40
+ require 'active_record/connection_adapters/sqlserver/type/timestamp.rb'
41
+
42
+ module ActiveRecord
43
+ module Type
44
+ SQLServer = ConnectionAdapters::SQLServer::Type
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class BigInteger < Integer
6
+
7
+ def type
8
+ :bigint
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class Binary < ActiveRecord::Type::Binary
6
+
7
+ def type
8
+ :binary_basic
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class Boolean < ActiveRecord::Type::Boolean
6
+
7
+
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,38 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class Char < String
6
+
7
+ def type
8
+ :char
9
+ end
10
+
11
+ def type_cast_for_database(value)
12
+ return if value.nil?
13
+ return value if value.is_a?(Data)
14
+ Data.new(super)
15
+ end
16
+
17
+ class Data
18
+
19
+ def initialize(value)
20
+ @value = value.to_s
21
+ end
22
+
23
+ def quoted
24
+ "'#{Utils.quote_string(@value)}'"
25
+ end
26
+
27
+ def to_s
28
+ @value
29
+ end
30
+ alias_method :to_str, :to_s
31
+
32
+ end
33
+
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ module Type
5
+ class Date < ActiveRecord::Type::Date
6
+
7
+ def type_cast_for_database(value)
8
+ return unless value.present?
9
+ return value if value.acts_like?(:string)
10
+ value.to_s(:_sqlserver_dateformat)
11
+ end
12
+
13
+ def type_cast_for_schema(value)
14
+ type_cast_for_database(value).inspect
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end