diff --git a/mysql-cast-rules.lisp b/mysql-cast-rules.lisp index 52f85e0..a2953a4 100644 --- a/mysql-cast-rules.lisp +++ b/mysql-cast-rules.lisp @@ -121,7 +121,12 @@ (:source (:type "year") :target (:type "integer")) (:source (:type "enum") - :target (:type ,#'cast-enum))) + :target (:type ,#'cast-enum)) + + ;; geometric data types, just POINT for now + (:source (:type "point") + :target (:type "point") + :using pgloader.transforms::convert-mysql-point)) "Data Type Casting rules to migrate from MySQL to PostgreSQL") (defvar *cast-rules* nil "Specific casting rules added in the command.") @@ -328,7 +333,8 @@ that would be int and int(7) or varchar and varchar(25)." ("k" "bigint" "bigint(20)" nil nil nil) ("l" "numeric" "numeric(18,3)" nil nil nil) ("m" "decimal" "decimal(15,5)" nil nil nil) - ("n" "timestamp" "timestamp" "CURRENT_TIMESTAMP" "NO" "on update CURRENT_TIMESTAMP")))) + ("n" "timestamp" "timestamp" "CURRENT_TIMESTAMP" "NO" "on update CURRENT_TIMESTAMP") + ("o" "point" "point" nil "YES" nil)))) (loop for (name dtype ctype nullable default extra) in columns diff --git a/mysql.lisp b/mysql.lisp index 7ae01aa..888659e 100644 --- a/mysql.lisp +++ b/mysql.lisp @@ -258,6 +258,15 @@ GROUP BY table_name, index_name;" dbname))) ;;; ;;; Map a function to each row extracted from MySQL ;;; +(defun get-column-sql-expression (name type) + "Return per-TYPE SQL expression to use given a column NAME. + + Mostly we just use the name, but in case of POINT we need to use + astext(name)." + (case (intern (string-upcase type) "KEYWORD") + (:point (format nil "astext(`~a`) as `~a`" name name)) + (t (format nil "`~a`" name)))) + (defun get-column-list-with-is-nulls (dbname table-name) "We can't just SELECT *, we need to cater for NULLs in text columns ourselves. This function assumes a valid connection to the MySQL server has been @@ -272,7 +281,7 @@ order by ordinal_position" dbname table-name))) "tinytext" "mediumtext" "longtext") :test #'string-equal) collect nil into nulls - collect (format nil "`~a`" name) into cols + collect (get-column-sql-expression name type) into cols when is-null collect (format nil "`~a` is null" name) into cols and collect t into nulls finally (return (values cols nulls)))) diff --git a/transforms.lisp b/transforms.lisp index 971bfde..ad31528 100644 --- a/transforms.lisp +++ b/transforms.lisp @@ -16,7 +16,8 @@ date-with-no-separator tinyint-to-boolean int-to-ip - ip-range)) + ip-range + convert-mysql-point)) (defun intern-symbol (symbol-name) (intern (string-upcase symbol-name) @@ -83,3 +84,14 @@ (let ((ip-start (int-to-ip (parse-integer start-integer-string))) (ip-end (int-to-ip (parse-integer end-integer-string)))) (concatenate 'simple-base-string ip-start "-" ip-end))) + +(defun convert-mysql-point (mysql-point-as-string) + "Transform the MYSQL-POINT-AS-STRING into a suitable representation for + PostgreSQL. + + Input: \"POINT(48.5513589 7.6926827)\" ; that's using astext(column) + Output: (48.5513589,7.6926827)" + (when mysql-point-as-string + (let* ((point (subseq mysql-point-as-string 5))) + (setf (aref point (position #\Space point)) #\,) + point)))