composite_primary_keys 12.0.5 → 13.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/History.rdoc +883 -862
- data/README.rdoc +181 -180
- data/lib/composite_primary_keys.rb +119 -118
- data/lib/composite_primary_keys/active_model/attribute_assignment.rb +19 -19
- data/lib/composite_primary_keys/associations/association_scope.rb +66 -68
- data/lib/composite_primary_keys/associations/join_dependency.rb +118 -103
- data/lib/composite_primary_keys/attribute_methods.rb +21 -9
- data/lib/composite_primary_keys/attribute_methods/primary_key.rb +0 -2
- data/lib/composite_primary_keys/attribute_methods/read.rb +30 -30
- data/lib/composite_primary_keys/attribute_methods/write.rb +35 -35
- data/lib/composite_primary_keys/base.rb +141 -141
- data/lib/composite_primary_keys/connection_adapters/abstract/database_statements.rb +37 -22
- data/lib/composite_primary_keys/connection_adapters/sqlserver/database_statements.rb +44 -44
- data/lib/composite_primary_keys/core.rb +48 -48
- data/lib/composite_primary_keys/nested_attributes.rb +1 -1
- data/lib/composite_primary_keys/persistence.rb +82 -81
- data/lib/composite_primary_keys/reflection.rb +91 -29
- data/lib/composite_primary_keys/relation.rb +197 -193
- data/lib/composite_primary_keys/relation/batches.rb +16 -8
- data/lib/composite_primary_keys/relation/calculations.rb +104 -81
- data/lib/composite_primary_keys/relation/finder_methods.rb +235 -235
- data/lib/composite_primary_keys/relation/predicate_builder/association_query_value.rb +39 -20
- data/lib/composite_primary_keys/relation/query_methods.rb +42 -42
- data/lib/composite_primary_keys/relation/where_clause.rb +18 -23
- data/lib/composite_primary_keys/table_metadata.rb +11 -0
- data/lib/composite_primary_keys/version.rb +8 -8
- data/test/abstract_unit.rb +114 -114
- data/test/connections/databases.ci.yml +22 -19
- data/test/fixtures/db_definitions/db2-create-tables.sql +112 -112
- data/test/fixtures/db_definitions/db2-drop-tables.sql +16 -16
- data/test/fixtures/db_definitions/mysql.sql +180 -180
- data/test/fixtures/db_definitions/oracle.drop.sql +41 -41
- data/test/fixtures/db_definitions/oracle.sql +199 -199
- data/test/fixtures/db_definitions/postgresql.sql +182 -182
- data/test/fixtures/db_definitions/sqlite.sql +169 -169
- data/test/fixtures/db_definitions/sqlserver.sql +176 -176
- data/test/fixtures/department.rb +16 -16
- data/test/fixtures/departments.yml +19 -15
- data/test/fixtures/employees.yml +33 -28
- data/test/fixtures/restaurants_suburbs.yml +10 -10
- data/test/fixtures/streets.yml +16 -16
- data/test/fixtures/suburbs.yml +14 -14
- data/test/fixtures/user.rb +11 -11
- data/test/test_associations.rb +364 -358
- data/test/test_attributes.rb +75 -60
- data/test/test_calculations.rb +49 -42
- data/test/test_create.rb +218 -180
- data/test/test_delete.rb +182 -179
- data/test/test_exists.rb +39 -39
- data/test/test_find.rb +170 -157
- data/test/test_ids.rb +112 -112
- data/test/test_nested_attributes.rb +67 -67
- data/test/test_update.rb +96 -96
- metadata +5 -5
- data/lib/composite_primary_keys/connection_adapters/mysql/database_statements.rb +0 -24
@@ -1,35 +1,35 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module AttributeMethods
|
3
|
-
module Write
|
4
|
-
def write_attribute(attr_name, value)
|
5
|
-
# CPK
|
6
|
-
#name = attr_name.to_s
|
7
|
-
name = attr_name
|
8
|
-
if self.class.attribute_alias?(name)
|
9
|
-
name = self.class.attribute_alias(name)
|
10
|
-
end
|
11
|
-
|
12
|
-
primary_key = self.class.primary_key
|
13
|
-
# CPK
|
14
|
-
# name = primary_key if name == "id" && primary_key
|
15
|
-
name = primary_key if name == "id" && primary_key && !composite?
|
16
|
-
|
17
|
-
_write_attribute(name, value)
|
18
|
-
end
|
19
|
-
|
20
|
-
def _write_attribute(attr_name, value) # :nodoc:
|
21
|
-
# CPK
|
22
|
-
if attr_name.kind_of?(Array)
|
23
|
-
attr_name.each_with_index do |attr_child_name, i|
|
24
|
-
child_value = value ? value[i] : value
|
25
|
-
@attributes.write_from_user(attr_child_name.to_s, child_value)
|
26
|
-
end
|
27
|
-
else
|
28
|
-
@attributes.write_from_user(attr_name.to_s, value)
|
29
|
-
end
|
30
|
-
|
31
|
-
value
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module AttributeMethods
|
3
|
+
module Write
|
4
|
+
def write_attribute(attr_name, value)
|
5
|
+
# CPK
|
6
|
+
#name = attr_name.to_s
|
7
|
+
name = attr_name
|
8
|
+
if self.class.attribute_alias?(name)
|
9
|
+
name = self.class.attribute_alias(name)
|
10
|
+
end
|
11
|
+
|
12
|
+
primary_key = self.class.primary_key
|
13
|
+
# CPK
|
14
|
+
# name = primary_key if name == "id" && primary_key
|
15
|
+
name = primary_key if name == "id" && primary_key && !composite?
|
16
|
+
|
17
|
+
_write_attribute(name, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
def _write_attribute(attr_name, value) # :nodoc:
|
21
|
+
# CPK
|
22
|
+
if attr_name.kind_of?(Array)
|
23
|
+
attr_name.each_with_index do |attr_child_name, i|
|
24
|
+
child_value = value ? value[i] : value
|
25
|
+
@attributes.write_from_user(attr_child_name.to_s, child_value)
|
26
|
+
end
|
27
|
+
else
|
28
|
+
@attributes.write_from_user(attr_name.to_s, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
value
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,141 +1,141 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
class CompositeKeyError < StandardError #:nodoc:
|
3
|
-
end
|
4
|
-
|
5
|
-
class Base
|
6
|
-
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
-
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
-
|
9
|
-
class << self
|
10
|
-
alias_method :primary_key_without_composite_key_support=, :primary_key=
|
11
|
-
def primary_key=(keys)
|
12
|
-
unless keys.kind_of?(Array)
|
13
|
-
self.primary_key_without_composite_key_support = keys
|
14
|
-
return
|
15
|
-
end
|
16
|
-
|
17
|
-
@primary_keys = keys.map { |k| k.to_s }.to_composite_keys
|
18
|
-
|
19
|
-
class_eval <<-EOV
|
20
|
-
extend CompositeClassMethods
|
21
|
-
include CompositeInstanceMethods
|
22
|
-
EOV
|
23
|
-
end
|
24
|
-
alias_method :primary_keys=, :primary_key=
|
25
|
-
|
26
|
-
def set_primary_keys(*keys)
|
27
|
-
ActiveSupport::Deprecation.warn(
|
28
|
-
"Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
|
29
|
-
)
|
30
|
-
|
31
|
-
keys = keys.first if keys.first.is_a?(Array)
|
32
|
-
if keys.length == 1
|
33
|
-
self.primary_key = keys.first
|
34
|
-
else
|
35
|
-
self.primary_keys = keys
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def composite?
|
40
|
-
false
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def composite?
|
45
|
-
self.class.composite?
|
46
|
-
end
|
47
|
-
|
48
|
-
module CompositeClassMethods
|
49
|
-
def primary_keys
|
50
|
-
@primary_keys = reset_primary_keys unless defined? @primary_keys
|
51
|
-
@primary_keys
|
52
|
-
end
|
53
|
-
|
54
|
-
# Don't like this method name, but its modeled after how AR does it
|
55
|
-
def reset_primary_keys #:nodoc:
|
56
|
-
if self == base_class
|
57
|
-
# CPK
|
58
|
-
self.primary_keys = get_primary_key(base_class.name)
|
59
|
-
else
|
60
|
-
self.primary_keys = base_class.primary_keys
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
def primary_key
|
65
|
-
primary_keys
|
66
|
-
end
|
67
|
-
|
68
|
-
def primary_key=(keys)
|
69
|
-
self.primary_keys = keys
|
70
|
-
end
|
71
|
-
|
72
|
-
def composite?
|
73
|
-
true
|
74
|
-
end
|
75
|
-
|
76
|
-
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
77
|
-
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
78
|
-
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
79
|
-
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
module CompositeInstanceMethods
|
84
|
-
# A model instance's primary keys is always available as model.ids
|
85
|
-
# whether you name it the default 'id' or set it to something else.
|
86
|
-
def id
|
87
|
-
attr_names = self.class.primary_keys
|
88
|
-
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
89
|
-
end
|
90
|
-
alias_method :ids, :id
|
91
|
-
|
92
|
-
# This is overridden purely for json serialization support. If the model is composite
|
93
|
-
# and one of the keys is id, then we don't want to call the id method, instead we want
|
94
|
-
# to get the id attribute value
|
95
|
-
def read_attribute_for_serialization(attribute)
|
96
|
-
if self.composite? && attribute == 'id'
|
97
|
-
read_attribute(attribute)
|
98
|
-
else
|
99
|
-
send(attribute)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def ids_hash
|
104
|
-
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
105
|
-
hash[key] = value
|
106
|
-
hash
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def id_before_type_cast
|
111
|
-
self.class.primary_keys.map do |key|
|
112
|
-
self.read_attribute_before_type_cast(key)
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Sets the primary ID.
|
117
|
-
def id=(ids)
|
118
|
-
ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
|
119
|
-
unless ids.length == self.class.primary_keys.length
|
120
|
-
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
121
|
-
end
|
122
|
-
[self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
123
|
-
id
|
124
|
-
end
|
125
|
-
|
126
|
-
def can_change_primary_key_values?
|
127
|
-
false
|
128
|
-
end
|
129
|
-
|
130
|
-
# Returns this record's primary keys values in an Array
|
131
|
-
# if any value is available
|
132
|
-
def to_key
|
133
|
-
ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
|
134
|
-
end
|
135
|
-
|
136
|
-
def to_param
|
137
|
-
persisted? ? to_key.to_composite_keys.to_s : nil
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
class CompositeKeyError < StandardError #:nodoc:
|
3
|
+
end
|
4
|
+
|
5
|
+
class Base
|
6
|
+
INVALID_FOR_COMPOSITE_KEYS = 'Not appropriate for composite primary keys'
|
7
|
+
NOT_IMPLEMENTED_YET = 'Not implemented for composite primary keys yet'
|
8
|
+
|
9
|
+
class << self
|
10
|
+
alias_method :primary_key_without_composite_key_support=, :primary_key=
|
11
|
+
def primary_key=(keys)
|
12
|
+
unless keys.kind_of?(Array)
|
13
|
+
self.primary_key_without_composite_key_support = keys
|
14
|
+
return
|
15
|
+
end
|
16
|
+
|
17
|
+
@primary_keys = keys.map { |k| k.to_s }.to_composite_keys
|
18
|
+
|
19
|
+
class_eval <<-EOV
|
20
|
+
extend CompositeClassMethods
|
21
|
+
include CompositeInstanceMethods
|
22
|
+
EOV
|
23
|
+
end
|
24
|
+
alias_method :primary_keys=, :primary_key=
|
25
|
+
|
26
|
+
def set_primary_keys(*keys)
|
27
|
+
ActiveSupport::Deprecation.warn(
|
28
|
+
"Calling set_primary_keys is deprecated. Please use `self.primary_keys = keys` instead."
|
29
|
+
)
|
30
|
+
|
31
|
+
keys = keys.first if keys.first.is_a?(Array)
|
32
|
+
if keys.length == 1
|
33
|
+
self.primary_key = keys.first
|
34
|
+
else
|
35
|
+
self.primary_keys = keys
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def composite?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def composite?
|
45
|
+
self.class.composite?
|
46
|
+
end
|
47
|
+
|
48
|
+
module CompositeClassMethods
|
49
|
+
def primary_keys
|
50
|
+
@primary_keys = reset_primary_keys unless defined? @primary_keys
|
51
|
+
@primary_keys
|
52
|
+
end
|
53
|
+
|
54
|
+
# Don't like this method name, but its modeled after how AR does it
|
55
|
+
def reset_primary_keys #:nodoc:
|
56
|
+
if self == base_class
|
57
|
+
# CPK
|
58
|
+
self.primary_keys = get_primary_key(base_class.name)
|
59
|
+
else
|
60
|
+
self.primary_keys = base_class.primary_keys
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def primary_key
|
65
|
+
primary_keys
|
66
|
+
end
|
67
|
+
|
68
|
+
def primary_key=(keys)
|
69
|
+
self.primary_keys = keys
|
70
|
+
end
|
71
|
+
|
72
|
+
def composite?
|
73
|
+
true
|
74
|
+
end
|
75
|
+
|
76
|
+
#ids_to_s([[1,2],[7,3]]) -> "(1,2),(7,3)"
|
77
|
+
#ids_to_s([[1,2],[7,3]], ',', ';') -> "1,2;7,3"
|
78
|
+
def ids_to_s(many_ids, id_sep = CompositePrimaryKeys::ID_SEP, list_sep = ',', left_bracket = '(', right_bracket = ')')
|
79
|
+
many_ids.map {|ids| "#{left_bracket}#{CompositePrimaryKeys::CompositeKeys.new(ids)}#{right_bracket}"}.join(list_sep)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module CompositeInstanceMethods
|
84
|
+
# A model instance's primary keys is always available as model.ids
|
85
|
+
# whether you name it the default 'id' or set it to something else.
|
86
|
+
def id
|
87
|
+
attr_names = self.class.primary_keys
|
88
|
+
::CompositePrimaryKeys::CompositeKeys.new(attr_names.map { |attr_name| read_attribute(attr_name) })
|
89
|
+
end
|
90
|
+
alias_method :ids, :id
|
91
|
+
|
92
|
+
# This is overridden purely for json serialization support. If the model is composite
|
93
|
+
# and one of the keys is id, then we don't want to call the id method, instead we want
|
94
|
+
# to get the id attribute value
|
95
|
+
def read_attribute_for_serialization(attribute)
|
96
|
+
if self.composite? && attribute == 'id'
|
97
|
+
read_attribute(attribute)
|
98
|
+
else
|
99
|
+
send(attribute)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def ids_hash
|
104
|
+
self.class.primary_key.zip(ids).inject(Hash.new) do |hash, (key, value)|
|
105
|
+
hash[key] = value
|
106
|
+
hash
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def id_before_type_cast
|
111
|
+
self.class.primary_keys.map do |key|
|
112
|
+
self.read_attribute_before_type_cast(key)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Sets the primary ID.
|
117
|
+
def id=(ids)
|
118
|
+
ids = CompositePrimaryKeys::CompositeKeys.parse(ids)
|
119
|
+
unless ids.length == self.class.primary_keys.length
|
120
|
+
raise "#{self.class}.id= requires #{self.class.primary_keys.length} ids"
|
121
|
+
end
|
122
|
+
[self.class.primary_keys, ids].transpose.each {|key, an_id| write_attribute(key , an_id)}
|
123
|
+
id
|
124
|
+
end
|
125
|
+
|
126
|
+
def can_change_primary_key_values?
|
127
|
+
false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Returns this record's primary keys values in an Array
|
131
|
+
# if any value is available
|
132
|
+
def to_key
|
133
|
+
ids.to_a if !ids.compact.empty? # XXX Maybe use primary_keys with send instead of ids
|
134
|
+
end
|
135
|
+
|
136
|
+
def to_param
|
137
|
+
persisted? ? to_key.to_composite_keys.to_s : nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -1,22 +1,37 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
module DatabaseStatements
|
4
|
-
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
5
|
-
sql, binds = to_sql_and_binds(arel, binds)
|
6
|
-
value = exec_insert(sql, name, binds, pk, sequence_name)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module DatabaseStatements
|
4
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
5
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
6
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
7
|
+
|
8
|
+
return id_value if id_value
|
9
|
+
|
10
|
+
if pk.is_a?(Array) && !value.empty?
|
11
|
+
# This is a CPK model and the query result is not empty. Thus we can figure out the new ids for each
|
12
|
+
# auto incremented field
|
13
|
+
pk.map {|key| value.first[key]}
|
14
|
+
elsif pk.is_a?(Array)
|
15
|
+
# This is CPK, but we don't know what autoincremented fields were updated.
|
16
|
+
result = Array.new(pk.size)
|
17
|
+
|
18
|
+
# Is there an autoincrementing field?
|
19
|
+
auto_key = pk.find do |key|
|
20
|
+
attribute = arel.ast.relation[key]
|
21
|
+
column = column_for_attribute(attribute)
|
22
|
+
if column.respond_to?(:auto_increment?)
|
23
|
+
column.auto_increment?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if auto_key
|
28
|
+
result[pk.index(auto_key)] = last_inserted_id(value)
|
29
|
+
end
|
30
|
+
result
|
31
|
+
else
|
32
|
+
last_inserted_id(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,44 +1,44 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
module ConnectionAdapters
|
3
|
-
module SQLServer
|
4
|
-
module DatabaseStatements
|
5
|
-
def sql_for_insert(sql, pk, binds)
|
6
|
-
if pk.nil?
|
7
|
-
table_name = query_requires_identity_insert?(sql)
|
8
|
-
pk = primary_key(table_name)
|
9
|
-
end
|
10
|
-
|
11
|
-
sql = if pk && use_output_inserted? && !database_prefix_remote_server?
|
12
|
-
# CPK
|
13
|
-
#quoted_pk = SQLServer::Utils.extract_identifiers(pk).quoted
|
14
|
-
quoted_pk = Array(pk).map {|subkey| SQLServer::Utils.extract_identifiers(subkey).quoted}
|
15
|
-
|
16
|
-
table_name ||= get_table_name(sql)
|
17
|
-
exclude_output_inserted = exclude_output_inserted_table_name?(table_name, sql)
|
18
|
-
if exclude_output_inserted
|
19
|
-
id_sql_type = exclude_output_inserted.is_a?(TrueClass) ? "bigint" : exclude_output_inserted
|
20
|
-
# CPK
|
21
|
-
# <<~SQL.squish
|
22
|
-
# DECLARE @ssaIdInsertTable table (#{quoted_pk} #{id_sql_type});
|
23
|
-
# #{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk} INTO @ssaIdInsertTable"}
|
24
|
-
# SELECT CAST(#{quoted_pk.join(',')} AS #{id_sql_type}) FROM @ssaIdInsertTable
|
25
|
-
# SQL
|
26
|
-
<<~SQL.squish
|
27
|
-
DECLARE @ssaIdInsertTable table (#{quoted_pk.map {|subkey| "#{subkey} #{id_sql_type}"}.join(", ")});
|
28
|
-
#{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk.join(', INSERTED.')} INTO @ssaIdInsertTable"}
|
29
|
-
SELECT #{quoted_pk.map {|subkey| "CAST(#{subkey} AS #{id_sql_type}) #{subkey}"}.join(", ")} FROM @ssaIdInsertTable
|
30
|
-
SQL
|
31
|
-
else
|
32
|
-
# CPK
|
33
|
-
# sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk}"
|
34
|
-
sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk.join(', INSERTED.')}"
|
35
|
-
end
|
36
|
-
else
|
37
|
-
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
38
|
-
end
|
39
|
-
super
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
1
|
+
module ActiveRecord
|
2
|
+
module ConnectionAdapters
|
3
|
+
module SQLServer
|
4
|
+
module DatabaseStatements
|
5
|
+
def sql_for_insert(sql, pk, binds)
|
6
|
+
if pk.nil?
|
7
|
+
table_name = query_requires_identity_insert?(sql)
|
8
|
+
pk = primary_key(table_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
sql = if pk && use_output_inserted? && !database_prefix_remote_server?
|
12
|
+
# CPK
|
13
|
+
#quoted_pk = SQLServer::Utils.extract_identifiers(pk).quoted
|
14
|
+
quoted_pk = Array(pk).map {|subkey| SQLServer::Utils.extract_identifiers(subkey).quoted}
|
15
|
+
|
16
|
+
table_name ||= get_table_name(sql)
|
17
|
+
exclude_output_inserted = exclude_output_inserted_table_name?(table_name, sql)
|
18
|
+
if exclude_output_inserted
|
19
|
+
id_sql_type = exclude_output_inserted.is_a?(TrueClass) ? "bigint" : exclude_output_inserted
|
20
|
+
# CPK
|
21
|
+
# <<~SQL.squish
|
22
|
+
# DECLARE @ssaIdInsertTable table (#{quoted_pk} #{id_sql_type});
|
23
|
+
# #{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk} INTO @ssaIdInsertTable"}
|
24
|
+
# SELECT CAST(#{quoted_pk.join(',')} AS #{id_sql_type}) FROM @ssaIdInsertTable
|
25
|
+
# SQL
|
26
|
+
<<~SQL.squish
|
27
|
+
DECLARE @ssaIdInsertTable table (#{quoted_pk.map {|subkey| "#{subkey} #{id_sql_type}"}.join(", ")});
|
28
|
+
#{sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk.join(', INSERTED.')} INTO @ssaIdInsertTable"}
|
29
|
+
SELECT #{quoted_pk.map {|subkey| "CAST(#{subkey} AS #{id_sql_type}) #{subkey}"}.join(", ")} FROM @ssaIdInsertTable
|
30
|
+
SQL
|
31
|
+
else
|
32
|
+
# CPK
|
33
|
+
# sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk}"
|
34
|
+
sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk.join(', INSERTED.')}"
|
35
|
+
end
|
36
|
+
else
|
37
|
+
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
|
38
|
+
end
|
39
|
+
super
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|