activerecord-sqlserver-adapter 6.1.2.1 → 6.1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5cbe90476efcde83329c5afc117491b77898865135cca90e25f44eed91b54e87
4
- data.tar.gz: fd41bbb523fdf9281e18120788dd0ff49653a31ff189dceb55ab49aba816d197
3
+ metadata.gz: 746931d24bb3806cafe400f5e4fed544e36dc7b06c6635a2ed4da4aacbf28590
4
+ data.tar.gz: dc87a51ccca60af1256b55f511f919c0ce6e5e9c7bb85a1a6865c52ed1e272f4
5
5
  SHA512:
6
- metadata.gz: b6555a063590ffe22617da22910c8f131935582dd366e76bb9f1b953670ef462416ca8cd28f290277d799449cd7e298e3abb5159578b074e59c66b18fd30cedb
7
- data.tar.gz: 8c5a255f1d37d1961c1dd5957535513370510316ace2266c1f91359a2c85700b9c94bf30aa47bb482d9e928c5399fa54fbb2415c8e52b65ebbec16c7fd38abad
6
+ metadata.gz: c33ad8a4f68a70fb8b15ae9b010d47043c412a17494a1248197651cdfebe3e8960fec51648c81bef28ccc9d4fae6dff08b9732a1f7dec9fe9f5cfcb66b8ccbbf
7
+ data.tar.gz: 3f40b13dd7c1d69af465467b5f00a60514c02d4d7f2051c6a78c365374a0ae42d475233b9b08646bb94d8ce4899b8627b836098217efee44fc785814b1cd8bf1
@@ -13,7 +13,10 @@ jobs:
13
13
  strategy:
14
14
  fail-fast: false
15
15
  matrix:
16
- ruby: [2.5.9, 2.6.7, 2.7.3, 3.0.1]
16
+ ruby:
17
+ - 2.7.5
18
+ - 3.0.3
19
+ - 3.1.0
17
20
 
18
21
  steps:
19
22
  - name: Checkout code
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## v6.1.3.0
2
+
3
+ [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v6.1.2.1...v6.1.3.0)
4
+
5
+ #### Fixed
6
+
7
+ - [#1006](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1006) Fix support for index types
8
+ - [#1041](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1041) Fix hook method that allows custom connection configuration.
9
+
10
+ #### Changed
11
+
12
+ - [#1014](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1014) Better handle SQL queries with invalid encoding
13
+
1
14
  ## v6.1.2.1
2
15
 
3
16
  [Full changelog](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/compare/v6.1.2.0...v6.1.2.1)
data/Gemfile CHANGED
@@ -7,9 +7,12 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
7
7
  gemspec
8
8
 
9
9
  gem "bcrypt"
10
- gem "pg", ">= 0.18.0"
10
+
11
+ gem "pg", "~> 1.3"
12
+
11
13
  gem "sqlite3", "~> 1.4"
12
14
  gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby]
15
+ gem "minitest", ">= 5.15.0", "< 5.16"
13
16
 
14
17
  if ENV["RAILS_SOURCE"]
15
18
  gemspec path: ENV["RAILS_SOURCE"]
data/README.md CHANGED
@@ -12,8 +12,8 @@ The SQL Server adapter for ActiveRecord using SQL Server 2012 or higher.
12
12
  Interested in older versions? We follow a rational versioning policy that tracks Rails. That means that our 6.x version of the adapter is only for the latest 6.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
14
  | Adapter Version | Rails Version | Support |
15
- | --------------- | ------------- | ------------------------------------------------------------------------------------------- |
16
- | `6.1.2.1` | `6.1.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
15
+ |-----------------| ------------- |---------------------------------------------------------------------------------------------|
16
+ | `6.1.3.0` | `6.1.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
17
17
  | `6.0.2` | `6.0.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
18
18
  | `5.2.1` | `5.2.x` | [active](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-2-stable) |
19
19
  | `5.1.6` | `5.1.x` | [ended](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/5-1-stable) |
@@ -84,7 +84,7 @@ end
84
84
 
85
85
  #### Configure Connection
86
86
 
87
- We currently conform to an unpublished and non-standard AbstractAdapter interface to configure connections made to the database. To do so, just override the `configure_connection` method in an initializer like so. In this case below we are setting the `TEXTSIZE` to 64 megabytes.
87
+ We currently conform to an unpublished and non-standard AbstractAdapter interface to configure connections made to the database. To do so, just implement the `configure_connection` method in an initializer like so. In this case below we are setting the `TEXTSIZE` to 64 megabytes.
88
88
 
89
89
  ```ruby
90
90
  module ActiveRecord
@@ -107,7 +107,7 @@ Below shows how you might use the database.yml file to use the process ID in you
107
107
  ```yaml
108
108
  development:
109
109
  adapter: sqlserver
110
- appname: <%= myapp_#{Process.pid} %>
110
+ appname: <%= "myapp_#{Process.pid}" %>
111
111
  ```
112
112
 
113
113
  #### Executing Stored Procedures
@@ -152,16 +152,25 @@ ActiveRecord::ConnectionAdapters::SQLServerAdapter.showplan_option = 'SHOWPLAN_X
152
152
  **NOTE:** The method we utilize to make SHOWPLANs work is very brittle to complex SQL. There is no getting around this as we have to deconstruct an already prepared statement for the sp_executesql method. If you find that explain breaks your app, simple disable it. Do not open a github issue unless you have a patch. Please [consult the Rails guides](http://guides.rubyonrails.org/active_record_querying.html#running-explain) for more info.
153
153
 
154
154
 
155
+ ## New Rails Applications
156
+
157
+ When creating a new Rails application you can specify that you want to use the SQL Server adapter using the `database` option:
158
+
159
+ ```
160
+ rails new my_app --database=sqlserver
161
+ ```
162
+
163
+ To then connect the application to your SQL Server instance edit the `config/database.yml` file with the username, password and host of your SQL Server instance.
164
+
165
+
155
166
  ## Installation
156
167
 
157
168
  The adapter has no strict gem dependencies outside of `ActiveRecord`. You will have to pick a connection mode, the default is dblib which uses the `TinyTDS` gem. Just bundle the gem and the adapter will use it.
158
169
 
159
170
  ```ruby
160
- gem 'tiny_tds'
161
171
  gem 'activerecord-sqlserver-adapter'
162
172
  ```
163
173
 
164
-
165
174
  ## Contributing
166
175
 
167
176
  If you would like to contribute a feature or bugfix, thanks! To make sure your fix/feature has a high chance of being added, please read the following guidelines. First, ask on the Gitter, or post a ticket on github issues. Second, make sure there are tests! We will not accept any patch that is not tested. Please read the [`RUNNING_UNIT_TESTS`](RUNNING_UNIT_TESTS.md) file for the details of how to run the unit tests.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 6.1.2.1
1
+ 6.1.3.0
data/appveyor.yml CHANGED
@@ -5,10 +5,10 @@ build: off
5
5
  matrix:
6
6
  fast_finish: true
7
7
  allow_failures:
8
- - ruby_version: "25"
9
- - ruby_version: "26"
10
8
  - ruby_version: "27"
11
9
  - ruby_version: "27-x64"
10
+ - ruby_version: "30"
11
+ - ruby_version: "30-x64"
12
12
  services:
13
13
  - mssql2014
14
14
 
@@ -38,9 +38,7 @@ environment:
38
38
  CI_AZURE_PASS:
39
39
  secure: cSQp8sk4urJYvq0utpsK+r7J+snJ2wpcdp8RdXJfB+w=
40
40
  matrix:
41
- - ruby_version: "25-x64"
42
- - ruby_version: "25"
43
- - ruby_version: "26-x64"
44
- - ruby_version: "26"
45
41
  - ruby_version: "27-x64"
46
42
  - ruby_version: "27"
43
+ - ruby_version: "30-x64"
44
+ - ruby_version: "30"
@@ -9,6 +9,8 @@ module ActiveRecord
9
9
 
10
10
  def write_query?(sql) # :nodoc:
11
11
  !READ_QUERY.match?(sql)
12
+ rescue ArgumentError # Invalid encoding
13
+ !READ_QUERY.match?(sql.b)
12
14
  end
13
15
 
14
16
  def execute(sql, name = nil)
@@ -34,17 +34,19 @@ module ActiveRecord
34
34
  end
35
35
 
36
36
  def visit_CreateIndexDefinition(o)
37
- if_not_exists = o.if_not_exists
38
-
39
- o.if_not_exists = false
40
-
41
- sql = super
37
+ index = o.index
42
38
 
43
- if if_not_exists
44
- sql = "IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = '#{o.index.name}') #{sql}"
45
- end
39
+ sql = []
40
+ sql << "IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = '#{o.index.name}')" if o.if_not_exists
41
+ sql << "CREATE"
42
+ sql << "UNIQUE" if index.unique
43
+ sql << index.type.upcase if index.type
44
+ sql << "INDEX"
45
+ sql << "#{quote_column_name(index.name)} ON #{quote_table_name(index.table)}"
46
+ sql << "(#{quoted_columns(index)})"
47
+ sql << "WHERE #{index.where}" if index.where
46
48
 
47
- sql
49
+ sql.join(" ")
48
50
  end
49
51
 
50
52
  def add_column_options!(sql, options)
@@ -531,17 +531,22 @@ module ActiveRecord
531
531
 
532
532
  # === SQLServer Specific (Misc Helpers) ========================= #
533
533
 
534
+ # Parses just the table name from the SQL. Table name does not include database/schema/etc.
534
535
  def get_table_name(sql)
535
- tn = if sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
536
- Regexp.last_match[3] || Regexp.last_match[4]
537
- elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
538
- Regexp.last_match[1]
539
- else
540
- nil
541
- end
536
+ tn = get_raw_table_name(sql)
542
537
  SQLServer::Utils.extract_identifiers(tn).object
543
538
  end
544
539
 
540
+ # Parses the raw table name that is used in the SQL. Table name could include database/schema/etc.
541
+ def get_raw_table_name(sql)
542
+ case sql
543
+ when /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
544
+ Regexp.last_match[3] || Regexp.last_match[4]
545
+ when /FROM\s+([^\(\s]+)\s*/i
546
+ Regexp.last_match[1]
547
+ end
548
+ end
549
+
545
550
  def default_constraint_name(table_name, column_name)
546
551
  "DF_#{table_name}_#{column_name}"
547
552
  end
@@ -46,7 +46,22 @@ module ActiveRecord
46
46
  end
47
47
 
48
48
  def fully_qualified?
49
- parts.compact.size == 4
49
+ qualified_level == :fully
50
+ end
51
+
52
+ def qualified_level
53
+ case parts.compact.size
54
+ when 4
55
+ :fully
56
+ when 3
57
+ :database
58
+ when 2
59
+ :schema
60
+ when 1
61
+ :table
62
+ else
63
+ :none
64
+ end
50
65
  end
51
66
 
52
67
  def to_s
@@ -140,7 +140,7 @@ module ActiveRecord
140
140
  def initialize(connection, logger, _connection_options, config)
141
141
  super(connection, logger, config)
142
142
  @connection_options = config
143
- configure_connection
143
+ perform_connection_configuration
144
144
  end
145
145
 
146
146
  # === Abstract Adapter ========================================== #
@@ -301,14 +301,6 @@ module ActiveRecord
301
301
  do_execute "IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION"
302
302
  end
303
303
 
304
- def configure_connection
305
- @spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
306
- @version_year = version_year
307
-
308
- initialize_dateformatter
309
- use_database
310
- end
311
-
312
304
  # === Abstract Adapter (Misc Support) =========================== #
313
305
 
314
306
  def tables_with_referential_integrity
@@ -530,7 +522,20 @@ module ActiveRecord
530
522
 
531
523
  def connect
532
524
  @connection = self.class.new_client(@connection_options)
533
- configure_connection
525
+ perform_connection_configuration
526
+ end
527
+
528
+ def perform_connection_configuration
529
+ configure_connection_defaults
530
+ configure_connection if self.respond_to?(:configure_connection)
531
+ end
532
+
533
+ def configure_connection_defaults
534
+ @spid = _raw_select("SELECT @@SPID", fetch: :rows).first.first
535
+ @version_year = version_year
536
+
537
+ initialize_dateformatter
538
+ use_database
534
539
  end
535
540
  end
536
541
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "cases/helper_sqlserver"
4
+
5
+ class ActiveSchemaTestSQLServer < ActiveRecord::TestCase
6
+ before do
7
+ connection.create_table :schema_test_table, force: true, id: false do |t|
8
+ t.column :foo, :string, limit: 100
9
+ t.column :state, :string
10
+ end
11
+ end
12
+
13
+ after do
14
+ connection.drop_table :schema_test_table rescue nil
15
+ end
16
+
17
+ it 'default index' do
18
+ assert_sql('CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
19
+ connection.add_index :schema_test_table, "foo"
20
+ end
21
+ end
22
+
23
+ it 'unique index' do
24
+ assert_sql('CREATE UNIQUE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])') do
25
+ connection.add_index :schema_test_table, "foo", unique: true
26
+ end
27
+ end
28
+
29
+ it 'where condition on index' do
30
+ assert_sql("CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo]) WHERE state = 'active'") do
31
+ connection.add_index :schema_test_table, "foo", where: "state = 'active'"
32
+ end
33
+ end
34
+
35
+ it 'if index does not exist' do
36
+ assert_sql("IF NOT EXISTS (SELECT name FROM sysindexes WHERE name = 'index_schema_test_table_on_foo') " \
37
+ "CREATE INDEX [index_schema_test_table_on_foo] ON [schema_test_table] ([foo])") do
38
+ connection.add_index :schema_test_table, "foo", if_not_exists: true
39
+ end
40
+ end
41
+
42
+ describe "index types" do
43
+ it 'clustered index' do
44
+ assert_sql('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_sql('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
+ end
@@ -92,6 +92,18 @@ module ActiveRecord
92
92
  Subscriber.send(:load_schema!)
93
93
  original_test_errors_when_an_insert_query_prefixed_by_a_double_dash_comment_is_called_while_preventing_writes
94
94
  end
95
+
96
+ coerce_tests! :test_doesnt_error_when_a_select_query_has_encoding_errors
97
+ def test_doesnt_error_when_a_select_query_has_encoding_errors_coerced
98
+ ActiveRecord::Base.while_preventing_writes do
99
+ # TinyTDS fail on encoding errors.
100
+ # But at least we can assert it fails in the client and not before when trying to
101
+ # match the query.
102
+ assert_raises ActiveRecord::StatementInvalid do
103
+ @connection.select_all("SELECT '\xC8'")
104
+ end
105
+ end
106
+ end
95
107
  end
96
108
  end
97
109
 
@@ -1195,7 +1207,7 @@ class RelationTest < ActiveRecord::TestCase
1195
1207
  sql_log = capture_sql do
1196
1208
  message = <<~MSG.squish
1197
1209
  `.reorder(nil)` with `.first` / `.first!` no longer
1198
- takes non-deterministic result in Rails 6.2.
1210
+ takes non-deterministic result in Rails 7.0.
1199
1211
  To continue taking non-deterministic result, use `.take` / `.take!` instead.
1200
1212
  MSG
1201
1213
  assert_deprecated(message) do
@@ -1402,7 +1414,8 @@ class YamlSerializationTest < ActiveRecord::TestCase
1402
1414
  coerce_tests! :test_types_of_virtual_columns_are_not_changed_on_round_trip
1403
1415
  def test_types_of_virtual_columns_are_not_changed_on_round_trip_coerced
1404
1416
  author = Author.select("authors.*, 5 as posts_count").first
1405
- dumped = YAML.load(YAML.dump(author))
1417
+ dumped_author = YAML.dump(author)
1418
+ dumped = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(dumped_author) : YAML.load(dumped_author)
1406
1419
  assert_equal 5, author.posts_count
1407
1420
  assert_equal 5, dumped.posts_count
1408
1421
  end
@@ -1893,17 +1906,22 @@ class AnnotateTest < ActiveRecord::TestCase
1893
1906
  def test_annotate_is_sanitized_coerced
1894
1907
  quoted_posts_id, quoted_posts = regexp_escape_table_name("posts.id"), regexp_escape_table_name("posts")
1895
1908
 
1896
- assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
1909
+ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* /foo/ \* \*/}i) do
1897
1910
  posts = Post.select(:id).annotate("*/foo/*")
1898
1911
  assert posts.first
1899
1912
  end
1900
1913
 
1901
- assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/}i) do
1914
+ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \*\* //foo// \*\* \*/}i) do
1902
1915
  posts = Post.select(:id).annotate("**//foo//**")
1903
1916
  assert posts.first
1904
1917
  end
1905
1918
 
1906
- assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* foo \*/ /\* bar \*/}i) do
1919
+ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* \* //foo// \* \* \*/}i) do
1920
+ posts = Post.select(:id).annotate("* *//foo//* *")
1921
+ assert posts.first
1922
+ end
1923
+
1924
+ assert_sql(%r{SELECT #{quoted_posts_id} FROM #{quoted_posts} /\* \* /foo/ \* \*/ /\* \* /bar \*/}i) do
1907
1925
  posts = Post.select(:id).annotate("*/foo/*").annotate("*/bar")
1908
1926
  assert posts.first
1909
1927
  end
@@ -176,7 +176,8 @@ class SQLServerRakeSchemaCacheDumpLoadTest < SQLServerRakeTest
176
176
  it "dumps schema cache with SQL Server metadata" do
177
177
  quietly { db_tasks.dump_schema_cache connection, filename }
178
178
 
179
- schema_cache = YAML.load(File.read(filename))
179
+ filedata = File.read(filename)
180
+ schema_cache = YAML.respond_to?(:unsafe_load) ? YAML.unsafe_load(filedata) : YAML.load(filedata)
180
181
 
181
182
  col_id, col_name = connection.schema_cache.columns("users")
182
183
 
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: 6.1.2.1
4
+ version: 6.1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ken Collins
@@ -11,10 +11,10 @@ authors:
11
11
  - Shawn Balestracci
12
12
  - Joe Rafaniello
13
13
  - Tom Ward
14
- autorequire:
14
+ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2021-09-08 00:00:00.000000000 Z
17
+ date: 2023-03-15 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: activerecord
@@ -142,6 +142,7 @@ files:
142
142
  - test/bin/install-freetds.sh
143
143
  - test/bin/install-openssl.sh
144
144
  - test/bin/setup.sh
145
+ - test/cases/active_schema_test_sqlserver.rb
145
146
  - test/cases/adapter_test_sqlserver.rb
146
147
  - test/cases/change_column_collation_test_sqlserver.rb
147
148
  - test/cases/change_column_null_test_sqlserver.rb
@@ -224,9 +225,9 @@ licenses:
224
225
  - MIT
225
226
  metadata:
226
227
  bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
227
- changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v6.1.2.1/CHANGELOG.md
228
- source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v6.1.2.1
229
- post_install_message:
228
+ changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v6.1.3.0/CHANGELOG.md
229
+ source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v6.1.3.0
230
+ post_install_message:
230
231
  rdoc_options: []
231
232
  require_paths:
232
233
  - lib
@@ -241,8 +242,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
241
242
  - !ruby/object:Gem::Version
242
243
  version: '0'
243
244
  requirements: []
244
- rubygems_version: 3.2.22
245
- signing_key:
245
+ rubygems_version: 3.2.33
246
+ signing_key:
246
247
  specification_version: 4
247
248
  summary: ActiveRecord SQL Server Adapter.
248
249
  test_files:
@@ -251,6 +252,7 @@ test_files:
251
252
  - test/bin/install-freetds.sh
252
253
  - test/bin/install-openssl.sh
253
254
  - test/bin/setup.sh
255
+ - test/cases/active_schema_test_sqlserver.rb
254
256
  - test/cases/adapter_test_sqlserver.rb
255
257
  - test/cases/change_column_collation_test_sqlserver.rb
256
258
  - test/cases/change_column_null_test_sqlserver.rb