Improve error reporting on connection error.

This commit is contained in:
Dimitri Fontaine 2014-12-19 14:24:35 +01:00
parent 4760934cab
commit 5b726e47a0
5 changed files with 131 additions and 65 deletions

View File

@ -70,8 +70,51 @@
;;;
;;; PostgreSQL COPY support, and generic sources API.
;;;
(defpackage #:pgloader.parse-date
(:use #:cl #:esrap)
(:export #:parse-date-string
#:parse-date-format))
(defpackage #:pgloader.sources
(:use #:cl #:pgloader.params #:pgloader.utils)
(:import-from #:pgloader.transforms #:precision #:scale)
(:import-from #:pgloader.parse-date
#:parse-date-string
#:parse-date-format)
(:export #:copy
#:source-db
#:target-db
#:source
#:target
#:fields
#:columns
#:transforms
#:map-rows
#:copy-from
#:copy-to-queue
#:copy-to
#:copy-database
;; conditions, error handling
#:connection-error
;; file based utils for CSV, fixed etc
#:filter-column-list
#:with-open-file-or-stream
#:get-pathname
#:get-absolute-pathname
#:project-fields
#:reformat-then-process
;; database cast machinery
#:*default-cast-rules*
#:*cast-rules*
#:cast))
(defpackage #:pgloader.pgsql
(:use #:cl #:pgloader.params #:pgloader.utils)
(:import-from #:pgloader.sources
#:connection-error)
(:export #:with-pgsql-transaction
#:with-pgsql-connection
#:pgsql-execute
@ -105,44 +148,6 @@
#:set-table-oids
#:reset-sequences))
(defpackage #:pgloader.parse-date
(:use #:cl #:esrap)
(:export #:parse-date-string
#:parse-date-format))
(defpackage #:pgloader.sources
(:use #:cl #:pgloader.params #:pgloader.utils)
(:import-from #:pgloader.transforms #:precision #:scale)
(:import-from #:pgloader.parse-date
#:parse-date-string
#:parse-date-format)
(:export #:copy
#:source-db
#:target-db
#:source
#:target
#:fields
#:columns
#:transforms
#:map-rows
#:copy-from
#:copy-to-queue
#:copy-to
#:copy-database
;; file based utils for CSV, fixed etc
#:filter-column-list
#:with-open-file-or-stream
#:get-pathname
#:get-absolute-pathname
#:project-fields
#:reformat-then-process
;; database cast machinery
#:*default-cast-rules*
#:*cast-rules*
#:cast))
(defpackage #:pgloader.queue
(:use #:cl #:pgloader.params)
(:import-from #:pgloader.monitor
@ -393,6 +398,8 @@
#:run-commands
#:parse-commands
#:with-database-uri)
(:import-from #:pgloader.sources
#:connection-error)
(:export #:*version-string*
#:*state*
#:*csv-path-root*

View File

@ -32,24 +32,51 @@
,@forms)))
;; no database given, create a new database connection
`(let (#+unix (cl-postgres::*unix-socket-dir* (get-unix-socket-dir)))
(pomo:with-connection (get-connection-spec :dbname ,dbname
:username ,username)
(log-message :debug "CONNECT")
(set-session-gucs *pg-settings*)
(handling-pgsql-notices ()
(pomo:with-transaction ()
(log-message :debug "BEGIN")
,@forms))))))
(let ((pomo:*database*
(handler-case
(apply #'pomo:connect (get-connection-spec :dbname ,dbname
:username ,username))
(condition (e)
(destructuring-bind (&key host port user &allow-other-keys)
*pgconn*
(error 'connection-error
:mesg (format nil "~a" e)
:type "PostgreSQL"
:host (if (consp host) (cdr host) host)
:port port
:user user))))))
(unwind-protect
(progn
(log-message :debug "CONNECT")
(set-session-gucs *pg-settings*)
(handling-pgsql-notices ()
(pomo:with-transaction ()
(log-message :debug "BEGIN")
,@forms)))
(pomo:disconnect pomo:*database*))))))
(defmacro with-pgsql-connection ((dbname) &body forms)
"Run FROMS within a PostgreSQL connection to DBNAME. To get the connection
spec from the DBNAME, use `get-connection-spec'."
`(let (#+unix (cl-postgres::*unix-socket-dir* (get-unix-socket-dir)))
(pomo:with-connection (get-connection-spec :dbname ,dbname)
(log-message :debug "CONNECT ~s" (get-connection-spec :dbname ,dbname))
(set-session-gucs *pg-settings*)
(handling-pgsql-notices ()
,@forms))))
(let ((pomo:*database*
(handler-case
(apply #'pomo:connect (get-connection-spec :dbname ,dbname))
(condition (e)
(destructuring-bind (&key host port user &allow-other-keys) *pgconn*
(error 'connection-error
:mesg (format nil "~a" e)
:type "PostgreSQL"
:host (if (consp host) (cdr host) host)
:port port
:user user))))))
(unwind-protect
(progn
(log-message :debug "CONNECT ~s" (get-connection-spec :dbname ,dbname))
(set-session-gucs *pg-settings*)
(handling-pgsql-notices ()
,@forms))
(pomo:disconnect pomo:*database*)))))
(defun get-unix-socket-dir ()
"When *pgconn* host is a (cons :unix path) value, return the right value

View File

@ -3,6 +3,20 @@
;;;
(in-package :pgloader.sources)
(define-condition connection-error (error)
((type :initarg :type :reader connection-error-type)
(mesg :initarg :mesg :reader connection-error-mesg)
(host :initarg :host :reader connection-error-host)
(port :initarg :port :reader connection-error-port)
(user :initarg :user :reader connection-error-user))
(:report (lambda (err stream)
(format stream "Failed to connect to ~a at ~s ~@[(port ~d)~]~@[ as user ~s: ~a~]"
(connection-error-type err)
(connection-error-host err)
(connection-error-port err)
(connection-error-user err)
(connection-error-mesg err)))))
;; Abstract classes to define the API with
;;
;; The source name might be a table name (database server source) or a

View File

@ -23,10 +23,17 @@
Connection parameters are *myconn-host*, *myconn-port*, *myconn-user* and
*myconn-pass*."
`(let* ((dbname (or ,dbname *ms-dbname*))
(*mssql-db* (mssql:connect dbname
*msconn-user*
*msconn-pass*
*msconn-host*)))
(*mssql-db* (handler-case
(mssql:connect dbname
*msconn-user*
*msconn-pass*
*msconn-host*)
(condition (e)
(error 'connection-error
:mesg (format nil "~a" e)
:type "MS SQL"
:host *msconn-host*
:user *msconn-user*)))))
(unwind-protect
(progn ,@forms)
(mssql:disconnect *mssql-db*))))

View File

@ -63,16 +63,27 @@
*myconn-pass*."
`(let* ((dbname (or ,dbname *my-dbname*))
(*connection*
(if (and (consp *myconn-host*) (eq :unix (car *myconn-host*)))
(qmynd:mysql-local-connect :path (cdr *myconn-host*)
:username *myconn-user*
:password *myconn-pass*
:database dbname)
(qmynd:mysql-connect :host *myconn-host*
:port *myconn-port*
:username *myconn-user*
:password *myconn-pass*
:database dbname))))
(handler-case
(if (and (consp *myconn-host*) (eq :unix (car *myconn-host*)))
(qmynd:mysql-local-connect :path (cdr *myconn-host*)
:username *myconn-user*
:password *myconn-pass*
:database dbname)
(qmynd:mysql-connect :host *myconn-host*
:port *myconn-port*
:username *myconn-user*
:password *myconn-pass*
:database dbname))
(condition (e)
(error 'connection-error
:mesg (format nil "~a" e)
:type "MySQL"
:host (if (and (consp *myconn-host*)
(eq :unix (car *myconn-host*)))
(cdr *myconn-host*)
*myconn-host*)
:port *myconn-port*
:user *myconn-user*)))))
(unwind-protect
(progn ,@forms)
(qmynd:mysql-disconnect *connection*))))