Implement support for on update CURRENT_TIMESTAMP.

That's the MySQL slang for a simple ON UPDATE trigger, and that's what
pgloader nows translate the expression to. Fix #195.
This commit is contained in:
Dimitri Fontaine 2016-03-27 00:58:45 +01:00
parent 156f5a4418
commit d72c711b45
3 changed files with 51 additions and 14 deletions

View File

@ -366,6 +366,7 @@
#:create-views #:create-views
#:format-pgsql-column #:format-pgsql-column
#:format-extra-type #:format-extra-type
#:format-extra-triggers
#:make-pgsql-fkey #:make-pgsql-fkey
#:format-pgsql-create-fkey #:format-pgsql-create-fkey
#:format-pgsql-drop-fkey #:format-pgsql-drop-fkey
@ -596,6 +597,7 @@
#:truncate-tables #:truncate-tables
#:format-pgsql-column #:format-pgsql-column
#:format-extra-type #:format-extra-type
#:format-extra-triggers
#:make-pgsql-fkey #:make-pgsql-fkey
#:format-pgsql-create-fkey #:format-pgsql-create-fkey
#:format-pgsql-drop-fkey #:format-pgsql-drop-fkey

View File

@ -21,24 +21,21 @@
column, or nil of none is required. If no special extra type is ever column, or nil of none is required. If no special extra type is ever
needed, it's allowed not to specialize this generic into a method.")) needed, it's allowed not to specialize this generic into a method."))
;; (defmethod format-pgsql-column ((col pgsql-column)) (defgeneric format-extra-trigger (col &key include-drop)
;; "Return a string representing the PostgreSQL column definition." (:documentation
;; (let* ((column-name "Return a list of string representing the extra SQL commands needed to
;; (apply-identifier-case (pgsql-column-name col))) implement PostgreSQL triggers."))
;; (type-definition
;; (format nil
;; "~a~@[~a~]~:[~; not null~]~@[ default ~a~]"
;; (pgsql-column-type-name col)
;; (pgsql-column-type-mod col)
;; (pgsql-column-nullable col)
;; (pgsql-column-default col))))
;; (format nil "~a ~22t ~a" column-name type-definition)))
(defmethod format-extra-type ((col T) &key include-drop) (defmethod format-extra-type ((col T) &key include-drop)
"The default `format-extra-type' implementation returns an empty list." "The default `format-extra-type' implementation returns an empty list."
(declare (ignorable include-drop)) (declare (ignorable include-drop))
nil) nil)
(defmethod format-extra-triggers ((col T) &key include-drop)
"The default `format-extra-triggers' implementation returns an empty list."
(declare (ignorable include-drop))
nil)
;;; ;;;
;;; API for Foreign Keys ;;; API for Foreign Keys
@ -143,13 +140,18 @@
:for extra-types := (loop :for field :in fields :for extra-types := (loop :for field :in fields
:append (format-extra-type :append (format-extra-type
field :include-drop include-drop)) field :include-drop include-drop))
:for extra-triggers := (loop :for field :in fields
:append (format-extra-triggers
field :include-drop include-drop))
:when include-drop :when include-drop
:collect (drop-table-if-exists-sql table) :collect (drop-table-if-exists-sql table)
:when extra-types :append extra-types :when extra-types :append extra-types
:collect (create-table-sql table :if-not-exists if-not-exists))) :collect (create-table-sql table :if-not-exists if-not-exists)
:when extra-triggers :append extra-triggers))
(defun create-table-list (table-list (defun create-table-list (table-list
&key &key

View File

@ -189,12 +189,45 @@
(let* ((type-name (let* ((type-name
(get-enum-type-name (mysql-column-table-name col) (get-enum-type-name (mysql-column-table-name col)
(mysql-column-name col)))) (mysql-column-name col))))
(format nil "DROP TYPE IF EXISTS ~a;" type-name))) (format nil "DROP TYPE IF EXISTS ~a;" type-name)))
(get-create-enum (mysql-column-table-name col) (get-create-enum (mysql-column-table-name col)
(mysql-column-name col) (mysql-column-name col)
(mysql-column-ctype col)))))) (mysql-column-ctype col))))))
(defmethod format-extra-triggers ((col mysql-column) &key include-drop)
"Return a list of string representing the extra SQL commands needed to
implement some MySQL features as PostgreSQL triggers, such as on update
CURRENT_TIMESTAMP."
(when (string= (mysql-column-extra col) "on update CURRENT_TIMESTAMP")
(let* ((col-name (apply-identifier-case (mysql-column-name col)))
(fun-name (format nil "on_update_current_timestamp_~a" col-name))
(update-fun-sql
(format nil "
CREATE OR REPLACE FUNCTION ~a()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
NEW.~a = now();
RETURN NEW;
END;
$$;"
fun-name col-name))
(trigger-sql
(format nil "
CREATE TRIGGER on_update_current_timestamp
BEFORE UPDATE ON ~a
FOR EACH ROW EXECUTE PROCEDURE ~a();"
(mysql-column-table-name col) fun-name)))
(append
(when include-drop
(list
(format nil "DROP FUNCTION IF EXISTS ~a();" fun-name)
(format nil "DROP TRIGGER IF EXISTS on_update_current_timestamp ON ~a;"
(mysql-column-table-name col))))
(list update-fun-sql trigger-sql)))))
(defmethod cast ((col mysql-column)) (defmethod cast ((col mysql-column))
"Return the PostgreSQL type definition from given MySQL column definition." "Return the PostgreSQL type definition from given MySQL column definition."
(with-slots (table-name name dtype ctype default nullable extra comment) (with-slots (table-name name dtype ctype default nullable extra comment)