Skip to content

Commit

Permalink
Support table names containing spaces (#1206)
Browse files Browse the repository at this point in the history
  • Loading branch information
aidanharan authored Jul 25, 2024
1 parent 0f02058 commit 682f102
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 10 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

#### Added

- [#1201](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1201) Support non-dbo schemas in schema dumper.
- [#1201](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1201) Support non-dbo schemas in schema dumper
- [#1206](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1206) Support table names containing spaces

## v7.1.4

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -673,12 +673,18 @@ def get_table_name(sql)

# Parses the raw table name that is used in the SQL. Table name could include database/schema/etc.
def get_raw_table_name(sql)
case sql
when /^\s*(INSERT|EXEC sp_executesql N'INSERT)(\s+INTO)?\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
Regexp.last_match[3] || Regexp.last_match[4]
when /FROM\s+([^\(\s]+)\s*/i
Regexp.last_match[1]
end
s = sql.gsub(/^\s*EXEC sp_executesql N'/i, "")

if s.match?(/^\s*INSERT INTO.*/i)
s.split(/INSERT INTO/i)[1]
.split(/OUTPUT INSERTED/i)[0]
.split(/(DEFAULT)?\s+VALUES/i)[0]
.match(/\s*([^(]*)/i)[0]
elsif s.match?(/^\s*UPDATE\s+.*/i)
s.match(/UPDATE\s+([^\(\s]+)\s*/i)[1]
else
s.match(/FROM\s+((\[[^\(\]]+\])|[^\(\s]+)\s*/i)[1]
end.strip
end

def default_constraint_name(table_name, column_name)
Expand Down
16 changes: 14 additions & 2 deletions test/cases/adapter_test_sqlserver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,23 @@ def test_doesnt_error_when_a_select_query_is_called_while_preventing_writes

describe 'table is in non-dbo schema' do
it "records can be created successfully" do
Alien.create!(name: 'Trisolarans')
assert_difference("Alien.count", 1) do
Alien.create!(name: 'Trisolarans')
end
end

it 'records can be inserted using SQL' do
Alien.connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
assert_difference("Alien.count", 2) do
Alien.connection.exec_insert("insert into [test].[aliens] (id, name) VALUES(1, 'Trisolarans'), (2, 'Xenomorph')")
end
end
end

describe 'table names contains spaces' do
it 'records can be created successfully' do
assert_difference("TableWithSpaces.count", 1) do
TableWithSpaces.create!(name: 'Bob')
end
end
end

Expand Down
48 changes: 47 additions & 1 deletion test/cases/schema_test_sqlserver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
assert_equal 1, columns.select { |c| c.is_identity? }.size
end

it "return correct varchar and nvarchar column limit length when table is in non dbo schema" do
it "return correct varchar and nvarchar column limit length when table is in non-dbo schema" do
columns = connection.columns("test.sst_schema_columns")

assert_equal 255, columns.find { |c| c.name == "name" }.limit
Expand All @@ -48,4 +48,50 @@ class SchemaTestSQLServer < ActiveRecord::TestCase
assert_equal 1000, columns.find { |c| c.name == "n_description" }.limit
end
end

describe "parsing table name from raw SQL" do
describe 'SELECT statements' do
it do
assert_equal "[sst_schema_columns]", connection.send(:get_raw_table_name, "SELECT [sst_schema_columns].[id] FROM [sst_schema_columns]")
end

it do
assert_equal "sst_schema_columns", connection.send(:get_raw_table_name, "SELECT [sst_schema_columns].[id] FROM sst_schema_columns")
end

it do
assert_equal "[WITH - SPACES]", connection.send(:get_raw_table_name, "SELECT id FROM [WITH - SPACES]")
end

it do
assert_equal "[WITH - SPACES$DOLLAR]", connection.send(:get_raw_table_name, "SELECT id FROM [WITH - SPACES$DOLLAR]")
end
end

describe 'INSERT statements' do
it do
assert_equal "[dashboards]", connection.send(:get_raw_table_name, "INSERT INTO [dashboards] DEFAULT VALUES; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident")
end

it do
assert_equal "lock_without_defaults", connection.send(:get_raw_table_name, "INSERT INTO lock_without_defaults(title) VALUES('title1')")
end

it do
assert_equal "json_data_type", connection.send(:get_raw_table_name, "insert into json_data_type (payload) VALUES ('null')")
end

it do
assert_equal "[auto_increments]", connection.send(:get_raw_table_name, "INSERT INTO [auto_increments] OUTPUT INSERTED.[id] DEFAULT VALUES")
end

it do
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")
end

it do
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'")
end
end
end
end
5 changes: 5 additions & 0 deletions test/models/sqlserver/table_with_spaces.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class TableWithSpaces < ActiveRecord::Base
self.table_name = "A Table With Spaces"
end
4 changes: 4 additions & 0 deletions test/schema/sqlserver_specific_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@
SELECT GETUTCDATE() utcdate
SQL

create_table 'A Table With Spaces', force: true do |t|
t.string :name
end

# Constraints

create_table(:sst_has_fks, force: true) do |t|
Expand Down

0 comments on commit 682f102

Please sign in to comment.