activerecord-sqlserver-adapter 6.1.2.1 → 7.2.4
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/.devcontainer/Dockerfile +30 -0
- data/.devcontainer/boot.sh +22 -0
- data/.devcontainer/devcontainer.json +38 -0
- data/.devcontainer/docker-compose.yml +42 -0
- data/.github/workflows/ci.yml +7 -4
- data/.gitignore +3 -1
- data/CHANGELOG.md +19 -42
- data/Dockerfile.ci +3 -3
- data/Gemfile +6 -1
- data/MIT-LICENSE +1 -1
- data/README.md +113 -27
- data/RUNNING_UNIT_TESTS.md +27 -14
- data/Rakefile +2 -6
- data/VERSION +1 -1
- data/activerecord-sqlserver-adapter.gemspec +3 -3
- data/appveyor.yml +4 -6
- data/docker-compose.ci.yml +2 -1
- data/lib/active_record/connection_adapters/sqlserver/core_ext/abstract_adapter.rb +20 -0
- data/lib/active_record/connection_adapters/sqlserver/core_ext/attribute_methods.rb +6 -4
- data/lib/active_record/connection_adapters/sqlserver/core_ext/calculations.rb +5 -23
- data/lib/active_record/connection_adapters/sqlserver/core_ext/explain.rb +10 -7
- 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 +12 -2
- data/lib/active_record/connection_adapters/sqlserver/core_ext/preloader.rb +24 -16
- data/lib/active_record/connection_adapters/sqlserver/database_limits.rb +0 -31
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +143 -155
- data/lib/active_record/connection_adapters/sqlserver/database_tasks.rb +5 -5
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +57 -56
- data/lib/active_record/connection_adapters/sqlserver/savepoints.rb +26 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_creation.rb +14 -12
- data/lib/active_record/connection_adapters/sqlserver/schema_dumper.rb +11 -0
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +213 -57
- data/lib/active_record/connection_adapters/sqlserver/showplan.rb +3 -3
- data/lib/active_record/connection_adapters/sqlserver/table_definition.rb +13 -2
- data/lib/active_record/connection_adapters/sqlserver/transaction.rb +4 -6
- data/lib/active_record/connection_adapters/sqlserver/type/data.rb +19 -1
- data/lib/active_record/connection_adapters/sqlserver/type/date.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/datetime.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/type/time.rb +1 -1
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +21 -10
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +187 -187
- data/lib/active_record/connection_adapters/sqlserver_column.rb +1 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +42 -33
- data/lib/arel/visitors/sqlserver.rb +77 -34
- data/test/cases/active_schema_test_sqlserver.rb +127 -0
- data/test/cases/adapter_test_sqlserver.rb +114 -26
- data/test/cases/coerced_tests.rb +1121 -340
- data/test/cases/column_test_sqlserver.rb +67 -64
- data/test/cases/connection_test_sqlserver.rb +3 -6
- data/test/cases/dbconsole.rb +19 -0
- data/test/cases/disconnected_test_sqlserver.rb +8 -5
- data/test/cases/eager_load_too_many_ids_test_sqlserver.rb +18 -0
- data/test/cases/enum_test_sqlserver.rb +49 -0
- data/test/cases/execute_procedure_test_sqlserver.rb +9 -5
- data/test/cases/fetch_test_sqlserver.rb +19 -0
- data/test/cases/helper_sqlserver.rb +11 -5
- data/test/cases/index_test_sqlserver.rb +8 -6
- data/test/cases/json_test_sqlserver.rb +1 -1
- data/test/cases/lateral_test_sqlserver.rb +2 -2
- data/test/cases/migration_test_sqlserver.rb +19 -1
- data/test/cases/optimizer_hints_test_sqlserver.rb +21 -12
- data/test/cases/pessimistic_locking_test_sqlserver.rb +8 -7
- data/test/cases/primary_keys_test_sqlserver.rb +2 -2
- data/test/cases/rake_test_sqlserver.rb +10 -5
- data/test/cases/schema_dumper_test_sqlserver.rb +155 -109
- data/test/cases/schema_test_sqlserver.rb +64 -1
- data/test/cases/showplan_test_sqlserver.rb +7 -7
- data/test/cases/specific_schema_test_sqlserver.rb +17 -13
- data/test/cases/transaction_test_sqlserver.rb +13 -8
- data/test/cases/trigger_test_sqlserver.rb +20 -0
- data/test/cases/utils_test_sqlserver.rb +2 -2
- data/test/cases/uuid_test_sqlserver.rb +8 -0
- data/test/cases/view_test_sqlserver.rb +58 -0
- data/test/config.yml +1 -2
- data/test/migrations/transaction_table/1_table_will_never_be_created.rb +1 -1
- data/test/models/sqlserver/alien.rb +5 -0
- data/test/models/sqlserver/table_with_spaces.rb +5 -0
- data/test/models/sqlserver/trigger.rb +8 -0
- data/test/schema/sqlserver_specific_schema.rb +54 -6
- data/test/support/coerceable_test_sqlserver.rb +4 -4
- data/test/support/connection_reflection.rb +3 -9
- data/test/support/core_ext/query_cache.rb +7 -1
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_6_1_topic_associations.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic.dump +0 -0
- data/test/support/marshal_compatibility_fixtures/SQLServer/rails_7_1_topic_associations.dump +0 -0
- data/test/support/query_assertions.rb +49 -0
- data/test/support/rake_helpers.rb +3 -1
- data/test/support/table_definition_sqlserver.rb +24 -0
- data/test/support/test_in_memory_oltp.rb +2 -2
- metadata +41 -17
- data/lib/active_record/sqlserver_base.rb +0 -18
- data/test/cases/scratchpad_test_sqlserver.rb +0 -8
- 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/sql_counter_sqlserver.rb +0 -29
@@ -10,8 +10,7 @@ module ActiveRecord
|
|
10
10
|
class SQLServerDatabaseTasks
|
11
11
|
DEFAULT_COLLATION = "SQL_Latin1_General_CP1_CI_AS"
|
12
12
|
|
13
|
-
delegate :
|
14
|
-
to: ActiveRecord::Base
|
13
|
+
delegate :with_connection, :establish_connection, to: ActiveRecord::Base
|
15
14
|
|
16
15
|
def self.using_database_configurations?
|
17
16
|
true
|
@@ -24,8 +23,10 @@ module ActiveRecord
|
|
24
23
|
|
25
24
|
def create(master_established = false)
|
26
25
|
establish_master_connection unless master_established
|
27
|
-
|
28
|
-
|
26
|
+
with_connection do |connection|
|
27
|
+
connection.create_database(configuration.database, configuration_hash.merge(collation: default_collation))
|
28
|
+
end
|
29
|
+
establish_connection(configuration)
|
29
30
|
rescue ActiveRecord::StatementInvalid => e
|
30
31
|
if /database .* already exists/i === e.message
|
31
32
|
raise DatabaseAlreadyExists
|
@@ -36,15 +37,15 @@ module ActiveRecord
|
|
36
37
|
|
37
38
|
def drop
|
38
39
|
establish_master_connection
|
39
|
-
connection.drop_database
|
40
|
+
with_connection { |connection| connection.drop_database(configuration.database) }
|
40
41
|
end
|
41
42
|
|
42
43
|
def charset
|
43
|
-
connection.charset
|
44
|
+
with_connection { |connection| connection.charset }
|
44
45
|
end
|
45
46
|
|
46
47
|
def collation
|
47
|
-
connection.collation
|
48
|
+
with_connection { |connection| connection.collation }
|
48
49
|
end
|
49
50
|
|
50
51
|
def purge
|
@@ -53,34 +54,42 @@ module ActiveRecord
|
|
53
54
|
create true
|
54
55
|
end
|
55
56
|
|
56
|
-
def
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
"-
|
63
|
-
"
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
57
|
+
def clear_active_connections!
|
58
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!(:all)
|
59
|
+
end
|
60
|
+
|
61
|
+
def structure_dump(filename, _extra_flags)
|
62
|
+
with_connection do |connection|
|
63
|
+
server_arg = "-S #{Shellwords.escape(configuration_hash[:host])}"
|
64
|
+
server_arg += ":#{Shellwords.escape(configuration_hash[:port])}" if configuration_hash[:port]
|
65
|
+
command = [
|
66
|
+
"defncopy-ttds",
|
67
|
+
server_arg,
|
68
|
+
"-D #{Shellwords.escape(configuration_hash[:database])}",
|
69
|
+
"-U #{Shellwords.escape(configuration_hash[:username])}",
|
70
|
+
"-P #{Shellwords.escape(configuration_hash[:password])}",
|
71
|
+
"-o #{Shellwords.escape(filename)}",
|
72
|
+
]
|
73
|
+
table_args = connection.tables.map { |t| Shellwords.escape(t) }
|
74
|
+
command.concat(table_args)
|
75
|
+
view_args = connection.views.map { |v| Shellwords.escape(v) }
|
76
|
+
command.concat(view_args)
|
77
|
+
raise "Error dumping database" unless Kernel.system(command.join(" "))
|
78
|
+
|
79
|
+
dump = File.read(filename)
|
80
|
+
dump.gsub!(/^USE .*$\nGO\n/, "") # Strip db USE statements
|
81
|
+
dump.gsub!(/^GO\n/, "") # Strip db GO statements
|
82
|
+
dump.gsub!(/nvarchar\(8000\)/, "nvarchar(4000)") # Fix nvarchar(8000) column defs
|
83
|
+
dump.gsub!(/nvarchar\(-1\)/, "nvarchar(max)") # Fix nvarchar(-1) column defs
|
84
|
+
dump.gsub!(/text\(\d+\)/, "text") # Fix text(16) column defs
|
85
|
+
File.open(filename, "w") { |file| file.puts dump }
|
86
|
+
end
|
80
87
|
end
|
81
88
|
|
82
|
-
def structure_load(filename,
|
83
|
-
connection
|
89
|
+
def structure_load(filename, _extra_flags)
|
90
|
+
with_connection do |connection|
|
91
|
+
connection.execute File.read(filename)
|
92
|
+
end
|
84
93
|
end
|
85
94
|
|
86
95
|
private
|
@@ -30,10 +30,46 @@ module Arel
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def visit_Arel_Nodes_UpdateStatement(o, collector)
|
33
|
-
if
|
34
|
-
o
|
33
|
+
if has_join_and_composite_primary_key?(o)
|
34
|
+
update_statement_using_join(o, collector)
|
35
|
+
else
|
36
|
+
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807) if o.orders.any? && o.limit.nil?
|
37
|
+
|
38
|
+
super
|
35
39
|
end
|
36
|
-
|
40
|
+
end
|
41
|
+
|
42
|
+
def visit_Arel_Nodes_DeleteStatement(o, collector)
|
43
|
+
if has_join_and_composite_primary_key?(o)
|
44
|
+
delete_statement_using_join(o, collector)
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def has_join_and_composite_primary_key?(o)
|
51
|
+
has_join_sources?(o) && o.relation.left.instance_variable_get(:@klass).composite_primary_key?
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_statement_using_join(o, collector)
|
55
|
+
collector.retryable = false
|
56
|
+
|
57
|
+
collector << "DELETE "
|
58
|
+
visit o.relation.left, collector
|
59
|
+
collector << " FROM "
|
60
|
+
visit o.relation, collector
|
61
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
62
|
+
end
|
63
|
+
|
64
|
+
def update_statement_using_join(o, collector)
|
65
|
+
collector.retryable = false
|
66
|
+
|
67
|
+
collector << "UPDATE "
|
68
|
+
visit o.relation.left, collector
|
69
|
+
collect_nodes_for o.values, collector, " SET "
|
70
|
+
collector << " FROM "
|
71
|
+
visit o.relation, collector
|
72
|
+
collect_nodes_for o.wheres, collector, " WHERE ", " AND "
|
37
73
|
end
|
38
74
|
|
39
75
|
def visit_Arel_Nodes_Lock(o, collector)
|
@@ -67,7 +103,7 @@ module Arel
|
|
67
103
|
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
68
104
|
collector.preparable = false
|
69
105
|
|
70
|
-
|
106
|
+
visit o.left, collector
|
71
107
|
|
72
108
|
if o.type == :in
|
73
109
|
collector << " IN ("
|
@@ -77,46 +113,45 @@ module Arel
|
|
77
113
|
|
78
114
|
values = o.casted_values
|
79
115
|
|
116
|
+
# Monkey-patch start.
|
117
|
+
column_name = o.attribute.name
|
118
|
+
column_type = o.attribute.relation.type_for_attribute(column_name)
|
119
|
+
column_type = column_type.cast_type if column_type.is_a?(ActiveRecord::Encryption::EncryptedAttributeType) # Use cast_type on encrypted attributes. Don't encrypt them again
|
120
|
+
|
80
121
|
if values.empty?
|
81
122
|
collector << @connection.quote(nil)
|
82
|
-
elsif @connection.prepared_statements
|
83
|
-
#
|
84
|
-
column_name = o.column_name
|
85
|
-
column_type = o.attribute.relation.type_for_attribute(o.column_name)
|
123
|
+
elsif @connection.prepared_statements && !column_type.serialized?
|
124
|
+
# Add query attribute bindings rather than just values.
|
86
125
|
attrs = values.map { |value| ActiveRecord::Relation::QueryAttribute.new(column_name, value, column_type) }
|
87
|
-
|
88
126
|
collector.add_binds(attrs, &bind_block)
|
89
|
-
# Monkey-patch end.
|
90
127
|
else
|
91
|
-
collector.add_binds(values, &bind_block)
|
128
|
+
collector.add_binds(values, o.proc_for_binds, &bind_block)
|
92
129
|
end
|
130
|
+
# Monkey-patch end.
|
93
131
|
|
94
132
|
collector << ")"
|
95
|
-
collector
|
96
133
|
end
|
97
134
|
|
98
135
|
def visit_Arel_Nodes_SelectStatement(o, collector)
|
99
136
|
@select_statement = o
|
137
|
+
optimizer_hints = nil
|
100
138
|
distinct_One_As_One_Is_So_Not_Fetch o
|
101
139
|
if o.with
|
102
140
|
collector = visit o.with, collector
|
103
141
|
collector << " "
|
104
142
|
end
|
105
|
-
collector = o.cores.inject(collector)
|
106
|
-
|
107
|
-
|
143
|
+
collector = o.cores.inject(collector) do |collect, core|
|
144
|
+
optimizer_hints = core.optimizer_hints if core.optimizer_hints
|
145
|
+
visit_Arel_Nodes_SelectCore(core, collect)
|
146
|
+
end
|
108
147
|
collector = visit_Orders_And_Let_Fetch_Happen o, collector
|
109
148
|
collector = visit_Make_Fetch_Happen o, collector
|
149
|
+
collector = maybe_visit optimizer_hints, collector
|
110
150
|
collector
|
111
151
|
ensure
|
112
152
|
@select_statement = nil
|
113
153
|
end
|
114
154
|
|
115
|
-
def visit_Arel_Nodes_SelectCore(o, collector)
|
116
|
-
collector = super
|
117
|
-
maybe_visit o.optimizer_hints, collector
|
118
|
-
end
|
119
|
-
|
120
155
|
def visit_Arel_Nodes_OptimizerHints(o, collector)
|
121
156
|
hints = o.expr.map { |v| sanitize_as_option_clause(v) }.join(", ")
|
122
157
|
collector << "OPTION (#{hints})"
|
@@ -128,10 +163,12 @@ module Arel
|
|
128
163
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
129
164
|
table_name =
|
130
165
|
begin
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
166
|
+
o.class.engine.with_connection do |connection|
|
167
|
+
if connection.respond_to?(:sqlserver?) && connection.database_prefix_remote_server?
|
168
|
+
remote_server_table_name(o)
|
169
|
+
else
|
170
|
+
quote_table_name(o.name)
|
171
|
+
end
|
135
172
|
end
|
136
173
|
rescue Exception
|
137
174
|
quote_table_name(o.name)
|
@@ -200,6 +237,11 @@ module Arel
|
|
200
237
|
collector
|
201
238
|
end
|
202
239
|
|
240
|
+
def visit_Arel_Nodes_WithRecursive(o, collector)
|
241
|
+
collector << "WITH "
|
242
|
+
collect_ctes(o.children, collector)
|
243
|
+
end
|
244
|
+
|
203
245
|
# SQLServer ToSql/Visitor (Additions)
|
204
246
|
|
205
247
|
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock(collector, options = {})
|
@@ -212,7 +254,7 @@ module Arel
|
|
212
254
|
|
213
255
|
def visit_Orders_And_Let_Fetch_Happen(o, collector)
|
214
256
|
make_Fetch_Possible_And_Deterministic o
|
215
|
-
|
257
|
+
if o.orders.any?
|
216
258
|
collector << " ORDER BY "
|
217
259
|
len = o.orders.length - 1
|
218
260
|
o.orders.each_with_index { |x, i|
|
@@ -260,15 +302,14 @@ module Arel
|
|
260
302
|
|
261
303
|
def make_Fetch_Possible_And_Deterministic(o)
|
262
304
|
return if o.limit.nil? && o.offset.nil?
|
305
|
+
return if o.orders.any?
|
263
306
|
|
264
307
|
t = table_From_Statement o
|
265
308
|
pk = primary_Key_From_Table t
|
266
309
|
return unless pk
|
267
310
|
|
268
|
-
|
269
|
-
|
270
|
-
o.orders = [pk.asc]
|
271
|
-
end
|
311
|
+
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
312
|
+
o.orders = [pk.asc]
|
272
313
|
end
|
273
314
|
|
274
315
|
def distinct_One_As_One_Is_So_Not_Fetch(o)
|
@@ -315,14 +356,16 @@ module Arel
|
|
315
356
|
end
|
316
357
|
|
317
358
|
def remote_server_table_name(o)
|
318
|
-
|
319
|
-
|
320
|
-
|
359
|
+
o.class.engine.with_connection do |connection|
|
360
|
+
ActiveRecord::ConnectionAdapters::SQLServer::Utils.extract_identifiers(
|
361
|
+
"#{connection.database_prefix}#{o.name}"
|
362
|
+
).quoted
|
363
|
+
end
|
321
364
|
end
|
322
365
|
|
323
|
-
# Need to remove ordering from
|
366
|
+
# Need to remove ordering from sub-queries unless TOP/OFFSET also used. Otherwise, SQLServer
|
324
367
|
# returns error "The ORDER BY clause is invalid in views, inline functions, derived tables,
|
325
|
-
#
|
368
|
+
# sub-queries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified."
|
326
369
|
def remove_invalid_ordering_from_select_statement(node)
|
327
370
|
return unless Arel::Nodes::SelectStatement === node
|
328
371
|
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "cases/helper_sqlserver"
|
4
|
+
|
5
|
+
class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
|
6
|
+
describe "indexes" do
|
7
|
+
before do
|
8
|
+
connection.create_table :schema_test_table, force: true, id: false do |t|
|
9
|
+
t.column :foo, :string, limit: 100
|
10
|
+
t.column :state, :string
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
connection.drop_table :schema_test_table rescue nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'default index' do
|
19
|
+
assert_queries_match('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
20
|
+
connection.add_index :schema_test_table, "foo"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'unique index' do
|
25
|
+
assert_queries_match('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
26
|
+
connection.add_index :schema_test_table, "foo", unique: true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'where condition on index' do
|
31
|
+
assert_queries_match("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
|
32
|
+
connection.add_index :schema_test_table, "foo", where: "state = 'active'"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'if index does not exist' do
|
37
|
+
assert_queries_match("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
|
38
|
+
"CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
|
39
|
+
connection.add_index :schema_test_table, "foo", if_not_exists: true
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'clustered index' do
|
44
|
+
assert_queries_match('CREATE CLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
45
|
+
connection.add_index :schema_test_table, "foo", type: :clustered
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'nonclustered index' do
|
50
|
+
assert_queries_match('CREATE NONCLUSTERED INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
|
51
|
+
connection.add_index :schema_test_table, "foo", type: :nonclustered
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'collation' do
|
57
|
+
it "create column with NOT NULL and COLLATE" do
|
58
|
+
assert_nothing_raised do
|
59
|
+
connection.create_table :not_null_with_collation_table, force: true, id: false do |t|
|
60
|
+
t.text :not_null_text_with_collation, null: false, collation: "Latin1_General_CS_AS"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
ensure
|
64
|
+
connection.drop_table :not_null_with_collation_table rescue nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'datetimeoffset precision' do
|
69
|
+
it 'valid precisions are correct' do
|
70
|
+
assert_nothing_raised do
|
71
|
+
connection.create_table :datetimeoffset_precisions do |t|
|
72
|
+
t.datetimeoffset :precision_default
|
73
|
+
t.datetimeoffset :precision_5, precision: 5
|
74
|
+
t.datetimeoffset :precision_7, precision: 7
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
columns = connection.columns("datetimeoffset_precisions")
|
79
|
+
|
80
|
+
assert_equal columns.find { |column| column.name == "precision_default" }.precision, 7
|
81
|
+
assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
|
82
|
+
assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
|
83
|
+
ensure
|
84
|
+
connection.drop_table :datetimeoffset_precisions rescue nil
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'invalid precision raises exception' do
|
88
|
+
assert_raise(ActiveRecord::ActiveRecordError) do
|
89
|
+
connection.create_table :datetimeoffset_precisions do |t|
|
90
|
+
t.datetimeoffset :precision_8, precision: 8
|
91
|
+
end
|
92
|
+
end
|
93
|
+
ensure
|
94
|
+
connection.drop_table :datetimeoffset_precisions rescue nil
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe 'time precision' do
|
99
|
+
it 'valid precisions are correct' do
|
100
|
+
assert_nothing_raised do
|
101
|
+
connection.create_table :time_precisions do |t|
|
102
|
+
t.time :precision_default
|
103
|
+
t.time :precision_5, precision: 5
|
104
|
+
t.time :precision_7, precision: 7
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
columns = connection.columns("time_precisions")
|
109
|
+
|
110
|
+
assert_equal columns.find { |column| column.name == "precision_default" }.precision, 7
|
111
|
+
assert_equal columns.find { |column| column.name == "precision_5" }.precision, 5
|
112
|
+
assert_equal columns.find { |column| column.name == "precision_7" }.precision, 7
|
113
|
+
ensure
|
114
|
+
connection.drop_table :time_precisions rescue nil
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'invalid precision raises exception' do
|
118
|
+
assert_raise(ActiveRecord::ActiveRecordError) do
|
119
|
+
connection.create_table :time_precisions do |t|
|
120
|
+
t.time :precision_8, precision: 8
|
121
|
+
end
|
122
|
+
end
|
123
|
+
ensure
|
124
|
+
connection.drop_table :time_precisions rescue nil
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|