activerecord-sqlserver-adapter 7.1.4 → 7.1.5

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: 4e12d59815d11d0cbecea5d206057d6251384ef3a37df229c3c20c92eb7e0312
4
- data.tar.gz: 25644794411a6dd0e709216a5cc444571645f94f2faf07ede21a6680c9682b35
3
+ metadata.gz: eea983d328f36bfb590c26ff592292369634d60b63ff38acc43e28c87e09c7ee
4
+ data.tar.gz: 7e9ab05308f76eb6be6ef5745977f4c0de684c608494d45d9d49d3ac54e1a4cb
5
5
  SHA512:
6
- metadata.gz: ff6fc5d218ed61de3c5b28024f72e42023ee15e710048f797e428d00487dd3be8284fadc8a23922aacb08ae22389aa0eaf7d9e86123d1a9d23ee9f2f222cc54e
7
- data.tar.gz: ee6cd4a68000ec209f06f39c5029b049dd870993652a9bce9125cc118efc829bced1a921631fec7a8353e7bf96790eacdd9718a606fa82dee8ff2e74143b45c5
6
+ metadata.gz: 67f76bc1083712be03b8a8b3eb5a2c48b9d4efc44442b8573604aecaff23ccbd0bd1586529948497776aca6b7c18257ead5d62e239f2b69d92e2ec14e5675192
7
+ data.tar.gz: 845923a58bda81c5f32a81b40a61157b1d36c909352ac258bd848d2e604f95ee94e09878f3c8f475f3d770725c8492b8b58c4c87146c4965e0b29d91b64872fc
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## v7.1.5
2
+
3
+ #### Added
4
+
5
+ - [#1201](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1201) Support non-dbo schemas in schema dumper
6
+ - [#1206](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1206) Support table names containing spaces
7
+
1
8
  ## v7.1.4
2
9
 
3
10
  #### Fixed
data/README.md CHANGED
@@ -13,7 +13,8 @@ Interested in older versions? We follow a rational versioning policy that tracks
13
13
 
14
14
  | Adapter Version | Rails Version | Support | Branch |
15
15
  |-----------------|---------------|---------|--------------------------------------------------------------------------------------------------|
16
- | `7.1.4` | `7.1.x` | Active | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
16
+ | Unreleased | `7.2.x` | In Development | [main](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/main) |
17
+ | `7.1.5` | `7.1.x` | Active | [7-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-1-stable) |
17
18
  | `7.0.7` | `7.0.x` | Active | [7-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/7-0-stable) |
18
19
  | `6.1.3.0` | `6.1.x` | Active | [6-1-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-1-stable) |
19
20
  | `6.0.3` | `6.0.x` | Ended | [6-0-stable](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/6-0-stable) |
data/VERSION CHANGED
@@ -1 +1 @@
1
- 7.1.4
1
+ 7.1.5
@@ -39,6 +39,17 @@ module ActiveRecord
39
39
  def default_primary_key?(column)
40
40
  super && column.is_identity?
41
41
  end
42
+
43
+ def schemas(stream)
44
+ schema_names = @connection.schema_names
45
+
46
+ if schema_names.any?
47
+ schema_names.sort.each do |name|
48
+ stream.puts " create_schema #{name.inspect}"
49
+ end
50
+ stream.puts
51
+ end
52
+ end
42
53
  end
43
54
  end
44
55
  end
@@ -393,19 +393,37 @@ module ActiveRecord
393
393
  execute "DROP SCHEMA [#{schema_name}]"
394
394
  end
395
395
 
396
+ # Returns an array of schema names.
397
+ def schema_names
398
+ sql = <<~SQL.squish
399
+ SELECT name
400
+ FROM sys.schemas
401
+ WHERE
402
+ name NOT LIKE 'db_%' AND
403
+ name NOT IN ('INFORMATION_SCHEMA', 'sys')
404
+ SQL
405
+
406
+ query_values(sql, "SCHEMA")
407
+ end
408
+
396
409
  private
397
410
 
398
411
  def data_source_sql(name = nil, type: nil)
399
- scope = quoted_scope name, type: type
412
+ scope = quoted_scope(name, type: type)
400
413
 
401
- table_name = lowercase_schema_reflection_sql 'TABLE_NAME'
402
- database = scope[:database].present? ? "#{scope[:database]}." : ""
414
+ table_schema = lowercase_schema_reflection_sql('TABLE_SCHEMA')
415
+ table_name = lowercase_schema_reflection_sql('TABLE_NAME')
416
+ database = scope[:database].present? ? "#{scope[:database]}." : ""
403
417
  table_catalog = scope[:database].present? ? quote(scope[:database]) : "DB_NAME()"
404
418
 
405
- sql = "SELECT #{table_name}"
419
+ sql = "SELECT "
420
+ sql += " CASE"
421
+ sql += " WHEN #{table_schema} = 'dbo' THEN #{table_name}"
422
+ sql += " ELSE CONCAT(#{table_schema}, '.', #{table_name})"
423
+ sql += " END"
406
424
  sql += " FROM #{database}INFORMATION_SCHEMA.TABLES WITH (NOLOCK)"
407
425
  sql += " WHERE TABLE_CATALOG = #{table_catalog}"
408
- sql += " AND TABLE_SCHEMA = #{quote(scope[:schema])}"
426
+ sql += " AND TABLE_SCHEMA = #{quote(scope[:schema])}" if scope[:schema]
409
427
  sql += " AND TABLE_NAME = #{quote(scope[:name])}" if scope[:name]
410
428
  sql += " AND TABLE_TYPE = #{quote(scope[:type])}" if scope[:type]
411
429
  sql += " ORDER BY #{table_name}"
@@ -414,9 +432,10 @@ module ActiveRecord
414
432
 
415
433
  def quoted_scope(name = nil, type: nil)
416
434
  identifier = SQLServer::Utils.extract_identifiers(name)
435
+
417
436
  {}.tap do |scope|
418
437
  scope[:database] = identifier.database if identifier.database
419
- scope[:schema] = identifier.schema || "dbo"
438
+ scope[:schema] = identifier.schema || "dbo" if name.present?
420
439
  scope[:name] = identifier.object if identifier.object
421
440
  scope[:type] = type if type
422
441
  end
@@ -654,12 +673,18 @@ module ActiveRecord
654
673
 
655
674
  # Parses the raw table name that is used in the SQL. Table name could include database/schema/etc.
656
675
  def get_raw_table_name(sql)
657
- case sql
658
- when /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
659
- Regexp.last_match[3] || Regexp.last_match[4]
660
- when /FROM\s+([^\(\s]+)\s*/i
661
- Regexp.last_match[1]
662
- end
676
+ s = sql.gsub(/^\s*EXEC sp_executesql N'/i, "")
677
+
678
+ if s.match?(/^\s*INSERT INTO.*/i)
679
+ s.split(/INSERT INTO/i)[1]
680
+ .split(/OUTPUT INSERTED/i)[0]
681
+ .split(/(DEFAULT)?\s+VALUES/i)[0]
682
+ .match(/\s*([^(]*)/i)[0]
683
+ elsif s.match?(/^\s*UPDATE\s+.*/i)
684
+ s.match(/UPDATE\s+([^\(\s]+)\s*/i)[1]
685
+ else
686
+ s.match(/FROM\s+((\[[^\(\]]+\])|[^\(\s]+)\s*/i)[1]
687
+ end.strip
663
688
  end
664
689
 
665
690
  def default_constraint_name(table_name, column_name)
@@ -550,11 +550,23 @@ class AdapterTestSQLServer < ActiveRecord::TestCase
550
550
 
551
551
  describe 'table is in non-dbo schema' do
552
552
  it "records can be created successfully" do
553
- Alien.create!(name: 'Trisolarans')
553
+ assert_difference("Alien.count", 1) do
554
+ Alien.create!(name: 'Trisolarans')
555
+ end
554
556
  end
555
557
 
556
558
  it 'records can be inserted using SQL' do
557
- Alien.connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
559
+ assert_difference("Alien.count", 2) do
560
+ Alien.connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
561
+ end
562
+ end
563
+ end
564
+
565
+ describe 'table names contains spaces' do
566
+ it 'records can be created successfully' do
567
+ assert_difference("TableWithSpaces.count", 1) do
568
+ TableWithSpaces.create!(name: 'Bob')
569
+ end
558
570
  end
559
571
  end
560
572
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "cases/helper_sqlserver"
4
+ require "stringio"
4
5
 
5
6
  class SchemaDumperTestSQLServer < ActiveRecord::TestCase
6
7
  before { all_tables }
@@ -141,7 +142,7 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
141
142
  it "honor nonstandard primary keys" do
142
143
  generate_schema_for_table("movies") do |output|
143
144
  match = output.match(%r{create_table "movies"(.*)do})
144
- assert_not_nil(match, "nonstandardpk table not found")
145
+ assert_not_nil(match, "non-standard primary key table not found")
145
146
  assert_match %r(primary_key: "movieid"), match[1], "non-standard primary key not preserved"
146
147
  end
147
148
  end
@@ -159,14 +160,32 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
159
160
  _(output.scan('t.integer "unique_field"').length).must_equal(1)
160
161
  end
161
162
 
163
+ it "schemas are dumped and tables names only include non-default schema" do
164
+ stream = StringIO.new
165
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
166
+ generated_schema = stream.string
167
+
168
+ # Only generate non-default schemas. Default schema is 'dbo'.
169
+ assert_not_includes generated_schema, 'create_schema "dbo"'
170
+ assert_includes generated_schema, 'create_schema "test"'
171
+ assert_includes generated_schema, 'create_schema "test2"'
172
+
173
+ # Only non-default schemas should be included in table names. Default schema is 'dbo'.
174
+ assert_includes generated_schema, 'create_table "accounts"'
175
+ assert_includes generated_schema, 'create_table "test.aliens"'
176
+ assert_includes generated_schema, 'create_table "test2.sst_schema_test_mulitple_schema"'
177
+ end
178
+
162
179
  private
163
180
 
164
181
  def generate_schema_for_table(*table_names)
165
- require "stringio"
182
+ previous_ignore_tables = ActiveRecord::SchemaDumper.ignore_tables
183
+ ActiveRecord::SchemaDumper.ignore_tables = all_tables - table_names
166
184
 
167
185
  stream = StringIO.new
168
186
  ActiveRecord::SchemaDumper.ignore_tables = all_tables - table_names
169
187
  ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, stream)
188
+
170
189
  @generated_schema = stream.string
171
190
  yield @generated_schema if block_given?
172
191
  @schema_lines = Hash.new
@@ -177,6 +196,8 @@ class SchemaDumperTestSQLServer < ActiveRecord::TestCase
177
196
  @schema_lines[Regexp.last_match[1]] = SchemaLine.new(line)
178
197
  end
179
198
  @generated_schema
199
+ ensure
200
+ ActiveRecord::SchemaDumper.ignore_tables = previous_ignore_tables
180
201
  end
181
202
 
182
203
  def line(column_name)
@@ -39,7 +39,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
39
39
  assert_equal 1, columns.select { |c| c.is_identity? }.size
40
40
  end
41
41
 
42
- it "return correct varchar and nvarchar column limit length when table is in non dbo schema" do
42
+ it "return correct varchar and nvarchar column limit length when table is in non-dbo schema" do
43
43
  columns = connection.columns("test.sst_schema_columns")
44
44
 
45
45
  assert_equal 255, columns.find { |c| c.name == "name" }.limit
@@ -48,4 +48,50 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
48
48
  assert_equal 1000, columns.find { |c| c.name == "n_description" }.limit
49
49
  end
50
50
  end
51
+
52
+ describe "parsing table name from raw SQL" do
53
+ describe 'SELECT statements' do
54
+ it do
55
+ assert_equal "[sst_schema_columns]", connection.send(:get_raw_table_name, "SELECT [sst_schema_columns].[id] FROM [sst_schema_columns]")
56
+ end
57
+
58
+ it do
59
+ assert_equal "sst_schema_columns", connection.send(:get_raw_table_name, "SELECT [sst_schema_columns].[id] FROM sst_schema_columns")
60
+ end
61
+
62
+ it do
63
+ assert_equal "[WITH - SPACES]", connection.send(:get_raw_table_name, "SELECT id FROM [WITH - SPACES]")
64
+ end
65
+
66
+ it do
67
+ assert_equal "[WITH - SPACES$DOLLAR]", connection.send(:get_raw_table_name, "SELECT id FROM [WITH - SPACES$DOLLAR]")
68
+ end
69
+ end
70
+
71
+ describe 'INSERT statements' do
72
+ it do
73
+ assert_equal "[dashboards]", connection.send(:get_raw_table_name, "INSERT INTO [dashboards] DEFAULT VALUES; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
74
+ end
75
+
76
+ it do
77
+ assert_equal "lock_without_defaults", connection.send(:get_raw_table_name, "INSERT INTO lock_without_defaults(title) VALUES('title1')")
78
+ end
79
+
80
+ it do
81
+ assert_equal "json_data_type", connection.send(:get_raw_table_name, "insert into json_data_type (payload) VALUES ('null')")
82
+ end
83
+
84
+ it do
85
+ assert_equal "[auto_increments]", connection.send(:get_raw_table_name, "INSERT INTO [auto_increments] OUTPUT INSERTED.[id] DEFAULT VALUES")
86
+ end
87
+
88
+ it do
89
+ assert_equal "[WITH - SPACES]", connection.send(:get_raw_table_name, "EXEC sp_executesql N'INSERT INTO [WITH - SPACES] ([external_id]) OUTPUT INSERTED.[id] VALUES (@0)', N'@0 bigint', @0 = 10")
90
+ end
91
+
92
+ it do
93
+ assert_equal "[test].[aliens]", connection.send(:get_raw_table_name, "EXEC sp_executesql N'INSERT INTO [test].[aliens] ([name]) OUTPUT INSERTED.[id] VALUES (@0)', N'@0 varchar(255)', @0 = 'Trisolarans'")
94
+ end
95
+ end
96
+ end
51
97
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TableWithSpaces < ActiveRecord::Base
4
+ self.table_name = "A Table With Spaces"
5
+ end
@@ -151,6 +151,10 @@ ActiveRecord::Schema.define do
151
151
  SELECT GETUTCDATE() utcdate
152
152
  SQL
153
153
 
154
+ create_table 'A Table With Spaces', force: true do |t|
155
+ t.string :name
156
+ end
157
+
154
158
  # Constraints
155
159
 
156
160
  create_table(:sst_has_fks, force: true) do |t|
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.4
4
+ version: 7.1.5
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: 2024-07-04 00:00:00.000000000 Z
18
+ date: 2024-07-25 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: activerecord
@@ -212,6 +212,7 @@ files:
212
212
  - test/models/sqlserver/string_default.rb
213
213
  - test/models/sqlserver/string_defaults_big_view.rb
214
214
  - test/models/sqlserver/string_defaults_view.rb
215
+ - test/models/sqlserver/table_with_spaces.rb
215
216
  - test/models/sqlserver/tinyint_pk.rb
216
217
  - test/models/sqlserver/trigger.rb
217
218
  - test/models/sqlserver/trigger_history.rb
@@ -239,8 +240,8 @@ licenses:
239
240
  - MIT
240
241
  metadata:
241
242
  bug_tracker_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/issues
242
- changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.4/CHANGELOG.md
243
- source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.4
243
+ changelog_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/blob/v7.1.5/CHANGELOG.md
244
+ source_code_uri: https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/tree/v7.1.5
244
245
  post_install_message:
245
246
  rdoc_options: []
246
247
  require_paths:
@@ -329,6 +330,7 @@ test_files:
329
330
  - test/models/sqlserver/string_default.rb
330
331
  - test/models/sqlserver/string_defaults_big_view.rb
331
332
  - test/models/sqlserver/string_defaults_view.rb
333
+ - test/models/sqlserver/table_with_spaces.rb
332
334
  - test/models/sqlserver/tinyint_pk.rb
333
335
  - test/models/sqlserver/trigger.rb
334
336
  - test/models/sqlserver/trigger_history.rb