提交 69700c9e 编写于 作者: J John Hawthorn

Move DatabaseAlreadyExists detection to DB adapter

Previously it was the responsibility of the database tasks to translate
the invalid statement from creating a duplicate database into an
ActiveRecord::Tasks::DatabaseAlreadyExists error.

It's actually easier for us to do this detection inside of the adapter,
where we already do a case statement on the return code to translate the
error.

This commit introduces ActiveRecord::DatabaseAlreadyExists, a subclass
of StatementInvalid, and updates both AbstractMysqlAdapter and
PostgresqlAdapter to return this more specific exception in that case.

Because this is a subclass of the old exception, StatementInvalid, it
should be backwards compatible with any code expecting that from
create_database.

This works for both create_database and exectute("CREATE DATABASE")
上级 2e6d9af6
......@@ -573,6 +573,7 @@ def extract_precision(sql_type)
end
# See https://dev.mysql.com/doc/refman/5.7/en/server-error-reference.html
ER_DB_CREATE_EXISTS = 1007
ER_DUP_ENTRY = 1062
ER_NOT_NULL_VIOLATION = 1048
ER_NO_REFERENCED_ROW = 1216
......@@ -592,6 +593,8 @@ def extract_precision(sql_type)
def translate_exception(exception, message:, sql:, binds:)
case error_number(exception)
when ER_DB_CREATE_EXISTS
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
when ER_DUP_ENTRY
RecordNotUnique.new(message, sql: sql, binds: binds)
when ER_NO_REFERENCED_ROW, ER_ROW_IS_REFERENCED, ER_ROW_IS_REFERENCED_2, ER_NO_REFERENCED_ROW_2
......
......@@ -467,6 +467,7 @@ def check_version # :nodoc:
UNIQUE_VIOLATION = "23505"
SERIALIZATION_FAILURE = "40001"
DEADLOCK_DETECTED = "40P01"
DUPLICATE_DATABASE = "42P04"
LOCK_NOT_AVAILABLE = "55P03"
QUERY_CANCELED = "57014"
......@@ -488,6 +489,8 @@ def translate_exception(exception, message:, sql:, binds:)
SerializationFailure.new(message, sql: sql, binds: binds)
when DEADLOCK_DETECTED
Deadlocked.new(message, sql: sql, binds: binds)
when DUPLICATE_DATABASE
DatabaseAlreadyExists.new(message, sql: sql, binds: binds)
when LOCK_NOT_AVAILABLE
LockWaitTimeout.new(message, sql: sql, binds: binds)
when QUERY_CANCELED
......
......@@ -187,6 +187,10 @@ class PreparedStatementInvalid < ActiveRecordError
class NoDatabaseError < StatementInvalid
end
# Raised when creating a database if it exists.
class DatabaseAlreadyExists < StatementInvalid
end
# Raised when PostgreSQL returns 'cached plan must not change result type' and
# we cannot retry gracefully (e.g. inside a transaction)
class PreparedStatementCacheExpired < StatementInvalid
......
......@@ -4,7 +4,6 @@
module ActiveRecord
module Tasks # :nodoc:
class DatabaseAlreadyExists < StandardError; end # :nodoc:
class DatabaseNotSupported < StandardError; end # :nodoc:
# ActiveRecord::Tasks::DatabaseTasks is a utility class, which encapsulates
......
......@@ -15,12 +15,6 @@ def create
establish_connection configuration_without_database
connection.create_database configuration["database"], creation_options
establish_connection configuration
rescue ActiveRecord::StatementInvalid => error
if connection.error_number(error.cause) == ER_DB_CREATE_EXISTS
raise DatabaseAlreadyExists
else
raise
end
end
def drop
......
......@@ -21,12 +21,6 @@ def create(master_established = false)
connection.create_database configuration["database"],
configuration.merge("encoding" => encoding)
establish_connection configuration
rescue ActiveRecord::StatementInvalid => error
if error.cause.is_a?(PG::DuplicateDatabase)
raise DatabaseAlreadyExists
else
raise
end
end
def drop
......
......@@ -93,11 +93,9 @@ def test_create_when_database_exists_outputs_info_to_stderr
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
proc { raise ActiveRecord::StatementInvalid }
proc { raise ActiveRecord::DatabaseAlreadyExists }
) do
ActiveRecord::Base.connection.stub(:error_number, 1007) do
ActiveRecord::Tasks::DatabaseTasks.create @configuration
end
ActiveRecord::Tasks::DatabaseTasks.create @configuration
assert_equal "Database 'my-app-db' already exists\n", $stderr.string
end
......
......@@ -129,7 +129,7 @@ def test_create_when_database_exists_outputs_info_to_stderr
with_stubbed_connection_establish_connection do
ActiveRecord::Base.connection.stub(
:create_database,
proc { raise ActiveRecord::Tasks::DatabaseAlreadyExists }
proc { raise ActiveRecord::DatabaseAlreadyExists }
) do
ActiveRecord::Tasks::DatabaseTasks.create @configuration
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册