pgloader/transforms.lisp

81 lines
2.8 KiB
Common Lisp

;;;
;;; Tools to handle data conversion to PostgreSQL format
;;;
;;; Any function that you want to use to transform data with will get looked
;;; up in the pgloader.transforms package, when using the default USING
;;; syntax for transformations.
(defpackage #:pgloader.transforms
(:use #:cl)
(:export #:intern-symbol))
(in-package :pgloader.transforms)
(defun intern-symbol (symbol-name)
(intern (string-upcase symbol-name)
(find-package "PGLOADER.TRANSFORMS")))
(defun zero-dates-to-null (date-string)
"MySQL accepts '0000-00-00' as a date, we want :null instead."
(cond
((null date-string) nil)
((string= date-string "") nil)
((string= date-string "0000-00-00") nil)
((string= date-string "0000-00-00 00:00:00") nil)
(t date-string)))
(defun date-with-no-separator
(date-string
&optional (format '((:year 0 4)
(:month 4 6)
(:day 6 8)
(:hour 8 10)
(:minute 10 12)
(:seconds 12 14))))
"Apply this function when input date in like '20041002152952'"
;; only process non-zero dates
(if (null (zero-dates-to-null date-string)) nil
(destructuring-bind (&key year month day hour minute seconds
&allow-other-keys)
(loop
for (name start end) in format
append (list name (subseq date-string start end)))
(format nil "~a-~a-~a ~a:~a:~a" year month day hour minute seconds))))
(defun tinyint-to-boolean (integer-string)
"When using MySQL, strange things will happen, like encoding booleans into
tinyiny that are either 0 (false) or 1 (true). Of course PostgreSQL wants
'f' and 't', respectively."
(if (string= "0" integer-string) "f" "t"))
(declaim (inline int-to-ip))
(defun int-to-ip (int)
"Transform an IP as integer into its dotted notation, optimised code from
stassats."
(declare (optimize speed)
(type (unsigned-byte 32) int))
(let ((table (load-time-value
(let ((vec (make-array (+ 1 #xFFFF))))
(loop for i to #xFFFF
do (setf (aref vec i)
(coerce (format nil "~a.~a"
(ldb (byte 8 8) i)
(ldb (byte 8 0) i))
'simple-base-string)))
vec)
t)))
(declare (type (simple-array simple-base-string (*)) table))
(concatenate 'simple-base-string
(aref table (ldb (byte 16 16) int))
"."
(aref table (ldb (byte 16 0) int)))))
(declaim (inline ip-range))
(defun ip-range (start-integer-string end-integer-string)
"Transform a couple of integers to an IP4R ip range notation."
(declare (optimize speed)
(type string start-integer-string end-integer-string))
(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)))