Review on update CURRENT_TIMESTAMP support.

Make it work on the second run, when the triggers and functions have
already been deplyed, by doing the DROP function and trigger before we
CREATE the table, then CREATE them again: we need to split the list
again.
This commit is contained in:
Dimitri Fontaine 2016-03-27 19:13:33 +02:00
parent 45924be87d
commit cdc5d2f06b
2 changed files with 37 additions and 21 deletions

View File

@ -21,7 +21,7 @@
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."))
(defgeneric format-extra-trigger (col &key include-drop)
(defgeneric format-extra-triggers (table col &key drop)
(:documentation
"Return a list of string representing the extra SQL commands needed to
implement PostgreSQL triggers."))
@ -31,9 +31,9 @@
(declare (ignorable include-drop))
nil)
(defmethod format-extra-triggers ((col T) &key include-drop)
(defmethod format-extra-triggers ((table T) (col T) &key drop)
"The default `format-extra-triggers' implementation returns an empty list."
(declare (ignorable include-drop))
(declare (ignorable table col drop))
nil)
@ -140,18 +140,25 @@
:for extra-types := (loop :for field :in fields
:append (format-extra-type
field :include-drop include-drop))
:for extra-triggers := (loop :for field :in fields
:append (format-extra-triggers
field :include-drop include-drop))
:for pre-extra-triggers
:= (when include-drop
(loop :for field :in fields
:append (format-extra-triggers table field :drop t)))
:for post-extra-triggers
:= (loop :for field :in fields
:append (format-extra-triggers table field))
:when include-drop
:collect (drop-table-if-exists-sql table)
:when extra-types :append extra-types
:when pre-extra-triggers :append pre-extra-triggers
:collect (create-table-sql table :if-not-exists if-not-exists)
:when extra-triggers :append extra-triggers))
:when post-extra-triggers :append post-extra-triggers))
(defun create-table-list (table-list
&key
@ -222,21 +229,21 @@
(catalog (table-list catalog-or-table))
(schema (table-list catalog-or-table))
(table (list catalog-or-table)))))))
(pomo:execute sql))))
(pgsql-execute sql))))
(defun disable-triggers (table-name)
"Disable triggers on TABLE-NAME. Needs to be called with a PostgreSQL
connection already opened."
(let ((sql (format nil "ALTER TABLE ~a DISABLE TRIGGER ALL;"
(apply-identifier-case table-name))))
(pomo:execute sql)))
(pgsql-execute sql)))
(defun enable-triggers (table-name)
"Disable triggers on TABLE-NAME. Needs to be called with a PostgreSQL
connection already opened."
(let ((sql (format nil "ALTER TABLE ~a ENABLE TRIGGER ALL;"
(apply-identifier-case table-name))))
(pomo:execute sql)))
(pgsql-execute sql)))
(defmacro with-disabled-triggers ((table-name &key disable-triggers)
&body forms)

View File

@ -195,12 +195,19 @@
(mysql-column-name col)
(mysql-column-ctype col))))))
(defmethod format-extra-triggers ((col mysql-column) &key include-drop)
(defmethod format-extra-triggers ((table table) (col mysql-column) &key 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."
CURRENT_TIMESTAMP.
When drop is t, only output the DROP sql statements."
(when (string= (mysql-column-extra col) "on update CURRENT_TIMESTAMP")
(let* ((col-name (apply-identifier-case (mysql-column-name col)))
(let* ((field-pos (position (mysql-column-name col)
(table-field-list table)
:key #'mysql-column-name
:test #'string=))
(col-name (funcall #'column-name
(nth field-pos (table-column-list table))))
(fun-name (format nil "on_update_current_timestamp_~a" col-name))
(update-fun-sql
(format nil "
@ -219,14 +226,16 @@ $$;"
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)))))
(format-table-name table) fun-name)))
(if drop
(list
;; don't DROP the function here, because it might be shared by
;; several tables with "on update" rules on a field sharing the
;; same name (such as "last_update").
;; the CREATE OR REPLACE FUNCTION will then be innoffensive.
(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))
"Return the PostgreSQL type definition from given MySQL column definition."