MySQL SET datatype support: convert to ENUM Arrays.

This commit is contained in:
Dimitri Fontaine 2013-11-01 11:34:43 +00:00
parent 86afe36c84
commit 63005168fd
4 changed files with 36 additions and 16 deletions

View File

@ -34,6 +34,13 @@
(declare (ignore type ctype typemod))
(format nil "~a_~a" table-name column-name))
(defun cast-set (table-name column-name type ctype typemod)
"Cast MySQL inline SET type to using a PostgreSQL ENUM Array.
The ENUM data type name is hardcoded to be table-name_column-name"
(declare (ignore type ctype typemod))
(format nil "~a_~a[]" table-name column-name))
;;;
;;; The default MySQL Type Casting Rules
;;;
@ -106,9 +113,14 @@
(:source (:type "timestamp") :target (:type "timestamptz"))
(:source (:type "year") :target (:type "integer"))
;; Inline MySQL "interesting" datatype
(:source (:type "enum")
:target (:type ,#'cast-enum))
(:source (:type "set")
:target (:type ,#'cast-set)
:using pgloader.transforms::set-to-enum-array)
;; geometric data types, just POINT for now
(:source (:type "point")
:target (:type "point")
@ -125,7 +137,8 @@
Beware that some data-type are using a typmod looking definition for
things that are not typmods at all: enum."
(unless (string= "enum" data-type)
(unless (or (string= "enum" data-type)
(string= "set" data-type))
(let ((start-1 (position #\( column-type)) ; just before start position
(end (position #\) column-type))) ; just before end position
(when start-1
@ -313,14 +326,15 @@ that would be int and int(7) or varchar and varchar(25)."
("e" "datetime" "datetime" "0000-00-00 00:00:00" nil nil)
("f" "date" "date" "0000-00-00" "NO" nil)
("g" "enum" "ENUM('a', 'b')" nil nil nil)
("h" "int" "int(11)" nil nil nil)
("i" "float" "float(12,2)" nil nil nil)
("j" "double" "double unsigned" nil nil nil)
("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")
("o" "point" "point" nil "YES" nil))))
("h" "set" "SET('a', 'b')" nil nil nil)
("i" "int" "int(11)" nil nil nil)
("j" "float" "float(12,2)" nil nil nil)
("k" "double" "double unsigned" nil nil nil)
("l" "bigint" "bigint(20)" nil nil nil)
("m" "numeric" "numeric(18,3)" nil nil nil)
("n" "decimal" "decimal(15,5)" nil nil nil)
("o" "timestamp" "timestamp" "CURRENT_TIMESTAMP" "NO" "on update CURRENT_TIMESTAMP")
("p" "point" "point" nil "YES" nil))))
(loop
for (name dtype ctype nullable default extra) in columns

View File

@ -101,7 +101,8 @@ order by table_name, ordinal_position" dbname only-tables)))
"MySQL declares ENUM types inline, PostgreSQL wants explicit CREATE TYPE."
(loop
for (name dtype ctype default nullable extra) in cols
when (string-equal "enum" dtype)
when (or (string-equal "enum" dtype)
(string-equal "set" dtype)) ; a SET is an Array of ENUMs
collect (when include-drop
(let* ((type-name
(get-enum-type-name table-name name identifier-case)))
@ -520,7 +521,7 @@ order by ordinal_position" dbname table-name)))
:identifier-case identifier-case)
do
(log-message :notice "~a" sql)
(lp:submit-task channel #'psql-execute-with-timing
(lp:submit-task channel #'pgsql-execute-with-timing
dbname label sql state))))
(defun stream-database (dbname

View File

@ -18,7 +18,8 @@
int-to-ip
ip-range
convert-mysql-point
float-to-string))
float-to-string
set-to-enum-array))
(defun intern-symbol (symbol-name)
(intern (string-upcase symbol-name)
@ -104,3 +105,7 @@
(declare (type float float))
(let ((*read-default-float-format* 'double-float))
(princ-to-string float)))
(defun set-to-enum-array (set-string)
"Transform a MySQL SET value into a PostgreSQL ENUM Array"
(format nil "{~a}" set-string))

View File

@ -8,8 +8,8 @@
*/
LOAD ARCHIVE
FROM http://pgsql.tapoueh.org/temp/foo.zip
INTO postgresql:///pgloader
FROM /Users/dim/Downloads/GeoLiteCity-latest.zip
INTO postgresql:///ip4r
BEFORE LOAD DO
$$ create extension if not exists ip4r; $$,
@ -49,7 +49,7 @@ LOAD ARCHIVE
metroCode null if blanks,
areaCode null if blanks
)
INTO postgresql:///pgloader?geolite.location
INTO postgresql:///ip4r?geolite.location
(
locid,country,region,city,postalCode,
location point using (format nil "(~a,~a)" longitude latitude),
@ -66,7 +66,7 @@ LOAD ARCHIVE
(
startIpNum, endIpNum, locId
)
INTO postgresql:///pgloader?geolite.blocks
INTO postgresql:///ip4r?geolite.blocks
(
iprange ip4r using (ip-range startIpNum endIpNum),
locId