Skip to content

Commit b65e45e

Browse files
committed
Use ActiveRecord's attributes_for_update hook to avoid identity inserts.
I found a better way! cc @annaswims
1 parent 77f6e85 commit b65e45e

File tree

5 files changed

+29
-27
lines changed

5 files changed

+29
-27
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,10 @@
4242
* edition
4343
* Removed tests for old issue #164. Handled by core types now.
4444
* The `activity_stats` method. Please put this in a gem if needed.
45-
* We no longger use regular expressions to fix identity inserts. Use ActiveRecord or public ID insert helper.
45+
* We no longer use regular expressions to fix identity inserts. Use ActiveRecord or public ID insert helper.
4646
* All auto reconnect and SQL retry logic. Got too complicated and stood in the way of AR's pool. Speed boost too.
4747
* The adapter will no longer try to remove duplicate order by clauses. Use relation `reorder`, `unscope`, etc.
48+
* We no longer use regular expressions to remove identity columns from updates. Now with `attributes_for_update` AR hook.
4849

4950
#### Fixed
5051

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
require 'active_record/attribute_methods'
2+
3+
module ActiveRecord
4+
module ConnectionAdapters
5+
module SQLServer
6+
module CoreExt
7+
module AttributeMethods
8+
9+
10+
private
11+
12+
def attributes_for_update(attribute_names)
13+
super.reject do |name|
14+
column = self.class.columns_hash[name]
15+
column && column.respond_to?(:is_identity?) && column.is_identity?
16+
end
17+
end
18+
19+
end
20+
end
21+
end
22+
end
23+
end
24+
25+
ActiveRecord::Base.send :include, ActiveRecord::ConnectionAdapters::SQLServer::CoreExt::AttributeMethods

lib/active_record/connection_adapters/sqlserver/database_statements.rb

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,7 @@ def execute(sql, name = nil)
1616
end
1717

1818
def exec_query(sql, name = 'SQL', binds = [], sqlserver_options = {})
19-
if update_sql?(sql)
20-
sql = strip_ident_from_update(sql)
21-
sp_executesql(sql, name, binds)
22-
else
23-
sp_executesql(sql, name, binds)
24-
end
19+
sp_executesql(sql, name, binds)
2520
end
2621

2722
def exec_insert(sql, name, binds, _pk = nil, _sequence_name = nil)

lib/active_record/connection_adapters/sqlserver/schema_statements.rb

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -411,26 +411,6 @@ def insert_sql?(sql)
411411
!(sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
412412
end
413413

414-
def strip_ident_from_update(sql)
415-
# We can't update Identiy columns in sqlserver. So, strip out the id from the update.
416-
# There has to be a better way to handle this, but this'll do for now.
417-
table_name = get_table_name(sql)
418-
id_column = identity_column(table_name)
419-
if id_column
420-
regex_col_name = Regexp.quote(quote_column_name(id_column.name))
421-
if sql =~ /, #{regex_col_name} = @?[0-9]*/
422-
sql = sql.gsub(/, #{regex_col_name} = @?[0-9]*/, '')
423-
elsif sql =~ /\s#{regex_col_name} = @?[0-9]*,/
424-
sql = sql.gsub(/\s#{regex_col_name} = @?[0-9]*,/, '')
425-
end
426-
end
427-
sql
428-
end
429-
430-
def update_sql?(sql)
431-
!(sql =~ /^\s*(UPDATE|EXEC sp_executesql N'UPDATE)/i).nil?
432-
end
433-
434414
def identity_column(table_name)
435415
schema_cache.columns(table_name).find(&:is_identity?)
436416
end

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
require 'active_record/connection_adapters/sqlserver/core_ext/explain'
77
require 'active_record/connection_adapters/sqlserver/core_ext/explain_subscriber'
88
require 'active_record/connection_adapters/sqlserver/core_ext/relation'
9+
require 'active_record/connection_adapters/sqlserver/core_ext/attribute_methods'
910
require 'active_record/connection_adapters/sqlserver/version'
1011
require 'active_record/connection_adapters/sqlserver/type'
1112
require 'active_record/connection_adapters/sqlserver/database_limits'

0 commit comments

Comments
 (0)