activerecord-sqlserver-adapter 5.2.1 → 6.0.0
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/.editorconfig +9 -0
- data/.github/issue_template.md +23 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +29 -0
- data/.travis.yml +6 -8
- data/CHANGELOG.md +38 -24
- data/{Dockerfile → Dockerfile.ci} +1 -1
- data/Gemfile +48 -41
- data/Guardfile +9 -8
- data/README.md +9 -30
- data/RUNNING_UNIT_TESTS.md +3 -0
- data/Rakefile +14 -16
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +25 -14
- data/appveyor.yml +24 -17
- data/docker-compose.ci.yml +7 -5
- data/guides/RELEASING.md +11 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/active_record.rb +2 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +3 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain_subscriber.rb +2 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/finder_methods.rb +8 -7
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +36 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/query_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +88 -44
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +9 -12
- data/lib/active_record/connection_adapters/sqlserver/errors.rb +2 -3
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +46 -8
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +16 -5
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +9 -7
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +190 -164
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_table.rb +4 -2
- data/lib/active_record/connection_adapters/sqlserver/showplan/printer_xml.rb +3 -1
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/sql_type_metadata.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +43 -44
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +7 -9
- data/lib/active_record/connection_adapters/sqlserver/type/big_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/binary.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/boolean.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/char.rb +7 -4
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +4 -3
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +8 -8
- data/lib/active_record/connection_adapters/sqlserver/type/datetime2.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/datetimeoffset.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/decimal.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/float.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/json.rb +2 -1
- data/lib/active_record/connection_adapters/sqlserver/type/money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/real.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/small_money.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/smalldatetime.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +6 -6
- data/lib/active_record/connection_adapters/sqlserver/type/time_value_fractional.rb +8 -9
- data/lib/active_record/connection_adapters/sqlserver/type/timestamp.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/tiny_integer.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_char.rb +5 -4
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_string.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_text.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/unicode_varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/uuid.rb +4 -3
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varbinary_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type/varchar.rb +6 -5
- data/lib/active_record/connection_adapters/sqlserver/type/varchar_max.rb +4 -4
- data/lib/active_record/connection_adapters/sqlserver/type.rb +37 -35
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +10 -11
- data/lib/active_record/connection_adapters/sqlserver/version.rb +2 -2
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +128 -92
- data/lib/active_record/connection_adapters/sqlserver_column.rb +9 -5
- data/lib/active_record/sqlserver_base.rb +9 -1
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +28 -32
- data/lib/activerecord-sqlserver-adapter.rb +3 -1
- data/lib/arel/visitors/sqlserver.rb +58 -24
- data/lib/arel_sqlserver.rb +4 -2
- data/test/appveyor/dbsetup.ps1 +4 -4
- data/test/cases/adapter_test_sqlserver.rb +214 -171
- data/test/cases/change_column_null_test_sqlserver.rb +14 -12
- data/test/cases/coerced_tests.rb +631 -356
- data/test/cases/column_test_sqlserver.rb +283 -284
- data/test/cases/connection_test_sqlserver.rb +17 -20
- data/test/cases/execute_procedure_test_sqlserver.rb +20 -20
- data/test/cases/fetch_test_sqlserver.rb +16 -22
- data/test/cases/fully_qualified_identifier_test_sqlserver.rb +15 -19
- data/test/cases/helper_sqlserver.rb +15 -15
- data/test/cases/in_clause_test_sqlserver.rb +36 -0
- data/test/cases/index_test_sqlserver.rb +15 -15
- data/test/cases/json_test_sqlserver.rb +25 -25
- data/test/cases/migration_test_sqlserver.rb +25 -29
- data/test/cases/order_test_sqlserver.rb +53 -54
- data/test/cases/pessimistic_locking_test_sqlserver.rb +27 -33
- data/test/cases/rake_test_sqlserver.rb +33 -45
- data/test/cases/schema_dumper_test_sqlserver.rb +107 -109
- data/test/cases/schema_test_sqlserver.rb +20 -26
- data/test/cases/scratchpad_test_sqlserver.rb +4 -4
- data/test/cases/showplan_test_sqlserver.rb +28 -35
- data/test/cases/specific_schema_test_sqlserver.rb +68 -65
- data/test/cases/transaction_test_sqlserver.rb +18 -20
- data/test/cases/trigger_test_sqlserver.rb +14 -13
- data/test/cases/utils_test_sqlserver.rb +70 -70
- data/test/cases/uuid_test_sqlserver.rb +13 -14
- data/test/debug.rb +8 -6
- data/test/migrations/create_clients_and_change_column_null.rb +3 -1
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +4 -4
- data/test/models/sqlserver/booking.rb +3 -1
- data/test/models/sqlserver/customers_view.rb +3 -1
- data/test/models/sqlserver/datatype.rb +2 -0
- data/test/models/sqlserver/datatype_migration.rb +2 -0
- data/test/models/sqlserver/dollar_table_name.rb +3 -1
- data/test/models/sqlserver/edge_schema.rb +3 -3
- data/test/models/sqlserver/fk_has_fk.rb +3 -1
- data/test/models/sqlserver/fk_has_pk.rb +3 -1
- data/test/models/sqlserver/natural_pk_data.rb +4 -2
- data/test/models/sqlserver/natural_pk_int_data.rb +3 -1
- data/test/models/sqlserver/no_pk_data.rb +3 -1
- data/test/models/sqlserver/object_default.rb +3 -1
- data/test/models/sqlserver/quoted_table.rb +4 -2
- data/test/models/sqlserver/quoted_view_1.rb +3 -1
- data/test/models/sqlserver/quoted_view_2.rb +3 -1
- data/test/models/sqlserver/sst_memory.rb +3 -1
- data/test/models/sqlserver/string_default.rb +3 -1
- data/test/models/sqlserver/string_defaults_big_view.rb +3 -1
- data/test/models/sqlserver/string_defaults_view.rb +3 -1
- data/test/models/sqlserver/tinyint_pk.rb +3 -1
- data/test/models/sqlserver/trigger.rb +4 -2
- data/test/models/sqlserver/trigger_history.rb +3 -1
- data/test/models/sqlserver/upper.rb +3 -1
- data/test/models/sqlserver/uppered.rb +3 -1
- data/test/models/sqlserver/uuid.rb +3 -1
- data/test/schema/sqlserver_specific_schema.rb +22 -22
- data/test/support/coerceable_test_sqlserver.rb +15 -9
- data/test/support/connection_reflection.rb +3 -2
- data/test/support/core_ext/query_cache.rb +4 -1
- data/test/support/load_schema_sqlserver.rb +5 -5
- data/test/support/minitest_sqlserver.rb +3 -1
- data/test/support/paths_sqlserver.rb +11 -11
- data/test/support/rake_helpers.rb +13 -10
- data/test/support/sql_counter_sqlserver.rb +3 -4
- data/test/support/test_in_memory_oltp.rb +9 -7
- metadata +17 -7
|
@@ -1,71 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
4
|
|
|
5
|
+
class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
5
6
|
after { SSTestEdgeSchema.delete_all }
|
|
6
7
|
|
|
7
|
-
it
|
|
8
|
+
it "handle dollar symbols" do
|
|
8
9
|
SSTestDollarTableName.create!
|
|
9
10
|
SSTestDollarTableName.limit(20).offset(1)
|
|
10
11
|
end
|
|
11
12
|
|
|
12
|
-
it
|
|
13
|
-
obj = SSTestTinyintPk.create! name:
|
|
14
|
-
_([
|
|
13
|
+
it "models can use tinyint pk tables" do
|
|
14
|
+
obj = SSTestTinyintPk.create! name: "1"
|
|
15
|
+
_(["Fixnum", "Integer"]).must_include obj.id.class.name
|
|
15
16
|
_(SSTestTinyintPk.find(obj.id)).must_equal obj
|
|
16
17
|
end
|
|
17
18
|
|
|
18
|
-
it
|
|
19
|
+
it "be able to complex count tables with no primary key" do
|
|
19
20
|
SSTestNoPkData.delete_all
|
|
20
21
|
10.times { |n| SSTestNoPkData.create! name: "Test#{n}" }
|
|
21
|
-
assert_equal 1, SSTestNoPkData.where(name:
|
|
22
|
+
assert_equal 1, SSTestNoPkData.where(name: "Test5").count
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
it
|
|
25
|
-
|
|
25
|
+
it "quote table names properly even when they are views" do
|
|
26
|
+
SSTestQuotedTable.create!
|
|
26
27
|
assert_nothing_raised { assert SSTestQuotedTable.first }
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
SSTestQuotedTableUser.create!
|
|
28
30
|
assert_nothing_raised { assert SSTestQuotedTableUser.first }
|
|
29
|
-
|
|
31
|
+
|
|
32
|
+
SSTestQuotedView1.create!
|
|
30
33
|
assert_nothing_raised { assert SSTestQuotedView1.first }
|
|
31
|
-
|
|
34
|
+
|
|
35
|
+
SSTestQuotedView2.create!
|
|
32
36
|
assert_nothing_raised { assert SSTestQuotedView2.first }
|
|
33
37
|
end
|
|
34
38
|
|
|
35
|
-
it
|
|
39
|
+
it "cope with multi line defaults" do
|
|
36
40
|
default = SSTestStringDefault.new
|
|
37
41
|
assert_equal "Some long default with a\nnew line.", default.string_with_multiline_default
|
|
38
42
|
end
|
|
39
43
|
|
|
40
|
-
it
|
|
44
|
+
it "default strings before save" do
|
|
41
45
|
default = SSTestStringDefault.new
|
|
42
46
|
assert_nil default.string_with_null_default
|
|
43
|
-
assert_equal
|
|
44
|
-
assert_equal
|
|
45
|
-
assert_equal
|
|
46
|
-
assert_equal
|
|
47
|
-
assert_equal
|
|
47
|
+
assert_equal "null", default.string_with_pretend_null_one
|
|
48
|
+
assert_equal "(null)", default.string_with_pretend_null_two
|
|
49
|
+
assert_equal "NULL", default.string_with_pretend_null_three
|
|
50
|
+
assert_equal "(NULL)", default.string_with_pretend_null_four
|
|
51
|
+
assert_equal "(3)", default.string_with_pretend_paren_three
|
|
48
52
|
end
|
|
49
53
|
|
|
50
|
-
it
|
|
54
|
+
it "default strings after save" do
|
|
51
55
|
default = SSTestStringDefault.create
|
|
52
56
|
assert_nil default.string_with_null_default
|
|
53
|
-
assert_equal
|
|
54
|
-
assert_equal
|
|
55
|
-
assert_equal
|
|
56
|
-
assert_equal
|
|
57
|
+
assert_equal "null", default.string_with_pretend_null_one
|
|
58
|
+
assert_equal "(null)", default.string_with_pretend_null_two
|
|
59
|
+
assert_equal "NULL", default.string_with_pretend_null_three
|
|
60
|
+
assert_equal "(NULL)", default.string_with_pretend_null_four
|
|
57
61
|
end
|
|
58
62
|
|
|
59
|
-
it
|
|
60
|
-
obj = SSTestObjectDefault.create! name:
|
|
61
|
-
_(obj.date).must_be_nil
|
|
63
|
+
it "default objects work" do
|
|
64
|
+
obj = SSTestObjectDefault.create! name: "MetaSkills"
|
|
65
|
+
_(obj.date).must_be_nil "since this is set on insert"
|
|
62
66
|
_(obj.reload.date).must_be_instance_of Date
|
|
63
67
|
end
|
|
64
68
|
|
|
65
|
-
it
|
|
66
|
-
_(SSTestBooking.columns_hash[
|
|
67
|
-
_(SSTestBooking.columns_hash[
|
|
68
|
-
obj1 = SSTestBooking.new name:
|
|
69
|
+
it "allows datetime2 as timestamps" do
|
|
70
|
+
_(SSTestBooking.columns_hash["created_at"].sql_type).must_equal "datetime2(7)"
|
|
71
|
+
_(SSTestBooking.columns_hash["updated_at"].sql_type).must_equal "datetime2(7)"
|
|
72
|
+
obj1 = SSTestBooking.new name: "test1"
|
|
69
73
|
obj1.save!
|
|
70
74
|
_(obj1.created_at).must_be_instance_of Time
|
|
71
75
|
_(obj1.updated_at).must_be_instance_of Time
|
|
@@ -73,35 +77,35 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
73
77
|
|
|
74
78
|
# Natural primary keys.
|
|
75
79
|
|
|
76
|
-
it
|
|
77
|
-
record = SSTestNaturalPkData.new name:
|
|
78
|
-
record.id =
|
|
80
|
+
it "work with identity inserts" do
|
|
81
|
+
record = SSTestNaturalPkData.new name: "Test", description: "Natural identity inserts."
|
|
82
|
+
record.id = "12345ABCDE"
|
|
79
83
|
assert record.save
|
|
80
|
-
assert_equal
|
|
84
|
+
assert_equal "12345ABCDE", record.reload.id
|
|
81
85
|
end
|
|
82
86
|
|
|
83
|
-
it
|
|
84
|
-
record = SSTestNaturalPkIntData.new name:
|
|
87
|
+
it "work with identity inserts when the key is an int" do
|
|
88
|
+
record = SSTestNaturalPkIntData.new name: "Test", description: "Natural identity inserts."
|
|
85
89
|
record.id = 12
|
|
86
90
|
assert record.save
|
|
87
91
|
assert_equal 12, record.reload.id
|
|
88
92
|
end
|
|
89
93
|
|
|
90
|
-
it
|
|
94
|
+
it "use primary key for row table order in pagination sql" do
|
|
91
95
|
sql = /ORDER BY \[sst_natural_pk_data\]\.\[legacy_id\] ASC OFFSET @0 ROWS FETCH NEXT @1 ROWS ONLY/
|
|
92
96
|
assert_sql(sql) { SSTestNaturalPkData.limit(5).offset(5).load }
|
|
93
97
|
end
|
|
94
98
|
|
|
95
99
|
# Special quoted column
|
|
96
100
|
|
|
97
|
-
it
|
|
101
|
+
it "work as normal" do
|
|
98
102
|
SSTestEdgeSchema.delete_all
|
|
99
|
-
r = SSTestEdgeSchema.create!
|
|
100
|
-
assert SSTestEdgeSchema.columns_hash[
|
|
101
|
-
assert_equal r, SSTestEdgeSchema.where(
|
|
103
|
+
r = SSTestEdgeSchema.create! "crazy]]quote" => "crazyqoute"
|
|
104
|
+
assert SSTestEdgeSchema.columns_hash["crazy]]quote"]
|
|
105
|
+
assert_equal r, SSTestEdgeSchema.where("crazy]]quote" => "crazyqoute").first
|
|
102
106
|
end
|
|
103
107
|
|
|
104
|
-
it
|
|
108
|
+
it "various methods to bypass national quoted columns for any column, but primarily useful for char/varchar" do
|
|
105
109
|
value = Class.new do
|
|
106
110
|
def quoted_id
|
|
107
111
|
"'T'"
|
|
@@ -113,14 +117,14 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
113
117
|
# Using our custom char type data.
|
|
114
118
|
type = ActiveRecord::Type::SQLServer::Char
|
|
115
119
|
data = ActiveRecord::Type::SQLServer::Data
|
|
116
|
-
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: data.new(
|
|
117
|
-
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: data.new(
|
|
120
|
+
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: data.new("T", type.new)).first }
|
|
121
|
+
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: data.new("T", type.new)).first }
|
|
118
122
|
# Taking care of everything.
|
|
119
|
-
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col:
|
|
120
|
-
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col:
|
|
123
|
+
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(char_col: "T").first }
|
|
124
|
+
assert_sql(/@0 = 'T'/) { SSTestDatatypeMigration.where(varchar_col: "T").first }
|
|
121
125
|
end
|
|
122
126
|
|
|
123
|
-
it
|
|
127
|
+
it "can update and hence properly quoted non-national char/varchar columns" do
|
|
124
128
|
o = SSTestDatatypeMigration.create!
|
|
125
129
|
o.varchar_col = "O'Reilly"
|
|
126
130
|
o.save!
|
|
@@ -132,28 +136,28 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
132
136
|
|
|
133
137
|
# With column names that have spaces
|
|
134
138
|
|
|
135
|
-
it
|
|
136
|
-
value =
|
|
139
|
+
it "create record using a custom attribute reader and be able to load it back in" do
|
|
140
|
+
value = "Saved value into a column that has a space in the name."
|
|
137
141
|
record = SSTestEdgeSchema.create! with_spaces: value
|
|
138
142
|
assert_equal value, SSTestEdgeSchema.find(record.id).with_spaces
|
|
139
143
|
end
|
|
140
144
|
|
|
141
145
|
# With description column
|
|
142
146
|
|
|
143
|
-
it
|
|
144
|
-
SSTestEdgeSchema.create! description:
|
|
145
|
-
SSTestEdgeSchema.create! description:
|
|
146
|
-
SSTestEdgeSchema.create! description:
|
|
147
|
-
assert_equal [
|
|
148
|
-
assert_equal [
|
|
149
|
-
assert_equal [
|
|
150
|
-
assert_equal [
|
|
151
|
-
assert_equal [
|
|
147
|
+
it "allow all sorts of ordering without adapter munging it up with special description column" do
|
|
148
|
+
SSTestEdgeSchema.create! description: "A"
|
|
149
|
+
SSTestEdgeSchema.create! description: "B"
|
|
150
|
+
SSTestEdgeSchema.create! description: "C"
|
|
151
|
+
assert_equal ["A", "B", "C"], SSTestEdgeSchema.order("description").map(&:description)
|
|
152
|
+
assert_equal ["A", "B", "C"], SSTestEdgeSchema.order("description asc").map(&:description)
|
|
153
|
+
assert_equal ["A", "B", "C"], SSTestEdgeSchema.order("description ASC").map(&:description)
|
|
154
|
+
assert_equal ["C", "B", "A"], SSTestEdgeSchema.order("description desc").map(&:description)
|
|
155
|
+
assert_equal ["C", "B", "A"], SSTestEdgeSchema.order("description DESC").map(&:description)
|
|
152
156
|
end
|
|
153
157
|
|
|
154
158
|
# For uniqueidentifier model helpers
|
|
155
159
|
|
|
156
|
-
it
|
|
160
|
+
it "returns a new id via connection newid_function" do
|
|
157
161
|
acceptable_uuid = ActiveRecord::ConnectionAdapters::SQLServer::Type::Uuid::ACCEPTABLE_UUID
|
|
158
162
|
db_uuid = ActiveRecord::Base.connection.newid_function
|
|
159
163
|
_(db_uuid).must_match(acceptable_uuid)
|
|
@@ -161,10 +165,9 @@ class SpecificSchemaTestSQLServer < ActiveRecord::TestCase
|
|
|
161
165
|
|
|
162
166
|
# with similar table definition in two schemas
|
|
163
167
|
|
|
164
|
-
it
|
|
168
|
+
it "returns the correct primary columns" do
|
|
165
169
|
connection = ActiveRecord::Base.connection
|
|
166
|
-
assert_equal
|
|
167
|
-
assert_equal
|
|
170
|
+
assert_equal "field_1", connection.columns("test.sst_schema_test_mulitple_schema").detect(&:is_primary?).name
|
|
171
|
+
assert_equal "field_2", connection.columns("test2.sst_schema_test_mulitple_schema").detect(&:is_primary?).name
|
|
168
172
|
end
|
|
169
|
-
|
|
170
173
|
end
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
#
|
|
2
|
-
require 'cases/helper_sqlserver'
|
|
3
|
-
require 'models/ship'
|
|
4
|
-
require 'models/developer'
|
|
1
|
+
# frozen_string_literal: true
|
|
5
2
|
|
|
6
|
-
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
|
+
require "models/ship"
|
|
5
|
+
require "models/developer"
|
|
7
6
|
|
|
7
|
+
class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
8
8
|
self.use_transactional_tests = false
|
|
9
9
|
|
|
10
10
|
before { delete_ships }
|
|
11
11
|
|
|
12
|
-
it
|
|
12
|
+
it "allow ActiveRecord::Rollback to work in 1 transaction block" do
|
|
13
13
|
Ship.transaction do
|
|
14
|
-
Ship.create! name:
|
|
14
|
+
Ship.create! name: "Black Pearl"
|
|
15
15
|
raise ActiveRecord::Rollback
|
|
16
16
|
end
|
|
17
17
|
assert_no_ships
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
it
|
|
20
|
+
it "allow nested transactions to totally rollback" do
|
|
21
21
|
begin
|
|
22
22
|
Ship.transaction do
|
|
23
|
-
Ship.create! name:
|
|
23
|
+
Ship.create! name: "Black Pearl"
|
|
24
24
|
Ship.transaction do
|
|
25
|
-
Ship.create! name:
|
|
26
|
-
raise
|
|
25
|
+
Ship.create! name: "Flying Dutchman"
|
|
26
|
+
raise "HELL"
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
|
-
rescue Exception
|
|
29
|
+
rescue Exception
|
|
30
30
|
assert_no_ships
|
|
31
31
|
end
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
it
|
|
34
|
+
it "can use an isolation level and reverts back to starting isolation level" do
|
|
35
35
|
in_level = nil
|
|
36
36
|
begin_level = connection.user_options_isolation_level
|
|
37
37
|
_(begin_level).must_match %r{read committed}i
|
|
38
38
|
Ship.transaction(isolation: :serializable) do
|
|
39
|
-
Ship.create! name:
|
|
39
|
+
Ship.create! name: "Black Pearl"
|
|
40
40
|
in_level = connection.user_options_isolation_level
|
|
41
41
|
end
|
|
42
42
|
after_level = connection.user_options_isolation_level
|
|
@@ -44,7 +44,7 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
|
44
44
|
_(after_level).must_match %r{read committed}i
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
it
|
|
47
|
+
it "can use an isolation level and reverts back to starting isolation level under exceptions" do
|
|
48
48
|
_(connection.user_options_isolation_level).must_match %r{read committed}i
|
|
49
49
|
_(lambda {
|
|
50
50
|
Ship.transaction(isolation: :serializable) { Ship.create! }
|
|
@@ -52,7 +52,7 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
|
52
52
|
_(connection.user_options_isolation_level).must_match %r{read committed}i
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
describe
|
|
55
|
+
describe "when READ_COMMITTED_SNAPSHOT is set" do
|
|
56
56
|
before do
|
|
57
57
|
connection.execute "ALTER DATABASE [#{connection.current_database}] SET ALLOW_SNAPSHOT_ISOLATION ON"
|
|
58
58
|
connection.execute "ALTER DATABASE [#{connection.current_database}] SET READ_COMMITTED_SNAPSHOT ON WITH ROLLBACK IMMEDIATE"
|
|
@@ -63,11 +63,11 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
|
63
63
|
connection.execute "ALTER DATABASE [#{connection.current_database}] SET READ_COMMITTED_SNAPSHOT OFF WITH ROLLBACK IMMEDIATE"
|
|
64
64
|
end
|
|
65
65
|
|
|
66
|
-
it
|
|
66
|
+
it "should use READ COMMITTED as an isolation level" do
|
|
67
67
|
_(connection.user_options_isolation_level).must_match "read committed snapshot"
|
|
68
68
|
|
|
69
69
|
Ship.transaction(isolation: :serializable) do
|
|
70
|
-
Ship.create! name:
|
|
70
|
+
Ship.create! name: "Black Pearl"
|
|
71
71
|
end
|
|
72
72
|
|
|
73
73
|
# We're actually testing that the isolation level was correctly reset to
|
|
@@ -77,7 +77,6 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
|
77
77
|
end
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
|
|
81
80
|
protected
|
|
82
81
|
|
|
83
82
|
def delete_ships
|
|
@@ -87,5 +86,4 @@ class TransactionTestSQLServer < ActiveRecord::TestCase
|
|
|
87
86
|
def assert_no_ships
|
|
88
87
|
assert Ship.count.zero?, "Expected Ship to have no models but it did have:\n#{Ship.all.inspect}"
|
|
89
88
|
end
|
|
90
|
-
|
|
91
89
|
end
|
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
3
4
|
|
|
4
5
|
class SQLServerTriggerTest < ActiveRecord::TestCase
|
|
5
|
-
after
|
|
6
|
+
after { exclude_output_inserted_table_names.clear }
|
|
6
7
|
|
|
7
8
|
let(:exclude_output_inserted_table_names) do
|
|
8
9
|
ActiveRecord::ConnectionAdapters::SQLServerAdapter.exclude_output_inserted_table_names
|
|
9
10
|
end
|
|
10
11
|
|
|
11
|
-
it
|
|
12
|
-
exclude_output_inserted_table_names[
|
|
12
|
+
it "can insert into a table with output inserted - with a true setting for table name" do
|
|
13
|
+
exclude_output_inserted_table_names["sst_table_with_trigger"] = true
|
|
13
14
|
assert SSTestTriggerHistory.all.empty?
|
|
14
|
-
obj = SSTestTrigger.create! event_name:
|
|
15
|
-
_([
|
|
16
|
-
_(obj.event_name).must_equal
|
|
15
|
+
obj = SSTestTrigger.create! event_name: "test trigger"
|
|
16
|
+
_(["Fixnum", "Integer"]).must_include obj.id.class.name
|
|
17
|
+
_(obj.event_name).must_equal "test trigger"
|
|
17
18
|
_(obj.id).must_be :present?
|
|
18
19
|
_(obj.id.to_s).must_equal SSTestTriggerHistory.first.id_source
|
|
19
20
|
end
|
|
20
21
|
|
|
21
|
-
it
|
|
22
|
-
exclude_output_inserted_table_names[
|
|
22
|
+
it "can insert into a table with output inserted - with a uniqueidentifier value" do
|
|
23
|
+
exclude_output_inserted_table_names["sst_table_with_uuid_trigger"] = "uniqueidentifier"
|
|
23
24
|
assert SSTestTriggerHistory.all.empty?
|
|
24
|
-
obj = SSTestTriggerUuid.create! event_name:
|
|
25
|
-
_(obj.id.class.name).must_equal
|
|
26
|
-
_(obj.event_name).must_equal
|
|
25
|
+
obj = SSTestTriggerUuid.create! event_name: "test uuid trigger"
|
|
26
|
+
_(obj.id.class.name).must_equal "String"
|
|
27
|
+
_(obj.event_name).must_equal "test uuid trigger"
|
|
27
28
|
_(obj.id).must_be :present?
|
|
28
29
|
_(obj.id.to_s).must_equal SSTestTriggerHistory.first.id_source
|
|
29
30
|
end
|
|
@@ -1,59 +1,62 @@
|
|
|
1
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
class UtilsTestSQLServer < ActiveRecord::TestCase
|
|
6
|
+
it ".quote_string" do
|
|
6
7
|
_(SQLServer::Utils.quote_string("I'll store this in C:\\Users")).must_equal "I''ll store this in C:\\Users"
|
|
7
8
|
end
|
|
8
9
|
|
|
9
|
-
it
|
|
10
|
+
it ".unquote_string" do
|
|
10
11
|
_(SQLServer::Utils.unquote_string("I''ll store this in C:\\Users")).must_equal "I'll store this in C:\\Users"
|
|
11
12
|
end
|
|
12
13
|
|
|
13
|
-
it
|
|
14
|
+
it ".quoted_raw" do
|
|
14
15
|
_(SQLServer::Utils.quoted_raw("some.Name")).must_equal "[some.Name]"
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
describe
|
|
18
|
-
|
|
18
|
+
describe ".extract_identifiers constructor and thus SQLServer::Utils::Name value object" do
|
|
19
19
|
let(:valid_names) { valid_names_unquoted + valid_names_quoted }
|
|
20
20
|
|
|
21
|
-
let(:valid_names_unquoted) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
21
|
+
let(:valid_names_unquoted) {
|
|
22
|
+
[
|
|
23
|
+
"server.database.schema.object",
|
|
24
|
+
"server.database..object",
|
|
25
|
+
"server..schema.object",
|
|
26
|
+
"server...object",
|
|
27
|
+
"database.schema.object",
|
|
28
|
+
"database..object",
|
|
29
|
+
"schema.object",
|
|
30
|
+
"object"
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let(:valid_names_quoted) {
|
|
35
|
+
[
|
|
36
|
+
"[server].[database].[schema].[object]",
|
|
37
|
+
"[server].[database]..[object]",
|
|
38
|
+
"[server]..[schema].[object]",
|
|
39
|
+
"[server]...[object]",
|
|
40
|
+
"[database].[schema].[object]",
|
|
41
|
+
"[database]..[object]",
|
|
42
|
+
"[schema].[object]",
|
|
43
|
+
"[object]"
|
|
44
|
+
]
|
|
45
|
+
}
|
|
42
46
|
|
|
43
47
|
let(:server_names) { valid_names.partition { |name| name =~ /server/ } }
|
|
44
48
|
let(:database_names) { valid_names.partition { |name| name =~ /database/ } }
|
|
45
49
|
let(:schema_names) { valid_names.partition { |name| name =~ /schema/ } }
|
|
46
50
|
|
|
47
|
-
it
|
|
51
|
+
it "extracts and returns #object identifier unquoted by default or quoted as needed" do
|
|
48
52
|
valid_names.each do |n|
|
|
49
53
|
name = extract_identifiers(n)
|
|
50
|
-
_(name.object).must_equal
|
|
51
|
-
_(name.object_quoted).must_equal
|
|
54
|
+
_(name.object).must_equal "object", "With #{n.inspect} for #object"
|
|
55
|
+
_(name.object_quoted).must_equal "[object]", "With #{n.inspect} for #object_quoted"
|
|
52
56
|
end
|
|
53
57
|
end
|
|
54
58
|
|
|
55
59
|
[:schema, :database, :server].each do |part|
|
|
56
|
-
|
|
57
60
|
it "extracts and returns #{part} identifier unquoted by default or quoted as needed" do
|
|
58
61
|
present, blank = send(:"#{part}_names")
|
|
59
62
|
present.each do |n|
|
|
@@ -67,57 +70,55 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
|
|
|
67
70
|
_(name.send(:"#{part}_quoted")).must_be_nil "With #{n.inspect} for ##{part}_quoted method"
|
|
68
71
|
end
|
|
69
72
|
end
|
|
70
|
-
|
|
71
73
|
end
|
|
72
74
|
|
|
73
|
-
it
|
|
75
|
+
it "does not blow up on nil or blank string name" do
|
|
74
76
|
_(extract_identifiers(nil).object).must_be_nil
|
|
75
|
-
_(extract_identifiers(
|
|
77
|
+
_(extract_identifiers(" ").object).must_be_nil
|
|
76
78
|
end
|
|
77
79
|
|
|
78
|
-
it
|
|
79
|
-
_(extract_identifiers(
|
|
80
|
-
_(extract_identifiers(
|
|
81
|
-
_(extract_identifiers(
|
|
80
|
+
it "has a #quoted that returns a fully quoted name with all identifiers as orginially passed in" do
|
|
81
|
+
_(extract_identifiers("object").quoted).must_equal "[object]"
|
|
82
|
+
_(extract_identifiers("server.database..object").quoted).must_equal "[server].[database]..[object]"
|
|
83
|
+
_(extract_identifiers("[server]...[object]").quoted).must_equal "[server]...[object]"
|
|
82
84
|
end
|
|
83
85
|
|
|
84
|
-
it
|
|
85
|
-
_(extract_identifiers(:object).object).must_equal
|
|
86
|
+
it "can take a symbol argument" do
|
|
87
|
+
_(extract_identifiers(:object).object).must_equal "object"
|
|
86
88
|
end
|
|
87
89
|
|
|
88
|
-
it
|
|
89
|
-
_(extract_identifiers(
|
|
90
|
-
_(extract_identifiers(
|
|
90
|
+
it "allows identifiers with periods to work" do
|
|
91
|
+
_(extract_identifiers("[obj.name]").quoted).must_equal "[obj.name]"
|
|
92
|
+
_(extract_identifiers("[obj.name].[foo]").quoted).must_equal "[obj.name].[foo]"
|
|
91
93
|
end
|
|
92
94
|
|
|
93
|
-
it
|
|
94
|
-
_(extract_identifiers(
|
|
95
|
-
_(extract_identifiers(
|
|
96
|
-
_(extract_identifiers(
|
|
97
|
-
_(extract_identifiers(
|
|
98
|
-
_(extract_identifiers(
|
|
99
|
-
_(extract_identifiers(
|
|
100
|
-
_(extract_identifiers(
|
|
101
|
-
_(extract_identifiers(
|
|
102
|
-
_(extract_identifiers(
|
|
103
|
-
_(extract_identifiers(
|
|
104
|
-
_(extract_identifiers(
|
|
105
|
-
_(extract_identifiers(
|
|
106
|
-
_(extract_identifiers(
|
|
107
|
-
_(extract_identifiers(
|
|
108
|
-
_(extract_identifiers(
|
|
109
|
-
_(extract_identifiers(
|
|
95
|
+
it "should indicate if a name is fully qualitified" do
|
|
96
|
+
_(extract_identifiers("object").fully_qualified?).must_equal false
|
|
97
|
+
_(extract_identifiers("schema.object").fully_qualified?).must_equal false
|
|
98
|
+
_(extract_identifiers("database.schema.object").fully_qualified?).must_equal false
|
|
99
|
+
_(extract_identifiers("database.object").fully_qualified?).must_equal false
|
|
100
|
+
_(extract_identifiers("server...object").fully_qualified?).must_equal false
|
|
101
|
+
_(extract_identifiers("server.database..object").fully_qualified?).must_equal false
|
|
102
|
+
_(extract_identifiers("server.database.schema.object").fully_qualified?).must_equal true
|
|
103
|
+
_(extract_identifiers("server.database.schema.").fully_qualified?).must_equal true
|
|
104
|
+
_(extract_identifiers("[obj.name]").fully_qualified?).must_equal false
|
|
105
|
+
_(extract_identifiers("[schema].[obj.name]").fully_qualified?).must_equal false
|
|
106
|
+
_(extract_identifiers("[database].[schema].[obj.name]").fully_qualified?).must_equal false
|
|
107
|
+
_(extract_identifiers("[database].[obj.name]").fully_qualified?).must_equal false
|
|
108
|
+
_(extract_identifiers("[server.name]...[obj.name]").fully_qualified?).must_equal false
|
|
109
|
+
_(extract_identifiers("[server.name].[database]..[obj.name]").fully_qualified?).must_equal false
|
|
110
|
+
_(extract_identifiers("[server.name].[database].[schema].[obj.name]").fully_qualified?).must_equal true
|
|
111
|
+
_(extract_identifiers("[server.name].[database].[schema].").fully_qualified?).must_equal true
|
|
110
112
|
end
|
|
111
113
|
|
|
112
|
-
it
|
|
113
|
-
name = extract_identifiers(
|
|
114
|
-
_(name.fully_qualified_database_quoted).must_equal
|
|
115
|
-
name = extract_identifiers(
|
|
116
|
-
_(name.fully_qualified_database_quoted).must_equal
|
|
117
|
-
name = extract_identifiers(
|
|
118
|
-
_(name.fully_qualified_database_quoted).must_equal
|
|
114
|
+
it "can return fully qualified quoted table name" do
|
|
115
|
+
name = extract_identifiers("[my.server].db.schema.")
|
|
116
|
+
_(name.fully_qualified_database_quoted).must_equal "[my.server].[db]"
|
|
117
|
+
name = extract_identifiers("[server.name].[database].[schema].[object]")
|
|
118
|
+
_(name.fully_qualified_database_quoted).must_equal "[server.name].[database]"
|
|
119
|
+
name = extract_identifiers("server.database.schema.object")
|
|
120
|
+
_(name.fully_qualified_database_quoted).must_equal "[server].[database]"
|
|
119
121
|
end
|
|
120
|
-
|
|
121
122
|
end
|
|
122
123
|
|
|
123
124
|
private
|
|
@@ -125,5 +126,4 @@ class UtilsTestSQLServer < ActiveRecord::TestCase
|
|
|
125
126
|
def extract_identifiers(name)
|
|
126
127
|
SQLServer::Utils.extract_identifiers(name)
|
|
127
128
|
end
|
|
128
|
-
|
|
129
129
|
end
|
|
@@ -1,47 +1,46 @@
|
|
|
1
|
-
#
|
|
2
|
-
require 'cases/helper_sqlserver'
|
|
1
|
+
# frozen_string_literal: true
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
require "cases/helper_sqlserver"
|
|
5
4
|
|
|
5
|
+
class SQLServerUuidTest < ActiveRecord::TestCase
|
|
6
6
|
let(:acceptable_uuid) { ActiveRecord::ConnectionAdapters::SQLServer::Type::Uuid::ACCEPTABLE_UUID }
|
|
7
7
|
|
|
8
|
-
it
|
|
9
|
-
_(SSTestUuid.columns_hash[
|
|
8
|
+
it "has a uuid primary key" do
|
|
9
|
+
_(SSTestUuid.columns_hash["id"].type).must_equal :uuid
|
|
10
10
|
assert SSTestUuid.primary_key
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
it
|
|
13
|
+
it "can create with a new pk" do
|
|
14
14
|
obj = SSTestUuid.create!
|
|
15
15
|
_(obj.id).must_be :present?
|
|
16
16
|
_(obj.id).must_match acceptable_uuid
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
it
|
|
19
|
+
it "can create other uuid column on reload" do
|
|
20
20
|
obj = SSTestUuid.create!
|
|
21
21
|
obj.reload
|
|
22
22
|
_(obj.other_uuid).must_match acceptable_uuid
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
it
|
|
26
|
-
_(connection.primary_key(SSTestUuid.table_name)).must_equal
|
|
25
|
+
it "can find uuid pk via connection" do
|
|
26
|
+
_(connection.primary_key(SSTestUuid.table_name)).must_equal "id"
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
it
|
|
29
|
+
it "changing column default" do
|
|
30
30
|
table_name = SSTestUuid.table_name
|
|
31
31
|
connection.add_column table_name, :thingy, :uuid, null: false, default: "NEWSEQUENTIALID()"
|
|
32
32
|
SSTestUuid.reset_column_information
|
|
33
|
-
column = SSTestUuid.columns_hash[
|
|
33
|
+
column = SSTestUuid.columns_hash["thingy"]
|
|
34
34
|
_(column.default_function).must_equal "newsequentialid()"
|
|
35
35
|
# Now to a different function.
|
|
36
36
|
connection.change_column table_name, :thingy, :uuid, null: false, default: "NEWID()"
|
|
37
37
|
SSTestUuid.reset_column_information
|
|
38
|
-
column = SSTestUuid.columns_hash[
|
|
38
|
+
column = SSTestUuid.columns_hash["thingy"]
|
|
39
39
|
_(column.default_function).must_equal "newid()"
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
-
it
|
|
42
|
+
it "can insert even when use_output_inserted to false " do
|
|
43
43
|
obj = with_use_output_inserted_disabled { SSTestUuid.create!(name: "😢") }
|
|
44
44
|
_(obj.id).must_be :nil?
|
|
45
45
|
end
|
|
46
|
-
|
|
47
46
|
end
|