activerecord-sqlserver-adapter 4.2.18 → 5.0.0

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -223
  3. data/Gemfile +18 -17
  4. data/RAILS5-TODO.md +36 -0
  5. data/README.md +27 -8
  6. data/RUNNING_UNIT_TESTS.md +0 -17
  7. data/Rakefile +2 -7
  8. data/VERSION +1 -1
  9. data/activerecord-sqlserver-adapter.gemspec +1 -1
  10. data/appveyor.yml +0 -2
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +15 -8
  12. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +45 -97
  13. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -2
  14. data/lib/active_record/connection_adapters/sqlserver/quoting.rb +31 -10
  15. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -18
  16. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -0
  17. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +101 -58
  18. data/lib/active_record/connection_adapters/sqlserver/showplan.rb +7 -7
  19. data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +20 -0
  20. data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +56 -32
  21. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +1 -1
  22. data/lib/active_record/connection_adapters/sqlserver/type.rb +34 -32
  23. data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +4 -0
  24. data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +6 -0
  25. data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -0
  26. data/lib/active_record/connection_adapters/sqlserver/type/char.rb +9 -20
  27. data/lib/active_record/connection_adapters/sqlserver/type/data.rb +30 -0
  28. data/lib/active_record/connection_adapters/sqlserver/type/date.rb +28 -4
  29. data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +28 -14
  30. data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
  31. data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +4 -16
  32. data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +9 -0
  33. data/lib/active_record/connection_adapters/sqlserver/type/float.rb +4 -0
  34. data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -0
  35. data/lib/active_record/connection_adapters/sqlserver/type/money.rb +5 -1
  36. data/lib/active_record/connection_adapters/sqlserver/type/real.rb +4 -0
  37. data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -1
  38. data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +5 -1
  39. data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +8 -1
  40. data/lib/active_record/connection_adapters/sqlserver/type/text.rb +4 -0
  41. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +20 -8
  42. data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +25 -10
  43. data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +4 -0
  44. data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -0
  45. data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +6 -0
  46. data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +4 -0
  47. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +7 -1
  48. data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +5 -1
  49. data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +15 -2
  50. data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +7 -1
  51. data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +5 -1
  52. data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +7 -1
  53. data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +5 -1
  54. data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -0
  55. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +71 -57
  56. data/lib/active_record/connection_adapters/sqlserver_column.rb +5 -30
  57. data/lib/active_record/sqlserver_base.rb +1 -5
  58. data/lib/arel/visitors/sqlserver.rb +11 -20
  59. data/test/bin/setup.sh +4 -6
  60. data/test/cases/adapter_test_sqlserver.rb +11 -20
  61. data/test/cases/coerced_tests.rb +233 -138
  62. data/test/cases/column_test_sqlserver.rb +244 -227
  63. data/test/cases/connection_test_sqlserver.rb +5 -76
  64. data/test/cases/fully_qualified_identifier_test_sqlserver.rb +7 -7
  65. data/test/cases/helper_sqlserver.rb +4 -15
  66. data/test/cases/pessimistic_locking_test_sqlserver.rb +1 -1
  67. data/test/cases/rake_test_sqlserver.rb +20 -14
  68. data/test/cases/schema_dumper_test_sqlserver.rb +94 -63
  69. data/test/cases/schema_test_sqlserver.rb +2 -2
  70. data/test/cases/showplan_test_sqlserver.rb +1 -1
  71. data/test/cases/specific_schema_test_sqlserver.rb +7 -14
  72. data/test/cases/transaction_test_sqlserver.rb +1 -1
  73. data/test/cases/uuid_test_sqlserver.rb +0 -1
  74. data/test/config.yml +0 -10
  75. data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
  76. data/test/schema/sqlserver_specific_schema.rb +0 -16
  77. data/test/support/coerceable_test_sqlserver.rb +6 -2
  78. data/test/support/connection_reflection.rb +0 -4
  79. data/test/support/sql_counter_sqlserver.rb +17 -21
  80. metadata +9 -7
  81. data/lib/active_record/connection_adapters/sqlserver/core_ext/odbc.rb +0 -34
  82. data/lib/active_record/connection_adapters/sqlserver/schema_cache.rb +0 -114
@@ -7,23 +7,38 @@ module ActiveRecord
7
7
  @native_database_types ||= initialize_native_database_types.freeze
8
8
  end
9
9
 
10
- def data_sources
11
- tables + views
10
+ def tables(name = nil)
11
+ ActiveSupport::Deprecation.warn 'Passing arguments to #tables is deprecated without replacement.' if name
12
+ tables_sql('BASE TABLE')
12
13
  end
13
14
 
14
- def tables(table_type = 'BASE TABLE')
15
- select_values "SELECT #{lowercase_schema_reflection_sql('TABLE_NAME')} FROM INFORMATION_SCHEMA.TABLES #{"WHERE TABLE_TYPE = '#{table_type}'" if table_type} ORDER BY TABLE_NAME", 'SCHEMA'
15
+ def table_exists?(table_name)
16
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
17
+ #table_exists? currently checks both tables and views.
18
+ This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
19
+ Use #data_source_exists? instead.
20
+ MSG
21
+ data_source_exists?(table_name)
16
22
  end
17
23
 
18
- def table_exists?(table_name)
24
+ def data_source_exists?(table_name)
19
25
  return false if table_name.blank?
20
26
  unquoted_table_name = SQLServer::Utils.extract_identifiers(table_name).object
21
- super || tables.include?(unquoted_table_name) || views.include?(unquoted_table_name)
27
+ super(unquoted_table_name)
28
+ end
29
+
30
+ def views
31
+ tables_sql('VIEW')
32
+ end
33
+
34
+ def view_exists?(table_name)
35
+ identifier = SQLServer::Utils.extract_identifiers(table_name)
36
+ super(identifier.object)
22
37
  end
23
38
 
24
- def create_table(table_name, options = {})
39
+ def create_table(table_name, comment: nil, **options)
25
40
  res = super
26
- schema_cache.clear_table_cache!(table_name)
41
+ clear_cache!
27
42
  res
28
43
  end
29
44
 
@@ -47,17 +62,41 @@ module ActiveRecord
47
62
  end
48
63
  end
49
64
 
50
- def columns(table_name, _name = nil)
65
+ def columns(table_name)
51
66
  return [] if table_name.blank?
52
67
  column_definitions(table_name).map do |ci|
53
- sqlserver_options = ci.slice :ordinal_position, :is_primary, :is_identity, :default_function, :table_name, :collation
54
- cast_type = lookup_cast_type(ci[:type])
55
- new_column ci[:name], ci[:default_value], cast_type, ci[:type], ci[:null], sqlserver_options
68
+ sqlserver_options = ci.slice :ordinal_position, :is_primary, :is_identity
69
+ sql_type_metadata = fetch_type_metadata ci[:type], sqlserver_options
70
+ new_column(
71
+ ci[:name],
72
+ ci[:default_value],
73
+ sql_type_metadata,
74
+ ci[:null],
75
+ ci[:table_name],
76
+ ci[:default_function],
77
+ ci[:collation],
78
+ nil,
79
+ sqlserver_options
80
+ )
56
81
  end
57
82
  end
58
83
 
59
- def new_column(name, default, cast_type, sql_type = nil, null = true, sqlserver_options={})
60
- SQLServerColumn.new name, default, cast_type, sql_type, null, sqlserver_options
84
+ def new_column(name, default, sql_type_metadata, null, table_name, default_function = nil, collation = nil, comment = nil, sqlserver_options = {})
85
+ SQLServerColumn.new(
86
+ name,
87
+ default,
88
+ sql_type_metadata,
89
+ null, table_name,
90
+ default_function,
91
+ collation,
92
+ comment,
93
+ sqlserver_options
94
+ )
95
+ end
96
+
97
+ def primary_keys(table_name)
98
+ primaries = schema_cache.columns(table_name).select(&:is_primary?).map(&:name)
99
+ primaries.present? ? primaries : identity_columns(table_name).map(&:name)
61
100
  end
62
101
 
63
102
  def rename_table(table_name, new_name)
@@ -82,11 +121,11 @@ module ActiveRecord
82
121
  indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) }
83
122
  remove_indexes(table_name, column_name)
84
123
  end
85
- sql_commands << "UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote_default_value(options[:default], column_object)} WHERE #{quote_column_name(column_name)} IS NULL" if !options[:null].nil? && options[:null] == false && !options[:default].nil?
124
+ 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?
86
125
  sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
87
126
  sql_commands[-1] << ' NOT NULL' if !options[:null].nil? && options[:null] == false
88
127
  if options_include_default?(options)
89
- sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_value(options[:default], column_object)} FOR #{quote_column_name(column_name)}"
128
+ sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_expression(options[:default], column_object)} FOR #{quote_column_name(column_name)}"
90
129
  end
91
130
  # Add any removed indexes back
92
131
  indexes.each do |index|
@@ -95,21 +134,22 @@ module ActiveRecord
95
134
  sql_commands.each { |c| do_execute(c) }
96
135
  end
97
136
 
98
- def change_column_default(table_name, column_name, default)
99
- schema_cache.clear_table_cache!(table_name)
137
+ def change_column_default(table_name, column_name, default_or_changes)
138
+ clear_cache!
139
+ column = column_for(table_name, column_name)
140
+ return unless column
100
141
  remove_default_constraint(table_name, column_name)
101
- column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s }
102
- do_execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote_default_value(default, column_object)} FOR #{quote_column_name(column_name)}"
103
- schema_cache.clear_table_cache!(table_name)
142
+ default = extract_new_default_value(default_or_changes)
143
+ 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)}"
144
+ clear_cache!
104
145
  end
105
146
 
106
147
  def rename_column(table_name, column_name, new_column_name)
107
- schema_cache.clear_table_cache!(table_name)
108
- detect_column_for! table_name, column_name
148
+ clear_cache!
109
149
  identifier = SQLServer::Utils.extract_identifiers("#{table_name}.#{column_name}")
110
150
  execute_procedure :sp_rename, identifier.quoted, new_column_name, 'COLUMN'
111
151
  rename_column_indexes(table_name, column_name, new_column_name)
112
- schema_cache.clear_table_cache!(table_name)
152
+ clear_cache!
113
153
  end
114
154
 
115
155
  def rename_index(table_name, old_name, new_name)
@@ -157,6 +197,16 @@ module ActiveRecord
157
197
  when 5..8 then 'bigint'
158
198
  else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
159
199
  end
200
+ when 'datetime2'
201
+ column_type_sql = super
202
+ if precision
203
+ if (0..7) === precision
204
+ column_type_sql << "(#{precision})"
205
+ else
206
+ raise(ActiveRecordError, "The dattime2 type has precision of #{precision}. The allowed range of precision is from 0 to 7")
207
+ end
208
+ end
209
+ column_type_sql
160
210
  else
161
211
  super
162
212
  end
@@ -171,6 +221,10 @@ module ActiveRecord
171
221
  [super, *order_columns].join(', ')
172
222
  end
173
223
 
224
+ def update_table_definition(table_name, base)
225
+ SQLServer::Table.new(table_name, base)
226
+ end
227
+
174
228
  def change_column_null(table_name, column_name, allow_null, default = nil)
175
229
  table_id = SQLServer::Utils.extract_identifiers(table_name)
176
230
  column_id = SQLServer::Utils.extract_identifiers(column_name)
@@ -183,12 +237,6 @@ module ActiveRecord
183
237
  do_execute sql
184
238
  end
185
239
 
186
- # === SQLServer Specific ======================================== #
187
-
188
- def views
189
- tables('VIEW')
190
- end
191
-
192
240
 
193
241
  protected
194
242
 
@@ -228,6 +276,12 @@ module ActiveRecord
228
276
  }
229
277
  end
230
278
 
279
+ def tables_sql(type)
280
+ tn = lowercase_schema_reflection_sql 'TABLE_NAME'
281
+ sql = "SELECT #{tn} FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = '#{type}' ORDER BY TABLE_NAME"
282
+ select_values sql, 'SCHEMA'
283
+ end
284
+
231
285
  def column_definitions(table_name)
232
286
  identifier = if database_prefix_remote_server?
233
287
  SQLServer::Utils.extract_identifiers("#{database_prefix}#{table_name}")
@@ -235,8 +289,8 @@ module ActiveRecord
235
289
  SQLServer::Utils.extract_identifiers(table_name)
236
290
  end
237
291
  database = identifier.fully_qualified_database_quoted
238
- view_exists = schema_cache.view_exists?(table_name)
239
- view_tblnm = table_name_or_views_table_name(table_name) if view_exists
292
+ view_exists = view_exists?(table_name)
293
+ view_tblnm = view_table_name(table_name) if view_exists
240
294
  sql = %{
241
295
  SELECT DISTINCT
242
296
  #{lowercase_schema_reflection_sql('columns.TABLE_NAME')} AS table_name,
@@ -246,7 +300,7 @@ module ActiveRecord
246
300
  columns.NUMERIC_SCALE AS numeric_scale,
247
301
  columns.NUMERIC_PRECISION AS numeric_precision,
248
302
  columns.DATETIME_PRECISION AS datetime_precision,
249
- columns.COLLATION_NAME AS collation,
303
+ columns.COLLATION_NAME AS [collation],
250
304
  columns.ordinal_position,
251
305
  CASE
252
306
  WHEN columns.DATA_TYPE IN ('nchar','nvarchar','char','varchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
@@ -264,7 +318,6 @@ module ActiveRecord
264
318
  FROM #{database}.INFORMATION_SCHEMA.COLUMNS columns
265
319
  LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
266
320
  ON TC.TABLE_NAME = columns.TABLE_NAME
267
- AND TC.TABLE_SCHEMA = columns.TABLE_SCHEMA
268
321
  AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
269
322
  LEFT OUTER JOIN #{database}.INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
270
323
  ON KCU.COLUMN_NAME = columns.COLUMN_NAME
@@ -282,12 +335,14 @@ module ActiveRecord
282
335
  INNER JOIN #{database}.sys.columns AS c
283
336
  ON o.object_id = c.object_id
284
337
  AND c.name = columns.COLUMN_NAME
285
- WHERE columns.TABLE_NAME = @0
286
- AND columns.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : '@1'}
338
+ WHERE columns.TABLE_NAME = #{prepared_statements ? '@0' : quote(identifier.object)}
339
+ AND columns.TABLE_SCHEMA = #{identifier.schema.blank? ? 'schema_name()' : (prepared_statements ? '@1' : quote(identifier.schema))}
287
340
  ORDER BY columns.ordinal_position
288
- }.gsub(/[ \t\r\n]+/, ' ')
289
- binds = [[info_schema_table_name_column, identifier.object]]
290
- binds << [info_schema_table_schema_column, identifier.schema] unless identifier.schema.blank?
341
+ }.gsub(/[ \t\r\n]+/, ' ').strip
342
+ binds = []
343
+ nv128 = SQLServer::Type::UnicodeVarchar.new limit: 128
344
+ binds << Relation::QueryAttribute.new('TABLE_NAME', identifier.object, nv128)
345
+ binds << Relation::QueryAttribute.new('TABLE_SCHEMA', identifier.schema, nv128) unless identifier.schema.blank?
291
346
  results = sp_executesql(sql, 'SCHEMA', binds)
292
347
  results.map do |ci|
293
348
  ci = ci.symbolize_keys
@@ -348,14 +403,6 @@ module ActiveRecord
348
403
  end
349
404
  end
350
405
 
351
- def info_schema_table_name_column
352
- @info_schema_table_name_column ||= new_column 'table_name', nil, lookup_cast_type('nvarchar(128)'), 'nvarchar(128)', true
353
- end
354
-
355
- def info_schema_table_schema_column
356
- @info_schema_table_schema_column ||= new_column 'table_schema', nil, lookup_cast_type('nvarchar(128)'), 'nvarchar(128)', true
357
- end
358
-
359
406
  def remove_check_constraints(table_name, column_name)
360
407
  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'
361
408
  constraints.each do |constraint|
@@ -409,7 +456,7 @@ module ActiveRecord
409
456
  # === SQLServer Specific (View Reflection) ====================== #
410
457
 
411
458
  def view_table_name(table_name)
412
- view_info = schema_cache.view_information(table_name)
459
+ view_info = view_information(table_name)
413
460
  view_info ? get_table_name(view_info['VIEW_DEFINITION']) : table_name
414
461
  end
415
462
 
@@ -430,12 +477,8 @@ module ActiveRecord
430
477
  view_info
431
478
  end
432
479
 
433
- def table_name_or_views_table_name(table_name)
434
- schema_cache.view_exists?(table_name) ? view_table_name(table_name) : table_name
435
- end
436
-
437
480
  def views_real_column_name(table_name, column_name)
438
- view_definition = schema_cache.view_information(table_name)[:VIEW_DEFINITION]
481
+ view_definition = view_information(table_name)[:VIEW_DEFINITION]
439
482
  return column_name unless view_definition
440
483
  match_data = view_definition.match(/([\w-]*)\s+as\s+#{column_name}/im)
441
484
  match_data ? match_data[1] : column_name
@@ -446,7 +489,7 @@ module ActiveRecord
446
489
  def query_requires_identity_insert?(sql)
447
490
  if insert_sql?(sql)
448
491
  table_name = get_table_name(sql)
449
- id_column = identity_column(table_name)
492
+ id_column = identity_columns(table_name).first
450
493
  id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? quote_table_name(table_name) : false
451
494
  else
452
495
  false
@@ -457,15 +500,15 @@ module ActiveRecord
457
500
  !(sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
458
501
  end
459
502
 
460
- def identity_column(table_name)
461
- schema_cache.columns(table_name).find(&:is_identity?)
503
+ def identity_columns(table_name)
504
+ columns(table_name).select(&:is_identity?)
462
505
  end
463
506
 
464
507
 
465
508
  private
466
509
 
467
- def create_table_definition(name, temporary, options, as = nil)
468
- SQLServer::TableDefinition.new native_database_types, name, temporary, options, as
510
+ def create_table_definition(*args)
511
+ SQLServer::TableDefinition.new(*args)
469
512
  end
470
513
 
471
514
  end
@@ -28,32 +28,32 @@ module ActiveRecord
28
28
  end
29
29
 
30
30
  def set_showplan_option(enable = true)
31
- sql = "SET #{option} #{enable ? 'ON' : 'OFF'}"
31
+ sql = "SET #{showplan_option} #{enable ? 'ON' : 'OFF'}"
32
32
  raw_connection_do(sql)
33
33
  rescue Exception
34
- raise ActiveRecordError, "#{option} could not be turned #{enable ? 'ON' : 'OFF'}, perhaps you do not have SHOWPLAN permissions?"
34
+ raise ActiveRecordError, "#{showplan_option} could not be turned #{enable ? 'ON' : 'OFF'}, perhaps you do not have SHOWPLAN permissions?"
35
35
  end
36
36
 
37
- def option
37
+ def showplan_option
38
38
  (SQLServerAdapter.showplan_option || OPTION_ALL).tap do |opt|
39
39
  raise(ArgumentError, "Unknown SHOWPLAN option #{opt.inspect} found.") if OPTIONS.exclude?(opt)
40
40
  end
41
41
  end
42
42
 
43
43
  def showplan_all?
44
- option == OPTION_ALL
44
+ showplan_option == OPTION_ALL
45
45
  end
46
46
 
47
47
  def showplan_text?
48
- option == OPTION_TEXT
48
+ showplan_option == OPTION_TEXT
49
49
  end
50
50
 
51
51
  def showplan_xml?
52
- option == OPTION_XML
52
+ showplan_option == OPTION_XML
53
53
  end
54
54
 
55
55
  def showplan_printer
56
- case option
56
+ case showplan_option
57
57
  when OPTION_XML then PrinterXml
58
58
  when OPTION_ALL, OPTION_TEXT then PrinterTable
59
59
  else PrinterTable
@@ -0,0 +1,20 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module SQLServer
4
+ class SqlTypeMetadata < ActiveRecord::ConnectionAdapters::SqlTypeMetadata
5
+
6
+ def initialize(**kwargs)
7
+ @sqlserver_options = kwargs.extract!(:sqlserver_options)
8
+ super(**kwargs)
9
+ end
10
+
11
+ protected
12
+
13
+ def attributes_for_hash
14
+ super + [@sqlserver_options]
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,76 +1,100 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module SQLServer
4
- class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
5
4
 
6
- def primary_key(name, type = :primary_key, options = {})
5
+ module ColumnMethods
6
+
7
+ def primary_key(name, type = :primary_key, **options)
7
8
  return super unless type == :uuid
8
9
  options[:default] = options.fetch(:default, 'NEWID()')
9
10
  options[:primary_key] = true
10
11
  column name, type, options
11
12
  end
12
13
 
13
- def real(name, options = {})
14
- column(name, :real, options)
14
+ def real(*args, **options)
15
+ args.each { |name| column(name, :real, options) }
16
+ end
17
+
18
+ def money(*args, **options)
19
+ args.each { |name| column(name, :money, options) }
15
20
  end
16
21
 
17
- def money(name, options = {})
18
- column(name, :money, options)
22
+ def datetime(*args, **options)
23
+ args.each do |name|
24
+ if options[:precision]
25
+ datetime2(name, options)
26
+ else
27
+ column(name, :datetime, options)
28
+ end
29
+ end
19
30
  end
20
31
 
21
- def datetime2(name, options = {})
22
- column(name, :datetime2, options)
32
+ def datetime2(*args, **options)
33
+ args.each { |name| column(name, :datetime2, options) }
23
34
  end
24
35
 
25
- def datetimeoffset(name, options = {})
26
- column(name, :datetimeoffset, options)
36
+ def datetimeoffset(*args, **options)
37
+ args.each { |name| column(name, :datetimeoffset, options) }
27
38
  end
28
39
 
29
- def smallmoney(name, options = {})
30
- column(name, :smallmoney, options)
40
+ def smallmoney(*args, **options)
41
+ args.each { |name| column(name, :smallmoney, options) }
31
42
  end
32
43
 
33
- def char(name, options = {})
34
- column(name, :char, options)
44
+ def char(*args, **options)
45
+ args.each { |name| column(name, :char, options) }
35
46
  end
36
47
 
37
- def varchar(name, options = {})
38
- column(name, :varchar, options)
48
+ def varchar(*args, **options)
49
+ args.each { |name| column(name, :varchar, options) }
39
50
  end
40
51
 
41
- def varchar_max(name, options = {})
42
- column(name, :varchar_max, options)
52
+ def varchar_max(*args, **options)
53
+ args.each { |name| column(name, :varchar_max, options) }
43
54
  end
44
55
 
45
- def text_basic(name, options = {})
46
- column(name, :text_basic, options)
56
+ def text_basic(*args, **options)
57
+ args.each { |name| column(name, :text_basic, options) }
47
58
  end
48
59
 
49
- def nchar(name, options = {})
50
- column(name, :nchar, options)
60
+ def nchar(*args, **options)
61
+ args.each { |name| column(name, :nchar, options) }
51
62
  end
52
63
 
53
- def ntext(name, options = {})
54
- column(name, :ntext, options)
64
+ def ntext(*args, **options)
65
+ args.each { |name| column(name, :ntext, options) }
55
66
  end
56
67
 
57
- def binary_basic(name, options = {})
58
- column(name, :binary_basic, options)
68
+ def binary_basic(*args, **options)
69
+ args.each { |name| column(name, :binary_basic, options) }
59
70
  end
60
71
 
61
- def varbinary(name, options = {})
62
- column(name, :varbinary, options)
72
+ def varbinary(*args, **options)
73
+ args.each { |name| column(name, :varbinary, options) }
63
74
  end
64
75
 
65
- def uuid(name, options = {})
66
- column(name, :uniqueidentifier, options)
76
+ def uuid(*args, **options)
77
+ args.each { |name| column(name, :uniqueidentifier, options) }
67
78
  end
68
79
 
69
- def ss_timestamp(name, options = {})
70
- column(name, :ss_timestamp, options)
80
+ def ss_timestamp(*args, **options)
81
+ args.each { |name| column(name, :ss_timestamp, options) }
71
82
  end
72
83
 
73
84
  end
85
+
86
+ class TableDefinition < ActiveRecord::ConnectionAdapters::TableDefinition
87
+ include ColumnMethods
88
+
89
+ def new_column_definition(name, type, options)
90
+ type = :datetime2 if type == :datetime && options[:precision]
91
+ super name, type, options
92
+ end
93
+ end
94
+
95
+ class Table < ActiveRecord::ConnectionAdapters::Table
96
+ include ColumnMethods
97
+ end
74
98
  end
75
99
  end
76
100
  end