       (do
         (log/info (trs "There are no pending migrations"))
         false))))
+
+(defn migrate! [db-connection-pool]
+  "Migrates database to the latest schema version. Does nothing if
+  database is already at the latest schema version.  Requires a
+  connection pool because some operations may require an indepdendent
+  database connection.  Returns true if there were any migrations."
+  (try
+    (run-migrations db-connection-pool)
+    (catch java.sql.SQLException e
+      (log/error e (trs "Caught SQLException during migration"))
+      (loop [ex (.getNextException e)]
+        (when ex
+          (log/error ex (trs "Unraveled exception"))
+          (recur (.getNextException ex))))
+      (throw e))))
 
 ;; SPECIAL INDEX HANDLING
 

                                (->> pending
                                     (map (fn [[version migration]]
                                            (let [t0 (now)]
                                            (log/info (trs "Applying database migration version {0}" version))
                                            (sql-or-die (fn [] (let [result (migration)]
                                                                    (record-migration! version)
                                                                    result)))
                                            (log/info (trs "Applied database migration version {0} in {1} ms"
                                                           version (in-millis (interval t0 (now))))))))
                                     (filter map?)
                                     (map ::vacuum-analyze)
                                     (apply set/union small-tables)

    (into (sorted-map)
          (select-keys migrations pending))))

(defn previous-migrations
  "Returns the list of migration numbers that existed before the
  current known set. These migrations can't be upgraded from, but are
