diff --git a/src/pgsql/schema.lisp b/src/pgsql/schema.lisp index 112f5b8..ae8280d 100644 --- a/src/pgsql/schema.lisp +++ b/src/pgsql/schema.lisp @@ -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) diff --git a/src/sources/mysql/mysql-cast-rules.lisp b/src/sources/mysql/mysql-cast-rules.lisp index 0e6a31e..b1c2541 100644 --- a/src/sources/mysql/mysql-cast-rules.lisp +++ b/src/sources/mysql/mysql-cast-rules.lisp @@ -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."