Skip to content

Commit c497da9

Browse files
committed
Fix multiple nil identity columns for merge insert
1 parent 6feabc2 commit c497da9

File tree

1 file changed

+30
-1
lines changed

1 file changed

+30
-1
lines changed

lib/active_record/connection_adapters/sqlserver/database_statements.rb

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def build_sql_for_merge_insert(insert:, insert_all:, columns_with_uniqueness_con
177177
SELECT *
178178
FROM (
179179
SELECT #{insert.send(:columns_list)}, #{partition_by_columns_with_uniqueness_constraints(columns_with_uniqueness_constraints:)}
180-
FROM (#{insert.values_list})
180+
FROM (#{merge_insert_values_list(insert:, insert_all:)})
181181
AS t1 (#{insert.send(:columns_list)})
182182
) AS ranked_source
183183
WHERE #{is_first_record_across_all_uniqueness_constraints(columns_with_uniqueness_constraints:)}
@@ -206,6 +206,35 @@ def build_sql_for_merge_insert(insert:, insert_all:, columns_with_uniqueness_con
206206
sql
207207
end
208208

209+
# For `nil` identity columns we need to ensure that the values do not match so that they are all inserted.
210+
# Method is a combination of `ActiveRecord::InsertAll#values_list` and `ActiveRecord::ConnectionAdapters::SQLServer::DatabaseStatements#default_insert_value`.
211+
def merge_insert_values_list(insert:, insert_all:)
212+
connection = insert.send(:connection)
213+
identity_index = 0
214+
215+
types = insert.send(:extract_types_from_columns_on, insert.model.table_name, keys: insert.keys_including_timestamps)
216+
217+
values_list = insert_all.map_key_with_value do |key, value|
218+
if Arel::Nodes::SqlLiteral === value
219+
value
220+
elsif insert.primary_keys.include?(key) && value.nil?
221+
column = insert.send(:column_from_key, key)
222+
223+
if column.is_identity?
224+
identity_index += 1
225+
table_name = quote(quote_table_name(column.table_name))
226+
Arel.sql("IDENT_CURRENT(#{table_name}) + IDENT_INCR(#{table_name}) * #{identity_index}")
227+
else
228+
connection.default_insert_value(column)
229+
end
230+
else
231+
ActiveModel::Type::SerializeCastValue.serialize(type = types[key], type.cast(value))
232+
end
233+
end
234+
235+
connection.visitor.compile(Arel::Nodes::ValuesList.new(values_list))
236+
end
237+
209238
# === SQLServer Specific ======================================== #
210239

211240
def execute_procedure(proc_name, *variables)

0 commit comments

Comments
 (0)