mirror of
https://github.com/dimitri/pgloader.git
synced 2025-08-08 23:37:00 +02:00
99 lines
4.3 KiB
Common Lisp
99 lines
4.3 KiB
Common Lisp
;;;
|
|
;;; Tools to handle the SQLite Database
|
|
;;;
|
|
|
|
(in-package :pgloader.sqlite)
|
|
|
|
(defvar *sqlite-db* nil
|
|
"The SQLite database connection handler.")
|
|
|
|
(defparameter *sqlite-default-cast-rules*
|
|
`((:source (:type "character") :target (:type "text" :drop-typemod t))
|
|
(:source (:type "varchar") :target (:type "text" :drop-typemod t))
|
|
(:source (:type "nvarchar") :target (:type "text" :drop-typemod t))
|
|
(:source (:type "char") :target (:type "text" :drop-typemod t))
|
|
(:source (:type "nchar") :target (:type "text" :drop-typemod t))
|
|
(:source (:type "clob") :target (:type "text" :drop-typemod t))
|
|
|
|
(:source (:type "tinyint") :target (:type "smallint"))
|
|
|
|
(:source (:type "float") :target (:type "float")
|
|
:using pgloader.transforms::float-to-string)
|
|
|
|
(:source (:type "real") :target (:type "real")
|
|
:using pgloader.transforms::float-to-string)
|
|
|
|
(:source (:type "double") :target (:type "double precision")
|
|
:using pgloader.transforms::float-to-string)
|
|
|
|
(:source (:type "numeric") :target (:type "numeric")
|
|
:using pgloader.transforms::float-to-string)
|
|
|
|
(:source (:type "blob") :target (:type "bytea")
|
|
:using pgloader.transforms::byte-vector-to-bytea)
|
|
|
|
(:source (:type "datetime") :target (:type "timestamptz")
|
|
:using pgloader.transforms::sqlite-timestamp-to-timestamp)
|
|
|
|
(:source (:type "timestamp") :target (:type "timestamp")
|
|
:using pgloader.transforms::sqlite-timestamp-to-timestamp)
|
|
|
|
(:source (:type "timestamptz") :target (:type "timestamptz")
|
|
:using pgloader.transforms::sqlite-timestamp-to-timestamp))
|
|
"Data Type Casting to migrate from SQLite to PostgreSQL")
|
|
|
|
(defstruct (coldef
|
|
(:constructor make-coldef (table-name
|
|
seq name dtype ctype
|
|
nullable default pk-id)))
|
|
table-name seq name dtype ctype nullable default pk-id)
|
|
|
|
(defun normalize (sqlite-type-name)
|
|
"SQLite only has a notion of what MySQL calls column_type, or ctype in the
|
|
CAST machinery. Transform it to the data_type, or dtype."
|
|
(if (string= sqlite-type-name "")
|
|
;; yes SQLite allows for empty type names
|
|
"text"
|
|
(let* ((sqlite-type-name (string-downcase sqlite-type-name))
|
|
(tokens (remove-if (lambda (token)
|
|
(or (member token '("unsigned" "short"
|
|
"varying" "native")
|
|
:test #'string-equal)
|
|
;; remove typemod too, as in "integer (8)"
|
|
(char= #\( (aref token 0))))
|
|
(sq:split-sequence #\Space sqlite-type-name))))
|
|
(assert (= 1 (length tokens)))
|
|
(first tokens))))
|
|
|
|
(defun ctype-to-dtype (sqlite-type-name)
|
|
"In SQLite we only get the ctype, e.g. int(7), but here we want the base
|
|
data type behind it, e.g. int."
|
|
(let* ((ctype (normalize sqlite-type-name))
|
|
(paren-pos (position #\( ctype)))
|
|
(if paren-pos (subseq ctype 0 paren-pos) ctype)))
|
|
|
|
(defun cast-sqlite-column-definition-to-pgsql (sqlite-column)
|
|
"Return the PostgreSQL column definition from the MySQL one."
|
|
(multiple-value-bind (column fn)
|
|
(with-slots (table-name name dtype ctype default nullable)
|
|
sqlite-column
|
|
(cast table-name name dtype ctype default nullable nil))
|
|
;; the SQLite driver smartly maps data to the proper CL type, but the
|
|
;; pgloader API only wants to see text representations to send down the
|
|
;; COPY protocol.
|
|
(values column (or fn (lambda (val) (if val (format nil "~a" val) :null))))))
|
|
|
|
(defmethod cast-to-bytea-p ((col coldef))
|
|
"Returns a generalized boolean, non-nil when the column is casted to a
|
|
PostgreSQL bytea column."
|
|
(string= "bytea" (cast-sqlite-column-definition-to-pgsql col)))
|
|
|
|
(defmethod format-pgsql-column ((col coldef))
|
|
"Return a string representing the PostgreSQL column definition."
|
|
(let* ((column-name (apply-identifier-case (coldef-name col)))
|
|
(type-definition
|
|
(with-slots (table-name name dtype ctype nullable default)
|
|
col
|
|
(cast table-name name dtype ctype default nullable nil))))
|
|
(format nil "~a ~22t ~a" column-name type-definition)))
|