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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/CHANGELOG.md +22 -39
- data/{Dockerfile → Dockerfile.ci} +0 -0
- data/Gemfile +1 -3
- data/README.md +5 -8
- data/VERSION +1 -1
- data/activerecord-jdbcsqlserver-adapter.gemspec +2 -3
- data/docker-compose.ci.yml +7 -5
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +25 -29
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +14 -18
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +43 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +26 -0
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +13 -2
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +53 -10
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver/jdbc_overrides.rb +5 -13
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +2 -1
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +43 -27
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +3 -4
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +7 -0
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +20 -14
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +3 -1
- data/lib/activerecord-jdbcsqlserver-adapter.rb +3 -0
- data/lib/arel/visitors/sqlserver.rb +1 -1
- data/lib/arel_sqlserver.rb +0 -1
- data/test/bin/install-freetds.sh +18 -0
- data/test/cases/adapter_test_sqlserver.rb +29 -21
- data/test/cases/change_column_null_test_sqlserver.rb +42 -0
- data/test/cases/coerced_tests.rb +304 -30
- data/test/cases/column_test_sqlserver.rb +496 -462
- data/test/cases/connection_test_sqlserver.rb +2 -2
- data/test/cases/fetch_test_sqlserver.rb +5 -5
- data/test/cases/helper_sqlserver.rb +6 -0
- data/test/cases/json_test_sqlserver.rb +6 -6
- data/test/cases/migration_test_sqlserver.rb +13 -3
- data/test/cases/order_test_sqlserver.rb +19 -19
- data/test/cases/pessimistic_locking_test_sqlserver.rb +9 -9
- data/test/cases/rake_test_sqlserver.rb +20 -20
- data/test/cases/schema_dumper_test_sqlserver.rb +34 -33
- data/test/cases/schema_test_sqlserver.rb +2 -2
- data/test/cases/showplan_test_sqlserver.rb +25 -10
- data/test/cases/specific_schema_test_sqlserver.rb +11 -11
- data/test/cases/transaction_test_sqlserver.rb +9 -9
- data/test/cases/trigger_test_sqlserver.rb +8 -8
- data/test/cases/utils_test_sqlserver.rb +36 -36
- data/test/cases/uuid_test_sqlserver.rb +8 -8
- data/test/migrations/create_clients_and_change_column_null.rb +23 -0
- data/test/schema/datatypes/2012.sql +1 -0
- data/test/schema/sqlserver_specific_schema.rb +9 -1
- data/test/support/core_ext/query_cache.rb +29 -0
- metadata +19 -10
- data/BACKERS.md +0 -32
@@ -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
|
-
|
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
|
-
|
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
|
36
|
-
data = (select("EXEC sp_helpindex #{quote(table_name)}",
|
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
|
-
|
46
|
+
orders = {}
|
47
|
+
columns = []
|
48
|
+
|
49
|
+
index[:index_keys].split(',').each do |column|
|
46
50
|
column.strip!
|
47
|
-
|
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
|
-
|
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
|
-
|
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
|
144
|
-
|
145
|
-
|
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
|
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
|
-
|
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 =
|
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
|
415
|
-
|
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
|
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 :
|
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,
|
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 :
|
62
|
-
|
61
|
+
RealTransaction.send :prepend, SQLServerRealTransaction
|
63
62
|
end
|
64
63
|
end
|
@@ -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
|
-
|
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
|
-
|
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
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
-
|
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
|
data/lib/arel_sqlserver.rb
CHANGED
@@ -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
|
-
|
19
|
-
string.must_match %r{
|
20
|
-
string.must_match %r{
|
21
|
-
string.must_match %r{
|
22
|
-
string.
|
23
|
-
string.wont_match %r{
|
24
|
-
string.wont_match %r{
|
25
|
-
string.wont_match %r{
|
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
|
278
|
+
it 'create smallints when limit is 2' do
|
273
279
|
assert_equal 'smallint', connection.type_to_sql(:integer, limit: 2)
|
274
|
-
|
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
|
-
|