activerecord-jdbcsqlserver-adapter 51.1.0 → 52.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/CHANGELOG.md +22 -39
  4. data/{Dockerfile → Dockerfile.ci} +0 -0
  5. data/Gemfile +1 -3
  6. data/README.md +5 -8
  7. data/VERSION +1 -1
  8. data/activerecord-jdbcsqlserver-adapter.gemspec +2 -3
  9. data/docker-compose.ci.yml +7 -5
  10. data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +25 -29
  11. data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +14 -18
  12. data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +43 -0
  13. data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +26 -0
  14. data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +13 -2
  15. data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +53 -10
  16. data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -0
  17. data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +5 -13
  18. data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +2 -1
  19. data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +2 -2
  20. data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +43 -27
  21. data/lib/active_record/connection_adapters/sqlserver/transaction.rb +3 -4
  22. data/lib/active_record/connection_adapters/sqlserver/type/json.rb +1 -1
  23. data/lib/active_record/connection_adapters/sqlserver/type/string.rb +7 -0
  24. data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -0
  25. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +20 -14
  26. data/lib/active_record/tasks/sqlserver_database_tasks.rb +3 -1
  27. data/lib/activerecord-jdbcsqlserver-adapter.rb +3 -0
  28. data/lib/arel/visitors/sqlserver.rb +1 -1
  29. data/lib/arel_sqlserver.rb +0 -1
  30. data/test/bin/install-freetds.sh +18 -0
  31. data/test/cases/adapter_test_sqlserver.rb +29 -21
  32. data/test/cases/change_column_null_test_sqlserver.rb +42 -0
  33. data/test/cases/coerced_tests.rb +304 -30
  34. data/test/cases/column_test_sqlserver.rb +496 -462
  35. data/test/cases/connection_test_sqlserver.rb +2 -2
  36. data/test/cases/fetch_test_sqlserver.rb +5 -5
  37. data/test/cases/helper_sqlserver.rb +6 -0
  38. data/test/cases/json_test_sqlserver.rb +6 -6
  39. data/test/cases/migration_test_sqlserver.rb +13 -3
  40. data/test/cases/order_test_sqlserver.rb +19 -19
  41. data/test/cases/pessimistic_locking_test_sqlserver.rb +9 -9
  42. data/test/cases/rake_test_sqlserver.rb +20 -20
  43. data/test/cases/schema_dumper_test_sqlserver.rb +34 -33
  44. data/test/cases/schema_test_sqlserver.rb +2 -2
  45. data/test/cases/showplan_test_sqlserver.rb +25 -10
  46. data/test/cases/specific_schema_test_sqlserver.rb +11 -11
  47. data/test/cases/transaction_test_sqlserver.rb +9 -9
  48. data/test/cases/trigger_test_sqlserver.rb +8 -8
  49. data/test/cases/utils_test_sqlserver.rb +36 -36
  50. data/test/cases/uuid_test_sqlserver.rb +8 -8
  51. data/test/migrations/create_clients_and_change_column_null.rb +23 -0
  52. data/test/schema/datatypes/2012.sql +1 -0
  53. data/test/schema/sqlserver_specific_schema.rb +9 -1
  54. data/test/support/core_ext/query_cache.rb +29 -0
  55. metadata +19 -10
  56. data/BACKERS.md +0 -32
@@ -12,6 +12,7 @@ module ActiveRecord
12
12
 
13
13
  def drop_database(database)
14
14
  name = SQLServer::Utils.extract_identifiers(database)
15
+ do_execute "ALTER DATABASE #{name} SET SINGLE_USER WITH ROLLBACK IMMEDIATE"
15
16
  do_execute "DROP DATABASE #{name}"
16
17
  end
17
18
 
@@ -140,25 +140,17 @@ module ActiveRecord
140
140
  [sql, binds, pk, sequence_name]
141
141
  end
142
142
 
143
+ # @Override original version uses driver specific query command
144
+ def sqlserver_version
145
+ @sqlserver_version ||= select_value('SELECT @@version').to_s
146
+ end
147
+
143
148
  # @Override
144
149
  def translate_exception(exception, message)
145
150
  return ActiveRecord::ValueTooLong.new(message) if exception.message.include?('java.sql.DataTruncation')
146
151
  super
147
152
  end
148
153
 
149
- # @Overwrite
150
- # Made it so we don't use the internal calls from the gem
151
- def version_year
152
- return @version_year if defined?(@version_year)
153
- @version_year = begin
154
- vstring = select_value('SELECT @@version').to_s
155
- return 2016 if vstring =~ /vNext/
156
- /SQL Server (\d+)/.match(vstring).to_a.last.to_s.to_i
157
- rescue Exception => e
158
- 2016
159
- end
160
- end
161
-
162
154
  private
163
155
 
164
156
  def _quote(value)
@@ -8,7 +8,8 @@ module ActiveRecord
8
8
  def visit_TableDefinition(o)
9
9
  if o.as
10
10
  table_name = quote_table_name(o.temporary ? "##{o.name}" : o.name)
11
- projections, source = @conn.to_sql(o.as).match(%r{SELECT\s+(.*)?\s+FROM\s+(.*)?}).captures
11
+ query = o.as.respond_to?(:to_sql) ? o.as.to_sql : o.as
12
+ projections, source = query.match(%r{SELECT\s+(.*)?\s+FROM\s+(.*)?}).captures
12
13
  select_into = "SELECT #{projections} INTO #{table_name} FROM #{source}"
13
14
  else
14
15
  o.instance_variable_set :@as, nil
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module SQLServer
4
- module SchemaDumper
4
+ class SchemaDumper < ConnectionAdapters::SchemaDumper
5
5
 
6
6
  SQLSEVER_NO_LIMIT_TYPES = [
7
7
  'text',
@@ -24,7 +24,7 @@ module ActiveRecord
24
24
 
25
25
  def schema_collation(column)
26
26
  return unless column.collation
27
- column.collation if column.collation != collation
27
+ column.collation if column.collation != @connection.collation
28
28
  end
29
29
 
30
30
  def default_primary_key?(column)
@@ -32,22 +32,32 @@ module ActiveRecord
32
32
  end
33
33
  end
34
34
 
35
- def indexes(table_name, name = nil)
36
- data = (select("EXEC sp_helpindex #{quote(table_name)}", name) || []) rescue [] # JDBC returns nil instead of an array or erring out for no results
35
+ def indexes(table_name)
36
+ data = (select("EXEC sp_helpindex #{quote(table_name)}", "SCHEMA") || []) rescue [] # JDBC returns nil instead of an array or erring out for no results
37
37
  data.reduce([]) do |indexes, index|
38
38
  index = index.with_indifferent_access
39
+
39
40
  if index[:index_description] =~ /primary key/
40
41
  indexes
41
42
  else
42
43
  name = index[:index_name]
43
44
  unique = index[:index_description] =~ /unique/
44
45
  where = select_value("SELECT [filter_definition] FROM sys.indexes WHERE name = #{quote(name)}")
45
- columns = index[:index_keys].split(',').map do |column|
46
+ orders = {}
47
+ columns = []
48
+
49
+ index[:index_keys].split(',').each do |column|
46
50
  column.strip!
47
- column.gsub! '(-)', '' if column.ends_with?('(-)')
48
- column
51
+
52
+ if column.ends_with?('(-)')
53
+ column.gsub! '(-)', ''
54
+ orders[column] = :desc
55
+ end
56
+
57
+ columns << column
49
58
  end
50
- indexes << IndexDefinition.new(table_name, name, unique, columns, nil, nil, where)
59
+
60
+ indexes << IndexDefinition.new(table_name, name, unique, columns, where: where, orders: orders)
51
61
  end
52
62
  end
53
63
  end
@@ -132,7 +142,13 @@ module ActiveRecord
132
142
  sql_commands = []
133
143
  indexes = []
134
144
  column_object = schema_cache.columns(table_name).find { |c| c.name.to_s == column_name.to_s }
135
- if options_include_default?(options) || (column_object && column_object.type != type.to_sym)
145
+ without_constraints = options.key?(:default) || options.key?(:limit)
146
+ default = if !options.key?(:default) && column_object
147
+ column_object.default
148
+ else
149
+ options[:default]
150
+ end
151
+ if without_constraints || (column_object && column_object.type != type.to_sym)
136
152
  remove_default_constraint(table_name, column_name)
137
153
  indexes = indexes(table_name).select { |index| index.columns.include?(column_name.to_s) }
138
154
  remove_indexes(table_name, column_name)
@@ -140,10 +156,9 @@ module ActiveRecord
140
156
  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?
141
157
  sql_commands << "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])}"
142
158
  sql_commands.last << ' NOT NULL' if !options[:null].nil? && options[:null] == false
143
- if options.key?(:default) && default_constraint_name(table_name, column_name).present?
144
- change_column_default(table_name, column_name, options[:default])
145
- elsif options_include_default?(options)
146
- 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)}"
159
+ if without_constraints
160
+ default = quote_default_expression(default, column_object || column_for(table_name, column_name))
161
+ sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{default} FOR #{quote_column_name(column_name)}"
147
162
  end
148
163
  # Add any removed indexes back
149
164
  indexes.each do |index|
@@ -211,7 +226,8 @@ module ActiveRecord
211
226
  case type.to_s
212
227
  when 'integer'
213
228
  case limit
214
- when 1..2 then 'smallint'
229
+ when 1 then 'tinyint'
230
+ when 2 then 'smallint'
215
231
  when 3..4, nil then 'integer'
216
232
  when 5..8 then 'bigint'
217
233
  else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
@@ -237,7 +253,8 @@ module ActiveRecord
237
253
  s.gsub(/\s+(?:ASC|DESC)\b/i, '')
238
254
  .gsub(/\s+NULLS\s+(?:FIRST|LAST)\b/i, '')
239
255
  }.reject(&:blank?).map.with_index { |column, i| "#{column} AS alias_#{i}" }
240
- [super, *order_columns].join(', ')
256
+
257
+ (order_columns << super).join(", ")
241
258
  end
242
259
 
243
260
  def update_table_definition(table_name, base)
@@ -247,7 +264,7 @@ module ActiveRecord
247
264
  def change_column_null(table_name, column_name, allow_null, default = nil)
248
265
  table_id = SQLServer::Utils.extract_identifiers(table_name)
249
266
  column_id = SQLServer::Utils.extract_identifiers(column_name)
250
- column = detect_column_for! table_name, column_name
267
+ column = column_for(table_name, column_name)
251
268
  if !allow_null.nil? && allow_null == false && !default.nil?
252
269
  do_execute("UPDATE #{table_id} SET #{column_id}=#{quote(default)} WHERE #{column_id} IS NULL")
253
270
  end
@@ -256,13 +273,17 @@ module ActiveRecord
256
273
  do_execute sql
257
274
  end
258
275
 
276
+ def create_schema_dumper(options)
277
+ SQLServer::SchemaDumper.create(self, options)
278
+ end
279
+
259
280
  private
260
281
 
261
282
  def data_source_sql(name = nil, type: nil)
262
283
  scope = quoted_scope name, type: type
263
284
  table_name = lowercase_schema_reflection_sql 'TABLE_NAME'
264
285
  sql = "SELECT #{table_name}"
265
- sql << ' FROM INFORMATION_SCHEMA.TABLES'
286
+ sql << ' FROM INFORMATION_SCHEMA.TABLES WITH (NOLOCK)'
266
287
  sql << ' WHERE TABLE_CATALOG = DB_NAME()'
267
288
  sql << " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
268
289
  sql << " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
@@ -408,11 +429,13 @@ module ActiveRecord
408
429
  ci[:default_function] = begin
409
430
  default = ci[:default_value]
410
431
  if default.nil? && view_exists
411
- default = select_value "
432
+ default = select_value %{
412
433
  SELECT c.COLUMN_DEFAULT
413
434
  FROM #{database}.INFORMATION_SCHEMA.COLUMNS c
414
- WHERE c.TABLE_NAME = '#{view_tblnm}'
415
- AND c.COLUMN_NAME = '#{views_real_column_name(table_name, ci[:name])}'".squish, 'SCHEMA'
435
+ WHERE
436
+ c.TABLE_NAME = '#{view_tblnm}'
437
+ AND c.COLUMN_NAME = '#{views_real_column_name(table_name, ci[:name])}'
438
+ }.squish, 'SCHEMA'
416
439
  end
417
440
  case default
418
441
  when nil
@@ -431,7 +454,7 @@ module ActiveRecord
431
454
  else ci[:type]
432
455
  end
433
456
  value = default.match(/\A\((.*)\)\Z/m)[1]
434
- value = select_value "SELECT CAST(#{value} AS #{type}) AS value", 'SCHEMA'
457
+ value = select_value("SELECT CAST(#{value} AS #{type}) AS value", 'SCHEMA')
435
458
  [value, nil]
436
459
  end
437
460
  end
@@ -482,13 +505,6 @@ module ActiveRecord
482
505
  "DF_#{table_name}_#{column_name}"
483
506
  end
484
507
 
485
- def detect_column_for!(table_name, column_name)
486
- unless column = schema_cache.columns(table_name).find { |c| c.name == column_name.to_s }
487
- raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
488
- end
489
- column
490
- end
491
-
492
508
  def lowercase_schema_reflection_sql(node)
493
509
  lowercase_schema_reflection ? "LOWER(#{node})" : node
494
510
  end
@@ -504,7 +520,7 @@ module ActiveRecord
504
520
  @view_information ||= {}
505
521
  @view_information[table_name] ||= begin
506
522
  identifier = SQLServer::Utils.extract_identifiers(table_name)
507
- view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = #{quote(identifier.object)}", 'SCHEMA'
523
+ view_info = select_one "SELECT * FROM INFORMATION_SCHEMA.VIEWS WITH (NOLOCK) WHERE TABLE_NAME = #{quote(identifier.object)}", 'SCHEMA'
508
524
  if view_info
509
525
  view_info = view_info.with_indifferent_access
510
526
  if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
@@ -26,13 +26,13 @@ module ActiveRecord
26
26
 
27
27
  end
28
28
 
29
- Transaction.send :include, SQLServerTransaction
29
+ Transaction.send :prepend, SQLServerTransaction
30
30
 
31
31
  module SQLServerRealTransaction
32
32
 
33
33
  attr_reader :starting_isolation_level
34
34
 
35
- def initialize(connection, options, run_commit_callbacks: false)
35
+ def initialize(connection, options, *args)
36
36
  @connection = connection
37
37
  @starting_isolation_level = current_isolation_level if options[:isolation]
38
38
  super
@@ -58,7 +58,6 @@ module ActiveRecord
58
58
 
59
59
  end
60
60
 
61
- RealTransaction.send :include, SQLServerRealTransaction
62
-
61
+ RealTransaction.send :prepend, SQLServerRealTransaction
63
62
  end
64
63
  end
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module ConnectionAdapters
3
3
  module SQLServer
4
4
  module Type
5
- class Json < ActiveRecord::Type::Internal::AbstractJson
5
+ class Json < ActiveRecord::Type::Json
6
6
 
7
7
  end
8
8
  end
@@ -4,6 +4,13 @@ module ActiveRecord
4
4
  module Type
5
5
  class String < ActiveRecord::Type::String
6
6
 
7
+ def changed_in_place?(raw_old_value, new_value)
8
+ if raw_old_value.is_a?(Data)
9
+ raw_old_value.value != new_value
10
+ else
11
+ super
12
+ end
13
+ end
7
14
 
8
15
  end
9
16
  end
@@ -20,6 +20,7 @@ module ActiveRecord
20
20
 
21
21
  # Currently only called from our custom Time type for formatting
22
22
  def _formatted(value)
23
+ return "#{value.to_s(:_sqlserver_time)}" unless precision
23
24
  "#{value.to_s(:_sqlserver_time)}.#{quote_fractional(value)}"
24
25
  end
25
26
 
@@ -7,6 +7,8 @@ require 'active_record/connection_adapters/sqlserver/core_ext/calculations'
7
7
  require 'active_record/connection_adapters/sqlserver/core_ext/explain' unless defined? JRUBY_VERSION
8
8
  require 'active_record/connection_adapters/sqlserver/core_ext/explain_subscriber'
9
9
  require 'active_record/connection_adapters/sqlserver/core_ext/attribute_methods'
10
+ require 'active_record/connection_adapters/sqlserver/core_ext/finder_methods'
11
+ require 'active_record/connection_adapters/sqlserver/core_ext/query_methods'
10
12
  require 'active_record/connection_adapters/sqlserver/version'
11
13
  require 'active_record/connection_adapters/sqlserver/type'
12
14
  require 'active_record/connection_adapters/sqlserver/database_limits'
@@ -34,7 +36,6 @@ module ActiveRecord
34
36
  SQLServer::Quoting,
35
37
  SQLServer::DatabaseStatements,
36
38
  SQLServer::Showplan,
37
- SQLServer::SchemaDumper,
38
39
  SQLServer::SchemaStatements,
39
40
  SQLServer::DatabaseLimits,
40
41
  SQLServer::DatabaseTasks
@@ -53,6 +54,9 @@ module ActiveRecord
53
54
 
54
55
  ADAPTER_NAME = 'SQLServer'.freeze
55
56
 
57
+ # Default precision for 'time' (See https://docs.microsoft.com/en-us/sql/t-sql/data-types/time-transact-sql)
58
+ DEFAULT_TIME_PRECISION = 7
59
+
56
60
  attr_reader :spid
57
61
 
58
62
  cattr_accessor :cs_equality_operator, instance_accessor: false
@@ -148,6 +152,10 @@ module ActiveRecord
148
152
  false
149
153
  end
150
154
 
155
+ def supports_savepoints?
156
+ true
157
+ end
158
+
151
159
  def supports_in_memory_oltp?
152
160
  @version_year >= 2014
153
161
  end
@@ -201,7 +209,7 @@ module ActiveRecord
201
209
 
202
210
  def tables_with_referential_integrity
203
211
  schemas_and_tables = select_rows <<-SQL.strip_heredoc
204
- SELECT s.name AS schema_name, o.name AS table_name
212
+ SELECT DISTINCT s.name AS schema_name, o.name AS table_name
205
213
  FROM sys.foreign_keys i
206
214
  INNER JOIN sys.objects o ON i.parent_object_id = o.OBJECT_ID
207
215
  INNER JOIN sys.schemas s ON o.schema_id = s.schema_id
@@ -224,7 +232,7 @@ module ActiveRecord
224
232
  end
225
233
 
226
234
  def sqlserver_azure?
227
- @sqlserver_azure ||= !!(select_value('SELECT @@version', 'SCHEMA') =~ /Azure/i)
235
+ !!(sqlserver_version =~ /Azure/i)
228
236
  end
229
237
 
230
238
  def database_prefix_remote_server?
@@ -265,7 +273,7 @@ module ActiveRecord
265
273
 
266
274
  # === Abstract Adapter (Misc Support) =========================== #
267
275
 
268
- def initialize_type_map(m)
276
+ def initialize_type_map(m = type_map)
269
277
  m.register_type %r{.*}, SQLServer::Type::UnicodeString.new
270
278
  # Exact Numerics
271
279
  register_class_with_limit m, 'bigint(8)', SQLServer::Type::BigInteger
@@ -305,8 +313,7 @@ module ActiveRecord
305
313
  end
306
314
  m.register_type 'smalldatetime', SQLServer::Type::SmallDateTime.new
307
315
  m.register_type %r{\Atime}i do |sql_type|
308
- scale = extract_scale(sql_type)
309
- precision = extract_precision(sql_type)
316
+ precision = extract_precision(sql_type) || DEFAULT_TIME_PRECISION
310
317
  SQLServer::Type::Time.new precision: precision
311
318
  end
312
319
  # Character Strings
@@ -447,16 +454,15 @@ module ActiveRecord
447
454
  end
448
455
 
449
456
  def version_year
450
- return @version_year if defined?(@version_year)
451
- @version_year = begin
452
- vstring = _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
453
- return 2016 if vstring =~ /vNext/
454
- /SQL Server (\d+)/.match(vstring).to_a.last.to_s.to_i
455
- rescue Exception => e
456
- 2016
457
- end
457
+ return 2016 if sqlserver_version =~ /vNext/
458
+ /SQL Server (\d+)/.match(sqlserver_version).to_a.last.to_s.to_i
459
+ rescue StandardError => e
460
+ 2016
458
461
  end
459
462
 
463
+ def sqlserver_version
464
+ @sqlserver_version ||= _raw_select('SELECT @@version', fetch: :rows).first.first.to_s
465
+ end
460
466
  end
461
467
  end
462
468
  end
@@ -49,9 +49,11 @@ module ActiveRecord
49
49
  end
50
50
 
51
51
  def structure_dump(filename, extra_flags)
52
+ server_arg = "-S #{Shellwords.escape(configuration['host'])}"
53
+ server_arg += ":#{Shellwords.escape(configuration['port'])}" if configuration['port']
52
54
  command = [
53
55
  "defncopy",
54
- "-S #{Shellwords.escape(configuration['host'])}",
56
+ server_arg,
55
57
  "-D #{Shellwords.escape(configuration['database'])}",
56
58
  "-U #{Shellwords.escape(configuration['username'])}",
57
59
  "-P #{Shellwords.escape(configuration['password'])}",
@@ -1,6 +1,9 @@
1
1
  # Our core date/time overrides to support prepared statements
2
2
  require 'active_record/connection_adapters/sqlserver/core_ext/date_time'
3
3
 
4
+ require 'active_support' # Need this for the next line
5
+ require 'active_record/log_subscriber' # Need to make sure this is loaded before we load Core for monkey patching
6
+
4
7
  # Load the jar file for the jdbc driver
5
8
  require_relative './jdbc_mssql_driver_loader'
6
9
 
@@ -14,7 +14,7 @@ module Arel
14
14
  # SQLServer ToSql/Visitor (Overides)
15
15
 
16
16
  def visit_Arel_Nodes_BindParam o, collector
17
- collector.add_bind(o) { |i| "@#{i-1}" }
17
+ collector.add_bind(o.value) { |i| "@#{i-1}" }
18
18
  end unless defined? JRUBY_VERSION # converts bind argument markers "?" to "@n", but JDBC wants "?"
19
19
 
20
20
  def visit_Arel_Nodes_Bin o, collector
@@ -1,3 +1,2 @@
1
1
  require 'arel'
2
- require 'arel/visitors/bind_visitor'
3
2
  require 'arel/visitors/sqlserver'
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ FREETDS_VERSION=1.00.21
7
+
8
+ wget http://www.freetds.org/files/stable/freetds-$FREETDS_VERSION.tar.gz
9
+ tar -xzf freetds-$FREETDS_VERSION.tar.gz
10
+ cd freetds-$FREETDS_VERSION
11
+ ./configure --prefix=/opt/local \
12
+ --with-openssl=/opt/local \
13
+ --with-tdsver=7.3
14
+ make
15
+ make install
16
+ cd ..
17
+ rm -rf freetds-$FREETDS_VERSION
18
+ rm freetds-$FREETDS_VERSION.tar.gz
@@ -15,14 +15,15 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
15
15
 
16
16
  it 'has basic and non-sensitive information in the adapters inspect method' do
17
17
  string = connection.inspect
18
- string.must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
19
- string.must_match %r{version\: \d+\.\d}
20
- string.must_match %r{mode: (dblib|jdbc)}
21
- string.must_match %r{azure: (true|false)}
22
- string.wont_match %r{host}
23
- string.wont_match %r{password}
24
- string.wont_match %r{username}
25
- string.wont_match %r{port}
18
+
19
+ _(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
20
+ _(string).must_match %r{version\: \d+\.\d}
21
+ _(string).must_match %r{mode: (dblib|jdbc)}
22
+ _(string).must_match %r{azure: (true|false)}
23
+ _(string).wont_match %r{host}
24
+ _(string).wont_match %r{password}
25
+ _(string).wont_match %r{username}
26
+ _(string).wont_match %r{port}
26
27
  end
27
28
 
28
29
  it 'has a 128 max #table_alias_length' do
@@ -162,7 +163,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
162
163
  end
163
164
 
164
165
  it 'return an empty array when calling #identity_columns for a table_name with no identity' do
165
- connection.send(:identity_columns, Subscriber.table_name).must_equal []
166
+ _(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
166
167
  end
167
168
 
168
169
  end
@@ -232,6 +233,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
232
233
  end
233
234
  end
234
235
 
236
+ it 'not disable referential integrity for the same table twice' do
237
+ tables = SSTestHasPk.connection.tables_with_referential_integrity
238
+ assert_equal tables.size, tables.uniq.size
239
+ end
240
+
235
241
  end
236
242
 
237
243
  describe 'database statements' do
@@ -269,9 +275,12 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
269
275
  assert_equal 'integer', connection.type_to_sql(:integer, limit: 3)
270
276
  end
271
277
 
272
- it 'create smallints when limit is less than 3' do
278
+ it 'create smallints when limit is 2' do
273
279
  assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
274
- assert_equal 'smallint', connection.type_to_sql(:integer, limit: 1)
280
+ end
281
+
282
+ it 'create tinyints when limit is 1' do
283
+ assert_equal 'tinyint', connection.type_to_sql(:integer, limit: 1)
275
284
  end
276
285
 
277
286
  it 'create bigints when limit is greateer than 4' do
@@ -296,7 +305,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
296
305
  end
297
306
 
298
307
  it 'find SSTestCustomersView table name' do
299
- connection.views.must_include 'sst_customers_view'
308
+ _(connection.views).must_include 'sst_customers_view'
300
309
  end
301
310
 
302
311
  it 'work with dynamic finders' do
@@ -337,9 +346,9 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
337
346
  end
338
347
 
339
348
  it 'find identity column' do
340
- SSTestCustomersView.primary_key.must_equal 'id'
341
- connection.primary_key(SSTestCustomersView.table_name).must_equal 'id'
342
- SSTestCustomersView.columns_hash['id'].must_be :is_identity?
349
+ _(SSTestCustomersView.primary_key).must_equal 'id'
350
+ _(connection.primary_key(SSTestCustomersView.table_name)).must_equal 'id'
351
+ _(SSTestCustomersView.columns_hash['id']).must_be :is_identity?
343
352
  end
344
353
 
345
354
  it 'find default values' do
@@ -364,9 +373,9 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
364
373
  end
365
374
 
366
375
  it 'find identity column' do
367
- SSTestStringDefaultsView.primary_key.must_equal 'id'
368
- connection.primary_key(SSTestStringDefaultsView.table_name).must_equal 'id'
369
- SSTestStringDefaultsView.columns_hash['id'].must_be :is_identity?
376
+ _(SSTestStringDefaultsView.primary_key).must_equal 'id'
377
+ _(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal 'id'
378
+ _(SSTestStringDefaultsView.columns_hash['id']).must_be :is_identity?
370
379
  end
371
380
 
372
381
  it 'find default values' do
@@ -415,12 +424,11 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
415
424
 
416
425
  it 'in_memory_oltp' do
417
426
  if ENV['IN_MEMORY_OLTP'] && connection.supports_in_memory_oltp?
418
- SSTMemory.primary_key.must_equal 'id'
419
- SSTMemory.columns_hash['id'].must_be :is_identity?
427
+ _(SSTMemory.primary_key).must_equal 'id'
428
+ _(SSTMemory.columns_hash['id']).must_be :is_identity?
420
429
  else
421
430
  skip 'supports_in_memory_oltp? => false'
422
431
  end
423
432
  end
424
433
 
425
434
  end
426
-