diff --git a/CHANGELOG.md b/CHANGELOG.md index d7186c7db..3fd510010 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +#### Fixed + +- [#1424](https://github.com/rails-sqlserver/activerecord-sqlserver-adapter/pull/1424) Fix table name parsing for `INSERT INTO WITH ()`. + ## v8.1.4 #### Fixed diff --git a/lib/active_record/connection_adapters/sqlserver/database_statements.rb b/lib/active_record/connection_adapters/sqlserver/database_statements.rb index daf635d63..cdc61d7c7 100644 --- a/lib/active_record/connection_adapters/sqlserver/database_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/database_statements.rb @@ -478,7 +478,7 @@ def query_requires_identity_insert?(sql) id_column = identity_columns(raw_table_name).first if id_column && ( - sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i || + sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+(?:WITH\s*\([^)]*\)\s*)?\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i || sql =~ /^\s*MERGE INTO.+THEN INSERT \([^)]*\b(#{id_column.name})\b,?[^)]*\)/im ) SQLServer::Utils.extract_identifiers(raw_table_name).quoted diff --git a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb index e7261565e..99f576e65 100644 --- a/lib/active_record/connection_adapters/sqlserver/schema_statements.rb +++ b/lib/active_record/connection_adapters/sqlserver/schema_statements.rb @@ -730,6 +730,7 @@ def get_raw_table_name(sql) .split(/OUTPUT INSERTED/i)[0] .split(/(DEFAULT)?\s+VALUES/i)[0] .split(/\bSELECT\b(?![^\[]*\])/i)[0] + .split(/\s+WITH\s*\(/i)[0] # Strip table hints (eg: "INSERT INTO books WITH (TABLOCK) (title)") .match(/\s*([^(]*)/i)[0] elsif s.match?(/^\s*UPDATE\s+.*/i) s.match(/UPDATE\s+([^(\s]+)\s*/i)[1] diff --git a/test/cases/adapter_test_sqlserver.rb b/test/cases/adapter_test_sqlserver.rb index 03b5d9cf2..ba8dc7443 100644 --- a/test/cases/adapter_test_sqlserver.rb +++ b/test/cases/adapter_test_sqlserver.rb @@ -103,6 +103,14 @@ class AdapterTestSQLServer < ActiveRecord::TestCase assert_equal "customers", connection.send(:get_table_name, basic_select_sql) end + it "execute INSERT statements with table hints" do + assert_difference -> { connection.select_value("SELECT COUNT(*) FROM [funny_jokes]") }, 2 do + connection.execute("INSERT INTO [funny_jokes] WITH (TABLOCK) ([name]) VALUES ('Knock knock')") + connection.execute("INSERT INTO [funny_jokes] WITH (TABLOCK) ([id], [name]) VALUES (420, 'Knock knock')") + end + assert_equal "Knock knock", connection.select_value("SELECT [name] FROM [funny_jokes] WHERE [id] = 420") + end + it "test bad connection" do assert_raise ActiveRecord::NoDatabaseError do db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")