From 5b6adb02b090081ef4a448f0f1b3d36561d57a18 Mon Sep 17 00:00:00 2001 From: Dimitri Fontaine Date: Sat, 10 Sep 2016 18:01:04 +0200 Subject: [PATCH] Implement and use DROP ... IF EXISTS. In cases where we have a WITH include drop option, we are generating lots of SQL DROP statements. We may be running an empty target database or in other situations where the target object of the DROP command might not exists. Add support for that case. --- src/pgsql/pgsql-create-schema.lisp | 13 ++++----- src/pgsql/pgsql-ddl.lisp | 42 +++++++++++++++++------------- src/utils/catalog.lisp | 2 +- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/src/pgsql/pgsql-create-schema.lisp b/src/pgsql/pgsql-create-schema.lisp index 479b634..c7879bc 100644 --- a/src/pgsql/pgsql-create-schema.lisp +++ b/src/pgsql/pgsql-create-schema.lisp @@ -26,7 +26,7 @@ (loop :for sqltype :in sqltype-list :when include-drop :count t - :do (pgsql-execute (format-drop-sql sqltype :cascade t) + :do (pgsql-execute (format-drop-sql sqltype :cascade t :if-exists t) :client-min-messages client-min-messages) :do (pgsql-execute (format-create-sql sqltype :if-not-exists if-not-exists) @@ -38,8 +38,9 @@ include-drop) "Return the list of CREATE TABLE statements to run against PostgreSQL." (loop :for table :in table-list + :when include-drop - :collect (format-drop-sql table :cascade t) + :collect (format-drop-sql table :cascade t :if-exists t) :collect (format-create-sql table :if-not-exists if-not-exists))) @@ -169,13 +170,13 @@ "Drop all Foreign Key Definitions given, to prepare for a clean run." (loop :for table :in (table-list catalog) :sum (loop :for fkey :in (table-fkey-list table) - :for sql := (format-drop-sql fkey :cascade cascade) + :for sql := (format-drop-sql fkey :cascade cascade :if-exists t) :do (pgsql-execute sql) :count t) ;; also DROP the foreign keys that depend on the indexes we want to DROP :sum (loop :for index :in (table-index-list table) :sum (loop :for fkey :in (index-fk-deps index) - :for sql := (format-drop-sql fkey :cascade t) + :for sql := (format-drop-sql fkey :cascade t :if-exists t) :do (progn (log-message :debug "EXTRA FK DEPS!") (pgsql-execute sql)) @@ -257,7 +258,7 @@ (table (table-index-list table-or-catalog)) (catalog (loop :for table :in (table-list table-or-catalog) :append (table-index-list table)))) - :collect (format-drop-sql index :cascade cascade)))) + :collect (format-drop-sql index :cascade cascade :if-exists t)))) (pgsql-execute sql-index-list) ;; return how many indexes we just DROPed (length sql-index-list))) @@ -265,7 +266,7 @@ ;;; ;;; Higher level API to care about indexes ;;; -(defun maybe-drop-indexes (catalog &key (section :pre) drop-indexes) +(defun maybe-drop-indexes (catalog &key drop-indexes) "Drop the indexes for TABLE-NAME on TARGET PostgreSQL connection, and returns a list of indexes to create again. A PostgreSQL connection must already be active when calling that function." diff --git a/src/pgsql/pgsql-ddl.lisp b/src/pgsql/pgsql-ddl.lisp index a029787..6ad5930 100644 --- a/src/pgsql/pgsql-ddl.lisp +++ b/src/pgsql/pgsql-ddl.lisp @@ -12,8 +12,9 @@ if-not-exists (schema-name schema))) -(defmethod format-drop-sql ((schema schema) &key (stream nil) cascade) - (format stream "DROP SCHEMA ~s~@[ CASCADE~];" (schema-name schema) cascade)) +(defmethod format-drop-sql ((schema schema) &key (stream nil) cascade if-exists) + (format stream "DROP SCHEMA~@[ IF EXISTS~] ~s~@[ CASCADE~];" + if-exists (schema-name schema) cascade)) ;;; @@ -27,8 +28,9 @@ (sqltype-name sqltype) (sqltype-extra sqltype))))) -(defmethod format-drop-sql ((sqltype sqltype) &key (stream nil) cascade) - (format stream "DROP TYPE ~s~@[ CASCADE~];" (sqltype-name sqltype) cascade)) +(defmethod format-drop-sql ((sqltype sqltype) &key (stream nil) cascade if-exists) + (format stream "DROP TYPE~:[~; IF EXISTS~] ~s~@[ CASCADE~];" + if-exists (sqltype-name sqltype) cascade)) ;;; @@ -59,11 +61,11 @@ (format s "~:[~;,~]~%" last?)))) (format s ");~%")))) -(defmethod format-drop-sql ((table table) &key (stream nil) cascade) +(defmethod format-drop-sql ((table table) &key (stream nil) cascade (if-exists t)) "Return the PostgreSQL DROP TABLE IF EXISTS statement for TABLE-NAME." (format stream - "DROP TABLE IF EXISTS ~a~@[ CASCADE~];" - (format-table-name table) cascade)) + "DROP TABLE~:[~; IF EXISTS~] ~a~@[ CASCADE~];" + if-exists (format-table-name table) cascade)) ;;; @@ -184,21 +186,23 @@ (index-columns index) (index-filter index))))))) -(defmethod format-drop-sql ((index index) &key (stream nil) cascade) +(defmethod format-drop-sql ((index index) &key (stream nil) cascade if-exists) (let* ((schema-name (schema-name (index-schema index))) (index-name (index-name index))) (cond ((index-conname index) ;; here always quote the constraint name, currently the name ;; comes from one source only, the PostgreSQL database catalogs, ;; so don't question it, quote it. - (format stream "ALTER TABLE ~a DROP CONSTRAINT ~s~@[ CASCADE~];" + (format stream + "ALTER TABLE ~a DROP CONSTRAINT~:[~; IF EXISTS~] ~s~@[ CASCADE~];" (format-table-name (index-table index)) + if-exists (index-conname index) cascade)) (t - (format stream "DROP INDEX ~@[~a.~]~a~@[ CASCADE~];" - schema-name index-name cascade))))) + (format stream "DROP INDEX~:[~; IF EXISTS~] ~@[~a.~]~a~@[ CASCADE~];" + if-exists schema-name index-name cascade))))) ;;; @@ -223,11 +227,11 @@ (fkey-delete-rule fk) (fkey-delete-rule fk)))) -(defmethod format-drop-sql ((fk fkey) &key (stream nil) cascade) +(defmethod format-drop-sql ((fk fkey) &key (stream nil) cascade if-exists) (let* ((constraint-name (fkey-name fk)) (table-name (format-table-name (fkey-table fk)))) - (format stream "ALTER TABLE ~a DROP CONSTRAINT ~s~@[ CASCADE~];" - table-name constraint-name cascade))) + (format stream "ALTER TABLE ~a DROP CONSTRAINT~:[~; IF EXISTS~] ~s~@[ CASCADE~];" + table-name if-exists constraint-name cascade))) ;;; @@ -242,9 +246,10 @@ (format-table-name (trigger-table trigger)) (trigger-procedure-name trigger))) -(defmethod format-drop-sql ((trigger trigger) &key (stream nil) cascade) +(defmethod format-drop-sql ((trigger trigger) &key (stream nil) cascade if-exists) (format stream - "DROP TRIGGER ~a ON ~a~@[ CASCADE~];" + "DROP TRIGGER~:[~; IF EXISTS~] ~a ON ~a~@[ CASCADE~];" + if-exists (trigger-name trigger) (format-table-name (trigger-table trigger)) cascade)) @@ -262,9 +267,10 @@ (procedure-language procedure) (procedure-body procedure))) -(defmethod format-drop-sql ((procedure procedure) &key (stream nil) cascade) +(defmethod format-drop-sql ((procedure procedure) &key (stream nil) cascade if-exists) (format stream - "DROP FUNCTION ~a()~@[ CASCADE~];" (procedure-name procedure) cascade)) + "DROP FUNCTION~:[~; IF EXISTS~] ~a()~@[ CASCADE~];" + if-exists (procedure-name procedure) cascade)) ;;; diff --git a/src/utils/catalog.lisp b/src/utils/catalog.lisp index dc3f329..5fc7c1d 100644 --- a/src/utils/catalog.lisp +++ b/src/utils/catalog.lisp @@ -27,7 +27,7 @@ (:documentation "Generate proper SQL command to create OBJECT in PostgreSQL. The output is written to STREAM.")) -(defgeneric format-drop-sql (object &key stream cascade) +(defgeneric format-drop-sql (object &key stream cascade if-exists) (:documentation "Generate proper SQL command to drop OBJECT in PostgreSQL. The output is written to STREAM."))