activerecord-sqlserver-adapter 6.0.0.rc1 → 6.0.0.rc2
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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +20 -0
- data/Gemfile +11 -5
- data/Guardfile +9 -8
- data/Rakefile +12 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +3 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +1 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +3 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +35 -32
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +7 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +0 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +7 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +106 -103
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +6 -8
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +1 -4
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -8
- data/lib/active_record/connection_adapters/sqlserver/type.rb +35 -35
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +0 -1
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +6 -9
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +1 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +1 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +8 -11
- data/lib/active_record/connection_adapters/sqlserver/version.rb +0 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +85 -83
- data/lib/active_record/connection_adapters/sqlserver_column.rb +0 -2
- data/lib/active_record/sqlserver_base.rb +1 -1
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +26 -32
- data/lib/activerecord-sqlserver-adapter.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +18 -14
- data/lib/arel_sqlserver.rb +2 -2
- data/test/cases/adapter_test_sqlserver.rb +161 -182
- data/test/cases/change_column_null_test_sqlserver.rb +12 -12
- data/test/cases/coerced_tests.rb +88 -270
- data/test/cases/column_test_sqlserver.rb +281 -283
- data/test/cases/connection_test_sqlserver.rb +15 -20
- data/test/cases/execute_procedure_test_sqlserver.rb +18 -20
- data/test/cases/fetch_test_sqlserver.rb +14 -22
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +12 -18
- data/test/cases/helper_sqlserver.rb +13 -15
- data/test/cases/in_clause_test_sqlserver.rb +9 -9
- data/test/cases/index_test_sqlserver.rb +13 -15
- data/test/cases/json_test_sqlserver.rb +23 -25
- data/test/cases/migration_test_sqlserver.rb +22 -28
- data/test/cases/order_test_sqlserver.rb +51 -54
- data/test/cases/pessimistic_locking_test_sqlserver.rb +25 -33
- data/test/cases/rake_test_sqlserver.rb +31 -45
- data/test/cases/schema_dumper_test_sqlserver.rb +104 -108
- data/test/cases/schema_test_sqlserver.rb +18 -26
- data/test/cases/scratchpad_test_sqlserver.rb +2 -4
- data/test/cases/showplan_test_sqlserver.rb +24 -33
- data/test/cases/specific_schema_test_sqlserver.rb +66 -65
- data/test/cases/transaction_test_sqlserver.rb +16 -19
- data/test/cases/trigger_test_sqlserver.rb +12 -12
- data/test/cases/utils_test_sqlserver.rb +68 -70
- data/test/cases/uuid_test_sqlserver.rb +11 -13
- data/test/debug.rb +6 -6
- data/test/migrations/create_clients_and_change_column_null.rb +1 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +2 -4
- data/test/models/sqlserver/booking.rb +1 -1
- data/test/models/sqlserver/customers_view.rb +1 -1
- data/test/models/sqlserver/dollar_table_name.rb +1 -1
- data/test/models/sqlserver/edge_schema.rb +1 -3
- data/test/models/sqlserver/fk_has_fk.rb +1 -1
- data/test/models/sqlserver/fk_has_pk.rb +1 -1
- data/test/models/sqlserver/natural_pk_data.rb +2 -2
- data/test/models/sqlserver/natural_pk_int_data.rb +1 -1
- data/test/models/sqlserver/no_pk_data.rb +1 -1
- data/test/models/sqlserver/object_default.rb +1 -1
- data/test/models/sqlserver/quoted_table.rb +2 -2
- data/test/models/sqlserver/quoted_view_1.rb +1 -1
- data/test/models/sqlserver/quoted_view_2.rb +1 -1
- data/test/models/sqlserver/sst_memory.rb +1 -1
- data/test/models/sqlserver/string_default.rb +1 -1
- data/test/models/sqlserver/string_defaults_big_view.rb +1 -1
- data/test/models/sqlserver/string_defaults_view.rb +1 -1
- data/test/models/sqlserver/tinyint_pk.rb +1 -1
- data/test/models/sqlserver/trigger.rb +2 -2
- data/test/models/sqlserver/trigger_history.rb +1 -1
- data/test/models/sqlserver/upper.rb +1 -1
- data/test/models/sqlserver/uppered.rb +1 -1
- data/test/models/sqlserver/uuid.rb +1 -1
- data/test/schema/sqlserver_specific_schema.rb +20 -22
- data/test/support/coerceable_test_sqlserver.rb +1 -4
- data/test/support/connection_reflection.rb +1 -2
- data/test/support/core_ext/query_cache.rb +1 -1
- data/test/support/load_schema_sqlserver.rb +3 -5
- data/test/support/minitest_sqlserver.rb +1 -1
- data/test/support/paths_sqlserver.rb +9 -11
- data/test/support/rake_helpers.rb +12 -10
- data/test/support/sql_counter_sqlserver.rb +0 -4
- data/test/support/test_in_memory_oltp.rb +7 -7
- metadata +5 -4
|
@@ -3,20 +3,18 @@
|
|
|
3
3
|
module Arel
|
|
4
4
|
module Visitors
|
|
5
5
|
class SQLServer < Arel::Visitors::ToSql
|
|
6
|
-
|
|
7
6
|
OFFSET = " OFFSET "
|
|
8
7
|
ROWS = " ROWS"
|
|
9
8
|
FETCH = " FETCH NEXT "
|
|
10
9
|
FETCH0 = " FETCH FIRST (SELECT 0) "
|
|
11
10
|
ROWS_ONLY = " ROWS ONLY"
|
|
12
11
|
|
|
13
|
-
|
|
14
12
|
private
|
|
15
13
|
|
|
16
14
|
# SQLServer ToSql/Visitor (Overides)
|
|
17
15
|
|
|
18
16
|
def visit_Arel_Nodes_BindParam o, collector
|
|
19
|
-
collector.add_bind(o.value) { |i| "@#{i-1}" }
|
|
17
|
+
collector.add_bind(o.value) { |i| "@#{i - 1}" }
|
|
20
18
|
end
|
|
21
19
|
|
|
22
20
|
def visit_Arel_Nodes_Bin o, collector
|
|
@@ -38,7 +36,7 @@ module Arel
|
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
def visit_Arel_Nodes_Lock o, collector
|
|
41
|
-
o.expr = Arel.sql(
|
|
39
|
+
o.expr = Arel.sql("WITH(UPDLOCK)") if o.expr.to_s =~ /FOR UPDATE/
|
|
42
40
|
collector << " "
|
|
43
41
|
visit o.expr, collector
|
|
44
42
|
end
|
|
@@ -72,7 +70,7 @@ module Arel
|
|
|
72
70
|
collector = visit o.with, collector
|
|
73
71
|
collector << " "
|
|
74
72
|
end
|
|
75
|
-
collector = o.cores.inject(collector) { |c,x|
|
|
73
|
+
collector = o.cores.inject(collector) { |c, x|
|
|
76
74
|
visit_Arel_Nodes_SelectCore(x, c)
|
|
77
75
|
}
|
|
78
76
|
collector = visit_Orders_And_Let_Fetch_Happen o, collector
|
|
@@ -86,15 +84,17 @@ module Arel
|
|
|
86
84
|
# Apparently, o.engine.connection can actually be a different adapter
|
|
87
85
|
# than sqlserver. Can be removed if fixed in ActiveRecord. See:
|
|
88
86
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
|
89
|
-
table_name =
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
87
|
+
table_name =
|
|
88
|
+
begin
|
|
89
|
+
if o.class.engine.connection.respond_to?(:sqlserver?) && o.class.engine.connection.database_prefix_remote_server?
|
|
90
|
+
remote_server_table_name(o)
|
|
91
|
+
else
|
|
92
|
+
quote_table_name(o.name)
|
|
93
|
+
end
|
|
94
|
+
rescue Exception
|
|
93
95
|
quote_table_name(o.name)
|
|
94
96
|
end
|
|
95
|
-
|
|
96
|
-
quote_table_name(o.name)
|
|
97
|
-
end
|
|
97
|
+
|
|
98
98
|
if o.table_alias
|
|
99
99
|
collector << "#{table_name} #{quote_table_name o.table_alias}"
|
|
100
100
|
else
|
|
@@ -109,7 +109,7 @@ module Arel
|
|
|
109
109
|
end
|
|
110
110
|
if o.right.any?
|
|
111
111
|
collector << " " if o.left
|
|
112
|
-
collector = inject_join o.right, collector,
|
|
112
|
+
collector = inject_join o.right, collector, " "
|
|
113
113
|
end
|
|
114
114
|
collector
|
|
115
115
|
end
|
|
@@ -178,6 +178,7 @@ module Arel
|
|
|
178
178
|
|
|
179
179
|
def node_value(node)
|
|
180
180
|
return nil unless node
|
|
181
|
+
|
|
181
182
|
case node.expr
|
|
182
183
|
when NilClass then nil
|
|
183
184
|
when Numeric then node.expr
|
|
@@ -191,9 +192,11 @@ module Arel
|
|
|
191
192
|
|
|
192
193
|
def make_Fetch_Possible_And_Deterministic o
|
|
193
194
|
return if o.limit.nil? && o.offset.nil?
|
|
195
|
+
|
|
194
196
|
t = table_From_Statement o
|
|
195
197
|
pk = primary_Key_From_Table t
|
|
196
198
|
return unless pk
|
|
199
|
+
|
|
197
200
|
if o.orders.empty?
|
|
198
201
|
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
|
199
202
|
o.orders = [pk.asc]
|
|
@@ -224,8 +227,9 @@ module Arel
|
|
|
224
227
|
|
|
225
228
|
def primary_Key_From_Table t
|
|
226
229
|
return unless t
|
|
230
|
+
|
|
227
231
|
column_name = @connection.schema_cache.primary_keys(t.name) ||
|
|
228
|
-
|
|
232
|
+
@connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
|
|
229
233
|
column_name ? t[column_name] : nil
|
|
230
234
|
end
|
|
231
235
|
|
data/lib/arel_sqlserver.rb
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "models/topic"
|
|
5
|
+
require "models/task"
|
|
6
|
+
require "models/post"
|
|
7
|
+
require "models/subscriber"
|
|
8
|
+
require "models/minimalistic"
|
|
9
9
|
|
|
10
10
|
class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
11
|
-
|
|
12
11
|
fixtures :tasks
|
|
13
12
|
|
|
14
13
|
let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
|
|
15
14
|
let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
|
|
16
15
|
let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
|
|
17
16
|
|
|
18
|
-
it
|
|
17
|
+
it "has basic and non-sensitive information in the adapters inspect method" do
|
|
19
18
|
string = connection.inspect
|
|
20
19
|
_(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
|
21
20
|
_(string).must_match %r{version\: \d.\d}
|
|
@@ -27,67 +26,66 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
27
26
|
_(string).wont_match %r{port}
|
|
28
27
|
end
|
|
29
28
|
|
|
30
|
-
it
|
|
29
|
+
it "has a 128 max #table_alias_length" do
|
|
31
30
|
assert connection.table_alias_length <= 128
|
|
32
31
|
end
|
|
33
32
|
|
|
34
|
-
it
|
|
33
|
+
it "raises invalid statement error for bad SQL" do
|
|
35
34
|
assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.update("UPDATE XXX") }
|
|
36
35
|
end
|
|
37
36
|
|
|
38
|
-
it
|
|
39
|
-
assert_equal
|
|
37
|
+
it "is has our adapter_name" do
|
|
38
|
+
assert_equal "SQLServer", connection.adapter_name
|
|
40
39
|
end
|
|
41
40
|
|
|
42
|
-
it
|
|
41
|
+
it "support DDL in transactions" do
|
|
43
42
|
assert connection.supports_ddl_transactions?
|
|
44
43
|
end
|
|
45
44
|
|
|
46
|
-
it
|
|
45
|
+
it "allow owner table name prefixs like dbo to still allow table exists to return true" do
|
|
47
46
|
begin
|
|
48
|
-
assert_equal
|
|
47
|
+
assert_equal "topics", Topic.table_name
|
|
49
48
|
assert Topic.table_exists?
|
|
50
|
-
Topic.table_name =
|
|
51
|
-
assert Topic.table_exists?,
|
|
49
|
+
Topic.table_name = "dbo.topics"
|
|
50
|
+
assert Topic.table_exists?, "Tasks table name of dbo.topics should return true for exists."
|
|
52
51
|
ensure
|
|
53
|
-
Topic.table_name =
|
|
52
|
+
Topic.table_name = "topics"
|
|
54
53
|
end
|
|
55
54
|
end
|
|
56
55
|
|
|
57
|
-
it
|
|
58
|
-
assert connection.send(:insert_sql?,
|
|
56
|
+
it "return true to insert sql query for inserts only" do
|
|
57
|
+
assert connection.send(:insert_sql?, "INSERT...")
|
|
59
58
|
assert connection.send(:insert_sql?, "EXEC sp_executesql N'INSERT INTO [fk_test_has_fks] ([fk_id]) VALUES (@0); SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident', N'@0 int', @0 = 0")
|
|
60
|
-
assert !connection.send(:insert_sql?,
|
|
61
|
-
assert !connection.send(:insert_sql?,
|
|
59
|
+
assert !connection.send(:insert_sql?, "UPDATE...")
|
|
60
|
+
assert !connection.send(:insert_sql?, "SELECT...")
|
|
62
61
|
end
|
|
63
62
|
|
|
64
|
-
it
|
|
65
|
-
assert_equal
|
|
66
|
-
assert_equal
|
|
67
|
-
assert_equal
|
|
63
|
+
it "return unquoted table name object from basic INSERT UPDATE and SELECT statements" do
|
|
64
|
+
assert_equal "funny_jokes", connection.send(:get_table_name, basic_insert_sql)
|
|
65
|
+
assert_equal "customers", connection.send(:get_table_name, basic_update_sql)
|
|
66
|
+
assert_equal "customers", connection.send(:get_table_name, basic_select_sql)
|
|
68
67
|
end
|
|
69
68
|
|
|
70
|
-
it
|
|
69
|
+
it "test bad connection" do
|
|
71
70
|
assert_raise ActiveRecord::NoDatabaseError do
|
|
72
|
-
config = ActiveRecord::Base.configurations[
|
|
71
|
+
config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
|
|
73
72
|
ActiveRecord::Base.sqlserver_connection config
|
|
74
73
|
end
|
|
75
74
|
end
|
|
76
75
|
|
|
77
|
-
it
|
|
78
|
-
config = ActiveRecord::Base.configurations[
|
|
76
|
+
it "test database exists returns false if database does not exist" do
|
|
77
|
+
config = ActiveRecord::Base.configurations["arunit"].merge(database: "inexistent_activerecord_unittest")
|
|
79
78
|
assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
|
|
80
|
-
|
|
79
|
+
"expected database to not exist"
|
|
81
80
|
end
|
|
82
81
|
|
|
83
|
-
it
|
|
84
|
-
config = ActiveRecord::Base.configurations[
|
|
82
|
+
it "test database exists returns true when the database exists" do
|
|
83
|
+
config = ActiveRecord::Base.configurations["arunit"]
|
|
85
84
|
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(config),
|
|
86
|
-
|
|
85
|
+
"expected database #{config[:database]} to exist"
|
|
87
86
|
end
|
|
88
87
|
|
|
89
|
-
describe
|
|
90
|
-
|
|
88
|
+
describe "with different language" do
|
|
91
89
|
before do
|
|
92
90
|
@default_language = connection.user_options_language
|
|
93
91
|
end
|
|
@@ -97,18 +95,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
97
95
|
connection.send :initialize_dateformatter
|
|
98
96
|
end
|
|
99
97
|
|
|
100
|
-
it
|
|
98
|
+
it "memos users dateformat" do
|
|
101
99
|
connection.execute("SET LANGUAGE us_english") rescue nil
|
|
102
100
|
dateformat = connection.instance_variable_get(:@database_dateformat)
|
|
103
|
-
assert_equal
|
|
101
|
+
assert_equal "mdy", dateformat
|
|
104
102
|
end
|
|
105
103
|
|
|
106
|
-
it
|
|
104
|
+
it "has a dateformatter" do
|
|
107
105
|
assert Date::DATE_FORMATS[:_sqlserver_dateformat]
|
|
108
106
|
assert Time::DATE_FORMATS[:_sqlserver_dateformat]
|
|
109
107
|
end
|
|
110
108
|
|
|
111
|
-
it
|
|
109
|
+
it "does a datetime insertion when language is german" do
|
|
112
110
|
connection.execute("SET LANGUAGE deutsch")
|
|
113
111
|
connection.send :initialize_dateformatter
|
|
114
112
|
assert_nothing_raised do
|
|
@@ -117,40 +115,36 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
117
115
|
Task.create! starting: starting, ending: ending
|
|
118
116
|
end
|
|
119
117
|
end
|
|
120
|
-
|
|
121
118
|
end
|
|
122
119
|
|
|
123
|
-
describe
|
|
124
|
-
|
|
120
|
+
describe "testing #lowercase_schema_reflection" do
|
|
125
121
|
before do
|
|
126
122
|
SSTestUpper.delete_all
|
|
127
|
-
SSTestUpper.create COLUMN1:
|
|
128
|
-
SSTestUpper.create COLUMN1:
|
|
123
|
+
SSTestUpper.create COLUMN1: "Got a minute?", COLUMN2: 419
|
|
124
|
+
SSTestUpper.create COLUMN1: "Favorite number?", COLUMN2: 69
|
|
129
125
|
end
|
|
130
126
|
|
|
131
127
|
after do
|
|
132
128
|
connection.lowercase_schema_reflection = false
|
|
133
129
|
end
|
|
134
130
|
|
|
135
|
-
it
|
|
136
|
-
assert SSTestUpper.columns_hash[
|
|
137
|
-
assert_equal
|
|
138
|
-
assert_equal
|
|
139
|
-
assert SSTestUpper.columns_hash[
|
|
131
|
+
it "not lowercase schema reflection by default" do
|
|
132
|
+
assert SSTestUpper.columns_hash["COLUMN1"]
|
|
133
|
+
assert_equal "Got a minute?", SSTestUpper.first.COLUMN1
|
|
134
|
+
assert_equal "Favorite number?", SSTestUpper.last.COLUMN1
|
|
135
|
+
assert SSTestUpper.columns_hash["COLUMN2"]
|
|
140
136
|
end
|
|
141
137
|
|
|
142
|
-
it
|
|
138
|
+
it "lowercase schema reflection when set" do
|
|
143
139
|
connection.lowercase_schema_reflection = true
|
|
144
|
-
assert SSTestUppered.columns_hash[
|
|
145
|
-
assert_equal
|
|
146
|
-
assert_equal
|
|
147
|
-
assert SSTestUppered.columns_hash[
|
|
140
|
+
assert SSTestUppered.columns_hash["column1"]
|
|
141
|
+
assert_equal "Got a minute?", SSTestUppered.first.column1
|
|
142
|
+
assert_equal "Favorite number?", SSTestUppered.last.column1
|
|
143
|
+
assert SSTestUppered.columns_hash["column2"]
|
|
148
144
|
end
|
|
149
|
-
|
|
150
145
|
end
|
|
151
146
|
|
|
152
|
-
describe
|
|
153
|
-
|
|
147
|
+
describe "identity inserts" do
|
|
154
148
|
before do
|
|
155
149
|
@identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
|
|
156
150
|
@identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
|
|
@@ -160,62 +154,60 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
160
154
|
@identity_insert_sql_unordered_sp = "EXEC sp_executesql N'INSERT INTO [funny_jokes] ([name],[id]) VALUES (@0, @1)', N'@0 nvarchar(255), @1 int', @0 = N'Knock knock', @1 = 420"
|
|
161
155
|
end
|
|
162
156
|
|
|
163
|
-
it
|
|
164
|
-
assert_equal
|
|
165
|
-
assert_equal
|
|
166
|
-
assert_equal
|
|
167
|
-
assert_equal
|
|
168
|
-
assert_equal
|
|
169
|
-
assert_equal
|
|
157
|
+
it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
|
|
158
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
|
|
159
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
|
|
160
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
|
|
161
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
|
|
162
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
|
|
163
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
|
|
170
164
|
end
|
|
171
165
|
|
|
172
|
-
it
|
|
166
|
+
it "return false to #query_requires_identity_insert? for normal SQL" do
|
|
173
167
|
[basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
|
|
174
|
-
assert !connection.send(:query_requires_identity_insert?,sql), "SQL was #{sql}"
|
|
168
|
+
assert !connection.send(:query_requires_identity_insert?, sql), "SQL was #{sql}"
|
|
175
169
|
end
|
|
176
170
|
end
|
|
177
171
|
|
|
178
|
-
it
|
|
179
|
-
task_id_column = Task.columns_hash[
|
|
172
|
+
it "find identity column using #identity_columns" do
|
|
173
|
+
task_id_column = Task.columns_hash["id"]
|
|
180
174
|
assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
|
|
181
175
|
assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
|
|
182
176
|
end
|
|
183
177
|
|
|
184
|
-
it
|
|
178
|
+
it "return an empty array when calling #identity_columns for a table_name with no identity" do
|
|
185
179
|
_(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
|
|
186
180
|
end
|
|
187
|
-
|
|
188
181
|
end
|
|
189
182
|
|
|
190
|
-
describe
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
assert_equal '1', connection.quoted_true
|
|
183
|
+
describe "quoting" do
|
|
184
|
+
it "return 1 for #quoted_true" do
|
|
185
|
+
assert_equal "1", connection.quoted_true
|
|
194
186
|
end
|
|
195
187
|
|
|
196
|
-
it
|
|
197
|
-
assert_equal
|
|
188
|
+
it "return 0 for #quoted_false" do
|
|
189
|
+
assert_equal "0", connection.quoted_false
|
|
198
190
|
end
|
|
199
191
|
|
|
200
|
-
it
|
|
192
|
+
it "not escape backslash characters like abstract adapter" do
|
|
201
193
|
string_with_backslashs = "\\n"
|
|
202
194
|
assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
|
|
203
195
|
end
|
|
204
196
|
|
|
205
|
-
it
|
|
206
|
-
assert_equal
|
|
207
|
-
assert_equal
|
|
208
|
-
assert_equal
|
|
197
|
+
it "quote column names with brackets" do
|
|
198
|
+
assert_equal "[foo]", connection.quote_column_name(:foo)
|
|
199
|
+
assert_equal "[foo]", connection.quote_column_name("foo")
|
|
200
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
209
201
|
end
|
|
210
202
|
|
|
211
|
-
it
|
|
212
|
-
assert_equal
|
|
213
|
-
assert_equal
|
|
203
|
+
it "not quote already quoted column names with brackets" do
|
|
204
|
+
assert_equal "[foo]", connection.quote_column_name("[foo]")
|
|
205
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("[foo].[bar]")
|
|
214
206
|
end
|
|
215
207
|
|
|
216
|
-
it
|
|
217
|
-
assert_equal
|
|
218
|
-
assert_equal
|
|
208
|
+
it "quote table names like columns" do
|
|
209
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
210
|
+
assert_equal "[foo].[bar].[baz]", connection.quote_column_name("foo.bar.baz")
|
|
219
211
|
end
|
|
220
212
|
|
|
221
213
|
it "surround string with national prefix" do
|
|
@@ -225,44 +217,40 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
225
217
|
it "escape all single quotes by repeating them" do
|
|
226
218
|
assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
|
|
227
219
|
end
|
|
228
|
-
|
|
229
220
|
end
|
|
230
221
|
|
|
231
|
-
describe
|
|
232
|
-
|
|
222
|
+
describe "disabling referential integrity" do
|
|
233
223
|
before do
|
|
234
224
|
connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
|
|
235
225
|
@parent = SSTestHasPk.create!
|
|
236
226
|
@member = SSTestHasFk.create!(fk_id: @parent.id)
|
|
237
227
|
end
|
|
238
228
|
|
|
239
|
-
it
|
|
240
|
-
SSTestHasPk.connection.disable_referential_integrity {
|
|
229
|
+
it "NOT ALLOW by default the deletion of a referenced parent" do
|
|
230
|
+
SSTestHasPk.connection.disable_referential_integrity {}
|
|
241
231
|
assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
|
|
242
232
|
end
|
|
243
233
|
|
|
244
|
-
it
|
|
234
|
+
it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
|
|
245
235
|
SSTestHasPk.connection.disable_referential_integrity { @parent.destroy }
|
|
246
236
|
end
|
|
247
237
|
|
|
248
|
-
it
|
|
238
|
+
it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
|
|
249
239
|
assert_raise(ActiveRecord::StatementInvalid) do
|
|
250
|
-
SSTestHasPk.connection.disable_referential_integrity {
|
|
240
|
+
SSTestHasPk.connection.disable_referential_integrity {}
|
|
251
241
|
@parent.destroy
|
|
252
242
|
end
|
|
253
243
|
end
|
|
254
244
|
|
|
255
|
-
it
|
|
245
|
+
it "not disable referential integrity for the same table twice" do
|
|
256
246
|
tables = SSTestHasPk.connection.tables_with_referential_integrity
|
|
257
247
|
assert_equal tables.size, tables.uniq.size
|
|
258
248
|
end
|
|
259
|
-
|
|
260
249
|
end
|
|
261
250
|
|
|
262
|
-
describe
|
|
263
|
-
|
|
251
|
+
describe "database statements" do
|
|
264
252
|
it "run the database consistency checker useroptions command" do
|
|
265
|
-
skip
|
|
253
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
266
254
|
keys = [:textsize, :language, :isolation_level, :dateformat]
|
|
267
255
|
user_options = connection.user_options
|
|
268
256
|
keys.each do |key|
|
|
@@ -272,185 +260,178 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
272
260
|
end
|
|
273
261
|
|
|
274
262
|
it "return a underscored key hash with indifferent access of the results" do
|
|
275
|
-
skip
|
|
263
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
276
264
|
user_options = connection.user_options
|
|
277
|
-
assert_equal
|
|
278
|
-
assert_equal
|
|
265
|
+
assert_equal "read committed", user_options["isolation_level"]
|
|
266
|
+
assert_equal "read committed", user_options[:isolation_level]
|
|
279
267
|
end
|
|
280
|
-
|
|
281
268
|
end
|
|
282
269
|
|
|
283
|
-
describe
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
assert_equal 'integer', connection.type_to_sql(:integer)
|
|
270
|
+
describe "schema statements" do
|
|
271
|
+
it "create integers when no limit supplied" do
|
|
272
|
+
assert_equal "integer", connection.type_to_sql(:integer)
|
|
287
273
|
end
|
|
288
274
|
|
|
289
|
-
it
|
|
290
|
-
assert_equal
|
|
275
|
+
it "create integers when limit is 4" do
|
|
276
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 4)
|
|
291
277
|
end
|
|
292
278
|
|
|
293
|
-
it
|
|
294
|
-
assert_equal
|
|
279
|
+
it "create integers when limit is 3" do
|
|
280
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 3)
|
|
295
281
|
end
|
|
296
282
|
|
|
297
|
-
it
|
|
298
|
-
assert_equal
|
|
283
|
+
it "create smallints when limit is 2" do
|
|
284
|
+
assert_equal "smallint", connection.type_to_sql(:integer, limit: 2)
|
|
299
285
|
end
|
|
300
286
|
|
|
301
|
-
it
|
|
302
|
-
assert_equal
|
|
287
|
+
it "create tinyints when limit is 1" do
|
|
288
|
+
assert_equal "tinyint", connection.type_to_sql(:integer, limit: 1)
|
|
303
289
|
end
|
|
304
290
|
|
|
305
|
-
it
|
|
306
|
-
assert_equal
|
|
307
|
-
assert_equal
|
|
308
|
-
assert_equal
|
|
309
|
-
assert_equal
|
|
291
|
+
it "create bigints when limit is greateer than 4" do
|
|
292
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 5)
|
|
293
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 6)
|
|
294
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 7)
|
|
295
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 8)
|
|
310
296
|
end
|
|
311
297
|
|
|
312
|
-
it
|
|
313
|
-
assert_equal
|
|
298
|
+
it "create floats when no limit supplied" do
|
|
299
|
+
assert_equal "float", connection.type_to_sql(:float)
|
|
314
300
|
end
|
|
315
|
-
|
|
316
301
|
end
|
|
317
302
|
|
|
318
|
-
describe
|
|
319
|
-
|
|
303
|
+
describe "views" do
|
|
320
304
|
# Using connection.views
|
|
321
305
|
|
|
322
|
-
it
|
|
306
|
+
it "return an array" do
|
|
323
307
|
assert_instance_of Array, connection.views
|
|
324
308
|
end
|
|
325
309
|
|
|
326
|
-
it
|
|
327
|
-
_(connection.views).must_include
|
|
310
|
+
it "find SSTestCustomersView table name" do
|
|
311
|
+
_(connection.views).must_include "sst_customers_view"
|
|
328
312
|
end
|
|
329
313
|
|
|
330
|
-
it
|
|
331
|
-
name =
|
|
314
|
+
it "work with dynamic finders" do
|
|
315
|
+
name = "MetaSkills"
|
|
332
316
|
customer = SSTestCustomersView.create! name: name
|
|
333
317
|
assert_equal customer, SSTestCustomersView.find_by_name(name)
|
|
334
318
|
end
|
|
335
319
|
|
|
336
|
-
it
|
|
337
|
-
systables = [
|
|
320
|
+
it "not contain system views" do
|
|
321
|
+
systables = ["sysconstraints", "syssegments"]
|
|
338
322
|
systables.each do |systable|
|
|
339
323
|
assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
|
|
340
324
|
end
|
|
341
325
|
end
|
|
342
326
|
|
|
343
|
-
it
|
|
344
|
-
view_info = connection.send(:view_information,
|
|
345
|
-
assert_equal(
|
|
346
|
-
assert_match(/CREATE VIEW sst_customers_view/, view_info[
|
|
327
|
+
it "allow the connection#view_information method to return meta data on the view" do
|
|
328
|
+
view_info = connection.send(:view_information, "sst_customers_view")
|
|
329
|
+
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
|
330
|
+
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
|
347
331
|
end
|
|
348
332
|
|
|
349
|
-
it
|
|
350
|
-
assert_equal
|
|
351
|
-
assert_equal
|
|
333
|
+
it "allow the connection#view_table_name method to return true table_name for the view" do
|
|
334
|
+
assert_equal "customers", connection.send(:view_table_name, "sst_customers_view")
|
|
335
|
+
assert_equal "topics", connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
|
|
352
336
|
end
|
|
353
337
|
|
|
354
338
|
# With same column names
|
|
355
339
|
|
|
356
|
-
it
|
|
357
|
-
columns = [
|
|
340
|
+
it "have matching column objects" do
|
|
341
|
+
columns = ["id", "name", "balance"]
|
|
358
342
|
assert !SSTestCustomersView.columns.blank?
|
|
359
343
|
assert_equal columns.size, SSTestCustomersView.columns.size
|
|
360
344
|
columns.each do |colname|
|
|
361
345
|
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
|
|
362
|
-
|
|
363
|
-
|
|
346
|
+
SSTestCustomersView.columns_hash[colname],
|
|
347
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
|
|
364
348
|
end
|
|
365
349
|
end
|
|
366
350
|
|
|
367
|
-
it
|
|
368
|
-
_(SSTestCustomersView.primary_key).must_equal
|
|
369
|
-
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal
|
|
370
|
-
_(SSTestCustomersView.columns_hash[
|
|
351
|
+
it "find identity column" do
|
|
352
|
+
_(SSTestCustomersView.primary_key).must_equal "id"
|
|
353
|
+
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal "id"
|
|
354
|
+
_(SSTestCustomersView.columns_hash["id"]).must_be :is_identity?
|
|
371
355
|
end
|
|
372
356
|
|
|
373
|
-
it
|
|
357
|
+
it "find default values" do
|
|
374
358
|
assert_equal 0, SSTestCustomersView.new.balance
|
|
375
359
|
end
|
|
376
360
|
|
|
377
|
-
it
|
|
361
|
+
it "respond true to data_source_exists?" do
|
|
378
362
|
assert SSTestCustomersView.connection.data_source_exists?(SSTestCustomersView.table_name)
|
|
379
363
|
end
|
|
380
364
|
|
|
381
365
|
# With aliased column names
|
|
382
366
|
|
|
383
|
-
it
|
|
384
|
-
columns = [
|
|
367
|
+
it "have matching column objects" do
|
|
368
|
+
columns = ["id", "pretend_null"]
|
|
385
369
|
assert !SSTestStringDefaultsView.columns.blank?
|
|
386
370
|
assert_equal columns.size, SSTestStringDefaultsView.columns.size
|
|
387
371
|
columns.each do |colname|
|
|
388
372
|
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
|
|
389
|
-
|
|
390
|
-
|
|
373
|
+
SSTestStringDefaultsView.columns_hash[colname],
|
|
374
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
|
|
391
375
|
end
|
|
392
376
|
end
|
|
393
377
|
|
|
394
|
-
it
|
|
395
|
-
_(SSTestStringDefaultsView.primary_key).must_equal
|
|
396
|
-
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal
|
|
397
|
-
_(SSTestStringDefaultsView.columns_hash[
|
|
378
|
+
it "find identity column" do
|
|
379
|
+
_(SSTestStringDefaultsView.primary_key).must_equal "id"
|
|
380
|
+
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal "id"
|
|
381
|
+
_(SSTestStringDefaultsView.columns_hash["id"]).must_be :is_identity?
|
|
398
382
|
end
|
|
399
383
|
|
|
400
|
-
it
|
|
401
|
-
assert_equal
|
|
402
|
-
|
|
384
|
+
it "find default values" do
|
|
385
|
+
assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
|
|
386
|
+
SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
|
|
403
387
|
end
|
|
404
388
|
|
|
405
|
-
it
|
|
389
|
+
it "respond true to data_source_exists?" do
|
|
406
390
|
assert SSTestStringDefaultsView.connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
|
407
391
|
end
|
|
408
392
|
|
|
409
393
|
# That have more than 4000 chars for their defintion
|
|
410
394
|
|
|
411
|
-
it
|
|
395
|
+
it "cope with null returned for the defintion" do
|
|
412
396
|
assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
|
|
413
397
|
end
|
|
414
398
|
|
|
415
|
-
it
|
|
416
|
-
assert_equal
|
|
417
|
-
|
|
399
|
+
it "using alternate view defintion still be able to find real default" do
|
|
400
|
+
assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
|
|
401
|
+
SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
|
|
418
402
|
end
|
|
419
|
-
|
|
420
403
|
end
|
|
421
404
|
|
|
422
|
-
describe
|
|
423
|
-
|
|
405
|
+
describe "database_prefix_remote_server?" do
|
|
424
406
|
after do
|
|
425
407
|
connection_options.delete(:database_prefix)
|
|
426
408
|
end
|
|
427
409
|
|
|
428
|
-
it
|
|
410
|
+
it "returns false if database_prefix is not configured" do
|
|
429
411
|
assert_equal false, connection.database_prefix_remote_server?
|
|
430
412
|
end
|
|
431
413
|
|
|
432
|
-
it
|
|
414
|
+
it "returns true if database_prefix has been set" do
|
|
433
415
|
connection_options[:database_prefix] = "server.database.schema."
|
|
434
416
|
assert_equal true, connection.database_prefix_remote_server?
|
|
435
417
|
end
|
|
436
418
|
|
|
437
|
-
it
|
|
419
|
+
it "returns false if database_prefix has been set incorrectly" do
|
|
438
420
|
connection_options[:database_prefix] = "server.database.schema"
|
|
439
421
|
assert_equal false, connection.database_prefix_remote_server?
|
|
440
422
|
end
|
|
441
|
-
|
|
442
423
|
end
|
|
443
424
|
|
|
444
|
-
it
|
|
445
|
-
if ENV[
|
|
446
|
-
_(SSTMemory.primary_key).must_equal
|
|
447
|
-
_(SSTMemory.columns_hash[
|
|
425
|
+
it "in_memory_oltp" do
|
|
426
|
+
if ENV["IN_MEMORY_OLTP"] && connection.supports_in_memory_oltp?
|
|
427
|
+
_(SSTMemory.primary_key).must_equal "id"
|
|
428
|
+
_(SSTMemory.columns_hash["id"]).must_be :is_identity?
|
|
448
429
|
else
|
|
449
|
-
skip
|
|
430
|
+
skip "supports_in_memory_oltp? => false"
|
|
450
431
|
end
|
|
451
432
|
end
|
|
452
433
|
|
|
453
|
-
describe
|
|
434
|
+
describe "block writes to a database" do
|
|
454
435
|
def setup
|
|
455
436
|
@conn = ActiveRecord::Base.connection
|
|
456
437
|
@connection_handler = ActiveRecord::Base.connection_handler
|
|
@@ -492,6 +473,4 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
492
473
|
end
|
|
493
474
|
end
|
|
494
475
|
end
|
|
495
|
-
|
|
496
476
|
end
|
|
497
|
-
|