Skip to content

Commit 620baf2

Browse files
committed
[Rails51] Base adapter tests passing.
* Fix #exec_insert to super up. * Dup frozen strings passed into database statements. * Remove tables/table_exists? deprecations. * Switch to bigint primary keys. * The `drop_table` with force cascade option now mimics in via pure SQL for us. * Support MismatchedForeignKey exception.
1 parent 6f3373a commit 620baf2

File tree

8 files changed

+41
-33
lines changed

8 files changed

+41
-33
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
#### Changed
66

7+
* The `drop_table` with force cascade option now mimics in via pure SQL for us.
8+
79
#### Added
810

11+
* Support MismatchedForeignKey exception.
912

lib/active_record/connection_adapters/sqlserver/database_statements.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,22 @@ def exec_query(sql, name = 'SQL', binds = [], prepare: false)
1919
sp_executesql(sql, name, binds, prepare: prepare)
2020
end
2121

22-
def exec_insert(sql, name, binds, pk = nil, _sequence_name = nil)
22+
def exec_insert(sql, name = nil, binds = [], pk = nil, _sequence_name = nil)
2323
if id_insert_table_name = exec_insert_requires_identity?(sql, pk, binds)
24-
with_identity_insert_enabled(id_insert_table_name) { exec_query(sql, name, binds) }
24+
with_identity_insert_enabled(id_insert_table_name) { super(sql, name, binds, pk) }
2525
else
26-
exec_query(sql, name, binds)
26+
super(sql, name, binds, pk)
2727
end
2828
end
2929

3030
def exec_delete(sql, name, binds)
31-
sql << '; SELECT @@ROWCOUNT AS AffectedRows'
32-
super.rows.first.first
31+
sql = sql.dup << '; SELECT @@ROWCOUNT AS AffectedRows'
32+
super(sql, name, binds).rows.first.first
3333
end
3434

3535
def exec_update(sql, name, binds)
36-
sql << '; SELECT @@ROWCOUNT AS AffectedRows'
37-
super.rows.first.first
36+
sql = sql.dup << '; SELECT @@ROWCOUNT AS AffectedRows'
37+
super(sql, name, binds).rows.first.first
3838
end
3939

4040
def supports_statement_cache?
@@ -198,7 +198,7 @@ def sql_for_insert(sql, pk, id_value, sequence_name, binds)
198198
end
199199
sql = if pk && self.class.use_output_inserted && !database_prefix_remote_server?
200200
quoted_pk = SQLServer::Utils.extract_identifiers(pk).quoted
201-
sql.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk}"
201+
sql.dup.insert sql.index(/ (DEFAULT )?VALUES/), " OUTPUT INSERTED.#{quoted_pk}"
202202
else
203203
"#{sql}; SELECT CAST(SCOPE_IDENTITY() AS bigint) AS Ident"
204204
end
@@ -261,7 +261,7 @@ def sp_executesql_sql(sql, types, params, name)
261261
if name == 'EXPLAIN'
262262
params.each.with_index do |param, index|
263263
substitute_at_finder = /(@#{index})(?=(?:[^']|'[^']*')*$)/ # Finds unquoted @n values.
264-
sql.sub! substitute_at_finder, param.to_s
264+
sql = sql.sub substitute_at_finder, param.to_s
265265
end
266266
else
267267
types = quote(types.join(', '))

lib/active_record/connection_adapters/sqlserver/schema_statements.rb

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,10 @@ def native_database_types
88
end
99

1010
def tables(name = nil)
11-
ActiveSupport::Deprecation.warn 'Passing arguments to #tables is deprecated without replacement.' if name
1211
tables_sql('BASE TABLE')
1312
end
1413

1514
def table_exists?(table_name)
16-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
17-
#table_exists? currently checks both tables and views.
18-
This behavior is deprecated and will be changed with Rails 5.1 to only check tables.
19-
Use #data_source_exists? instead.
20-
MSG
2115
data_source_exists?(table_name)
2216
end
2317

@@ -43,6 +37,17 @@ def create_table(table_name, comment: nil, **options)
4337
end
4438

4539
def drop_table(table_name, options = {})
40+
# Mimic CASCADE option as best we can.
41+
if options[:force] == :cascade
42+
execute_procedure(:sp_fkeys, pktable_name: table_name).each do |fkdata|
43+
fktable = fkdata['FKTABLE_NAME']
44+
fkcolmn = fkdata['FKCOLUMN_NAME']
45+
pktable = fkdata['PKTABLE_NAME']
46+
pkcolmn = fkdata['PKCOLUMN_NAME']
47+
remove_foreign_key fktable, name: fkdata['FK_NAME']
48+
do_execute "DELETE FROM #{quote_table_name(fktable)} WHERE #{quote_column_name(fkcolmn)} IN ( SELECT #{quote_column_name(pkcolmn)} FROM #{quote_table_name(pktable)} )"
49+
end
50+
end
4651
if options[:if_exists] && @version_year != 2016
4752
execute "IF EXISTS(SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = #{quote(table_name)}) DROP TABLE #{quote_table_name(table_name)}"
4853
else
@@ -252,7 +257,7 @@ def change_column_null(table_name, column_name, allow_null, default = nil)
252257

253258
def initialize_native_database_types
254259
{
255-
primary_key: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY',
260+
primary_key: 'bigint NOT NULL IDENTITY(1,1) PRIMARY KEY',
256261
primary_key_nonclustered: 'int NOT NULL IDENTITY(1,1) PRIMARY KEY NONCLUSTERED',
257262
integer: { name: 'int', limit: 4 },
258263
bigint: { name: 'bigint' },

lib/active_record/connection_adapters/sqlserver_adapter.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,10 +147,10 @@ def supports_in_memory_oltp?
147147

148148
def disable_referential_integrity
149149
tables = tables_with_referential_integrity
150-
tables.each { |t| do_execute "ALTER TABLE #{t} NOCHECK CONSTRAINT ALL" }
150+
tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} NOCHECK CONSTRAINT ALL" }
151151
yield
152152
ensure
153-
tables.each { |t| do_execute "ALTER TABLE #{t} CHECK CONSTRAINT ALL" }
153+
tables.each { |t| do_execute "ALTER TABLE #{quote_table_name(t)} CHECK CONSTRAINT ALL" }
154154
end
155155

156156
# === Abstract Adapter (Connection Management) ================== #
@@ -327,6 +327,16 @@ def translate_exception(e, message)
327327
NoDatabaseError.new(message)
328328
when /data would be truncated/
329329
ValueTooLong.new(message)
330+
when /Column '(.*)' is not the same data type as referencing column '(.*)' in foreign key/
331+
pk_id, fk_id = SQLServer::Utils.extract_identifiers($1), SQLServer::Utils.extract_identifiers($2)
332+
MismatchedForeignKey.new(
333+
self,
334+
message: message,
335+
table: fk_id.schema,
336+
foreign_key: fk_id.object,
337+
target_table: pk_id.schema,
338+
primary_key: pk_id.object
339+
)
330340
else
331341
super
332342
end

lib/active_record/tasks/sqlserver_database_tasks.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def purge
4848
create true
4949
end
5050

51-
def structure_dump(filename)
51+
def structure_dump(filename, extra_flags)
5252
command = [
5353
"defncopy",
5454
"-S #{Shellwords.escape(configuration['host'])}",
@@ -71,7 +71,7 @@ def structure_dump(filename)
7171
File.open(filename, "w") { |file| file.puts dump }
7272
end
7373

74-
def structure_load(filename)
74+
def structure_load(filename, extra_flags)
7575
connection.execute File.read(filename)
7676
end
7777

lib/arel/visitors/sqlserver.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,8 @@ def table_From_Statement o
190190

191191
def primary_Key_From_Table t
192192
return unless t
193-
column_name = schema_cache.primary_keys(t.name) || column_cache(t.name).first.try(:second).try(:name)
193+
column_name = @connection.schema_cache.primary_keys(t.name) ||
194+
@connection.schema_cache.columns_hash(t.name).first.try(:second).try(:name)
194195
column_name ? t[column_name] : nil
195196
end
196197

test/cases/pessimistic_locking_test_sqlserver.rb

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,17 +46,6 @@ class PessimisticLockingTestSQLServer < ActiveRecord::TestCase
4646
end
4747
end
4848

49-
it 'reload with lock when #lock! called' do
50-
assert_nothing_raised do
51-
Person.transaction do
52-
person = Person.find 1
53-
old, person.first_name = person.first_name, 'fooman'
54-
person.lock!
55-
assert_equal old, person.first_name
56-
end
57-
end
58-
end
59-
6049
it 'can add a custom lock directive' do
6150
assert_sql %r|SELECT \[people\]\.\* FROM \[people\] WITH\(HOLDLOCK, ROWLOCK\)| do
6251
Person.lock('WITH(HOLDLOCK, ROWLOCK)').load

test/schema/sqlserver_specific_schema.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148

149149
# Constraints
150150

151-
create_table(:sst_has_fks, force: true) { |t| t.column(:fk_id, :integer, null: false) }
151+
create_table(:sst_has_fks, force: true) { |t| t.column(:fk_id, :bigint, null: false) }
152152
create_table(:sst_has_pks, force: true) { }
153153
execute <<-ADDFKSQL
154154
ALTER TABLE sst_has_fks

0 commit comments

Comments
 (0)