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,20 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Arel
|
|
2
4
|
module Visitors
|
|
3
5
|
class SQLServer < Arel::Visitors::ToSql
|
|
4
|
-
|
|
5
6
|
OFFSET = " OFFSET "
|
|
6
7
|
ROWS = " ROWS"
|
|
7
8
|
FETCH = " FETCH NEXT "
|
|
8
9
|
FETCH0 = " FETCH FIRST (SELECT 0) "
|
|
9
10
|
ROWS_ONLY = " ROWS ONLY"
|
|
10
11
|
|
|
11
|
-
|
|
12
12
|
private
|
|
13
13
|
|
|
14
14
|
# SQLServer ToSql/Visitor (Overides)
|
|
15
15
|
|
|
16
16
|
def visit_Arel_Nodes_BindParam o, collector
|
|
17
|
-
collector.add_bind(o.value) { |i| "@#{i-1}" }
|
|
17
|
+
collector.add_bind(o.value) { |i| "@#{i - 1}" }
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def visit_Arel_Nodes_Bin o, collector
|
|
@@ -22,6 +22,12 @@ module Arel
|
|
|
22
22
|
collector << " #{ActiveRecord::ConnectionAdapters::SQLServerAdapter.cs_equality_operator} "
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def visit_Arel_Nodes_Concat(o, collector)
|
|
26
|
+
visit o.left, collector
|
|
27
|
+
collector << " + "
|
|
28
|
+
visit o.right, collector
|
|
29
|
+
end
|
|
30
|
+
|
|
25
31
|
def visit_Arel_Nodes_UpdateStatement(o, a)
|
|
26
32
|
if o.orders.any? && o.limit.nil?
|
|
27
33
|
o.limit = Nodes::Limit.new(9_223_372_036_854_775_807)
|
|
@@ -30,8 +36,8 @@ module Arel
|
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
def visit_Arel_Nodes_Lock o, collector
|
|
33
|
-
o.expr = Arel.sql(
|
|
34
|
-
collector <<
|
|
39
|
+
o.expr = Arel.sql("WITH(UPDLOCK)") if o.expr.to_s =~ /FOR UPDATE/
|
|
40
|
+
collector << " "
|
|
35
41
|
visit o.expr, collector
|
|
36
42
|
end
|
|
37
43
|
|
|
@@ -52,14 +58,19 @@ module Arel
|
|
|
52
58
|
end
|
|
53
59
|
end
|
|
54
60
|
|
|
61
|
+
def visit_Arel_Nodes_Grouping(o, collector)
|
|
62
|
+
remove_invalid_ordering_from_select_statement(o.expr)
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
|
|
55
66
|
def visit_Arel_Nodes_SelectStatement o, collector
|
|
56
67
|
@select_statement = o
|
|
57
68
|
distinct_One_As_One_Is_So_Not_Fetch o
|
|
58
69
|
if o.with
|
|
59
70
|
collector = visit o.with, collector
|
|
60
|
-
collector <<
|
|
71
|
+
collector << " "
|
|
61
72
|
end
|
|
62
|
-
collector = o.cores.inject(collector) { |c,x|
|
|
73
|
+
collector = o.cores.inject(collector) { |c, x|
|
|
63
74
|
visit_Arel_Nodes_SelectCore(x, c)
|
|
64
75
|
}
|
|
65
76
|
collector = visit_Orders_And_Let_Fetch_Happen o, collector
|
|
@@ -73,15 +84,17 @@ module Arel
|
|
|
73
84
|
# Apparently, o.engine.connection can actually be a different adapter
|
|
74
85
|
# than sqlserver. Can be removed if fixed in ActiveRecord. See:
|
|
75
86
|
# github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues/450
|
|
76
|
-
table_name =
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
table_name =
|
|
88
|
+
begin
|
|
89
|
+
if o.class.engine.connection.respond_to?(:sqlserver?) && o.class.engine.connection.database_prefix_remote_server?
|
|
90
|
+
remote_server_table_name(o)
|
|
91
|
+
else
|
|
92
|
+
quote_table_name(o.name)
|
|
93
|
+
end
|
|
94
|
+
rescue Exception
|
|
80
95
|
quote_table_name(o.name)
|
|
81
96
|
end
|
|
82
|
-
|
|
83
|
-
quote_table_name(o.name)
|
|
84
|
-
end
|
|
97
|
+
|
|
85
98
|
if o.table_alias
|
|
86
99
|
collector << "#{table_name} #{quote_table_name o.table_alias}"
|
|
87
100
|
else
|
|
@@ -95,8 +108,8 @@ module Arel
|
|
|
95
108
|
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector
|
|
96
109
|
end
|
|
97
110
|
if o.right.any?
|
|
98
|
-
collector <<
|
|
99
|
-
collector = inject_join o.right, collector,
|
|
111
|
+
collector << " " if o.left
|
|
112
|
+
collector = inject_join o.right, collector, " "
|
|
100
113
|
end
|
|
101
114
|
collector
|
|
102
115
|
end
|
|
@@ -106,7 +119,7 @@ module Arel
|
|
|
106
119
|
collector = visit o.left, collector
|
|
107
120
|
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
|
108
121
|
if o.right
|
|
109
|
-
collector <<
|
|
122
|
+
collector << " "
|
|
110
123
|
visit(o.right, collector)
|
|
111
124
|
else
|
|
112
125
|
collector
|
|
@@ -117,16 +130,26 @@ module Arel
|
|
|
117
130
|
collector << "LEFT OUTER JOIN "
|
|
118
131
|
collector = visit o.left, collector
|
|
119
132
|
collector = visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, space: true
|
|
120
|
-
collector <<
|
|
133
|
+
collector << " "
|
|
121
134
|
visit o.right, collector
|
|
122
135
|
end
|
|
123
136
|
|
|
137
|
+
def collect_in_clause(left, right, collector)
|
|
138
|
+
if Array === right
|
|
139
|
+
right.each { |node| remove_invalid_ordering_from_select_statement(node) }
|
|
140
|
+
else
|
|
141
|
+
remove_invalid_ordering_from_select_statement(right)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
super
|
|
145
|
+
end
|
|
146
|
+
|
|
124
147
|
# SQLServer ToSql/Visitor (Additions)
|
|
125
148
|
|
|
126
149
|
def visit_Arel_Nodes_SelectStatement_SQLServer_Lock collector, options = {}
|
|
127
150
|
if select_statement_lock?
|
|
128
151
|
collector = visit @select_statement.lock, collector
|
|
129
|
-
collector <<
|
|
152
|
+
collector << " " if options[:space]
|
|
130
153
|
end
|
|
131
154
|
collector
|
|
132
155
|
end
|
|
@@ -134,12 +157,11 @@ module Arel
|
|
|
134
157
|
def visit_Orders_And_Let_Fetch_Happen o, collector
|
|
135
158
|
make_Fetch_Possible_And_Deterministic o
|
|
136
159
|
unless o.orders.empty?
|
|
137
|
-
collector <<
|
|
138
|
-
collector << ORDER_BY
|
|
160
|
+
collector << " ORDER BY "
|
|
139
161
|
len = o.orders.length - 1
|
|
140
162
|
o.orders.each_with_index { |x, i|
|
|
141
163
|
collector = visit(x, collector)
|
|
142
|
-
collector <<
|
|
164
|
+
collector << ", " unless len == i
|
|
143
165
|
}
|
|
144
166
|
end
|
|
145
167
|
collector
|
|
@@ -156,6 +178,7 @@ module Arel
|
|
|
156
178
|
|
|
157
179
|
def node_value(node)
|
|
158
180
|
return nil unless node
|
|
181
|
+
|
|
159
182
|
case node.expr
|
|
160
183
|
when NilClass then nil
|
|
161
184
|
when Numeric then node.expr
|
|
@@ -169,9 +192,11 @@ module Arel
|
|
|
169
192
|
|
|
170
193
|
def make_Fetch_Possible_And_Deterministic o
|
|
171
194
|
return if o.limit.nil? && o.offset.nil?
|
|
195
|
+
|
|
172
196
|
t = table_From_Statement o
|
|
173
197
|
pk = primary_Key_From_Table t
|
|
174
198
|
return unless pk
|
|
199
|
+
|
|
175
200
|
if o.orders.empty?
|
|
176
201
|
# Prefer deterministic vs a simple `(SELECT NULL)` expr.
|
|
177
202
|
o.orders = [pk.asc]
|
|
@@ -196,14 +221,15 @@ module Arel
|
|
|
196
221
|
elsif Arel::Nodes::SqlLiteral === core.from
|
|
197
222
|
Arel::Table.new(core.from)
|
|
198
223
|
elsif Arel::Nodes::JoinSource === core.source
|
|
199
|
-
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left
|
|
224
|
+
Arel::Nodes::SqlLiteral === core.source.left ? Arel::Table.new(core.source.left, @engine) : core.source.left.left
|
|
200
225
|
end
|
|
201
226
|
end
|
|
202
227
|
|
|
203
228
|
def primary_Key_From_Table t
|
|
204
229
|
return unless t
|
|
230
|
+
|
|
205
231
|
column_name = @connection.schema_cache.primary_keys(t.name) ||
|
|
206
|
-
|
|
232
|
+
@connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
|
|
207
233
|
column_name ? t[column_name] : nil
|
|
208
234
|
end
|
|
209
235
|
|
|
@@ -213,6 +239,14 @@ module Arel
|
|
|
213
239
|
).quoted
|
|
214
240
|
end
|
|
215
241
|
|
|
242
|
+
# Need to remove ordering from subqueries unless TOP/OFFSET also used. Otherwise, SQLServer
|
|
243
|
+
# returns error "The ORDER BY clause is invalid in views, inline functions, derived tables,
|
|
244
|
+
# subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified."
|
|
245
|
+
def remove_invalid_ordering_from_select_statement(node)
|
|
246
|
+
return unless Arel::Nodes::SelectStatement === node
|
|
247
|
+
|
|
248
|
+
node.orders = [] unless node.offset || node.limit
|
|
249
|
+
end
|
|
216
250
|
end
|
|
217
251
|
end
|
|
218
252
|
end
|
data/lib/arel_sqlserver.rb
CHANGED
data/test/appveyor/dbsetup.ps1
CHANGED
|
@@ -5,15 +5,15 @@ Write-Output "Setting up..."
|
|
|
5
5
|
|
|
6
6
|
Write-Output "Setting variables..."
|
|
7
7
|
$serverName = $env:COMPUTERNAME
|
|
8
|
-
$
|
|
8
|
+
$instanceNames = @('SQL2014')
|
|
9
9
|
$smo = 'Microsoft.SqlServer.Management.Smo.'
|
|
10
10
|
$wmi = new-object ($smo + 'Wmi.ManagedComputer')
|
|
11
11
|
|
|
12
12
|
Write-Output "Configure Instances..."
|
|
13
|
-
foreach ($
|
|
14
|
-
Write-Output "Instance $
|
|
13
|
+
foreach ($instanceName in $instanceNames) {
|
|
14
|
+
Write-Output "Instance $instanceName ..."
|
|
15
15
|
Write-Output "Enable TCP/IP and port 1433..."
|
|
16
|
-
$uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$
|
|
16
|
+
$uri = "ManagedComputer[@Name='$serverName']/ServerInstance[@Name='$instanceName']/ServerProtocol[@Name='Tcp']"
|
|
17
17
|
$tcp = $wmi.GetSmoObject($uri)
|
|
18
18
|
$tcp.IsEnabled = $true
|
|
19
19
|
foreach ($ipAddress in $Tcp.IPAddresses) {
|