activerecord-sqlserver-adapter 7.1.0.rc1 → 7.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +10 -10
- data/VERSION +1 -1
- data/lib/active_record/connection_adapters/sqlserver/database_statements.rb +3 -0
- data/lib/active_record/connection_adapters/sqlserver/quoting.rb +15 -11
- data/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +23 -0
- data/lib/active_record/connection_adapters/sqlserver/utils.rb +4 -8
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +4 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +1 -1
- data/lib/arel/visitors/sqlserver.rb +32 -0
- data/test/cases/coerced_tests.rb +58 -0
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58c19846ce74967bacd12d1accd41c82b31f2fb04829ee8a19ea529f73dd97a7
|
4
|
+
data.tar.gz: 81d8ea6ee564704c1bf0178c3e28de18979892a0b18881eb3cee2f5d96052101
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9369b4c86d3ea8ef36eeb47a19e5e2bc5a31024ead3aa1e1d535346a486526e0e9e196d95e8f2667a57d1532f8daa5f48b7909e657eb2c699450480e23974e85
|
7
|
+
data.tar.gz: c10c097a4ebd447e7dd25b6f6235023773a15bbf8c3650c7cc3e73cee27b4a37c82a85b493b807b71bf5fd971258fd40300e3696b3a92f4a8e585f55e0562cf0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
## v7.1.0
|
2
|
+
|
3
|
+
#### Added
|
4
|
+
|
5
|
+
- [#1141](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1141) Added support for check constraints.
|
6
|
+
|
7
|
+
## v7.1.0.rc2
|
8
|
+
|
9
|
+
#### Added
|
10
|
+
|
11
|
+
- [#1136](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1136) Prevent marking broken connections as verified
|
12
|
+
- [#1138](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1138) Cache quoted names
|
13
|
+
|
1
14
|
## v7.1.0.rc1
|
2
15
|
|
3
16
|
#### Added
|
data/README.md
CHANGED
@@ -11,16 +11,16 @@ The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
|
|
11
11
|
|
12
12
|
Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 7.x version of the adapter is only for the latest 7.x version of Rails. If you need the adapter for SQL Server 2008 or 2005, you are still in the right spot. Just install the latest 3.2.x to 4.1.x version of the adapter that matches your Rails version. We also have stable branches for each major/minor release of ActiveRecord.
|
13
13
|
|
14
|
-
| Adapter Version | Rails Version | Support
|
15
|
-
|
16
|
-
| `7.1.0
|
17
|
-
| `7.0.5.1` | `7.0.x` | Active
|
18
|
-
| `6.1.3.0` | `6.1.x` | Active
|
19
|
-
| `6.0.3` | `6.0.x` | Ended
|
20
|
-
| `5.2.1` | `5.2.x` | Ended
|
21
|
-
| `5.1.6` | `5.1.x` | Ended
|
22
|
-
| `4.2.18` | `4.2.x` | Ended
|
23
|
-
| `4.1.8` | `4.1.x` | Ended
|
14
|
+
| Adapter Version | Rails Version | Support | Branch |
|
15
|
+
|-----------------|---------------|---------|--------------------------------------------------------------------------------------------------|
|
16
|
+
| `7.1.0` | `7.1.x` | Active | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
|
17
|
+
| `7.0.5.1` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
|
18
|
+
| `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
|
19
|
+
| `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
|
20
|
+
| `5.2.1` | `5.2.x` | Ended | [5-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
|
21
|
+
| `5.1.6` | `5.1.x` | Ended | [5-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
|
22
|
+
| `4.2.18` | `4.2.x` | Ended | [4-2-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-2-stable) |
|
23
|
+
| `4.1.8` | `4.1.x` | Ended | [4-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/4-1-stable) |
|
24
24
|
|
25
25
|
For older versions, please check their stable branches.
|
26
26
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
7.1.0
|
1
|
+
7.1.0
|
@@ -23,6 +23,7 @@ module ActiveRecord
|
|
23
23
|
else
|
24
24
|
internal_raw_execute(sql, conn, perform_do: true)
|
25
25
|
end
|
26
|
+
verified!
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
@@ -50,6 +51,7 @@ module ActiveRecord
|
|
50
51
|
else
|
51
52
|
result = internal_exec_sql_query(sql, conn)
|
52
53
|
end
|
54
|
+
verified!
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
@@ -175,6 +177,7 @@ module ActiveRecord
|
|
175
177
|
log(sql, "Execute Procedure") do
|
176
178
|
with_raw_connection do |conn|
|
177
179
|
result = internal_raw_execute(sql, conn)
|
180
|
+
verified!
|
178
181
|
options = { as: :hash, cache_rows: true, timezone: ActiveRecord.default_timezone || :utc }
|
179
182
|
|
180
183
|
result.each(options) do |row|
|
@@ -4,18 +4,18 @@ module ActiveRecord
|
|
4
4
|
module ConnectionAdapters
|
5
5
|
module SQLServer
|
6
6
|
module Quoting
|
7
|
-
|
8
|
-
|
9
|
-
QUOTED_STRING_PREFIX = "N".freeze
|
7
|
+
QUOTED_COLUMN_NAMES = Concurrent::Map.new # :nodoc:
|
8
|
+
QUOTED_TABLE_NAMES = Concurrent::Map.new # :nodoc:
|
10
9
|
|
11
10
|
def fetch_type_metadata(sql_type, sqlserver_options = {})
|
12
11
|
cast_type = lookup_cast_type(sql_type)
|
12
|
+
|
13
13
|
simple_type = SqlTypeMetadata.new(
|
14
|
-
sql_type:
|
15
|
-
type:
|
16
|
-
limit:
|
14
|
+
sql_type: sql_type,
|
15
|
+
type: cast_type.type,
|
16
|
+
limit: cast_type.limit,
|
17
17
|
precision: cast_type.precision,
|
18
|
-
scale:
|
18
|
+
scale: cast_type.scale
|
19
19
|
)
|
20
20
|
|
21
21
|
SQLServer::TypeMetadata.new(simple_type, **sqlserver_options)
|
@@ -34,7 +34,11 @@ module ActiveRecord
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def quote_column_name(name)
|
37
|
-
SQLServer::Utils.extract_identifiers(name).quoted
|
37
|
+
QUOTED_COLUMN_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
38
|
+
end
|
39
|
+
|
40
|
+
def quote_table_name(name)
|
41
|
+
QUOTED_TABLE_NAMES[name] ||= SQLServer::Utils.extract_identifiers(name).quoted
|
38
42
|
end
|
39
43
|
|
40
44
|
def quote_default_expression(value, column)
|
@@ -47,7 +51,7 @@ module ActiveRecord
|
|
47
51
|
end
|
48
52
|
|
49
53
|
def quoted_true
|
50
|
-
|
54
|
+
'1'
|
51
55
|
end
|
52
56
|
|
53
57
|
def unquoted_true
|
@@ -55,7 +59,7 @@ module ActiveRecord
|
|
55
59
|
end
|
56
60
|
|
57
61
|
def quoted_false
|
58
|
-
|
62
|
+
'0'
|
59
63
|
end
|
60
64
|
|
61
65
|
def unquoted_false
|
@@ -117,7 +121,7 @@ module ActiveRecord
|
|
117
121
|
when ActiveRecord::Type::SQLServer::Data
|
118
122
|
value.quoted
|
119
123
|
when String, ActiveSupport::Multibyte::Chars
|
120
|
-
"#{
|
124
|
+
"N#{super}"
|
121
125
|
else
|
122
126
|
super
|
123
127
|
end
|
@@ -267,6 +267,29 @@ module ActiveRecord
|
|
267
267
|
end
|
268
268
|
end
|
269
269
|
|
270
|
+
def check_constraints(table_name)
|
271
|
+
sql = <<~SQL
|
272
|
+
select chk.name AS 'name',
|
273
|
+
chk.definition AS 'expression'
|
274
|
+
from sys.check_constraints chk
|
275
|
+
inner join sys.tables st on chk.parent_object_id = st.object_id
|
276
|
+
where
|
277
|
+
st.name = '#{table_name}'
|
278
|
+
SQL
|
279
|
+
|
280
|
+
chk_info = internal_exec_query(sql, "SCHEMA")
|
281
|
+
|
282
|
+
chk_info.map do |row|
|
283
|
+
options = {
|
284
|
+
name: row["name"]
|
285
|
+
}
|
286
|
+
expression = row["expression"]
|
287
|
+
expression = expression[1..-2] if expression.start_with?("(") && expression.end_with?(")")
|
288
|
+
|
289
|
+
CheckConstraintDefinition.new(table_name, expression, options)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
|
270
293
|
def type_to_sql(type, limit: nil, precision: nil, scale: nil, **)
|
271
294
|
type_limitable = %w(string integer float char nchar varchar nvarchar).include?(type.to_s)
|
272
295
|
limit = nil unless type_limitable
|
@@ -6,13 +6,9 @@ module ActiveRecord
|
|
6
6
|
module ConnectionAdapters
|
7
7
|
module SQLServer
|
8
8
|
module Utils
|
9
|
-
QUOTED_STRING_PREFIX = "N"
|
10
|
-
|
11
9
|
# Value object to return identifiers from SQL Server names http://bit.ly/1CZ3EiL
|
12
10
|
# Inspired from Rails PostgreSQL::Name adapter object in their own Utils.
|
13
|
-
#
|
14
11
|
class Name
|
15
|
-
SEPARATOR = "."
|
16
12
|
UNQUOTED_SCANNER = /\]?\./
|
17
13
|
QUOTED_SCANNER = /\A\[.*?\]\./
|
18
14
|
QUOTED_CHECKER = /\A\[/
|
@@ -42,7 +38,7 @@ module ActiveRecord
|
|
42
38
|
end
|
43
39
|
|
44
40
|
def fully_qualified_database_quoted
|
45
|
-
[server_quoted, database_quoted].compact.join(
|
41
|
+
[server_quoted, database_quoted].compact.join('.')
|
46
42
|
end
|
47
43
|
|
48
44
|
def fully_qualified?
|
@@ -69,7 +65,7 @@ module ActiveRecord
|
|
69
65
|
end
|
70
66
|
|
71
67
|
def quoted
|
72
|
-
parts.map { |p| quote(p) if p }.join
|
68
|
+
parts.map { |p| quote(p) if p }.join('.')
|
73
69
|
end
|
74
70
|
|
75
71
|
def quoted_raw
|
@@ -132,7 +128,7 @@ module ActiveRecord
|
|
132
128
|
extend self
|
133
129
|
|
134
130
|
def quote_string(s)
|
135
|
-
s.to_s.gsub
|
131
|
+
s.to_s.gsub(/\'/, "''")
|
136
132
|
end
|
137
133
|
|
138
134
|
def quote_string_single(s)
|
@@ -140,7 +136,7 @@ module ActiveRecord
|
|
140
136
|
end
|
141
137
|
|
142
138
|
def quote_string_single_national(s)
|
143
|
-
"
|
139
|
+
"N'#{quote_string(s)}'"
|
144
140
|
end
|
145
141
|
|
146
142
|
def quoted_raw(name)
|
@@ -64,6 +64,38 @@ module Arel
|
|
64
64
|
super
|
65
65
|
end
|
66
66
|
|
67
|
+
def visit_Arel_Nodes_HomogeneousIn(o, collector)
|
68
|
+
collector.preparable = false
|
69
|
+
|
70
|
+
visit o.left, collector
|
71
|
+
|
72
|
+
if o.type == :in
|
73
|
+
collector << " IN ("
|
74
|
+
else
|
75
|
+
collector << " NOT IN ("
|
76
|
+
end
|
77
|
+
|
78
|
+
values = o.casted_values
|
79
|
+
|
80
|
+
# Monkey-patch start.
|
81
|
+
column_name = o.attribute.name
|
82
|
+
column_type = o.attribute.relation.type_for_attribute(column_name)
|
83
|
+
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
|
84
|
+
|
85
|
+
if values.empty?
|
86
|
+
collector << @connection.quote(nil)
|
87
|
+
elsif @connection.prepared_statements && !column_type.serialized?
|
88
|
+
# Add query attribute bindings rather than just values.
|
89
|
+
attrs = values.map { |value| ActiveRecord::Relation::QueryAttribute.new(column_name, value, column_type) }
|
90
|
+
collector.add_binds(attrs, &bind_block)
|
91
|
+
else
|
92
|
+
collector.add_binds(values, o.proc_for_binds, &bind_block)
|
93
|
+
end
|
94
|
+
# Monkey-patch end.
|
95
|
+
|
96
|
+
collector << ")"
|
97
|
+
end
|
98
|
+
|
67
99
|
def visit_Arel_Nodes_SelectStatement(o, collector)
|
68
100
|
@select_statement = o
|
69
101
|
distinct_One_As_One_Is_So_Not_Fetch o
|
data/test/cases/coerced_tests.rb
CHANGED
@@ -1580,6 +1580,13 @@ class SchemaDumperTest < ActiveRecord::TestCase
|
|
1580
1580
|
|
1581
1581
|
# Tests are not about a specific adapter.
|
1582
1582
|
coerce_tests! :test_do_not_dump_foreign_keys_when_bypassed_by_config
|
1583
|
+
|
1584
|
+
# SQL Server formats the check constraint expression differently.
|
1585
|
+
coerce_tests! :test_schema_dumps_check_constraints
|
1586
|
+
def test_schema_dumps_check_constraints_coerced
|
1587
|
+
constraint_definition = dump_table_schema("products").split(/\n/).grep(/t.check_constraint.*products_price_check/).first.strip
|
1588
|
+
assert_equal 't.check_constraint "[price]>[discounted_price]", name: "products_price_check"', constraint_definition
|
1589
|
+
end
|
1583
1590
|
end
|
1584
1591
|
|
1585
1592
|
class SchemaDumperDefaultsTest < ActiveRecord::TestCase
|
@@ -2585,3 +2592,54 @@ module ActiveRecord
|
|
2585
2592
|
end
|
2586
2593
|
end
|
2587
2594
|
end
|
2595
|
+
|
2596
|
+
module ActiveRecord
|
2597
|
+
class Migration
|
2598
|
+
class CheckConstraintTest < ActiveRecord::TestCase
|
2599
|
+
# SQL Server formats the check constraint expression differently.
|
2600
|
+
coerce_tests! :test_check_constraints
|
2601
|
+
def test_check_constraints_coerced
|
2602
|
+
check_constraints = @connection.check_constraints("products")
|
2603
|
+
assert_equal 1, check_constraints.size
|
2604
|
+
|
2605
|
+
constraint = check_constraints.first
|
2606
|
+
assert_equal "products", constraint.table_name
|
2607
|
+
assert_equal "products_price_check", constraint.name
|
2608
|
+
assert_equal "[price]>[discounted_price]", constraint.expression
|
2609
|
+
end
|
2610
|
+
|
2611
|
+
# SQL Server formats the check constraint expression differently.
|
2612
|
+
coerce_tests! :test_add_check_constraint
|
2613
|
+
def test_add_check_constraint_coerced
|
2614
|
+
@connection.add_check_constraint :trades, "quantity > 0"
|
2615
|
+
|
2616
|
+
check_constraints = @connection.check_constraints("trades")
|
2617
|
+
assert_equal 1, check_constraints.size
|
2618
|
+
|
2619
|
+
constraint = check_constraints.first
|
2620
|
+
assert_equal "trades", constraint.table_name
|
2621
|
+
assert_equal "chk_rails_2189e9f96c", constraint.name
|
2622
|
+
assert_equal "[quantity]>(0)", constraint.expression
|
2623
|
+
end
|
2624
|
+
|
2625
|
+
# SQL Server formats the check constraint expression differently.
|
2626
|
+
coerce_tests! :test_remove_check_constraint
|
2627
|
+
def test_remove_check_constraint_coerced
|
2628
|
+
@connection.add_check_constraint :trades, "price > 0", name: "price_check"
|
2629
|
+
@connection.add_check_constraint :trades, "quantity > 0", name: "quantity_check"
|
2630
|
+
|
2631
|
+
assert_equal 2, @connection.check_constraints("trades").size
|
2632
|
+
@connection.remove_check_constraint :trades, name: "quantity_check"
|
2633
|
+
assert_equal 1, @connection.check_constraints("trades").size
|
2634
|
+
|
2635
|
+
constraint = @connection.check_constraints("trades").first
|
2636
|
+
assert_equal "trades", constraint.table_name
|
2637
|
+
assert_equal "price_check", constraint.name
|
2638
|
+
assert_equal "[price]>(0)", constraint.expression
|
2639
|
+
|
2640
|
+
@connection.remove_check_constraint :trades, name: :price_check # name as a symbol
|
2641
|
+
assert_empty @connection.check_constraints("trades")
|
2642
|
+
end
|
2643
|
+
end
|
2644
|
+
end
|
2645
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-sqlserver-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.1.0
|
4
|
+
version: 7.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ken Collins
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2023-11-
|
18
|
+
date: 2023-11-21 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activerecord
|
@@ -235,8 +235,8 @@ licenses:
|
|
235
235
|
- MIT
|
236
236
|
metadata:
|
237
237
|
bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
|
238
|
-
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.0
|
239
|
-
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.0
|
238
|
+
changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.0/CHANGELOG.md
|
239
|
+
source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.0
|
240
240
|
post_install_message:
|
241
241
|
rdoc_options: []
|
242
242
|
require_paths:
|
@@ -248,9 +248,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
248
248
|
version: 2.7.0
|
249
249
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
250
250
|
requirements:
|
251
|
-
- - "
|
251
|
+
- - ">="
|
252
252
|
- !ruby/object:Gem::Version
|
253
|
-
version:
|
253
|
+
version: '0'
|
254
254
|
requirements: []
|
255
255
|
rubygems_version: 3.4.7
|
256
256
|
signing_key:
|