31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
# File 'lib/activerecord/insert_many.rb', line 31
def insert_many_sql(fixtures, table_name, options={})
returning = options[:returning]
columns = schema_cache.columns_hash(table_name)
sample = fixtures.first
key_list = sample.map { |name, _value| quote_column_name(name) }
returning = returning.map { |name| quote_column_name(name) } if returning
value_lists = fixtures.map do |fixture|
binds = fixture.map do |name, value|
name = name.to_s
if column = columns[name]
type = lookup_cast_type_from_column(column)
Relation::QueryAttribute.new(name, value, type)
else
raise Fixture::FixtureError, %(table "#{table_name}" has no column named #{name.inspect}.)
end
end
binds.map(&:value_for_database).map do |value|
begin
quote(value)
rescue TypeError
quote(YAML.dump(value))
end
end
end
sql = "INSERT INTO #{quote_table_name(table_name)} (#{key_list.join(",")}) VALUES #{value_lists.map { |value| "(#{value.join(",")})" }.join(", ")}"
if conflict = options[:on_conflict]
raise ArgumentError, "To use the :on_conflict option, you must be using Postgres >= 9.5" unless supports_on_conflict?
conflict_columns = Array.wrap(conflict.fetch(:column, schema_cache.primary_keys(table_name)))
raise ArgumentError, "To use the :on_conflict option, you must specify :column" unless conflict_columns.any?
conflict_do = conflict.fetch(:do)
raise ArgumentError, "#{conflict_do.inspect} is an unknown value for conflict[:do]; must be :nothing or :update" unless [:nothing, :update].member?(conflict_do)
conflict_columns = conflict_columns.map(&method(:quote_column_name))
sql << " ON CONFLICT(#{conflict_columns.join(",")})"
sql << " WHERE #{conflict[:where]}" if conflict[:where]
if conflict_do == :nothing
sql << " DO NOTHING"
else
primary_keys = Array(schema_cache.primary_keys(table_name)).map(&method(:quote_column_name))
updatable_keys = key_list - conflict_columns - primary_keys
sql << " DO UPDATE SET #{updatable_keys.map { |key| "#{key} = excluded.#{key}" }.join(", ")}"
end
end
sql << " RETURNING #{returning.join(",")}" if returning
sql
end
|