diff --git a/src/package.lisp b/src/package.lisp index e2a61aa..a0f7363 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -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* diff --git a/src/pgsql/queries.lisp b/src/pgsql/queries.lisp index 3a6fcfd..663305f 100644 --- a/src/pgsql/queries.lisp +++ b/src/pgsql/queries.lisp @@ -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 diff --git a/src/sources.lisp b/src/sources.lisp index 04e23c4..10f7615 100644 --- a/src/sources.lisp +++ b/src/sources.lisp @@ -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 diff --git a/src/sources/mssql/mssql-schema.lisp b/src/sources/mssql/mssql-schema.lisp index 09ebc99..c89d1f7 100644 --- a/src/sources/mssql/mssql-schema.lisp +++ b/src/sources/mssql/mssql-schema.lisp @@ -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*)))) diff --git a/src/sources/mysql/mysql-schema.lisp b/src/sources/mysql/mysql-schema.lisp index 0473a4d..afb9b25 100644 --- a/src/sources/mysql/mysql-schema.lisp +++ b/src/sources/mysql/mysql-schema.lisp @@ -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*))))