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")