activerecord-sqlserver-adapter 4.2.18 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
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