activerecord-sqlserver-adapter 6.0.0.rc1 → 6.1.0.0.rc1
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/.github/workflows/ci.yml +26 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/CHANGELOG.md +18 -23
- data/Gemfile +11 -5
- data/Guardfile +9 -8
- data/README.md +32 -3
- data/RUNNING_UNIT_TESTS.md +1 -1
- data/Rakefile +12 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +4 -4
- 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 -13
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +8 -5
- 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_limits.rb +0 -4
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +58 -43
- 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 +15 -15
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +22 -3
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +16 -10
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +131 -105
- 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 +25 -7
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +1 -5
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +6 -10
- data/lib/active_record/connection_adapters/sqlserver/type.rb +36 -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/decimal_without_scale.rb +22 -0
- 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 +170 -136
- data/lib/active_record/connection_adapters/sqlserver_column.rb +16 -1
- data/lib/active_record/sqlserver_base.rb +9 -15
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +36 -39
- data/lib/activerecord-sqlserver-adapter.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +126 -50
- data/lib/arel_sqlserver.rb +2 -2
- data/test/cases/adapter_test_sqlserver.rb +203 -190
- data/test/cases/change_column_collation_test_sqlserver.rb +33 -0
- data/test/cases/change_column_null_test_sqlserver.rb +12 -12
- data/test/cases/coerced_tests.rb +656 -318
- data/test/cases/column_test_sqlserver.rb +285 -284
- data/test/cases/connection_test_sqlserver.rb +15 -20
- data/test/cases/disconnected_test_sqlserver.rb +39 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +26 -19
- 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 +36 -9
- data/test/cases/index_test_sqlserver.rb +13 -15
- data/test/cases/json_test_sqlserver.rb +23 -25
- data/test/cases/lateral_test_sqlserver.rb +35 -0
- data/test/cases/migration_test_sqlserver.rb +71 -26
- data/test/cases/optimizer_hints_test_sqlserver.rb +72 -0
- data/test/cases/order_test_sqlserver.rb +57 -53
- data/test/cases/pessimistic_locking_test_sqlserver.rb +25 -33
- data/test/cases/primary_keys_test_sqlserver.rb +103 -0
- data/test/cases/rake_test_sqlserver.rb +33 -46
- data/test/cases/schema_dumper_test_sqlserver.rb +121 -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_collation.rb +19 -0
- 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/sst_string_collation.rb +3 -0
- 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 +36 -21
- 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/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_0_topic_associations.dump +0 -0
- 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 +14 -16
- data/test/support/test_in_memory_oltp.rb +7 -7
- metadata +31 -11
- data/.travis.yml +0 -23
data/lib/arel_sqlserver.rb
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
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
|
+
require "models/college"
|
|
9
10
|
|
|
10
11
|
class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
11
|
-
|
|
12
12
|
fixtures :tasks
|
|
13
13
|
|
|
14
14
|
let(:basic_insert_sql) { "INSERT INTO [funny_jokes] ([name]) VALUES('Knock knock')" }
|
|
15
15
|
let(:basic_update_sql) { "UPDATE [customers] SET [address_street] = NULL WHERE [id] = 2" }
|
|
16
16
|
let(:basic_select_sql) { "SELECT * FROM [customers] WHERE ([customers].[id] = 1)" }
|
|
17
17
|
|
|
18
|
-
it
|
|
18
|
+
it "has basic and non-sensitive information in the adapters inspect method" do
|
|
19
19
|
string = connection.inspect
|
|
20
20
|
_(string).must_match %r{ActiveRecord::ConnectionAdapters::SQLServerAdapter}
|
|
21
21
|
_(string).must_match %r{version\: \d.\d}
|
|
@@ -27,67 +27,100 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
27
27
|
_(string).wont_match %r{port}
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
it
|
|
30
|
+
it "has a 128 max #table_alias_length" do
|
|
31
31
|
assert connection.table_alias_length <= 128
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
it
|
|
34
|
+
it "raises invalid statement error for bad SQL" do
|
|
35
35
|
assert_raise(ActiveRecord::StatementInvalid) { Topic.connection.update("UPDATE XXX") }
|
|
36
36
|
end
|
|
37
37
|
|
|
38
|
-
it
|
|
39
|
-
assert_equal
|
|
38
|
+
it "is has our adapter_name" do
|
|
39
|
+
assert_equal "SQLServer", connection.adapter_name
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
it
|
|
42
|
+
it "support DDL in transactions" do
|
|
43
43
|
assert connection.supports_ddl_transactions?
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
it
|
|
46
|
+
it "table exists works if table name prefixed by schema and owner" do
|
|
47
47
|
begin
|
|
48
|
-
assert_equal
|
|
48
|
+
assert_equal "topics", Topic.table_name
|
|
49
49
|
assert Topic.table_exists?
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
|
|
51
|
+
# Test when owner included in table name.
|
|
52
|
+
Topic.table_name = "dbo.topics"
|
|
53
|
+
assert Topic.table_exists?, "Topics table name of 'dbo.topics' should return true for exists."
|
|
54
|
+
|
|
55
|
+
# Test when database and owner included in table name.
|
|
56
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
57
|
+
Topic.table_name = "#{db_config.database}.dbo.topics"
|
|
58
|
+
assert Topic.table_exists?, "Topics table name of '[DATABASE].dbo.topics' should return true for exists."
|
|
52
59
|
ensure
|
|
53
|
-
Topic.table_name =
|
|
60
|
+
Topic.table_name = "topics"
|
|
54
61
|
end
|
|
55
62
|
end
|
|
56
63
|
|
|
57
|
-
it
|
|
58
|
-
|
|
64
|
+
it "test table existence across database schemas" do
|
|
65
|
+
arunit_connection = Topic.connection
|
|
66
|
+
arunit2_connection = College.connection
|
|
67
|
+
|
|
68
|
+
arunit_database = arunit_connection.pool.db_config.database
|
|
69
|
+
arunit2_database = arunit2_connection.pool.db_config.database
|
|
70
|
+
|
|
71
|
+
# Assert that connections use different default databases schemas.
|
|
72
|
+
assert_not_equal arunit_database, arunit2_database
|
|
73
|
+
|
|
74
|
+
# Assert that the Topics table exists when using the Topics connection.
|
|
75
|
+
assert arunit_connection.table_exists?('topics'), 'Topics table exists using table name'
|
|
76
|
+
assert arunit_connection.table_exists?('dbo.topics'), 'Topics table exists using owner and table name'
|
|
77
|
+
assert arunit_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using database, owner and table name'
|
|
78
|
+
|
|
79
|
+
# Assert that the Colleges table exists when using the Colleges connection.
|
|
80
|
+
assert arunit2_connection.table_exists?('colleges'), 'College table exists using table name'
|
|
81
|
+
assert arunit2_connection.table_exists?('dbo.colleges'), 'College table exists using owner and table name'
|
|
82
|
+
assert arunit2_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'College table exists using database, owner and table name'
|
|
83
|
+
|
|
84
|
+
# Assert that the tables exist when using each others connection.
|
|
85
|
+
assert arunit_connection.table_exists?("#{arunit2_database}.dbo.colleges"), 'Colleges table exists using Topics connection'
|
|
86
|
+
assert arunit2_connection.table_exists?("#{arunit_database}.dbo.topics"), 'Topics table exists using Colleges connection'
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "return true to insert sql query for inserts only" do
|
|
90
|
+
assert connection.send(:insert_sql?, "INSERT...")
|
|
59
91
|
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?,
|
|
92
|
+
assert !connection.send(:insert_sql?, "UPDATE...")
|
|
93
|
+
assert !connection.send(:insert_sql?, "SELECT...")
|
|
62
94
|
end
|
|
63
95
|
|
|
64
|
-
it
|
|
65
|
-
assert_equal
|
|
66
|
-
assert_equal
|
|
67
|
-
assert_equal
|
|
96
|
+
it "return unquoted table name object from basic INSERT UPDATE and SELECT statements" do
|
|
97
|
+
assert_equal "funny_jokes", connection.send(:get_table_name, basic_insert_sql)
|
|
98
|
+
assert_equal "customers", connection.send(:get_table_name, basic_update_sql)
|
|
99
|
+
assert_equal "customers", connection.send(:get_table_name, basic_select_sql)
|
|
68
100
|
end
|
|
69
101
|
|
|
70
|
-
it
|
|
102
|
+
it "test bad connection" do
|
|
71
103
|
assert_raise ActiveRecord::NoDatabaseError do
|
|
72
|
-
|
|
73
|
-
|
|
104
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
105
|
+
configuration = db_config.configuration_hash.merge(database: "inexistent_activerecord_unittest")
|
|
106
|
+
ActiveRecord::Base.sqlserver_connection configuration
|
|
74
107
|
end
|
|
75
108
|
end
|
|
76
109
|
|
|
77
|
-
it
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
it "test database exists returns false if database does not exist" do
|
|
111
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
112
|
+
configuration = db_config.configuration_hash.merge(database: "inexistent_activerecord_unittest")
|
|
113
|
+
assert_not ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(configuration),
|
|
114
|
+
"expected database to not exist"
|
|
81
115
|
end
|
|
82
116
|
|
|
83
|
-
it
|
|
84
|
-
|
|
85
|
-
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(
|
|
86
|
-
|
|
117
|
+
it "test database exists returns true when the database exists" do
|
|
118
|
+
db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")
|
|
119
|
+
assert ActiveRecord::ConnectionAdapters::SQLServerAdapter.database_exists?(db_config.configuration_hash),
|
|
120
|
+
"expected database #{db_config.database} to exist"
|
|
87
121
|
end
|
|
88
122
|
|
|
89
|
-
describe
|
|
90
|
-
|
|
123
|
+
describe "with different language" do
|
|
91
124
|
before do
|
|
92
125
|
@default_language = connection.user_options_language
|
|
93
126
|
end
|
|
@@ -97,18 +130,18 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
97
130
|
connection.send :initialize_dateformatter
|
|
98
131
|
end
|
|
99
132
|
|
|
100
|
-
it
|
|
133
|
+
it "memos users dateformat" do
|
|
101
134
|
connection.execute("SET LANGUAGE us_english") rescue nil
|
|
102
135
|
dateformat = connection.instance_variable_get(:@database_dateformat)
|
|
103
|
-
assert_equal
|
|
136
|
+
assert_equal "mdy", dateformat
|
|
104
137
|
end
|
|
105
138
|
|
|
106
|
-
it
|
|
139
|
+
it "has a dateformatter" do
|
|
107
140
|
assert Date::DATE_FORMATS[:_sqlserver_dateformat]
|
|
108
141
|
assert Time::DATE_FORMATS[:_sqlserver_dateformat]
|
|
109
142
|
end
|
|
110
143
|
|
|
111
|
-
it
|
|
144
|
+
it "does a datetime insertion when language is german" do
|
|
112
145
|
connection.execute("SET LANGUAGE deutsch")
|
|
113
146
|
connection.send :initialize_dateformatter
|
|
114
147
|
assert_nothing_raised do
|
|
@@ -117,40 +150,36 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
117
150
|
Task.create! starting: starting, ending: ending
|
|
118
151
|
end
|
|
119
152
|
end
|
|
120
|
-
|
|
121
153
|
end
|
|
122
154
|
|
|
123
|
-
describe
|
|
124
|
-
|
|
155
|
+
describe "testing #lowercase_schema_reflection" do
|
|
125
156
|
before do
|
|
126
157
|
SSTestUpper.delete_all
|
|
127
|
-
SSTestUpper.create COLUMN1:
|
|
128
|
-
SSTestUpper.create COLUMN1:
|
|
158
|
+
SSTestUpper.create COLUMN1: "Got a minute?", COLUMN2: 419
|
|
159
|
+
SSTestUpper.create COLUMN1: "Favorite number?", COLUMN2: 69
|
|
129
160
|
end
|
|
130
161
|
|
|
131
162
|
after do
|
|
132
163
|
connection.lowercase_schema_reflection = false
|
|
133
164
|
end
|
|
134
165
|
|
|
135
|
-
it
|
|
136
|
-
assert SSTestUpper.columns_hash[
|
|
137
|
-
assert_equal
|
|
138
|
-
assert_equal
|
|
139
|
-
assert SSTestUpper.columns_hash[
|
|
166
|
+
it "not lowercase schema reflection by default" do
|
|
167
|
+
assert SSTestUpper.columns_hash["COLUMN1"]
|
|
168
|
+
assert_equal "Got a minute?", SSTestUpper.first.COLUMN1
|
|
169
|
+
assert_equal "Favorite number?", SSTestUpper.last.COLUMN1
|
|
170
|
+
assert SSTestUpper.columns_hash["COLUMN2"]
|
|
140
171
|
end
|
|
141
172
|
|
|
142
|
-
it
|
|
173
|
+
it "lowercase schema reflection when set" do
|
|
143
174
|
connection.lowercase_schema_reflection = true
|
|
144
|
-
assert SSTestUppered.columns_hash[
|
|
145
|
-
assert_equal
|
|
146
|
-
assert_equal
|
|
147
|
-
assert SSTestUppered.columns_hash[
|
|
175
|
+
assert SSTestUppered.columns_hash["column1"]
|
|
176
|
+
assert_equal "Got a minute?", SSTestUppered.first.column1
|
|
177
|
+
assert_equal "Favorite number?", SSTestUppered.last.column1
|
|
178
|
+
assert SSTestUppered.columns_hash["column2"]
|
|
148
179
|
end
|
|
149
|
-
|
|
150
180
|
end
|
|
151
181
|
|
|
152
|
-
describe
|
|
153
|
-
|
|
182
|
+
describe "identity inserts" do
|
|
154
183
|
before do
|
|
155
184
|
@identity_insert_sql = "INSERT INTO [funny_jokes] ([id],[name]) VALUES(420,'Knock knock')"
|
|
156
185
|
@identity_insert_sql_unquoted = "INSERT INTO funny_jokes (id, name) VALUES(420, 'Knock knock')"
|
|
@@ -160,62 +189,60 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
160
189
|
@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
190
|
end
|
|
162
191
|
|
|
163
|
-
it
|
|
164
|
-
assert_equal
|
|
165
|
-
assert_equal
|
|
166
|
-
assert_equal
|
|
167
|
-
assert_equal
|
|
168
|
-
assert_equal
|
|
169
|
-
assert_equal
|
|
192
|
+
it "return quoted table_name to #query_requires_identity_insert? when INSERT sql contains id column" do
|
|
193
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql)
|
|
194
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted)
|
|
195
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered)
|
|
196
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_sp)
|
|
197
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unquoted_sp)
|
|
198
|
+
assert_equal "funny_jokes", connection.send(:query_requires_identity_insert?, @identity_insert_sql_unordered_sp)
|
|
170
199
|
end
|
|
171
200
|
|
|
172
|
-
it
|
|
201
|
+
it "return false to #query_requires_identity_insert? for normal SQL" do
|
|
173
202
|
[basic_insert_sql, basic_update_sql, basic_select_sql].each do |sql|
|
|
174
|
-
assert !connection.send(:query_requires_identity_insert?,sql), "SQL was #{sql}"
|
|
203
|
+
assert !connection.send(:query_requires_identity_insert?, sql), "SQL was #{sql}"
|
|
175
204
|
end
|
|
176
205
|
end
|
|
177
206
|
|
|
178
|
-
it
|
|
179
|
-
task_id_column = Task.columns_hash[
|
|
207
|
+
it "find identity column using #identity_columns" do
|
|
208
|
+
task_id_column = Task.columns_hash["id"]
|
|
180
209
|
assert_equal task_id_column.name, connection.send(:identity_columns, Task.table_name).first.name
|
|
181
210
|
assert_equal task_id_column.sql_type, connection.send(:identity_columns, Task.table_name).first.sql_type
|
|
182
211
|
end
|
|
183
212
|
|
|
184
|
-
it
|
|
213
|
+
it "return an empty array when calling #identity_columns for a table_name with no identity" do
|
|
185
214
|
_(connection.send(:identity_columns, Subscriber.table_name)).must_equal []
|
|
186
215
|
end
|
|
187
|
-
|
|
188
216
|
end
|
|
189
217
|
|
|
190
|
-
describe
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
assert_equal '1', connection.quoted_true
|
|
218
|
+
describe "quoting" do
|
|
219
|
+
it "return 1 for #quoted_true" do
|
|
220
|
+
assert_equal "1", connection.quoted_true
|
|
194
221
|
end
|
|
195
222
|
|
|
196
|
-
it
|
|
197
|
-
assert_equal
|
|
223
|
+
it "return 0 for #quoted_false" do
|
|
224
|
+
assert_equal "0", connection.quoted_false
|
|
198
225
|
end
|
|
199
226
|
|
|
200
|
-
it
|
|
227
|
+
it "not escape backslash characters like abstract adapter" do
|
|
201
228
|
string_with_backslashs = "\\n"
|
|
202
229
|
assert_equal string_with_backslashs, connection.quote_string(string_with_backslashs)
|
|
203
230
|
end
|
|
204
231
|
|
|
205
|
-
it
|
|
206
|
-
assert_equal
|
|
207
|
-
assert_equal
|
|
208
|
-
assert_equal
|
|
232
|
+
it "quote column names with brackets" do
|
|
233
|
+
assert_equal "[foo]", connection.quote_column_name(:foo)
|
|
234
|
+
assert_equal "[foo]", connection.quote_column_name("foo")
|
|
235
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
209
236
|
end
|
|
210
237
|
|
|
211
|
-
it
|
|
212
|
-
assert_equal
|
|
213
|
-
assert_equal
|
|
238
|
+
it "not quote already quoted column names with brackets" do
|
|
239
|
+
assert_equal "[foo]", connection.quote_column_name("[foo]")
|
|
240
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("[foo].[bar]")
|
|
214
241
|
end
|
|
215
242
|
|
|
216
|
-
it
|
|
217
|
-
assert_equal
|
|
218
|
-
assert_equal
|
|
243
|
+
it "quote table names like columns" do
|
|
244
|
+
assert_equal "[foo].[bar]", connection.quote_column_name("foo.bar")
|
|
245
|
+
assert_equal "[foo].[bar].[baz]", connection.quote_column_name("foo.bar.baz")
|
|
219
246
|
end
|
|
220
247
|
|
|
221
248
|
it "surround string with national prefix" do
|
|
@@ -225,44 +252,40 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
225
252
|
it "escape all single quotes by repeating them" do
|
|
226
253
|
assert_equal "N'''quotation''s'''", connection.quote("'quotation's'")
|
|
227
254
|
end
|
|
228
|
-
|
|
229
255
|
end
|
|
230
256
|
|
|
231
|
-
describe
|
|
232
|
-
|
|
257
|
+
describe "disabling referential integrity" do
|
|
233
258
|
before do
|
|
234
259
|
connection.disable_referential_integrity { SSTestHasPk.delete_all; SSTestHasFk.delete_all }
|
|
235
260
|
@parent = SSTestHasPk.create!
|
|
236
261
|
@member = SSTestHasFk.create!(fk_id: @parent.id)
|
|
237
262
|
end
|
|
238
263
|
|
|
239
|
-
it
|
|
240
|
-
SSTestHasPk.connection.disable_referential_integrity {
|
|
264
|
+
it "NOT ALLOW by default the deletion of a referenced parent" do
|
|
265
|
+
SSTestHasPk.connection.disable_referential_integrity {}
|
|
241
266
|
assert_raise(ActiveRecord::StatementInvalid) { @parent.destroy }
|
|
242
267
|
end
|
|
243
268
|
|
|
244
|
-
it
|
|
269
|
+
it "ALLOW deletion of referenced parent using #disable_referential_integrity block" do
|
|
245
270
|
SSTestHasPk.connection.disable_referential_integrity { @parent.destroy }
|
|
246
271
|
end
|
|
247
272
|
|
|
248
|
-
it
|
|
273
|
+
it "again NOT ALLOW deletion of referenced parent after #disable_referential_integrity block" do
|
|
249
274
|
assert_raise(ActiveRecord::StatementInvalid) do
|
|
250
|
-
SSTestHasPk.connection.disable_referential_integrity {
|
|
275
|
+
SSTestHasPk.connection.disable_referential_integrity {}
|
|
251
276
|
@parent.destroy
|
|
252
277
|
end
|
|
253
278
|
end
|
|
254
279
|
|
|
255
|
-
it
|
|
280
|
+
it "not disable referential integrity for the same table twice" do
|
|
256
281
|
tables = SSTestHasPk.connection.tables_with_referential_integrity
|
|
257
282
|
assert_equal tables.size, tables.uniq.size
|
|
258
283
|
end
|
|
259
|
-
|
|
260
284
|
end
|
|
261
285
|
|
|
262
|
-
describe
|
|
263
|
-
|
|
286
|
+
describe "database statements" do
|
|
264
287
|
it "run the database consistency checker useroptions command" do
|
|
265
|
-
skip
|
|
288
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
266
289
|
keys = [:textsize, :language, :isolation_level, :dateformat]
|
|
267
290
|
user_options = connection.user_options
|
|
268
291
|
keys.each do |key|
|
|
@@ -272,193 +295,185 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
272
295
|
end
|
|
273
296
|
|
|
274
297
|
it "return a underscored key hash with indifferent access of the results" do
|
|
275
|
-
skip
|
|
298
|
+
skip "on azure" if connection_sqlserver_azure?
|
|
276
299
|
user_options = connection.user_options
|
|
277
|
-
assert_equal
|
|
278
|
-
assert_equal
|
|
300
|
+
assert_equal "read committed", user_options["isolation_level"]
|
|
301
|
+
assert_equal "read committed", user_options[:isolation_level]
|
|
279
302
|
end
|
|
280
|
-
|
|
281
303
|
end
|
|
282
304
|
|
|
283
|
-
describe
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
assert_equal 'integer', connection.type_to_sql(:integer)
|
|
305
|
+
describe "schema statements" do
|
|
306
|
+
it "create integers when no limit supplied" do
|
|
307
|
+
assert_equal "integer", connection.type_to_sql(:integer)
|
|
287
308
|
end
|
|
288
309
|
|
|
289
|
-
it
|
|
290
|
-
assert_equal
|
|
310
|
+
it "create integers when limit is 4" do
|
|
311
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 4)
|
|
291
312
|
end
|
|
292
313
|
|
|
293
|
-
it
|
|
294
|
-
assert_equal
|
|
314
|
+
it "create integers when limit is 3" do
|
|
315
|
+
assert_equal "integer", connection.type_to_sql(:integer, limit: 3)
|
|
295
316
|
end
|
|
296
317
|
|
|
297
|
-
it
|
|
298
|
-
assert_equal
|
|
318
|
+
it "create smallints when limit is 2" do
|
|
319
|
+
assert_equal "smallint", connection.type_to_sql(:integer, limit: 2)
|
|
299
320
|
end
|
|
300
321
|
|
|
301
|
-
it
|
|
302
|
-
assert_equal
|
|
322
|
+
it "create tinyints when limit is 1" do
|
|
323
|
+
assert_equal "tinyint", connection.type_to_sql(:integer, limit: 1)
|
|
303
324
|
end
|
|
304
325
|
|
|
305
|
-
it
|
|
306
|
-
assert_equal
|
|
307
|
-
assert_equal
|
|
308
|
-
assert_equal
|
|
309
|
-
assert_equal
|
|
326
|
+
it "create bigints when limit is greateer than 4" do
|
|
327
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 5)
|
|
328
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 6)
|
|
329
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 7)
|
|
330
|
+
assert_equal "bigint", connection.type_to_sql(:integer, limit: 8)
|
|
310
331
|
end
|
|
311
332
|
|
|
312
|
-
it
|
|
313
|
-
assert_equal
|
|
333
|
+
it "create floats when no limit supplied" do
|
|
334
|
+
assert_equal "float", connection.type_to_sql(:float)
|
|
314
335
|
end
|
|
315
|
-
|
|
316
336
|
end
|
|
317
337
|
|
|
318
|
-
describe
|
|
319
|
-
|
|
338
|
+
describe "views" do
|
|
320
339
|
# Using connection.views
|
|
321
340
|
|
|
322
|
-
it
|
|
341
|
+
it "return an array" do
|
|
323
342
|
assert_instance_of Array, connection.views
|
|
324
343
|
end
|
|
325
344
|
|
|
326
|
-
it
|
|
327
|
-
_(connection.views).must_include
|
|
345
|
+
it "find SSTestCustomersView table name" do
|
|
346
|
+
_(connection.views).must_include "sst_customers_view"
|
|
328
347
|
end
|
|
329
348
|
|
|
330
|
-
it
|
|
331
|
-
name =
|
|
349
|
+
it "work with dynamic finders" do
|
|
350
|
+
name = "MetaSkills"
|
|
332
351
|
customer = SSTestCustomersView.create! name: name
|
|
333
352
|
assert_equal customer, SSTestCustomersView.find_by_name(name)
|
|
334
353
|
end
|
|
335
354
|
|
|
336
|
-
it
|
|
337
|
-
systables = [
|
|
355
|
+
it "not contain system views" do
|
|
356
|
+
systables = ["sysconstraints", "syssegments"]
|
|
338
357
|
systables.each do |systable|
|
|
339
358
|
assert !connection.views.include?(systable), "This systable #{systable} should not be in the views array."
|
|
340
359
|
end
|
|
341
360
|
end
|
|
342
361
|
|
|
343
|
-
it
|
|
344
|
-
view_info = connection.send(:view_information,
|
|
345
|
-
assert_equal(
|
|
346
|
-
assert_match(/CREATE VIEW sst_customers_view/, view_info[
|
|
362
|
+
it "allow the connection#view_information method to return meta data on the view" do
|
|
363
|
+
view_info = connection.send(:view_information, "sst_customers_view")
|
|
364
|
+
assert_equal("sst_customers_view", view_info["TABLE_NAME"])
|
|
365
|
+
assert_match(/CREATE VIEW sst_customers_view/, view_info["VIEW_DEFINITION"])
|
|
347
366
|
end
|
|
348
367
|
|
|
349
|
-
it
|
|
350
|
-
assert_equal
|
|
351
|
-
assert_equal
|
|
368
|
+
it "allow the connection#view_table_name method to return true table_name for the view" do
|
|
369
|
+
assert_equal "customers", connection.send(:view_table_name, "sst_customers_view")
|
|
370
|
+
assert_equal "topics", connection.send(:view_table_name, "topics"), "No view here, the same table name should come back."
|
|
352
371
|
end
|
|
353
372
|
|
|
354
373
|
# With same column names
|
|
355
374
|
|
|
356
|
-
it
|
|
357
|
-
columns = [
|
|
375
|
+
it "have matching column objects" do
|
|
376
|
+
columns = ["id", "name", "balance"]
|
|
358
377
|
assert !SSTestCustomersView.columns.blank?
|
|
359
378
|
assert_equal columns.size, SSTestCustomersView.columns.size
|
|
360
379
|
columns.each do |colname|
|
|
361
380
|
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
|
|
362
|
-
|
|
363
|
-
|
|
381
|
+
SSTestCustomersView.columns_hash[colname],
|
|
382
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestCustomersView.columns.map(&:name).inspect}"
|
|
364
383
|
end
|
|
365
384
|
end
|
|
366
385
|
|
|
367
|
-
it
|
|
368
|
-
_(SSTestCustomersView.primary_key).must_equal
|
|
369
|
-
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal
|
|
370
|
-
_(SSTestCustomersView.columns_hash[
|
|
386
|
+
it "find identity column" do
|
|
387
|
+
_(SSTestCustomersView.primary_key).must_equal "id"
|
|
388
|
+
_(connection.primary_key(SSTestCustomersView.table_name)).must_equal "id"
|
|
389
|
+
_(SSTestCustomersView.columns_hash["id"]).must_be :is_identity?
|
|
371
390
|
end
|
|
372
391
|
|
|
373
|
-
it
|
|
392
|
+
it "find default values" do
|
|
374
393
|
assert_equal 0, SSTestCustomersView.new.balance
|
|
375
394
|
end
|
|
376
395
|
|
|
377
|
-
it
|
|
396
|
+
it "respond true to data_source_exists?" do
|
|
378
397
|
assert SSTestCustomersView.connection.data_source_exists?(SSTestCustomersView.table_name)
|
|
379
398
|
end
|
|
380
399
|
|
|
381
400
|
# With aliased column names
|
|
382
401
|
|
|
383
|
-
it
|
|
384
|
-
columns = [
|
|
402
|
+
it "have matching column objects" do
|
|
403
|
+
columns = ["id", "pretend_null"]
|
|
385
404
|
assert !SSTestStringDefaultsView.columns.blank?
|
|
386
405
|
assert_equal columns.size, SSTestStringDefaultsView.columns.size
|
|
387
406
|
columns.each do |colname|
|
|
388
407
|
assert_instance_of ActiveRecord::ConnectionAdapters::SQLServerColumn,
|
|
389
|
-
|
|
390
|
-
|
|
408
|
+
SSTestStringDefaultsView.columns_hash[colname],
|
|
409
|
+
"Column name #{colname.inspect} was not found in these columns #{SSTestStringDefaultsView.columns.map(&:name).inspect}"
|
|
391
410
|
end
|
|
392
411
|
end
|
|
393
412
|
|
|
394
|
-
it
|
|
395
|
-
_(SSTestStringDefaultsView.primary_key).must_equal
|
|
396
|
-
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal
|
|
397
|
-
_(SSTestStringDefaultsView.columns_hash[
|
|
413
|
+
it "find identity column" do
|
|
414
|
+
_(SSTestStringDefaultsView.primary_key).must_equal "id"
|
|
415
|
+
_(connection.primary_key(SSTestStringDefaultsView.table_name)).must_equal "id"
|
|
416
|
+
_(SSTestStringDefaultsView.columns_hash["id"]).must_be :is_identity?
|
|
398
417
|
end
|
|
399
418
|
|
|
400
|
-
it
|
|
401
|
-
assert_equal
|
|
402
|
-
|
|
419
|
+
it "find default values" do
|
|
420
|
+
assert_equal "null", SSTestStringDefaultsView.new.pretend_null,
|
|
421
|
+
SSTestStringDefaultsView.columns_hash["pretend_null"].inspect
|
|
403
422
|
end
|
|
404
423
|
|
|
405
|
-
it
|
|
424
|
+
it "respond true to data_source_exists?" do
|
|
406
425
|
assert SSTestStringDefaultsView.connection.data_source_exists?(SSTestStringDefaultsView.table_name)
|
|
407
426
|
end
|
|
408
427
|
|
|
409
428
|
# That have more than 4000 chars for their defintion
|
|
410
429
|
|
|
411
|
-
it
|
|
430
|
+
it "cope with null returned for the defintion" do
|
|
412
431
|
assert_nothing_raised() { SSTestStringDefaultsBigView.columns }
|
|
413
432
|
end
|
|
414
433
|
|
|
415
|
-
it
|
|
416
|
-
assert_equal
|
|
417
|
-
|
|
434
|
+
it "using alternate view defintion still be able to find real default" do
|
|
435
|
+
assert_equal "null", SSTestStringDefaultsBigView.new.pretend_null,
|
|
436
|
+
SSTestStringDefaultsBigView.columns_hash["pretend_null"].inspect
|
|
418
437
|
end
|
|
419
|
-
|
|
420
438
|
end
|
|
421
439
|
|
|
422
|
-
describe
|
|
423
|
-
|
|
440
|
+
describe "database_prefix_remote_server?" do
|
|
424
441
|
after do
|
|
425
442
|
connection_options.delete(:database_prefix)
|
|
426
443
|
end
|
|
427
444
|
|
|
428
|
-
it
|
|
445
|
+
it "returns false if database_prefix is not configured" do
|
|
429
446
|
assert_equal false, connection.database_prefix_remote_server?
|
|
430
447
|
end
|
|
431
448
|
|
|
432
|
-
it
|
|
449
|
+
it "returns true if database_prefix has been set" do
|
|
433
450
|
connection_options[:database_prefix] = "server.database.schema."
|
|
434
451
|
assert_equal true, connection.database_prefix_remote_server?
|
|
435
452
|
end
|
|
436
453
|
|
|
437
|
-
it
|
|
454
|
+
it "returns false if database_prefix has been set incorrectly" do
|
|
438
455
|
connection_options[:database_prefix] = "server.database.schema"
|
|
439
456
|
assert_equal false, connection.database_prefix_remote_server?
|
|
440
457
|
end
|
|
441
|
-
|
|
442
458
|
end
|
|
443
459
|
|
|
444
|
-
it
|
|
445
|
-
if ENV[
|
|
446
|
-
_(SSTMemory.primary_key).must_equal
|
|
447
|
-
_(SSTMemory.columns_hash[
|
|
460
|
+
it "in_memory_oltp" do
|
|
461
|
+
if ENV["IN_MEMORY_OLTP"] && connection.supports_in_memory_oltp?
|
|
462
|
+
_(SSTMemory.primary_key).must_equal "id"
|
|
463
|
+
_(SSTMemory.columns_hash["id"]).must_be :is_identity?
|
|
448
464
|
else
|
|
449
|
-
skip
|
|
465
|
+
skip "supports_in_memory_oltp? => false"
|
|
450
466
|
end
|
|
451
467
|
end
|
|
452
468
|
|
|
453
|
-
describe
|
|
469
|
+
describe "block writes to a database" do
|
|
454
470
|
def setup
|
|
455
471
|
@conn = ActiveRecord::Base.connection
|
|
456
|
-
@connection_handler = ActiveRecord::Base.connection_handler
|
|
457
472
|
end
|
|
458
473
|
|
|
459
474
|
def test_errors_when_an_insert_query_is_called_while_preventing_writes
|
|
460
475
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
461
|
-
|
|
476
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
462
477
|
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
463
478
|
end
|
|
464
479
|
end
|
|
@@ -468,7 +483,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
468
483
|
@conn.insert("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
469
484
|
|
|
470
485
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
471
|
-
|
|
486
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
472
487
|
@conn.update("UPDATE [subscribers] SET [subscribers].[name] = 'Aidan' WHERE [subscribers].[nick] = 'aido'")
|
|
473
488
|
end
|
|
474
489
|
end
|
|
@@ -478,7 +493,7 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
478
493
|
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
479
494
|
|
|
480
495
|
assert_raises(ActiveRecord::ReadOnlyError) do
|
|
481
|
-
|
|
496
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
482
497
|
@conn.execute("DELETE FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
|
483
498
|
end
|
|
484
499
|
end
|
|
@@ -487,11 +502,9 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
|
|
|
487
502
|
def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes
|
|
488
503
|
@conn.execute("INSERT INTO [subscribers] ([nick]) VALUES ('aido')")
|
|
489
504
|
|
|
490
|
-
|
|
505
|
+
ActiveRecord::Base.while_preventing_writes do
|
|
491
506
|
assert_equal 1, @conn.execute("SELECT * FROM [subscribers] WHERE [subscribers].[nick] = 'aido'")
|
|
492
507
|
end
|
|
493
508
|
end
|
|
494
509
|
end
|
|
495
|
-
|
|
496
510
|
end
|
|
497
|
-
|