未验证 提交 0e2cd3d7 编写于 作者: R Ryuta Kamizono 提交者: GitHub

Add new error class `QueryCanceled` which will be raised when canceling...

Add new error class `QueryCanceled` which will be raised when canceling statement due to user request (#31235)

This changes `StatementTimeout` to `QueryCanceled` for PostgreSQL.

In MySQL, errno 1317 (`ER_QUERY_INTERRUPTED`) is only used when the
query is manually cancelled.

But in PostgreSQL, `QUERY_CANCELED` error code (57014) which is used
`StatementTimeout` is also used when the both case. And, we can not tell
which reason happened.

So I decided to introduce new error class `QueryCanceled` closer to the
error code name.
上级 ad0630f0
* Add new error class `QueryCanceled` which will be raised
when canceling statement due to user request.
*Ryuta Kamizono*
* Add `#up_only` to database migrations for code that is only relevant when
migrating up, e.g. populating a new column.
......
......@@ -635,6 +635,7 @@ def add_options_for_index_columns(quoted_columns, **options)
ER_CANNOT_ADD_FOREIGN = 1215
ER_CANNOT_CREATE_TABLE = 1005
ER_LOCK_WAIT_TIMEOUT = 1205
ER_QUERY_INTERRUPTED = 1317
ER_QUERY_TIMEOUT = 3024
def translate_exception(exception, message)
......@@ -663,6 +664,8 @@ def translate_exception(exception, message)
LockWaitTimeout.new(message)
when ER_QUERY_TIMEOUT
StatementTimeout.new(message)
when ER_QUERY_INTERRUPTED
QueryCanceled.new(message)
else
super
end
......
......@@ -420,7 +420,7 @@ def translate_exception(exception, message)
when LOCK_NOT_AVAILABLE
LockWaitTimeout.new(message)
when QUERY_CANCELED
StatementTimeout.new(message)
QueryCanceled.new(message)
else
super
end
......
......@@ -343,6 +343,10 @@ class LockWaitTimeout < StatementInvalid
class StatementTimeout < StatementInvalid
end
# QueryCanceled will be raised when canceling statement due to user request.
class QueryCanceled < StatementInvalid
end
# UnknownAttributeReference is raised when an unknown and potentially unsafe
# value is passed to a query method when allow_unsafe_raw_sql is set to
# :disabled. For example, passing a non column name value to a relation's
......
......@@ -116,5 +116,32 @@ class Sample < ActiveRecord::Base
end
end
end
test "raises QueryCanceled when canceling statement due to user request" do
assert_raises(ActiveRecord::QueryCanceled) do
s = Sample.create!(value: 1)
latch = Concurrent::CountDownLatch.new
thread = Thread.new do
Sample.transaction do
Sample.lock.find(s.id)
latch.count_down
sleep(0.5)
conn = Sample.connection
pid = conn.query_value("SELECT id FROM information_schema.processlist WHERE info LIKE '% FOR UPDATE'")
conn.execute("KILL QUERY #{pid}")
end
end
begin
Sample.transaction do
latch.wait
Sample.lock.find(s.id)
end
ensure
thread.join
end
end
end
end
end
......@@ -120,8 +120,8 @@ class Sample < ActiveRecord::Base
end
end
test "raises StatementTimeout when statement timeout exceeded" do
assert_raises(ActiveRecord::StatementTimeout) do
test "raises QueryCanceled when statement timeout exceeded" do
assert_raises(ActiveRecord::QueryCanceled) do
s = Sample.create!(value: 1)
latch1 = Concurrent::CountDownLatch.new
latch2 = Concurrent::CountDownLatch.new
......@@ -148,6 +148,33 @@ class Sample < ActiveRecord::Base
end
end
test "raises QueryCanceled when canceling statement due to user request" do
assert_raises(ActiveRecord::QueryCanceled) do
s = Sample.create!(value: 1)
latch = Concurrent::CountDownLatch.new
thread = Thread.new do
Sample.transaction do
Sample.lock.find(s.id)
latch.count_down
sleep(0.5)
conn = Sample.connection
pid = conn.query_value("SELECT pid FROM pg_stat_activity WHERE query LIKE '% FOR UPDATE'")
conn.execute("SELECT pg_cancel_backend(#{pid})")
end
end
begin
Sample.transaction do
latch.wait
Sample.lock.find(s.id)
end
ensure
thread.join
end
end
end
private
def with_warning_suppression
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册