mirror of
https://github.com/dimitri/pgloader.git
synced 2025-08-07 23:07:00 +02:00
Implement MySQL migration option "downcase|quote identifier".
This commit is contained in:
parent
020cd7d3ed
commit
c9dd959fbd
@ -7,6 +7,12 @@
|
|||||||
;;;
|
;;;
|
||||||
;;; Some functions to deal with ENUM types
|
;;; Some functions to deal with ENUM types
|
||||||
;;;
|
;;;
|
||||||
|
(defun apply-identifier-case (identifier case)
|
||||||
|
"Return a SQL string to use in the output part of a MySQL query."
|
||||||
|
(ecase case
|
||||||
|
(:downcase (string-downcase identifier))
|
||||||
|
(:quote (format nil "\"~a\"" identifier))))
|
||||||
|
|
||||||
(defun explode-mysql-enum (ctype)
|
(defun explode-mysql-enum (ctype)
|
||||||
"Convert MySQL ENUM expression into a list of labels."
|
"Convert MySQL ENUM expression into a list of labels."
|
||||||
;; from: "ENUM('small', 'medium', 'large')"
|
;; from: "ENUM('small', 'medium', 'large')"
|
||||||
@ -14,15 +20,17 @@
|
|||||||
(mapcar (lambda (x) (string-trim "' )" x))
|
(mapcar (lambda (x) (string-trim "' )" x))
|
||||||
(sq:split-sequence #\, ctype :start (position #\' ctype))))
|
(sq:split-sequence #\, ctype :start (position #\' ctype))))
|
||||||
|
|
||||||
(defun get-enum-type-name (table-name column-name)
|
(defun get-enum-type-name (table-name column-name identifier-case)
|
||||||
"Return the Type Name we're going to use in PostgreSQL."
|
"Return the Type Name we're going to use in PostgreSQL."
|
||||||
(format nil "~a_~a" table-name column-name))
|
(apply-identifier-case (format nil "~a_~a" table-name column-name)
|
||||||
|
identifier-case))
|
||||||
|
|
||||||
(defun get-create-enum (table-name column-name ctype)
|
(defun get-create-enum (table-name column-name ctype
|
||||||
|
&key (identifier-case :downcase))
|
||||||
"Return a PostgreSQL CREATE ENUM TYPE statement from MySQL enum column."
|
"Return a PostgreSQL CREATE ENUM TYPE statement from MySQL enum column."
|
||||||
(with-output-to-string (s)
|
(with-output-to-string (s)
|
||||||
(format s "CREATE TYPE ~a AS ENUM (~{'~a'~^, ~});"
|
(format s "CREATE TYPE ~a AS ENUM (~{'~a'~^, ~});"
|
||||||
(get-enum-type-name table-name column-name)
|
(get-enum-type-name table-name column-name identifier-case)
|
||||||
(explode-mysql-enum ctype))))
|
(explode-mysql-enum ctype))))
|
||||||
|
|
||||||
(defun cast-enum (table-name column-name type ctype typemod)
|
(defun cast-enum (table-name column-name type ctype typemod)
|
||||||
|
50
mysql.lisp
50
mysql.lisp
@ -72,45 +72,65 @@ order by table_name, ordinal_position" dbname)))
|
|||||||
;; free resources
|
;; free resources
|
||||||
(cl-mysql:disconnect)))
|
(cl-mysql:disconnect)))
|
||||||
|
|
||||||
(defun get-create-type (table-name cols &key include-drop)
|
(defun get-create-type (table-name cols &key identifier-case include-drop)
|
||||||
"MySQL declares ENUM types inline, PostgreSQL wants explicit CREATE TYPE."
|
"MySQL declares ENUM types inline, PostgreSQL wants explicit CREATE TYPE."
|
||||||
(loop
|
(loop
|
||||||
for (name dtype ctype default nullable extra) in cols
|
for (name dtype ctype default nullable extra) in cols
|
||||||
when (string-equal "enum" dtype)
|
when (string-equal "enum" dtype)
|
||||||
collect (when include-drop
|
collect (when include-drop
|
||||||
(let ((type-name (get-enum-type-name table-name name)))
|
(let* ((type-name
|
||||||
|
(get-enum-type-name table-name name identifier-case)))
|
||||||
(format nil "DROP TYPE IF EXISTS ~a;" type-name)))
|
(format nil "DROP TYPE IF EXISTS ~a;" type-name)))
|
||||||
and collect (get-create-enum table-name name ctype)))
|
and collect (get-create-enum table-name name ctype
|
||||||
|
:identifier-case identifier-case)))
|
||||||
|
|
||||||
(defun get-create-table (table-name cols)
|
(defun get-create-table (table-name cols &key identifier-case)
|
||||||
"Return a PostgreSQL CREATE TABLE statement from MySQL columns"
|
"Return a PostgreSQL CREATE TABLE statement from MySQL columns"
|
||||||
(with-output-to-string (s)
|
(with-output-to-string (s)
|
||||||
(format s "CREATE TABLE ~a ~%(~%" table-name)
|
(let ((table-name (apply-identifier-case table-name identifier-case)))
|
||||||
|
(format s "CREATE TABLE ~a ~%(~%" table-name))
|
||||||
(loop
|
(loop
|
||||||
for ((name dtype ctype default nullable extra) . last?) on cols
|
for ((name dtype ctype default nullable extra) . last?) on cols
|
||||||
for pg-coldef = (cast table-name name dtype ctype default nullable extra)
|
for pg-coldef = (cast table-name name dtype ctype default nullable extra)
|
||||||
do (format s " \"~a\" ~22t ~a~:[~;,~]~%" name pg-coldef last?))
|
for colname = (apply-identifier-case name identifier-case)
|
||||||
|
do (format s " ~a ~22t ~a~:[~;,~]~%" colname pg-coldef last?))
|
||||||
(format s ");~%")))
|
(format s ");~%")))
|
||||||
|
|
||||||
(defun get-drop-table-if-exists (table-name)
|
(defun get-drop-table-if-exists (table-name &key identifier-case)
|
||||||
"Return the PostgreSQL DROP TABLE IF EXISTS statement for TABLE-NAME."
|
"Return the PostgreSQL DROP TABLE IF EXISTS statement for TABLE-NAME."
|
||||||
(format nil "DROP TABLE IF EXISTS ~a;~%" table-name))
|
(let ((table-name (apply-identifier-case table-name identifier-case)))
|
||||||
|
(format nil "DROP TABLE IF EXISTS ~a;~%" table-name)))
|
||||||
|
|
||||||
(defun get-pgsql-create-tables (all-columns &key include-drop)
|
(defun get-pgsql-create-tables (all-columns
|
||||||
|
&key
|
||||||
|
include-drop
|
||||||
|
(identifier-case :downcase))
|
||||||
"Return the list of CREATE TABLE statements to run against PostgreSQL"
|
"Return the list of CREATE TABLE statements to run against PostgreSQL"
|
||||||
(loop
|
(loop
|
||||||
for (table-name . cols) in all-columns
|
for (table-name . cols) in all-columns
|
||||||
for extra-types = (get-create-type table-name cols :include-drop include-drop)
|
for extra-types = (get-create-type table-name cols
|
||||||
when include-drop collect (get-drop-table-if-exists table-name)
|
:identifier-case identifier-case
|
||||||
|
:include-drop include-drop)
|
||||||
|
when include-drop
|
||||||
|
collect (get-drop-table-if-exists table-name
|
||||||
|
:identifier-case identifier-case)
|
||||||
|
|
||||||
when extra-types append extra-types
|
when extra-types append extra-types
|
||||||
collect (get-create-table table-name cols)))
|
|
||||||
|
collect (get-create-table table-name cols
|
||||||
|
:identifier-case identifier-case)))
|
||||||
|
|
||||||
(defun pgsql-create-tables (dbname all-columns
|
(defun pgsql-create-tables (dbname all-columns
|
||||||
&key (pg-dbname dbname) include-drop)
|
&key
|
||||||
|
(identifier-case :downcase)
|
||||||
|
(pg-dbname dbname)
|
||||||
|
include-drop)
|
||||||
"Create all MySQL tables in database dbname in PostgreSQL"
|
"Create all MySQL tables in database dbname in PostgreSQL"
|
||||||
(loop
|
(loop
|
||||||
for nb-tables from 0
|
for nb-tables from 0
|
||||||
for sql in (get-pgsql-create-tables all-columns :include-drop include-drop)
|
for sql in (get-pgsql-create-tables all-columns
|
||||||
|
:identifier-case identifier-case
|
||||||
|
:include-drop include-drop)
|
||||||
do (pgloader.pgsql:execute pg-dbname sql)
|
do (pgloader.pgsql:execute pg-dbname sql)
|
||||||
finally (return nb-tables)))
|
finally (return nb-tables)))
|
||||||
|
|
||||||
@ -430,6 +450,7 @@ order by ordinal_position" dbname table-name)))
|
|||||||
(include-drop nil)
|
(include-drop nil)
|
||||||
(create-indexes t)
|
(create-indexes t)
|
||||||
(reset-sequences t)
|
(reset-sequences t)
|
||||||
|
(identifier-case :downcase) ; or :quote
|
||||||
(truncate t)
|
(truncate t)
|
||||||
only-tables)
|
only-tables)
|
||||||
"Export MySQL data and Import it into PostgreSQL"
|
"Export MySQL data and Import it into PostgreSQL"
|
||||||
@ -443,6 +464,7 @@ order by ordinal_position" dbname table-name)))
|
|||||||
(with-silent-timing *state* dbname
|
(with-silent-timing *state* dbname
|
||||||
(format nil "~:[~;DROP then ~]CREATE TABLES" include-drop)
|
(format nil "~:[~;DROP then ~]CREATE TABLES" include-drop)
|
||||||
(pgsql-create-tables dbname all-columns
|
(pgsql-create-tables dbname all-columns
|
||||||
|
:identifier-case identifier-case
|
||||||
:pg-dbname pg-dbname
|
:pg-dbname pg-dbname
|
||||||
:include-drop include-drop)))
|
:include-drop include-drop)))
|
||||||
|
|
||||||
|
23
parser.lisp
23
parser.lisp
@ -154,7 +154,10 @@ Here's a quick description of the format we're parsing here:
|
|||||||
(def-keyword-rule "name")
|
(def-keyword-rule "name")
|
||||||
(def-keyword-rule "tables")
|
(def-keyword-rule "tables")
|
||||||
(def-keyword-rule "indexes")
|
(def-keyword-rule "indexes")
|
||||||
(def-keyword-rule "sequences"))
|
(def-keyword-rule "sequences")
|
||||||
|
(def-keyword-rule "downcase")
|
||||||
|
(def-keyword-rule "quote")
|
||||||
|
(def-keyword-rule "identifiers"))
|
||||||
|
|
||||||
(defrule kw-auto-increment (and "auto_increment" (* (or #\Tab #\Space)))
|
(defrule kw-auto-increment (and "auto_increment" (* (or #\Tab #\Space)))
|
||||||
(:constant :auto-increment))
|
(:constant :auto-increment))
|
||||||
@ -370,12 +373,19 @@ Here's a quick description of the format we're parsing here:
|
|||||||
(defrule option-reset-sequences (and kw-reset kw-sequences)
|
(defrule option-reset-sequences (and kw-reset kw-sequences)
|
||||||
(:constant (cons :reset-sequences t)))
|
(:constant (cons :reset-sequences t)))
|
||||||
|
|
||||||
|
(defrule option-identifiers-case (and (or kw-downcase kw-quote) kw-identifiers)
|
||||||
|
(:lambda (id-case)
|
||||||
|
(destructuring-bind (action id) id-case
|
||||||
|
(declare (ignore id))
|
||||||
|
(cons :identifier-case action))))
|
||||||
|
|
||||||
(defrule mysql-option (or option-workers
|
(defrule mysql-option (or option-workers
|
||||||
option-truncate
|
option-truncate
|
||||||
option-drop-tables
|
option-drop-tables
|
||||||
option-create-tables
|
option-create-tables
|
||||||
option-create-indexes
|
option-create-indexes
|
||||||
option-reset-sequences))
|
option-reset-sequences
|
||||||
|
option-identifiers-case))
|
||||||
|
|
||||||
(defrule another-mysql-option (and #\, ignore-whitespace mysql-option)
|
(defrule another-mysql-option (and #\, ignore-whitespace mysql-option)
|
||||||
(:lambda (source)
|
(:lambda (source)
|
||||||
@ -891,10 +901,11 @@ LOAD FROM http:///tapoueh.org/db.t
|
|||||||
LOAD DATABASE FROM mysql://localhost:3306/dbname
|
LOAD DATABASE FROM mysql://localhost:3306/dbname
|
||||||
INTO postgresql://localhost/db
|
INTO postgresql://localhost/db
|
||||||
WITH drop tables,
|
WITH drop tables,
|
||||||
truncate,
|
truncate,
|
||||||
create tables,
|
create tables,
|
||||||
create indexes,
|
create indexes,
|
||||||
reset sequences
|
reset sequences,
|
||||||
|
downcase identifiers
|
||||||
SET guc_1 = 'value', guc_2 = 'other value'
|
SET guc_1 = 'value', guc_2 = 'other value'
|
||||||
CAST column col1 to timestamptz drop default using zero-dates-to-null,
|
CAST column col1 to timestamptz drop default using zero-dates-to-null,
|
||||||
type varchar to text,
|
type varchar to text,
|
||||||
|
Loading…
Reference in New Issue
Block a user