1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

MySQL: Raise ActiveRecord::InvalidForeignKey for foreign-key constraint violations on delete

This commit is contained in:
George Claghorn 2018-07-30 08:40:48 -04:00
parent cfee9feee4
commit 59c3ed1b3f
3 changed files with 20 additions and 7 deletions

View file

@ -619,6 +619,7 @@ module ActiveRecord
ER_DUP_ENTRY = 1062
ER_NOT_NULL_VIOLATION = 1048
ER_DO_NOT_HAVE_DEFAULT = 1364
ER_ROW_IS_REFERENCED_2 = 1451
ER_NO_REFERENCED_ROW_2 = 1452
ER_DATA_TOO_LONG = 1406
ER_OUT_OF_RANGE = 1264
@ -633,7 +634,7 @@ module ActiveRecord
case error_number(exception)
when ER_DUP_ENTRY
RecordNotUnique.new(message)
when ER_NO_REFERENCED_ROW_2
when ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
InvalidForeignKey.new(message)
when ER_CANNOT_ADD_FOREIGN
mismatched_foreign_key(message)

View file

@ -111,7 +111,8 @@ module ActiveRecord
class RecordNotUnique < WrappedDatabaseException
end
# Raised when a record cannot be inserted or updated because it references a non-existent record.
# Raised when a record cannot be inserted or updated because it references a non-existent record,
# or when a record cannot be deleted because a parent record references it.
class InvalidForeignKey < WrappedDatabaseException
end

View file

@ -304,6 +304,8 @@ module ActiveRecord
class AdapterForeignKeyTest < ActiveRecord::TestCase
self.use_transactional_tests = false
fixtures :fk_test_has_pk
def setup
@connection = ActiveRecord::Base.connection
end
@ -322,7 +324,7 @@ module ActiveRecord
assert_not_nil error.cause
end
def test_foreign_key_violations_are_translated_to_specific_exception
def test_foreign_key_violations_on_insert_are_translated_to_specific_exception
error = assert_raises(ActiveRecord::InvalidForeignKey) do
insert_into_fk_test_has_fk
end
@ -330,6 +332,16 @@ module ActiveRecord
assert_not_nil error.cause
end
def test_foreign_key_violations_on_delete_are_translated_to_specific_exception
insert_into_fk_test_has_fk fk_id: 1
error = assert_raises(ActiveRecord::InvalidForeignKey) do
@connection.execute "DELETE FROM fk_test_has_pk WHERE pk_id = 1"
end
assert_not_nil error.cause
end
def test_disable_referential_integrity
assert_nothing_raised do
@connection.disable_referential_integrity do
@ -342,14 +354,13 @@ module ActiveRecord
end
private
def insert_into_fk_test_has_fk
def insert_into_fk_test_has_fk(fk_id: 0)
# Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
if @connection.prefetch_primary_key?
id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
@connection.execute "INSERT INTO fk_test_has_fk (id,fk_id) VALUES (#{id_value},0)"
@connection.execute "INSERT INTO fk_test_has_fk (id,fk_id) VALUES (#{id_value},#{fk_id})"
else
@connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
@connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (#{fk_id})"
end
end
end