asa-2000 1.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.
@@ -0,0 +1,36 @@
1
+ module ActiveRecord
2
+
3
+ class LostConnection < WrappedDatabaseException
4
+ end
5
+
6
+ class DeadlockVictim < WrappedDatabaseException
7
+ end
8
+
9
+ module ConnectionAdapters
10
+ module Sqlserver
11
+ module Errors
12
+
13
+ LOST_CONNECTION_EXCEPTIONS = {
14
+ :dblib => ['TinyTds::Error'],
15
+ :odbc => ['ODBC::Error']
16
+ }.freeze
17
+
18
+ LOST_CONNECTION_MESSAGES = {
19
+ :dblib => [/closed connection/, /dead or not enabled/, /server failed/i],
20
+ :odbc => [/link failure/, /server failed/, /connection was already closed/, /invalid handle/i]
21
+ }.freeze
22
+
23
+
24
+ def lost_connection_exceptions
25
+ exceptions = LOST_CONNECTION_EXCEPTIONS[@connection_options[:mode]]
26
+ @lost_connection_exceptions ||= exceptions ? exceptions.map{ |e| e.constantize rescue nil }.compact : []
27
+ end
28
+
29
+ def lost_connection_messages
30
+ LOST_CONNECTION_MESSAGES[@connection_options[:mode]]
31
+ end
32
+
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,104 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module Quoting
5
+
6
+ QUOTED_TRUE, QUOTED_FALSE = '1', '0'
7
+ QUOTED_STRING_PREFIX = 'N'
8
+
9
+ def quote(value, column = nil)
10
+ case value
11
+ when String, ActiveSupport::Multibyte::Chars
12
+ if column && column.type == :integer && value.blank?
13
+ nil
14
+ elsif column && column.type == :binary
15
+ column.class.string_to_binary(value)
16
+ elsif value.is_utf8? || (column && column.type == :string)
17
+ "#{quoted_string_prefix}'#{quote_string(value)}'"
18
+ else
19
+ super
20
+ end
21
+ when Date, Time
22
+ if column && column.sql_type == 'datetime'
23
+ "'#{quoted_datetime(value)}'"
24
+ elsif column && (column.sql_type == 'datetimeoffset' || column.sql_type == 'time')
25
+ "'#{quoted_full_iso8601(value)}'"
26
+ else
27
+ super
28
+ end
29
+ when nil
30
+ column.respond_to?(:sql_type) && column.sql_type == 'timestamp' ? 'DEFAULT' : super
31
+ else
32
+ super
33
+ end
34
+ end
35
+
36
+ def quoted_string_prefix
37
+ QUOTED_STRING_PREFIX
38
+ end
39
+
40
+ def quote_string(string)
41
+ string.to_s.gsub(/\'/, "''")
42
+ end
43
+
44
+ def quote_column_name(name)
45
+ schema_cache.quote_name(name)
46
+ end
47
+
48
+ def quote_table_name(name)
49
+ quote_column_name(name)
50
+ end
51
+
52
+ def substitute_at(column, index)
53
+ if column.respond_to?(:sql_type) && column.sql_type == 'timestamp'
54
+ nil
55
+ else
56
+ Arel.sql "@#{index}"
57
+ end
58
+ end
59
+
60
+ def quoted_true
61
+ QUOTED_TRUE
62
+ end
63
+
64
+ def quoted_false
65
+ QUOTED_FALSE
66
+ end
67
+
68
+ def quoted_datetime(value)
69
+ if value.acts_like?(:time)
70
+ value.is_a?(Date) ? quoted_value_acts_like_time_filter(value).to_time.xmlschema.to(18) : quoted_value_acts_like_time_filter(value).iso8601(3).to(22)
71
+ else
72
+ quoted_date(value)
73
+ end
74
+ end
75
+
76
+ def quoted_full_iso8601(value)
77
+ if value.acts_like?(:time)
78
+ value.is_a?(Date) ? quoted_value_acts_like_time_filter(value).to_time.xmlschema.to(18) : quoted_value_acts_like_time_filter(value).iso8601(7).to(22)
79
+ else
80
+ quoted_date(value)
81
+ end
82
+ end
83
+
84
+ def quoted_date(value)
85
+ if value.acts_like?(:time) && value.respond_to?(:usec)
86
+ "#{super}.#{sprintf("%03d",value.usec/1000)}"
87
+ elsif value.acts_like?(:date)
88
+ value.to_s(:_sqlserver_dateformat)
89
+ else
90
+ super
91
+ end
92
+ end
93
+
94
+ protected
95
+
96
+ def quoted_value_acts_like_time_filter(value)
97
+ zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
98
+ value.respond_to?(zone_conversion_method) ? value.send(zone_conversion_method) : value
99
+ end
100
+
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,85 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ class SchemaCache < ActiveRecord::ConnectionAdapters::SchemaCache
5
+
6
+ attr_reader :view_information
7
+
8
+ def initialize(conn)
9
+ super
10
+ @table_names = nil
11
+ @view_names = nil
12
+ @view_information = {}
13
+ @quoted_names = {}
14
+ end
15
+
16
+ # Superclass Overrides
17
+
18
+ def table_exists?(table_name)
19
+ return false if table_name.blank?
20
+ key = table_name_key(table_name)
21
+ return @tables[key] if @tables.key? key
22
+ @tables[key] = connection.table_exists?(table_name)
23
+ end
24
+
25
+ def clear!
26
+ super
27
+ @table_names = nil
28
+ @view_names = nil
29
+ @view_information.clear
30
+ @quoted_names.clear
31
+ end
32
+
33
+ def clear_table_cache!(table_name)
34
+ key = table_name_key(table_name)
35
+ super(key)
36
+ super(table_name)
37
+ # SQL Server Specific
38
+ if @table_names
39
+ @table_names.delete key
40
+ @table_names.delete table_name
41
+ end
42
+ if @view_names
43
+ @view_names.delete key
44
+ @view_names.delete table_name
45
+ end
46
+ @view_information.delete key
47
+ end
48
+
49
+ # SQL Server Specific
50
+
51
+ def table_names
52
+ @table_names ||= connection.tables
53
+ end
54
+
55
+ def view_names
56
+ @view_names ||= connection.views
57
+ end
58
+
59
+ def view_exists?(table_name)
60
+ table_exists?(table_name)
61
+ end
62
+
63
+ def view_information(table_name)
64
+ key = table_name_key(table_name)
65
+ return @view_information[key] if @view_information.key? key
66
+ @view_information[key] = connection.send(:view_information, table_name)
67
+ end
68
+
69
+ def quote_name(name)
70
+ return @quoted_names[name] if @quoted_names.key? name
71
+ @quoted_names[name] = name.to_s.split('.').map{ |n| n =~ /^\[.*\]$/ ? n : "[#{n.to_s.gsub(']', ']]')}]" }.join('.')
72
+ end
73
+
74
+
75
+ private
76
+
77
+ def table_name_key(table_name)
78
+ Utils.unqualify_table_name(table_name)
79
+ end
80
+
81
+ end
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,364 @@
1
+ module ActiveRecord
2
+ module ConnectionAdapters
3
+ module Sqlserver
4
+ module SchemaStatements
5
+
6
+ def native_database_types
7
+ @native_database_types ||= initialize_native_database_types.freeze
8
+ end
9
+
10
+ def tables(table_type = 'BASE TABLE')
11
+ info_schema_query do
12
+ select_values "SELECT #{lowercase_schema_reflection_sql('TABLE_NAME')} FROM INFORMATION_SCHEMA.TABLES #{"WHERE TABLE_TYPE = '#{table_type}'" if table_type} ORDER BY TABLE_NAME"
13
+ end
14
+ end
15
+
16
+ def table_exists?(table_name)
17
+ return false if table_name.blank?
18
+ unquoted_table_name = Utils.unqualify_table_name(table_name)
19
+ super || tables.include?(unquoted_table_name) || views.include?(unquoted_table_name)
20
+ end
21
+
22
+ def indexes(table_name, name = nil)
23
+ data = select("EXEC sp_helpindex #{quote(table_name)}",name) rescue []
24
+ data.inject([]) do |indexes,index|
25
+ index = index.with_indifferent_access
26
+ if index[:index_description] =~ /primary key/
27
+ indexes
28
+ else
29
+ name = index[:index_name]
30
+ unique = index[:index_description] =~ /unique/
31
+ columns = index[:index_keys].split(',').map do |column|
32
+ column.strip!
33
+ column.gsub! '(-)', '' if column.ends_with?('(-)')
34
+ column
35
+ end
36
+ indexes << IndexDefinition.new(table_name, name, unique, columns)
37
+ end
38
+ end
39
+ end
40
+
41
+ def columns(table_name, name = nil)
42
+ return [] if table_name.blank?
43
+ column_definitions(table_name).collect do |ci|
44
+ sqlserver_options = ci.except(:name,:default_value,:type,:null).merge(:database_year=>database_year)
45
+ SQLServerColumn.new ci[:name], ci[:default_value], ci[:type], ci[:null], sqlserver_options
46
+ end
47
+ end
48
+
49
+ def rename_table(table_name, new_name)
50
+ do_execute "EXEC sp_rename '#{table_name}', '#{new_name}'"
51
+ end
52
+
53
+ def remove_column(table_name, *column_names)
54
+ raise ArgumentError.new("You must specify at least one column name. Example: remove_column(:people, :first_name)") if column_names.empty?
55
+ column_names.flatten.each do |column_name|
56
+ remove_check_constraints(table_name, column_name)
57
+ remove_default_constraint(table_name, column_name)
58
+ remove_indexes(table_name, column_name)
59
+ do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP COLUMN #{quote_column_name(column_name)}"
60
+ end
61
+ end
62
+
63
+ def change_column(table_name, column_name, type, options = {})
64
+ sql_commands = []
65
+ column_object = schema_cache.columns[table_name].detect { |c| c.name.to_s == column_name.to_s }
66
+ change_column_sql = "ALTER TABLE #{quote_table_name(table_name)} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
67
+ change_column_sql << " NOT NULL" if options[:null] == false
68
+ sql_commands << change_column_sql
69
+ if options_include_default?(options) || (column_object && column_object.type != type.to_sym)
70
+ remove_default_constraint(table_name,column_name)
71
+ end
72
+ if options_include_default?(options)
73
+ sql_commands << "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name,column_name)} DEFAULT #{quote(options[:default])} FOR #{quote_column_name(column_name)}"
74
+ end
75
+ sql_commands.each { |c| do_execute(c) }
76
+ end
77
+
78
+ def change_column_default(table_name, column_name, default)
79
+ remove_default_constraint(table_name, column_name)
80
+ do_execute "ALTER TABLE #{quote_table_name(table_name)} ADD CONSTRAINT #{default_constraint_name(table_name, column_name)} DEFAULT #{quote(default)} FOR #{quote_column_name(column_name)}"
81
+ end
82
+
83
+ def rename_column(table_name, column_name, new_column_name)
84
+ detect_column_for! table_name, column_name
85
+ do_execute "EXEC sp_rename '#{table_name}.#{column_name}', '#{new_column_name}', 'COLUMN'"
86
+ end
87
+
88
+ def remove_index!(table_name, index_name)
89
+ do_execute "DROP INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)}"
90
+ end
91
+
92
+ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
93
+ type_limitable = ['string','integer','float','char','nchar','varchar','nvarchar'].include?(type.to_s)
94
+ limit = nil unless type_limitable
95
+ case type.to_s
96
+ when 'integer'
97
+ case limit
98
+ when 1..2 then 'smallint'
99
+ when 3..4, nil then 'integer'
100
+ when 5..8 then 'bigint'
101
+ else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
102
+ end
103
+ else
104
+ super
105
+ end
106
+ end
107
+
108
+ def change_column_null(table_name, column_name, null, default = nil)
109
+ column = detect_column_for! table_name, column_name
110
+ unless null || default.nil?
111
+ do_execute("UPDATE #{quote_table_name(table_name)} SET #{quote_column_name(column_name)}=#{quote(default)} WHERE #{quote_column_name(column_name)} IS NULL")
112
+ end
113
+ sql = "ALTER TABLE #{table_name} ALTER COLUMN #{quote_column_name(column_name)} #{type_to_sql column.type, column.limit, column.precision, column.scale}"
114
+ sql << " NOT NULL" unless null
115
+ do_execute sql
116
+ end
117
+
118
+ # === SQLServer Specific ======================================== #
119
+
120
+ def views
121
+ tables('VIEW')
122
+ end
123
+
124
+
125
+ protected
126
+
127
+ # === SQLServer Specific ======================================== #
128
+
129
+ def initialize_native_database_types
130
+ {
131
+ :primary_key => "int NOT NULL IDENTITY(1,1) PRIMARY KEY",
132
+ :string => { :name => native_string_database_type, :limit => 255 },
133
+ :text => { :name => native_text_database_type },
134
+ :integer => { :name => "int", :limit => 4 },
135
+ :float => { :name => "float", :limit => 8 },
136
+ :decimal => { :name => "decimal" },
137
+ :datetime => { :name => "datetime" },
138
+ :timestamp => { :name => "datetime" },
139
+ :time => { :name => native_time_database_type },
140
+ :date => { :name => native_date_database_type },
141
+ :binary => { :name => native_binary_database_type },
142
+ :boolean => { :name => "bit"},
143
+ # These are custom types that may move somewhere else for good schema_dumper.rb hacking to output them.
144
+ :char => { :name => 'char' },
145
+ :varchar_max => { :name => 'varchar(max)' },
146
+ :nchar => { :name => "nchar" },
147
+ :nvarchar => { :name => "nvarchar", :limit => 255 },
148
+ :nvarchar_max => { :name => "nvarchar(max)" },
149
+ :ntext => { :name => "ntext" },
150
+ :ss_timestamp => { :name => 'timestamp' }
151
+ }
152
+ end
153
+
154
+ def column_definitions(table_name)
155
+ db_name = Utils.unqualify_db_name(table_name)
156
+ db_name_with_period = "#{db_name}." if db_name
157
+ table_schema = Utils.unqualify_table_schema(table_name)
158
+ table_name = Utils.unqualify_table_name(table_name)
159
+ sql = %{
160
+ SELECT DISTINCT
161
+ #{lowercase_schema_reflection_sql('columns.TABLE_NAME')} AS table_name,
162
+ #{lowercase_schema_reflection_sql('columns.COLUMN_NAME')} AS name,
163
+ columns.DATA_TYPE AS type,
164
+ columns.COLUMN_DEFAULT AS default_value,
165
+ columns.NUMERIC_SCALE AS numeric_scale,
166
+ columns.NUMERIC_PRECISION AS numeric_precision,
167
+ columns.ordinal_position,
168
+ CASE
169
+ WHEN columns.DATA_TYPE IN ('nchar','nvarchar') THEN columns.CHARACTER_MAXIMUM_LENGTH
170
+ ELSE COL_LENGTH(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME, columns.COLUMN_NAME)
171
+ END AS [length],
172
+ CASE
173
+ WHEN columns.IS_NULLABLE = 'YES' THEN 1
174
+ ELSE NULL
175
+ END AS [is_nullable],
176
+ CASE
177
+ WHEN KCU.COLUMN_NAME IS NOT NULL AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY' THEN 1
178
+ ELSE NULL
179
+ END AS [is_primary],
180
+ CASE
181
+ WHEN COLUMNPROPERTY(OBJECT_ID(columns.TABLE_SCHEMA+'.'+columns.TABLE_NAME), columns.COLUMN_NAME, 'IsIdentity') = 1 THEN 1
182
+ ELSE NULL
183
+ END AS [is_identity]
184
+ FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS columns
185
+ LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC
186
+ ON TC.TABLE_NAME = columns.TABLE_NAME
187
+ AND TC.CONSTRAINT_TYPE = N'PRIMARY KEY'
188
+ LEFT OUTER JOIN #{db_name_with_period}INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
189
+ ON KCU.COLUMN_NAME = columns.COLUMN_NAME
190
+ AND KCU.CONSTRAINT_NAME = TC.CONSTRAINT_NAME
191
+ AND KCU.CONSTRAINT_CATALOG = TC.CONSTRAINT_CATALOG
192
+ AND KCU.CONSTRAINT_SCHEMA = TC.CONSTRAINT_SCHEMA
193
+ WHERE columns.TABLE_NAME = @0
194
+ ORDER BY columns.ordinal_position
195
+ }.gsub(/[ \t\r\n]+/,' ')
196
+ binds = [['table_name', table_name]]
197
+ binds << ['table_schema',table_schema] unless table_schema.blank?
198
+ results = info_schema_query { do_exec_query(sql, 'InfoSchema::ColumnDefinitions', binds) }
199
+ results.collect do |ci|
200
+ ci = ci.symbolize_keys
201
+ ci[:type] = case ci[:type]
202
+ when /^bit|image|text|ntext|datetime$/
203
+ ci[:type]
204
+ when /^numeric|decimal$/i
205
+ "#{ci[:type]}(#{ci[:numeric_precision]},#{ci[:numeric_scale]})"
206
+ when /^float|real$/i
207
+ "#{ci[:type]}(#{ci[:numeric_precision]})"
208
+ when /^char|nchar|varchar|nvarchar|varbinary|bigint|int|smallint$/
209
+ ci[:length].to_i == -1 ? "#{ci[:type]}(max)" : "#{ci[:type]}(#{ci[:length]})"
210
+ else
211
+ ci[:type]
212
+ end
213
+ if ci[:default_value].nil? && schema_cache.view_names.include?(table_name)
214
+ real_table_name = table_name_or_views_table_name(table_name)
215
+ real_column_name = views_real_column_name(table_name,ci[:name])
216
+ col_default_sql = "SELECT c.COLUMN_DEFAULT FROM #{db_name_with_period}INFORMATION_SCHEMA.COLUMNS c WHERE c.TABLE_NAME = '#{real_table_name}' AND c.COLUMN_NAME = '#{real_column_name}'"
217
+ ci[:default_value] = info_schema_query { select_value(col_default_sql) }
218
+ end
219
+ ci[:default_value] = case ci[:default_value]
220
+ when nil, '(null)', '(NULL)'
221
+ nil
222
+ when /\A\((\w+\(\))\)\Z/
223
+ ci[:default_function] = $1
224
+ nil
225
+ else
226
+ match_data = ci[:default_value].match(/\A\(+N?'?(.*?)'?\)+\Z/m)
227
+ match_data ? match_data[1] : nil
228
+ end
229
+ ci[:null] = ci[:is_nullable].to_i == 1 ; ci.delete(:is_nullable)
230
+ ci[:is_primary] = ci[:is_primary].to_i == 1
231
+ ci[:is_identity] = ci[:is_identity].to_i == 1
232
+ ci
233
+ end
234
+ end
235
+
236
+ def remove_check_constraints(table_name, column_name)
237
+ constraints = info_schema_query { select_values("SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE where TABLE_NAME = '#{quote_string(table_name)}' and COLUMN_NAME = '#{quote_string(column_name)}'") }
238
+ constraints.each do |constraint|
239
+ do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{quote_column_name(constraint)}"
240
+ end
241
+ end
242
+
243
+ def remove_default_constraint(table_name, column_name)
244
+ # If their are foreign keys in this table, we could still get back a 2D array, so flatten just in case.
245
+ select_all("EXEC sp_helpconstraint '#{quote_string(table_name)}','nomsg'").flatten.select do |row|
246
+ row['constraint_type'] == "DEFAULT on column #{column_name}"
247
+ end.each do |row|
248
+ do_execute "ALTER TABLE #{quote_table_name(table_name)} DROP CONSTRAINT #{row['constraint_name']}"
249
+ end
250
+ end
251
+
252
+ def remove_indexes(table_name, column_name)
253
+ indexes(table_name).select{ |index| index.columns.include?(column_name.to_s) }.each do |index|
254
+ remove_index(table_name, {:name => index.name})
255
+ end
256
+ end
257
+
258
+ # === SQLServer Specific (Misc Helpers) ========================= #
259
+
260
+ def info_schema_query
261
+ log_info_schema_queries ? yield : ActiveRecord::Base.silence{ yield }
262
+ end
263
+
264
+ def get_table_name(sql)
265
+ if sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)\s+INTO\s+([^\(\s]+)\s*|^\s*update\s+([^\(\s]+)\s*/i
266
+ $2 || $3
267
+ elsif sql =~ /FROM\s+([^\(\s]+)\s*/i
268
+ $1
269
+ else
270
+ nil
271
+ end
272
+ end
273
+
274
+ def default_constraint_name(table_name, column_name)
275
+ "DF_#{table_name}_#{column_name}"
276
+ end
277
+
278
+ def detect_column_for!(table_name, column_name)
279
+ unless column = schema_cache.columns[table_name].detect { |c| c.name == column_name.to_s }
280
+ raise ActiveRecordError, "No such column: #{table_name}.#{column_name}"
281
+ end
282
+ column
283
+ end
284
+
285
+ def lowercase_schema_reflection_sql(node)
286
+ lowercase_schema_reflection ? "LOWER(#{node})" : node
287
+ end
288
+
289
+ # === SQLServer Specific (View Reflection) ====================== #
290
+
291
+ def view_table_name(table_name)
292
+ view_info = schema_cache.view_information(table_name)
293
+ view_info ? get_table_name(view_info['VIEW_DEFINITION']) : table_name
294
+ end
295
+
296
+ def view_information(table_name)
297
+ table_name = Utils.unqualify_table_name(table_name)
298
+ view_info = info_schema_query { select_one("SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_NAME = '#{table_name}'") }
299
+ if view_info
300
+ view_info = view_info.with_indifferent_access
301
+ if view_info[:VIEW_DEFINITION].blank? || view_info[:VIEW_DEFINITION].length == 4000
302
+ view_info[:VIEW_DEFINITION] = info_schema_query do
303
+ begin
304
+ select_values("EXEC sp_helptext #{quote_table_name(table_name)}").join
305
+ rescue
306
+ warn "No view definition found, possible permissions problem.\nPlease run GRANT VIEW DEFINITION TO your_user;"
307
+ nil
308
+ end
309
+ end
310
+ end
311
+ end
312
+ view_info
313
+ end
314
+
315
+ def table_name_or_views_table_name(table_name)
316
+ unquoted_table_name = Utils.unqualify_table_name(table_name)
317
+ schema_cache.view_names.include?(unquoted_table_name) ? view_table_name(unquoted_table_name) : unquoted_table_name
318
+ end
319
+
320
+ def views_real_column_name(table_name,column_name)
321
+ view_definition = schema_cache.view_information(table_name)[:VIEW_DEFINITION]
322
+ match_data = view_definition.match(/([\w-]*)\s+as\s+#{column_name}/im)
323
+ match_data ? match_data[1] : column_name
324
+ end
325
+
326
+ # === SQLServer Specific (Identity Inserts) ===================== #
327
+
328
+ def query_requires_identity_insert?(sql)
329
+ if insert_sql?(sql)
330
+ table_name = get_table_name(sql)
331
+ id_column = identity_column(table_name)
332
+ id_column && sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)[^(]+\([^)]*\b(#{id_column.name})\b,?[^)]*\)/i ? quote_table_name(table_name) : false
333
+ else
334
+ false
335
+ end
336
+ end
337
+
338
+ def insert_sql?(sql)
339
+ !(sql =~ /^\s*(INSERT|EXEC sp_executesql N'INSERT)/i).nil?
340
+ end
341
+
342
+ def with_identity_insert_enabled(table_name)
343
+ table_name = quote_table_name(table_name_or_views_table_name(table_name))
344
+ set_identity_insert(table_name, true)
345
+ yield
346
+ ensure
347
+ set_identity_insert(table_name, false)
348
+ end
349
+
350
+ def set_identity_insert(table_name, enable = true)
351
+ sql = "SET IDENTITY_INSERT #{table_name} #{enable ? 'ON' : 'OFF'}"
352
+ do_execute sql,'InfoSchema::SetIdentityInsert'
353
+ rescue Exception => e
354
+ raise ActiveRecordError, "IDENTITY_INSERT could not be turned #{enable ? 'ON' : 'OFF'} for table #{table_name}"
355
+ end
356
+
357
+ def identity_column(table_name)
358
+ schema_cache.columns[table_name].detect(&:is_identity?)
359
+ end
360
+
361
+ end
362
+ end
363
+ end
364
+ end