activerecord-sqlserver-adapter 5.2.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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) {
|