From 782561fd4efed9f39442a2beff0ff0d2fe612b79 Mon Sep 17 00:00:00 2001 From: Dimitri Fontaine Date: Wed, 3 Feb 2016 12:27:58 +0100 Subject: [PATCH] Handle default value transforms errors, fix #333. It turns out that MySQL catalog always store default value as strings even when the column itself is of type bytea. In some cases, it's then impossible to transform the expected bytea from a string. In passing, move some code around to fix dependencies and make it possible to issue log warnings from the default value printing code. --- pgloader.asd | 4 ++++ src/package.lisp | 6 ++--- src/utils/pg-format-column.lisp | 40 +++++++++++++++++++++++++++++++++ src/utils/schema-structs.lisp | 32 -------------------------- src/utils/transforms.lisp | 4 +++- 5 files changed, 49 insertions(+), 37 deletions(-) create mode 100644 src/utils/pg-format-column.lisp diff --git a/pgloader.asd b/pgloader.asd index 0ab7010..f2b55df 100644 --- a/pgloader.asd +++ b/pgloader.asd @@ -76,6 +76,10 @@ "report")) (:file "archive" :depends-on ("logs")) + (:file "pg-format-column" :depends-on ("schema-structs" + "monitor" + "state")) + ;; generic connection api (:file "connection" :depends-on ("archive")))) diff --git a/src/package.lisp b/src/package.lisp index 4642838..4219148 100644 --- a/src/package.lisp +++ b/src/package.lisp @@ -68,7 +68,7 @@ #:column-name #:column-type-name #:column-type-mod - #:column-type-nullable + #:column-nullable #:column-default #:column-comment #:column-transform @@ -99,9 +99,7 @@ #:push-to-end #:with-schema - #:format-table-name - #:format-default-value - #:format-column)) + #:format-table-name)) (defpackage #:pgloader.state (:use #:cl #:pgloader.params #:pgloader.schema) diff --git a/src/utils/pg-format-column.lisp b/src/utils/pg-format-column.lisp new file mode 100644 index 0000000..ad371b9 --- /dev/null +++ b/src/utils/pg-format-column.lisp @@ -0,0 +1,40 @@ +;;; +;;; PostgreSQL column and type output +;;; + +(in-package #:pgloader.utils) + +(defun format-default-value (default &optional transform) + "Returns suitably quoted default value for CREATE TABLE command." + (cond + ((null default) "NULL") + ((and (stringp default) (string= "NULL" default)) default) + ((and (stringp default) (string= "CURRENT_TIMESTAMP" default)) default) + ((and (stringp default) (string= "CURRENT TIMESTAMP" default)) + "CURRENT_TIMESTAMP") + ((and (stringp default) (string= "newsequentialid()" default)) + "uuid_generate_v1()") + (t + ;; apply the transformation function to the default value + (if transform (format-default-value + (handler-case + (funcall transform default) + (condition (c) + (log-message :warning + "Failed to transform default value ~s: ~a" + default c) + ;; can't transform: return nil + nil))) + (format nil "'~a'" default))))) + +(defmethod format-column ((column column)) + "Format the PostgreSQL data type." + (format nil + "~a ~22t ~a~:[~*~;~a~]~:[ not null~;~]~:[~; default ~a~]" + (column-name column) + (column-type-name column) + (column-type-mod column) + (column-type-mod column) + (column-nullable column) + (column-default column) + (column-default column))) diff --git a/src/utils/schema-structs.lisp b/src/utils/schema-structs.lisp index 6eac209..d05c02e 100644 --- a/src/utils/schema-structs.lisp +++ b/src/utils/schema-structs.lisp @@ -347,35 +347,3 @@ (cdr ,table-name))) (string ,table-name)))) ,@body)) - - - -;;; -;;; PostgreSQL column and type output -;;; -(defun format-default-value (default &optional transform) - "Returns suitably quoted default value for CREATE TABLE command." - (cond - ((null default) "NULL") - ((and (stringp default) (string= "NULL" default)) default) - ((and (stringp default) (string= "CURRENT_TIMESTAMP" default)) default) - ((and (stringp default) (string= "CURRENT TIMESTAMP" default)) - "CURRENT_TIMESTAMP") - ((and (stringp default) (string= "newsequentialid()" default)) - "uuid_generate_v1()") - (t - ;; apply the transformation function to the default value - (if transform (format-default-value (funcall transform default)) - (format nil "'~a'" default))))) - -(defmethod format-column ((column column)) - "Format the PostgreSQL data type." - (with-slots (name type-name type-mod nullable default transform) column - (format nil - "~a ~22t ~a~:[~*~;~a~]~:[ not null~;~]~:[~; default ~a~]" - name - type-name - type-mod - type-mod - nullable - default default))) diff --git a/src/utils/transforms.lisp b/src/utils/transforms.lisp index 4e33e66..757cded 100644 --- a/src/utils/transforms.lisp +++ b/src/utils/transforms.lisp @@ -226,7 +226,9 @@ (declare (type (or null string (simple-array (unsigned-byte 8) (*))) vector)) (etypecase vector (null nil) - (string (assert (string= "" vector)) nil) + (string (if (string= "" vector) + nil + (error "byte-vector-to-bytea called on a string: ~s" vector))) (simple-array (let ((hex-digits "0123456789abcdef") (bytea (make-array (+ 2 (* 2 (length vector)))