Permalink
Browse files

Handle more disconnection errors

This adds handling of disconnection errors to the ado adapter
and the do postgres subadapter.

It handles more types of disconnection errors in the postgres
adapter.  It fixes the mysql adapter after the previous
commit's disconnection changes, and fixes disconnect
detection during transactions to the odbc and tinytds adapters.
  • Loading branch information...
1 parent 147847d commit 61dc406a0a28a3645e1863f4653c9db61323b79e @jeremyevans committed Jul 5, 2011
View
@@ -1,5 +1,9 @@
=== HEAD
+* Handle another type of disconnection in the postgres adapter (jeremyevans)
+
+* Handle disconnections in the ado adapter and do postgres subadapter (jeremyevans)
+
* Recognize disconnections when issuing BEGIN/ROLLBACK/COMMIT statements (jeremyevans) (#368)
=== 3.25.0 (2011-07-01)
View
@@ -4,6 +4,8 @@ module Sequel
# The ADO adapter provides connectivity to ADO databases in Windows.
module ADO
class Database < Sequel::Database
+ DISCONNECT_ERROR_RE = /Communication link failure/
+
set_adapter_scheme :ado
def initialize(opts)
@@ -87,9 +89,17 @@ def _transaction(conn, o={})
end
end
+ def database_error_classes
+ [::WIN32OLERuntimeError]
+ end
+
def disconnect_connection(conn)
conn.Close
end
+
+ def disconnect_error?(e, opts)
+ super || (e.is_a?(::WIN32OLERuntimeError) && e.message =~ DISCONNECT_ERROR_RE)
+ end
end
class Dataset < Sequel::Dataset
View
@@ -36,6 +36,8 @@ module DataObjects
# Sequel::DataObjects::Database object, or hack DataObjects (or Extlib) to
# use a pool size at least as large as the pool size being used by Sequel.
class Database < Sequel::Database
+ DISCONNECT_ERROR_RE = /terminating connection due to administrator command/
+
set_adapter_scheme :do
# Call the DATABASE_SETUP proc directly after initialization,
@@ -145,10 +147,20 @@ def connection_execute_method
:execute_non_query
end
+ # dataobjects uses the DataObjects::Error class as the main error class.
+ def database_error_classes
+ [::DataObjects::Error]
+ end
+
# Close the given database connection.
def disconnect_connection(c)
c.close
end
+
+ # Recognize DataObjects::ConnectionError instances as disconnect errors.
+ def disconnect_error?(e, opts)
+ super || (e.is_a?(::DataObjects::Error) && (e.is_a?(::DataObjects::ConnectionError) || e.message =~ DISCONNECT_ERROR_RE))
+ end
# Execute SQL on the connection by creating a command first
def log_connection_execute(conn, sql)
@@ -213,7 +213,7 @@ def _execute(conn, sql, opts)
conn.next_result
r = conn.use_result
rescue Mysql::Error => e
- raise_error(e)
+ raise_error(e, :disconnect=>true) if MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)
break
end
yield r if opts[:type] == :select
@@ -230,7 +230,7 @@ def _execute(conn, sql, opts)
conn.next_result
r = conn.use_result
rescue Mysql::Error => e
- raise_error(e)
+ raise_error(e, :disconnect=>true) if MYSQL_DATABASE_DISCONNECT_ERRORS.match(e.message)
break
end
r.free if r
@@ -77,6 +77,10 @@ def connection_execute_method
:do
end
+ def database_error_classes
+ [::ODBC::Error]
+ end
+
def disconnect_connection(c)
c.disconnect
end
@@ -136,7 +136,10 @@ def self.use_iso_date_format=(v)
# PGconn subclass for connection specific methods used with the
# pg, postgres, or postgres-pr driver.
class Adapter < ::PGconn
+ DISCONNECT_ERROR_RE = /\Acould not receive data from server: Software caused connection abort/
+
include Sequel::Postgres::AdapterMethods
+
self.translate_results = false if respond_to?(:translate_results=)
# Hash of prepared statements for this connection. Keys are
@@ -155,20 +158,23 @@ def apply_connection_settings
end
@prepared_statements = {} if SEQUEL_POSTGRES_USES_PG
end
-
+
# Raise a Sequel::DatabaseDisconnectError if a PGError is raised and
# the connection status cannot be determined or it is not OK.
def check_disconnect_errors
begin
yield
rescue PGError =>e
+ disconnect = false
begin
s = status
rescue PGError
- raise Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)
+ disconnect = true
end
status_ok = (s == Adapter::CONNECTION_OK)
- status_ok ? raise : raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError))
+ disconnect ||= !status_ok
+ disconnect ||= e.message =~ DISCONNECT_ERROR_RE
+ disconnect ? raise(Sequel.convert_exception_class(e, Sequel::DatabaseDisconnectError)) : raise
ensure
block if status_ok
end
@@ -74,12 +74,17 @@ def column_list_sql(g)
super
end
+ # tiny_tds uses TinyTds::Error as the base error class.
+ def database_error_classes
+ [TinyTds::Error]
+ end
+
# Close the TinyTds::Client object.
def disconnect_connection(c)
c.close
end
- def disconnect_error(e, opts)
+ def disconnect_error?(e, opts)
super || (opts[:conn] && !opts[:conn].active?)
end
end

0 comments on commit 61dc406

Please sign in to comment.