activerecord-sqlserver-adapter 6.0.0.rc1 → 6.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +29 -0
  4. data/CHANGELOG.md +20 -0
  5. data/Gemfile +11 -5
  6. data/Guardfile +9 -8
  7. data/Rakefile +12 -16
  8. data/VERSION +1 -1
  9. data/activerecord-sqlserver-adapter.gemspec +3 -3
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +0 -4
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +1 -4
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +3 -4
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +1 -3
  14. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -3
  15. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +2 -3
  16. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +35 -32
  17. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +7 -12
  18. data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -3
  19. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +8 -8
  20. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -2
  21. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +7 -7
  22. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +106 -103
  23. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +6 -8
  24. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +2 -2
  25. data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
  26. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +0 -2
  27. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +1 -4
  28. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -8
  29. data/lib/active_record/connection_adapters/sqlserver/type.rb +35 -35
  30. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -2
  31. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +0 -2
  32. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +0 -2
  33. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +2 -2
  34. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +0 -2
  35. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +2 -3
  36. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +2 -3
  37. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +0 -2
  38. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +0 -2
  39. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +0 -2
  40. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +0 -2
  41. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +0 -2
  42. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +0 -1
  43. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +0 -2
  44. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +0 -2
  45. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +0 -2
  46. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +0 -2
  47. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +0 -2
  48. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +0 -2
  49. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +0 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +2 -3
  51. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +6 -9
  52. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +0 -2
  53. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +0 -2
  54. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +1 -3
  55. data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +0 -2
  56. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +0 -2
  57. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +0 -2
  58. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +0 -2
  59. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +1 -2
  60. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +1 -3
  61. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +0 -2
  62. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +1 -3
  63. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +0 -2
  64. data/lib/active_record/connection_adapters/sqlserver/utils.rb +8 -11
  65. data/lib/active_record/connection_adapters/sqlserver/version.rb +0 -2
  66. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +85 -83
  67. data/lib/active_record/connection_adapters/sqlserver_column.rb +0 -2
  68. data/lib/active_record/sqlserver_base.rb +1 -1
  69. data/lib/active_record/tasks/sqlserver_database_tasks.rb +26 -32
  70. data/lib/activerecord-sqlserver-adapter.rb +1 -1
  71. data/lib/arel/visitors/sqlserver.rb +18 -14
  72. data/lib/arel_sqlserver.rb +2 -2
  73. data/test/cases/adapter_test_sqlserver.rb +161 -182
  74. data/test/cases/change_column_null_test_sqlserver.rb +12 -12
  75. data/test/cases/coerced_tests.rb +88 -270
  76. data/test/cases/column_test_sqlserver.rb +281 -283
  77. data/test/cases/connection_test_sqlserver.rb +15 -20
  78. data/test/cases/execute_procedure_test_sqlserver.rb +18 -20
  79. data/test/cases/fetch_test_sqlserver.rb +14 -22
  80. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +12 -18
  81. data/test/cases/helper_sqlserver.rb +13 -15
  82. data/test/cases/in_clause_test_sqlserver.rb +9 -9
  83. data/test/cases/index_test_sqlserver.rb +13 -15
  84. data/test/cases/json_test_sqlserver.rb +23 -25
  85. data/test/cases/migration_test_sqlserver.rb +22 -28
  86. data/test/cases/order_test_sqlserver.rb +51 -54
  87. data/test/cases/pessimistic_locking_test_sqlserver.rb +25 -33
  88. data/test/cases/rake_test_sqlserver.rb +31 -45
  89. data/test/cases/schema_dumper_test_sqlserver.rb +104 -108
  90. data/test/cases/schema_test_sqlserver.rb +18 -26
  91. data/test/cases/scratchpad_test_sqlserver.rb +2 -4
  92. data/test/cases/showplan_test_sqlserver.rb +24 -33
  93. data/test/cases/specific_schema_test_sqlserver.rb +66 -65
  94. data/test/cases/transaction_test_sqlserver.rb +16 -19
  95. data/test/cases/trigger_test_sqlserver.rb +12 -12
  96. data/test/cases/utils_test_sqlserver.rb +68 -70
  97. data/test/cases/uuid_test_sqlserver.rb +11 -13
  98. data/test/debug.rb +6 -6
  99. data/test/migrations/create_clients_and_change_column_null.rb +1 -1
  100. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +2 -4
  101. data/test/models/sqlserver/booking.rb +1 -1
  102. data/test/models/sqlserver/customers_view.rb +1 -1
  103. data/test/models/sqlserver/dollar_table_name.rb +1 -1
  104. data/test/models/sqlserver/edge_schema.rb +1 -3
  105. data/test/models/sqlserver/fk_has_fk.rb +1 -1
  106. data/test/models/sqlserver/fk_has_pk.rb +1 -1
  107. data/test/models/sqlserver/natural_pk_data.rb +2 -2
  108. data/test/models/sqlserver/natural_pk_int_data.rb +1 -1
  109. data/test/models/sqlserver/no_pk_data.rb +1 -1
  110. data/test/models/sqlserver/object_default.rb +1 -1
  111. data/test/models/sqlserver/quoted_table.rb +2 -2
  112. data/test/models/sqlserver/quoted_view_1.rb +1 -1
  113. data/test/models/sqlserver/quoted_view_2.rb +1 -1
  114. data/test/models/sqlserver/sst_memory.rb +1 -1
  115. data/test/models/sqlserver/string_default.rb +1 -1
  116. data/test/models/sqlserver/string_defaults_big_view.rb +1 -1
  117. data/test/models/sqlserver/string_defaults_view.rb +1 -1
  118. data/test/models/sqlserver/tinyint_pk.rb +1 -1
  119. data/test/models/sqlserver/trigger.rb +2 -2
  120. data/test/models/sqlserver/trigger_history.rb +1 -1
  121. data/test/models/sqlserver/upper.rb +1 -1
  122. data/test/models/sqlserver/uppered.rb +1 -1
  123. data/test/models/sqlserver/uuid.rb +1 -1
  124. data/test/schema/sqlserver_specific_schema.rb +20 -22
  125. data/test/support/coerceable_test_sqlserver.rb +1 -4
  126. data/test/support/connection_reflection.rb +1 -2
  127. data/test/support/core_ext/query_cache.rb +1 -1
  128. data/test/support/load_schema_sqlserver.rb +3 -5
  129. data/test/support/minitest_sqlserver.rb +1 -1
  130. data/test/support/paths_sqlserver.rb +9 -11
  131. data/test/support/rake_helpers.rb +12 -10
  132. data/test/support/sql_counter_sqlserver.rb +0 -4
  133. data/test/support/test_in_memory_oltp.rb +7 -7
  134. metadata +5 -4
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  module DatabaseTasks
7
-
8
7
  def create_database(database, options = {})
9
8
  name = SQLServer::Utils.extract_identifiers(database)
10
9
  db_options = create_database_options(options)
@@ -19,7 +18,7 @@ module ActiveRecord
19
18
  end
20
19
 
21
20
  def current_database
22
- select_value 'SELECT DB_NAME()'
21
+ select_value "SELECT DB_NAME()"
23
22
  end
24
23
 
25
24
  def charset
@@ -32,20 +31,20 @@ module ActiveRecord
32
31
 
33
32
  private
34
33
 
35
- def create_database_options(options={})
34
+ def create_database_options(options = {})
36
35
  keys = [:collate]
37
36
  copts = @connection_options
38
37
  options = {
39
38
  collate: copts[:collation]
40
39
  }.merge(options.symbolize_keys).select { |_, v|
41
40
  v.present?
42
- }.slice(*keys).map { |k,v|
41
+ }.slice(*keys).map { |k, v|
43
42
  "#{k.to_s.upcase} #{v}"
44
- }.join(' ')
43
+ }.join(" ")
45
44
  options
46
45
  end
47
46
 
48
- def create_database_edition_options(options={})
47
+ def create_database_edition_options(options = {})
49
48
  keys = [:maxsize, :edition, :service_objective]
50
49
  copts = @connection_options
51
50
  edition_options = {
@@ -54,17 +53,13 @@ module ActiveRecord
54
53
  service_objective: copts[:azure_service_objective]
55
54
  }.merge(options.symbolize_keys).select { |_, v|
56
55
  v.present?
57
- }.slice(*keys).map { |k,v|
56
+ }.slice(*keys).map { |k, v|
58
57
  "#{k.to_s.upcase} = #{v}"
59
- }.join(', ')
58
+ }.join(", ")
60
59
  edition_options = "( #{edition_options} )" if edition_options.present?
61
60
  edition_options
62
61
  end
63
-
64
62
  end
65
63
  end
66
64
  end
67
65
  end
68
-
69
-
70
-
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActiveRecord
4
-
5
4
  class DeadlockVictim < WrappedDatabaseException
6
5
  end
7
-
8
-
9
6
  end
@@ -4,10 +4,9 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  module Quoting
7
-
8
- QUOTED_TRUE = '1'.freeze
9
- QUOTED_FALSE = '0'.freeze
10
- QUOTED_STRING_PREFIX = 'N'.freeze
7
+ QUOTED_TRUE = "1".freeze
8
+ QUOTED_FALSE = "0".freeze
9
+ QUOTED_STRING_PREFIX = "N".freeze
11
10
 
12
11
  def fetch_type_metadata(sql_type, sqlserver_options = {})
13
12
  cast_type = lookup_cast_type(sql_type)
@@ -63,10 +62,12 @@ module ActiveRecord
63
62
  end
64
63
 
65
64
  def quoted_date(value)
66
- if value.acts_like?(:date)
67
- Type::Date.new.serialize(value)
68
- else value.acts_like?(:time)
65
+ if value.acts_like?(:time)
69
66
  Type::DateTime.new.serialize(value)
67
+ elsif value.acts_like?(:date)
68
+ Type::Date.new.serialize(value)
69
+ else
70
+ value
70
71
  end
71
72
  end
72
73
 
@@ -130,7 +131,6 @@ module ActiveRecord
130
131
  super
131
132
  end
132
133
  end
133
-
134
134
  end
135
135
  end
136
136
  end
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  class SchemaCreation < AbstractAdapter::SchemaCreation
7
-
8
7
  private
9
8
 
10
9
  def visit_TableDefinition(o)
@@ -63,7 +62,6 @@ module ActiveRecord
63
62
  def options_primary_key_with_nil_default?(options)
64
63
  options[:primary_key] && options.include?(:default) && options[:default].nil?
65
64
  end
66
-
67
65
  end
68
66
  end
69
67
  end
@@ -4,13 +4,12 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  class SchemaDumper < ConnectionAdapters::SchemaDumper
7
-
8
7
  SQLSEVER_NO_LIMIT_TYPES = [
9
- 'text',
10
- 'ntext',
11
- 'varchar(max)',
12
- 'nvarchar(max)',
13
- 'varbinary(max)'
8
+ "text",
9
+ "ntext",
10
+ "varchar(max)",
11
+ "nvarchar(max)",
12
+ "varbinary(max)"
14
13
  ].freeze
15
14
 
16
15
  private
@@ -21,18 +20,19 @@ module ActiveRecord
21
20
 
22
21
  def schema_limit(column)
23
22
  return if SQLSEVER_NO_LIMIT_TYPES.include?(column.sql_type)
23
+
24
24
  super
25
25
  end
26
26
 
27
27
  def schema_collation(column)
28
28
  return unless column.collation
29
+
29
30
  column.collation if column.collation != @connection.collation
30
31
  end
31
32
 
32
33
  def default_primary_key?(column)
33
34
  super && column.is_primary? && column.is_identity?
34
35
  end
35
-
36
36
  end
37
37
  end
38
38
  end
@@ -4,7 +4,6 @@ module ActiveRecord
4
4
  module ConnectionAdapters
5
5
  module SQLServer
6
6
  module SchemaStatements
7
-
8
7
  def native_database_types
9
8
  @native_database_types ||= initialize_native_database_types.freeze
10
9
  end
@@ -19,11 +18,11 @@ module ActiveRecord
19
18
  # Mimic CASCADE option as best we can.
20
19
  if options[:force] == :cascade
21
20
  execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata|
22
- fktable = fkdata['FKTABLE_NAME']
23
- fkcolmn = fkdata['FKCOLUMN_NAME']
24
- pktable = fkdata['PKTABLE_NAME']
25
- pkcolmn = fkdata['PKCOLUMN_NAME']
26
- remove_foreign_key fktable, name: fkdata['FK_NAME']
21
+ fktable = fkdata["FKTABLE_NAME"]
22
+ fkcolmn = fkdata["FKCOLUMN_NAME"]
23
+ pktable = fkdata["PKTABLE_NAME"]
24
+ pkcolmn = fkdata["PKCOLUMN_NAME"]
25
+ remove_foreign_key fktable, name: fkdata["FK_NAME"]
27
26
  do_execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )"
28
27
  end
29
28
  end
@@ -49,11 +48,11 @@ module ActiveRecord
49
48
  orders = {}
50
49
  columns = []
51
50
 
52
- index[:index_keys].split(',').each do |column|
51
+ index[:index_keys].split(",").each do |column|
53
52
  column.strip!
54
53
 
55
- if column.ends_with?('(-)')
56
- column.gsub! '(-)', ''
54
+ if column.ends_with?("(-)")
55
+ column.gsub! "(-)", ""
57
56
  orders[column] = :desc
58
57
  end
59
58
 
@@ -67,6 +66,7 @@ module ActiveRecord
67
66
 
68
67
  def columns(table_name)
69
68
  return [] if table_name.blank?
69
+
70
70
  column_definitions(table_name).map do |ci|
71
71
  sqlserver_options = ci.slice :ordinal_position, :is_primary, :is_identity, :table_name
72
72
  sql_type_metadata = fetch_type_metadata ci[:type], sqlserver_options
@@ -105,7 +105,7 @@ module ActiveRecord
105
105
  identifier = database_prefix_identifier(table_name)
106
106
  database = identifier.fully_qualified_database_quoted
107
107
  sql = %{
108
- SELECT KCU.COLUMN_NAME AS [name]
108
+ SELECT #{lowercase_schema_reflection_sql('KCU.COLUMN_NAME')} AS [name]
109
109
  FROM #{database}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
110
110
  LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
111
111
  ON KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
@@ -117,12 +117,12 @@ module ActiveRecord
117
117
  AND KCU.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : (prepared_statements ? '@1' : quote(identifier.schema))}
118
118
  AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
119
119
  ORDER BY KCU.ORDINAL_POSITION ASC
120
- }.gsub(/[[:space:]]/, ' ')
120
+ }.gsub(/[[:space:]]/, " ")
121
121
  binds = []
122
122
  nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
123
- binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
124
- binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
125
- sp_executesql(sql, 'SCHEMA', binds).map { |r| r['name'] }
123
+ binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128)
124
+ binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank?
125
+ sp_executesql(sql, "SCHEMA", binds).map { |r| r["name"] }
126
126
  end
127
127
 
128
128
  def rename_table(table_name, new_name)
@@ -131,7 +131,8 @@ module ActiveRecord
131
131
  end
132
132
 
133
133
  def remove_column(table_name, column_name, type = nil, options = {})
134
- raise ArgumentError.new('You must specify at least one column name. Example: remove_column(:people, :first_name)') if column_name.is_a? Array
134
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_name.is_a? Array
135
+
135
136
  remove_check_constraints(table_name, column_name)
136
137
  remove_default_constraint(table_name, column_name)
137
138
  remove_indexes(table_name, column_name)
@@ -144,10 +145,10 @@ module ActiveRecord
144
145
  column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s }
145
146
  without_constraints = options.key?(:default) || options.key?(:limit)
146
147
  default = if !options.key?(:default) && column_object
147
- column_object.default
148
- else
149
- options[:default]
150
- end
148
+ column_object.default
149
+ else
150
+ options[:default]
151
+ end
151
152
  if without_constraints || (column_object && column_object.type != type.to_sym)
152
153
  remove_default_constraint(table_name, column_name)
153
154
  indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) }
@@ -155,7 +156,7 @@ module ActiveRecord
155
156
  end
156
157
  sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_expression(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil?
157
158
  alter_command = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, limit: options[:limit], precision: options[:precision], scale: options[:scale])}"
158
- alter_command += ' NOT NULL' if !options[:null].nil? && options[:null] == false
159
+ alter_command += " NOT NULL" if !options[:null].nil? && options[:null] == false
159
160
  sql_commands << alter_command
160
161
  if without_constraints
161
162
  default = quote_default_expression(default, column_object || column_for(table_name, column_name))
@@ -173,6 +174,7 @@ module ActiveRecord
173
174
  clear_cache!
174
175
  column = column_for(table_name, column_name)
175
176
  return unless column
177
+
176
178
  remove_default_constraint(table_name, column_name)
177
179
  default = extract_new_default_value(default_or_changes)
178
180
  do_execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_expression(default, column)} FOR #{quote_column_name(column_name)}"
@@ -182,15 +184,16 @@ module ActiveRecord
182
184
  def rename_column(table_name, column_name, new_column_name)
183
185
  clear_cache!
184
186
  identifier = SQLServer::Utils.extract_identifiers("#{table_name}.#{column_name}")
185
- execute_procedure :sp_rename, identifier.quoted, new_column_name, 'COLUMN'
187
+ execute_procedure :sp_rename, identifier.quoted, new_column_name, "COLUMN"
186
188
  rename_column_indexes(table_name, column_name, new_column_name)
187
189
  clear_cache!
188
190
  end
189
191
 
190
192
  def rename_index(table_name, old_name, new_name)
191
193
  raise ArgumentError, "Index name '#{new_name}' on table '#{table_name}' is too long; the limit is #{allowed_index_name_length} characters" if new_name.length > allowed_index_name_length
194
+
192
195
  identifier = SQLServer::Utils.extract_identifiers("#{table_name}.#{old_name}")
193
- execute_procedure :sp_rename, identifier.quoted, new_name, 'INDEX'
196
+ execute_procedure :sp_rename, identifier.quoted, new_name, "INDEX"
194
197
  end
195
198
 
196
199
  def remove_index!(table_name, index_name)
@@ -202,13 +205,13 @@ module ActiveRecord
202
205
  fk_info = execute_procedure :sp_fkeys, nil, identifier.schema, nil, identifier.object, identifier.schema
203
206
  fk_info.map do |row|
204
207
  from_table = identifier.object
205
- to_table = row['PKTABLE_NAME']
208
+ to_table = row["PKTABLE_NAME"]
206
209
  options = {
207
- name: row['FK_NAME'],
208
- column: row['FKCOLUMN_NAME'],
209
- primary_key: row['PKCOLUMN_NAME'],
210
- on_update: extract_foreign_key_action('update', row['FK_NAME']),
211
- on_delete: extract_foreign_key_action('delete', row['FK_NAME'])
210
+ name: row["FK_NAME"],
211
+ column: row["FKCOLUMN_NAME"],
212
+ primary_key: row["PKCOLUMN_NAME"],
213
+ on_update: extract_foreign_key_action("update", row["FK_NAME"]),
214
+ on_delete: extract_foreign_key_action("delete", row["FK_NAME"])
212
215
  }
213
216
  ForeignKeyDefinition.new from_table, to_table, options
214
217
  end
@@ -216,8 +219,8 @@ module ActiveRecord
216
219
 
217
220
  def extract_foreign_key_action(action, fk_name)
218
221
  case select_value("SELECT #{action}_referential_action_desc FROM sys.foreign_keys WHERE name = '#{fk_name}'")
219
- when 'CASCADE' then :cascade
220
- when 'SET_NULL' then :nullify
222
+ when "CASCADE" then :cascade
223
+ when "SET_NULL" then :nullify
221
224
  end
222
225
  end
223
226
 
@@ -225,15 +228,15 @@ module ActiveRecord
225
228
  type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
226
229
  limit = nil unless type_limitable
227
230
  case type.to_s
228
- when 'integer'
231
+ when "integer"
229
232
  case limit
230
- when 1 then 'tinyint'
231
- when 2 then 'smallint'
232
- when 3..4, nil then 'integer'
233
- when 5..8 then 'bigint'
233
+ when 1 then "tinyint"
234
+ when 2 then "smallint"
235
+ when 3..4, nil then "integer"
236
+ when 5..8 then "bigint"
234
237
  else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
235
238
  end
236
- when 'datetime2'
239
+ when "datetime2"
237
240
  column_type_sql = super
238
241
  if precision
239
242
  if (0..7) === precision
@@ -249,11 +252,11 @@ module ActiveRecord
249
252
  end
250
253
 
251
254
  def columns_for_distinct(columns, orders)
252
- order_columns = orders.reject(&:blank?).map{ |s|
253
- s = s.to_sql unless s.is_a?(String)
254
- s.gsub(/\s+(?:ASC|DESC)\b/i, '')
255
- .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
256
- }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
255
+ order_columns = orders.reject(&:blank?).map { |s|
256
+ s = s.to_sql unless s.is_a?(String)
257
+ s.gsub(/\s+(?:ASC|DESC)\b/i, "")
258
+ .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, "")
259
+ }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
257
260
 
258
261
  (order_columns << super).join(", ")
259
262
  end
@@ -270,7 +273,7 @@ module ActiveRecord
270
273
  do_execute("UPDATE #{table_id} SET #{column_id}=#{quote(default)} WHERE #{column_id} IS NULL")
271
274
  end
272
275
  sql = "ALTER TABLE #{table_id} ALTER COLUMN #{column_id} #{type_to_sql column.type, limit: column.limit, precision: column.precision, scale: column.scale}"
273
- sql += ' NOT NULL' if !allow_null.nil? && allow_null == false
276
+ sql += " NOT NULL" if !allow_null.nil? && allow_null == false
274
277
  do_execute sql
275
278
  end
276
279
 
@@ -282,10 +285,10 @@ module ActiveRecord
282
285
 
283
286
  def data_source_sql(name = nil, type: nil)
284
287
  scope = quoted_scope name, type: type
285
- table_name = lowercase_schema_reflection_sql 'TABLE_NAME'
288
+ table_name = lowercase_schema_reflection_sql "TABLE_NAME"
286
289
  sql = "SELECT #{table_name}"
287
- sql += ' FROM INFORMATION_SCHEMA.TABLES WITH (NOLOCK)'
288
- sql += ' WHERE TABLE_CATALOG = DB_NAME()'
290
+ sql += " FROM INFORMATION_SCHEMA.TABLES WITH (NOLOCK)"
291
+ sql += " WHERE TABLE_CATALOG = DB_NAME()"
289
292
  sql += " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
290
293
  sql += " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
291
294
  sql += " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
@@ -296,7 +299,7 @@ module ActiveRecord
296
299
  def quoted_scope(name = nil, type: nil)
297
300
  identifier = SQLServer::Utils.extract_identifiers(name)
298
301
  {}.tap do |scope|
299
- scope[:schema] = identifier.schema || 'dbo'
302
+ scope[:schema] = identifier.schema || "dbo"
300
303
  scope[:name] = identifier.object if identifier.object
301
304
  scope[:type] = type if type
302
305
  end
@@ -306,37 +309,37 @@ module ActiveRecord
306
309
 
307
310
  def initialize_native_database_types
308
311
  {
309
- primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
310
- primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
311
- integer: { name: 'int', limit: 4 },
312
- bigint: { name: 'bigint' },
313
- boolean: { name: 'bit' },
314
- decimal: { name: 'decimal' },
315
- money: { name: 'money' },
316
- smallmoney: { name: 'smallmoney' },
317
- float: { name: 'float' },
318
- real: { name: 'real' },
319
- date: { name: 'date' },
320
- datetime: { name: 'datetime' },
321
- datetime2: { name: 'datetime2' },
322
- datetimeoffset: { name: 'datetimeoffset' },
323
- smalldatetime: { name: 'smalldatetime' },
324
- timestamp: { name: 'datetime' },
325
- time: { name: 'time' },
326
- char: { name: 'char' },
327
- varchar: { name: 'varchar', limit: 8000 },
328
- varchar_max: { name: 'varchar(max)' },
329
- text_basic: { name: 'text' },
330
- nchar: { name: 'nchar' },
331
- string: { name: 'nvarchar', limit: 4000 },
332
- text: { name: 'nvarchar(max)' },
333
- ntext: { name: 'ntext' },
334
- binary_basic: { name: 'binary' },
335
- varbinary: { name: 'varbinary', limit: 8000 },
336
- binary: { name: 'varbinary(max)' },
337
- uuid: { name: 'uniqueidentifier' },
338
- ss_timestamp: { name: 'timestamp' },
339
- json: { name: 'nvarchar(max)' }
312
+ primary_key: "bigint NOT NULL IDENTITY(1,1) PRIMARY KEY",
313
+ primary_key_nonclustered: "int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED",
314
+ integer: { name: "int", limit: 4 },
315
+ bigint: { name: "bigint" },
316
+ boolean: { name: "bit" },
317
+ decimal: { name: "decimal" },
318
+ money: { name: "money" },
319
+ smallmoney: { name: "smallmoney" },
320
+ float: { name: "float" },
321
+ real: { name: "real" },
322
+ date: { name: "date" },
323
+ datetime: { name: "datetime" },
324
+ datetime2: { name: "datetime2" },
325
+ datetimeoffset: { name: "datetimeoffset" },
326
+ smalldatetime: { name: "smalldatetime" },
327
+ timestamp: { name: "datetime" },
328
+ time: { name: "time" },
329
+ char: { name: "char" },
330
+ varchar: { name: "varchar", limit: 8000 },
331
+ varchar_max: { name: "varchar(max)" },
332
+ text_basic: { name: "text" },
333
+ nchar: { name: "nchar" },
334
+ string: { name: "nvarchar", limit: 4000 },
335
+ text: { name: "nvarchar(max)" },
336
+ ntext: { name: "ntext" },
337
+ binary_basic: { name: "binary" },
338
+ varbinary: { name: "varbinary", limit: 8000 },
339
+ binary: { name: "varbinary(max)" },
340
+ uuid: { name: "uniqueidentifier" },
341
+ ss_timestamp: { name: "timestamp" },
342
+ json: { name: "nvarchar(max)" }
340
343
  }
341
344
  end
342
345
 
@@ -350,9 +353,9 @@ module ActiveRecord
350
353
 
351
354
  binds = []
352
355
  nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
353
- binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
354
- binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
355
- results = sp_executesql(sql, 'SCHEMA', binds)
356
+ binds << Relation::QueryAttribute.new("TABLE_NAME", identifier.object, nv128)
357
+ binds << Relation::QueryAttribute.new("TABLE_SCHEMA", identifier.schema, nv128) unless identifier.schema.blank?
358
+ results = sp_executesql(sql, "SCHEMA", binds)
356
359
  results.map do |ci|
357
360
  ci = ci.symbolize_keys
358
361
  ci[:_type] = ci[:type]
@@ -383,7 +386,7 @@ module ActiveRecord
383
386
  WHERE
384
387
  c.TABLE_NAME = '#{view_tblnm}'
385
388
  AND c.COLUMN_NAME = '#{views_real_column_name(table_name, ci[:name])}'
386
- }.squish, 'SCHEMA'
389
+ }.squish, "SCHEMA"
387
390
  end
388
391
  case default
389
392
  when nil
@@ -402,7 +405,7 @@ module ActiveRecord
402
405
  else ci[:type]
403
406
  end
404
407
  value = default.match(/\A\((.*)\)\Z/m)[1]
405
- value = select_value("SELECT CAST(#{value} AS #{type}) AS value", 'SCHEMA')
408
+ value = select_value("SELECT CAST(#{value} AS #{type}) AS value", "SCHEMA")
406
409
  [value, nil]
407
410
  end
408
411
  end
@@ -415,11 +418,11 @@ module ActiveRecord
415
418
  end
416
419
 
417
420
  def column_definitions_sql(database, identifier)
418
- object_name = prepared_statements ? '@0' : quote(identifier.object)
419
- schema_name = if identifier.schema.blank?
420
- 'schema_name()'
421
+ object_name = prepared_statements ? "@0" : quote(identifier.object)
422
+ schema_name = if identifier.schema.blank?
423
+ "schema_name()"
421
424
  else
422
- prepared_statements ? '@1' : quote(identifier.schema)
425
+ prepared_statements ? "@1" : quote(identifier.schema)
423
426
  end
424
427
 
425
428
  %{
@@ -478,11 +481,11 @@ module ActiveRecord
478
481
  AND s.name = #{schema_name}
479
482
  ORDER BY
480
483
  c.column_id
481
- }.gsub(/[ \t\r\n]+/, ' ').strip
484
+ }.gsub(/[ \t\r\n]+/, " ").strip
482
485
  end
483
486
 
484
487
  def remove_check_constraints(table_name, column_name)
485
- constraints = select_values "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{quote_string(table_name)}' and COLUMN_NAME = '#{quote_string(column_name)}'", 'SCHEMA'
488
+ constraints = select_values "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{quote_string(table_name)}' and COLUMN_NAME = '#{quote_string(column_name)}'", "SCHEMA"
486
489
  constraints.each do |constraint|
487
490
  do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint)}"
488
491
  end
@@ -490,8 +493,8 @@ module ActiveRecord
490
493
 
491
494
  def remove_default_constraint(table_name, column_name)
492
495
  # If their are foreign keys in this table, we could still get back a 2D array, so flatten just in case.
493
- execute_procedure(:sp_helpconstraint, table_name, 'nomsg').flatten.select do |row|
494
- row['constraint_type'] == "DEFAULT on column #{column_name}"
496
+ execute_procedure(:sp_helpconstraint, table_name, "nomsg").flatten.select do |row|
497
+ row["constraint_type"] == "DEFAULT on column #{column_name}"
495
498
  end.each do |row|
496
499
  do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{row['constraint_name']}"
497
500
  end
@@ -507,12 +510,12 @@ module ActiveRecord
507
510
 
508
511
  def get_table_name(sql)
509
512
  tn = if sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
510
- Regexp.last_match[3] || Regexp.last_match[4]
511
- elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
512
- Regexp.last_match[1]
513
- else
514
- nil
515
- end
513
+ Regexp.last_match[3] || Regexp.last_match[4]
514
+ elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
515
+ Regexp.last_match[1]
516
+ else
517
+ nil
518
+ end
516
519
  SQLServer::Utils.extract_identifiers(tn).object
517
520
  end
518
521
 
@@ -528,22 +531,22 @@ module ActiveRecord
528
531
 
529
532
  def view_table_name(table_name)
530
533
  view_info = view_information(table_name)
531
- view_info ? get_table_name(view_info['VIEW_DEFINITION']) : table_name
534
+ view_info ? get_table_name(view_info["VIEW_DEFINITION"]) : table_name
532
535
  end
533
536
 
534
537
  def view_information(table_name)
535
538
  @view_information ||= {}
536
539
  @view_information[table_name] ||= begin
537
540
  identifier = SQLServer::Utils.extract_identifiers(table_name)
538
- view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", 'SCHEMA'
541
+ view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", "SCHEMA"
539
542
  if view_info
540
543
  view_info = view_info.with_indifferent_access
541
544
  if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
542
545
  view_info[:VIEW_DEFINITION] = begin
543
- select_values("EXEC sp_helptext #{identifier.object_quoted}", 'SCHEMA').join
544
- rescue
545
- warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
546
- nil
546
+ select_values("EXEC sp_helptext #{identifier.object_quoted}", "SCHEMA").join
547
+ rescue
548
+ warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
549
+ nil
547
550
  end
548
551
  end
549
552
  end
@@ -554,6 +557,7 @@ module ActiveRecord
554
557
  def views_real_column_name(table_name, column_name)
555
558
  view_definition = view_information(table_name)[:VIEW_DEFINITION]
556
559
  return column_name unless view_definition
560
+
557
561
  match_data = view_definition.match(/([\w-]*)\s+as\s+#{column_name}/im)
558
562
  match_data ? match_data[1] : column_name
559
563
  end
@@ -561,7 +565,6 @@ module ActiveRecord
561
565
  def create_table_definition(*args, **options)
562
566
  SQLServer::TableDefinition.new(self, *args, **options)
563
567
  end
564
-
565
568
  end
566
569
  end
567
570
  end