GithubHelp home page GithubHelp logo

migratus's Introduction

Migratus

CircleCI

MIGRATE ALL THE THINGS!

A general migration framework, with implementations for migrations as SQL scripts or general Clojure code.

Designed to be compatible with a git based work flow where multiple topic branches may exist simultaneously, and be merged into a master branch in unpredictable order.

This is accomplished two ways:

  1. Migration ids are not assumed to be incremented integers. It is recommended that they be timestamps (e.g. '20111202091200').
  2. Migrations are considered for completion independently.

Using a 14 digit timestamp will accommodate migrations granularity to a second, reducing the chance of collisions for a distributed team.

In contrast, using a single global version for a store and incremented integers for migration versions, it is possible for a higher numbered migration to get merged to master and deployed before a lower numbered migration, in which case the lower numbered migration would never get run, unless it is renumbered.

Migratus does not use a single global version for a store. It considers each migration independently, and runs all uncompleted migrations in sorted order.

Quick Start

  • add the Migratus dependency:

Clojars Project Open Source Helpers

  • Add the following code to resources/migrations/20111206154000-create-foo-table.up.sql

    CREATE TABLE IF NOT EXISTS foo(id BIGINT);

  • Add the following code to resources/migrations/20111206154000-create-foo-table.down.sql

    DROP TABLE IF EXISTS foo;

Multiple Statements

If you would like to run multiple statements in your migration, then separate them with --;;. For example:

CREATE TABLE IF NOT EXISTS quux(id bigint, name varchar(255));
--;;
CREATE INDEX quux_name on quux(name);

This is necessary because JDBC does not have a method that allows you to send multiple SQL commands for execution. Migratus will split your commands, and attempt to execute them inside of a transaction.

Note that some databases, such as MySQL, do not support transactional DDL commands. If you're working with such a database then it will not be able to rollback all the DDL statements that were applied in case a statement fails.

Disabling transactions

Migratus attempts to run migrations within a transaction by default. However, some databases do not support transactional DDL statements. Transactions can be disabled by adding the following line at the start of the migration file:

-- :disable-transaction

Running Functions in Migrations

Functions inside migrations may need to be additionally wrapped, a PostgreSQL example would look as follows:

DO $func$
 BEGIN
 PERFORM schema_name.function_name('foo', 10);
END;$func$;

Supporting use statements

To run migrations against several different databases (in MySQL, or "schemas" in Postgres, etc.), with embedded use statements in your migrations, specify the database in your migration-table-name in the connections, i.e. database_name.table_name not table_name.

Property substitution

Migratus supports property substitution where migration files can contain placeholders with the format of ${property.name}, these placeholders will be replaced with values found in the environment as a result of calling (System/getenv).

Shell variables will be normalized into Java properties style by being lower cased and with _ being transformed into ., e.g:

FOO_BAR - > foo.bar

This feature is enabled when the :properties flag is set in the configuration.

Migratus will look for the following default properties:

  • migratus.schema
  • migratus.user
  • migratus.database
  • migratus.timestamp (defaults to the value of (.getTime (java.util.Date.)))

Additional property can be specified using the :env key or by providing a map of custom properties using the :env key:

{:store :database
 :properties {:env ["database.table"]
              :map {:database {:user "bob"}}}
 :db {:dbtype   "h2"
      :dbname   "site.db"}}

For example, given the following template:

GRANT SELECT,INSERT ON ${database.table} TO ${database.user};

The environment variable associated with the database.table key will replace ${database.table} tag in the template, while {:database {:user "bob"}} will replace ${database.user} with "bob".

Setup

  • Add Migratus as a dependency to your project.clj
:dependencies [[migratus <VERSION>]]

There are hidden dependencies on slf4j inside migratus, so to avoid errors or silent failures you'll need to also add

[org.slf4j/slf4j-log4j12 <VERSION>]

or if you're using Timbre

[com.fzakaria/slf4j-timbre <VERSION>]

Next, create a namespace to manage the migrations:

(ns my-migrations
 (:require [migratus.core :as migratus]))

(def config {:store                :database
             :migration-dir        "migrations/"
             :init-script          "init.sql" ;script should be located in the :migration-dir path
             ;defaults to true, some databases do not support
             ;schema initialization in a transaction
             :init-in-transaction? false
             :migration-table-name "foo_bar"
             :db {:dbtype "h2"
                  :dbname "site.db"}})

;initialize the database using the 'init.sql' script
(migratus/init config)

;apply pending migrations
(migratus/migrate config)

;rollback the migration with the latest timestamp
(migratus/rollback config)

;bring up migrations matching the ids
(migratus/up config 20111206154000)

;bring down migrations matching the ids
(migratus/down config 20111206154000)

Alternative setup

It is possible to pass a java.sql.Connection or javax.sql.DataSource in place of a db spec map, e.g:

(ns my-migrations
  (:require [next.jdbc :as jdbc]))

(def connection (jdbc/get-connection
                  {:dbtype "h2"
                   :dbname "site.db"}))

(def config {:db {:connection connection}})

;; With next.jdbc >= 1.2.790 you can use {:connection-uri ...} format (as well as raw {:datasource ...} without :user/:password).
(def config {:db {:connection-uri ...}})

;; Migratus will close the connection by default
;; providing :managed-connection? hint allows managing the state of the connection externally
;; in case you wish to reuse the connection for other purposes
(def config {:connection conn :managed-connection? true})
(ns my-migrations
  (:require [hikari-cp.core :as hk]))
;; Hikari: https://github.com/tomekw/hikari-cp

(def datasource-options {:adapter "h2"
                         :url     "jdbc:h2:./site.db"})

(def config {:db {:datasource (hk/make-datasource datasource-options)}})

Running as native image (Postgres only)

PGMig is a standalone tool built with migratus that's compiled as a standalone GraalVM native image executable.

Generate migration files

Migratus also provides a convenience function for creating migration files:

(migratus/create config "create-user")
;; minimal config needed to call create while specifying the destination path
(migratus/create {:migration-dir "migrations"} "create-user")

This will result with up/down migration files being created prefixed with the current timestamp, e.g:

20150701134958-create-user.up.sql
20150701134958-create-user.down.sql

Code-based Migrations

Application developers often encounter situations where migrations cannot be easily expressed as a SQL script. For instance:

  • Executing programmatically-generated DDL statements (e.g. updating the schema of a dynamically-sharded table).
  • Transferring data between database servers.
  • Backfilling existing records with information that must be retrieved from an external system.

A common approach in these scenarios is to write one-off scripts which an admin must manually apply for each instance of the application, but issues arise if a script is not run or run multiple times.

Migratus addresses this problem by providing support for code-based migrations. You can write a migration as a Clojure function, and Migratus will ensure that it's run exactly once for each instance of the application.

Defining a code-based migration

Create a code-based migration by adding a .edn file to your migrations directory that contains the namespace and up/down functions to run, e.g. resources/migrations/20170331141500-import-users.edn:

{:ns app.migrations.import-users
 :up-fn migrate-up
 :down-fn migrate-down
 :transaction? true}

Migrations will run within a transaction by default, set transaction? to false to disable transactions.

Then, in src/app/migrations/import_users.clj:

(ns app.migrations.import-users)

(defn migrate-up [config]
   ;; do stuff here
   )

(defn migrate-down [config]
   ;; maybe undo stuff here
   )
  • The up and down migration functions should both accept a single parameter, which is the config map passed to Migratus (so your migrations can be configurable).
  • You can omit the up or down migration by setting :up-fn or down-fn to nil in the EDN file.
  • The :up-fn and :down-fn entries can optionally be a vector containing the migration function followed by additional args to be passed after the config map, e.g. {..., :up-fn [migrate-up "arg1" :arg2], ...}.

Generate code-based migration files

The migratus.core/create function accepts an optional type parameter, which you can pass as :edn to create a new migration file.

(migratus/create config "import-users" :edn)

Mixing SQL and code-based migrations

You can include both SQL and code-based migrations in the same migrations directory, in which case they will be run intermixed in the order defined by their timestamps and their status stored in the same table in the migrations database. This way if there are dependencies between your SQL and code-based migrations, you can be assured that they'll run in the correct order.

Quick Start with Leiningen

Migratus provides a Leiningen plugin:

  • Add migratus-lein as a plugin in addition to the Migratus dependency:

Clojars Project

  • Add the following key and value to your project.clj:
:migratus {:store :database
           :migration-dir "migrations"
           :db {:dbtype "mysql"
                :dbname "//localhost/migratus"
                :user "root"
                :password ""}}

To apply pending migrations:

  • Run lein migratus migrate

To rollback the migration with the last creation timestamp:

  • Run lein migratus rollback

Then follow the rest of the above instructions.

Configuration

Migratus is configured via a configuration map that you pass in as its first parameter. The :store key describes the type of store against which migrations should be run. All other keys/values in the configuration map are store specific.

Databases

To run migrations against a database use a :store of :database, and specify the database connection configuration in the :db key of the configuration map.

  • :migration-dir - directory where migration files are found
  • :exclude-scripts - a collection of script name globs that will be excluded from migrations
  • :db - One of java.sql.Connection or javax.sql.DataSource instance or a next.jdbc database spec. See next.jdbc docs for the version you are using: https://cljdoc.org/d/com.github.seancorfield/next.jdbc/1.2.780/api/next.jdbc#get-datasource
  • :command-separator - the separator will be used to split the commands within each transaction when specified
  • :expect-results? - allows comparing migration query results using the -- expect n comment
  • :tx-handles-ddl? - skips the automatic down that occurs on exception
  • :init-script - string pointing to a script that should be run when the database is initialized
  • :init-in-transaction? - defaults to true, but some databases do not support schema initialization in a transaction
  • :migration-table-name - string specifying a custom name for the migration table, defaults to schema_migrations

example configurations

{:store :database
 :migration-dir "migrations"
 :exclude-scripts ["*.clj"]
 :db {:dbtype "mysql"
      :dbname "migratus"
      :user "root"
      :password ""}}

The :migration-dir key specifies the directory on the classpath in which to find SQL migration files. Each file should be named with the following pattern [id]-[name].[direction].sql where id is a unique integer id (ideally it should be a timestamp) for the migration, name is some human readable description of the migration, and direction is either up or down.

When the expect-results? key is set in the config, an assertion can be added to the migrations to check that the expected number of rows was updated:

-- expect 17;;
update foobar set thing = 'c' where thing = 'a';

--;;

-- expect 1;;
delete from foobar where thing = 'c';

If Migratus is trying to run either the up or down migration and it does not exist, then an Exception will be thrown.

See test/migrations in this repository for an example of how database migrations work.

Modify sql fn

If you want to do some processing of the sql before it gets executed, you can provide a :modify-sql-fn in the config data structure to do so. It expects a sql-string and can return either a modified sql-string or a sequence of sql-strings. This is intended for use with http://2ndquadrant.com/en/resources/pglogical/ and similar systems, where DDL statements need to be executed via an extension-provided function.

Usage

Migratus can be used programmatically by calling one of the following functions:

Function Description
migratus.core/init Runs a script to initialize the database, e.g: create a new schema.
migratus.core/create Create a new migration with the current date.
migratus.core/migrate Run up for any migrations that have not been run. Returns nil if successful, :ignore if the table is reserved. Supports thread cancellation.
migratus.core/rollback Run down for the last migration that was run.
migratus.core/rollback-until-just-after Run down all migrations after migration-id. This only considers completed migrations, and will not migrate up.
migratus.core/up Run up for the specified migration ids. Will skip any migration that is already up.
migratus.core/down Run down for the specified migration ids. Will skip any migration that is already down.
migratus.core/reset Reset the database by down-ing all migrations successfully applied, then up-ing all migratinos.
migratus.core/pending-list Returns a list of pending migrations.
migratus.core/migrate-until-just-before Run up for for any pending migrations which precede the given migration id (good for testing migrations).

See the docstrings of each function for more details.

Migratus can also be used from leiningen if you add it as a plugin dependency.

:plugins [[migratus-lein <VERSION>]]

And add a configuration :migratus key to your project.clj.

:migratus {:store :database
           :migration-dir "migrations"
           :db {:dbtype "mysql"
                :dbname "migratus"
                :user "root"
                :password ""}}

You can then run the following tasks:

Task Description
lein migratus create Create a new migration with the current date.
lein migratus migrate Run 'up' for any migrations that have not been run.
lein migratus rollback Run 'down' for the last migration that was run.
lein migratus up & ids Run 'up' for the specified migration ids. Will skip any migration that is already up.
lein migratus down & ids Run 'down' for the specified migration ids. Will skip any migration that is already down.
lein migratus reset Run 'down' for all migrations that have been run, and 'up' for all migrations.
lein migratus pending Run 'pending-list' to get all pending migrations.

Quickstart with native Clojure projects

See clj-migratus for more information.

Usage

Add the following to your deps.edn:

:aliases {:migrate {:extra-deps {com.github.paulbutcher/clj-migratus {:git/tag "v1.0.0"
                                                                      :git/sha "67d0fe5"}}
                     :main-opts ["-m" "clj-migratus"]}}

Create a Migratus configuration file. This can either be migratus.edn:

{:store :database
 :migration-dir "migrations"
 :db {:dbtype "mysql"
      :dbname "migratus"
      :user "root"
      :password ""}}

Or (recommended) migratus.clj, allowing credentials to be taken from the environment:

{:store :database
 :db {:jdbcUrl (get (System/getenv) "JDBC_DATABASE_URL")}}

Then run, for example:

$ clj -M:migrate init
$ clj -M:migrate migrate
$ clj -M:migrate create create-user-table

See Migratus Usage for documentation on each command.

Working on migratus itself

You can use either lein or clj for now as it has both project definitions.

Run tests with kaocha:

   #  https://cljdoc.org/d/lambdaisland/kaocha/1.68.1059/doc/4-running-kaocha-cli

   bin/kaocha --test-help

   bin/kaocha --fail-fast

   bin/kaocha --fail-fast --focus migratus.test.migration.sql/test-run-sql-migrations

   # Run only integration tests - defined in tests.edn
   bin/kaocha testcontainers

License

Copyright ยฉ 2016 Paul Stadig, Dmitri Sotnikov

Licensed under the Apache License, Version 2.0.

migratus's People

Contributors

ajroetker avatar alexhall avatar b-ryan avatar codetriage-readme-bot avatar fl00r avatar greglook avatar gumpt avatar ieugen avatar jonathannewman avatar josedonizetti avatar katox avatar kenrestivo-stem avatar kingpong avatar mullr avatar mveytsman avatar p-himik avatar paulbutcher avatar pbzdyl avatar pjstadig avatar pupeno avatar rune-brinckmeyer avatar s4g4r avatar sagarjauhari avatar samroberton avatar sandre1 avatar slowcod avatar snoe avatar uhnuser avatar whenceforth avatar yogthos avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

migratus's Issues

migrates reset not worked now

oscardeiMac:lspatent oscar$ lein migratus reset
resetting the database
16-Feb-25 10:44:01 oscardeiMac.local INFO [slf4j-timbre.adapter] - Starting migrations
16-Feb-25 10:44:01 oscardeiMac.local INFO [slf4j-timbre.adapter] - Ending migrations
Exception in thread "main" java.lang.ClassCastException: migratus.database.Database cannot be cast to clojure.lang.IFn, compiling:(/private/var/folders/09/1sxxd1nn2mj3lnv6f90kstb40000gn/T/form-init3851805279291647805.clj:1:125)
at clojure.lang.Compiler.load(Compiler.java:7239)
at clojure.lang.Compiler.loadFile(Compiler.java:7165)
at clojure.main$load_script.invoke(main.clj:275)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invoke(main.clj:308)
at clojure.main$null_opt.invoke(main.clj:343)
at clojure.main$main.doInvoke(main.clj:421)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.ClassCastException: migratus.database.Database cannot be cast to clojure.lang.IFn
at migratus.core$reset_STAR_.invoke(core.clj:104)
at migratus.core$run.invoke(core.clj:25)
at migratus.core$reset.invoke(core.clj:116)
at user$eval334.invoke(form-init3851805279291647805.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6782)
at clojure.lang.Compiler.eval(Compiler.java:6772)
at clojure.lang.Compiler.load(Compiler.java:7227)
... 11 more
Subprocess failed

Feature request: Allow for multiple statements on a single migration file

Migratus 0.8.1 fails when attempting to run a migration which contains multiple statements, for instance, two CREATE TABLE statements.

Exception in thread "main" org.postgresql.util.PSQLException: Too many update results were returned., compiling:(/private/var/folders/64/ckdtdxm14059n9wh8rhf1mvw0000gn/T/form-init7217067018953698863.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.postgresql.util.PSQLException: Too many update results were returned.
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleCommandStatus(AbstractJdbc2Statement.java:2733)
    at org.postgresql.core.v3.QueryExecutorImpl.interpretCommandStatus(QueryExecutorImpl.java:2324)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1955)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:421)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2929)
    at clojure.java.jdbc$execute_batch.invoke(jdbc.clj:401)
    at clojure.java.jdbc$db_do_commands$fn__20246.invoke(jdbc.clj:675)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:674)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:636)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:668)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_$fn__20702.invoke(database.clj:62)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_.invoke(database.clj:55)
    at clojure.lang.AFn.applyToHelper(AFn.java:165)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:630)
    at robert.bruce$try_try_again$fn__20457.invoke(bruce.clj:118)
    at robert.bruce$retry.invoke(bruce.clj:94)
    at robert.bruce$retry$fn__20450.invoke(bruce.clj:109)
    at clojure.core$trampoline.invoke(core.clj:6037)
    at clojure.core$trampoline.doInvoke(core.clj:6042)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at robert.bruce$try_try_again.doInvoke(bruce.clj:118)
    at clojure.lang.RestFn.invoke(RestFn.java:512)
    at migratus.database.Migration.up(database.clj:151)
    at migratus.core$up_STAR_.invoke(core.clj:47)
    at migratus.core$migrate_up_STAR_.invoke(core.clj:54)
    at migratus.core$migrate_STAR_.invoke(core.clj:58)
    at migratus.core$run.invoke(core.clj:25)
(etc)

clojure.lang.PersistentVector cannot be cast to clojure.lang.Named

[conman "0.4.9"]
[org.postgresql/postgresql "9.4.1208.jre7"]
[migratus "0.8.14"]

(def config  {:store :database
              :migration-dir "migrations"
              :db <jdbc uri here>})

Throws

             clojure.lang.ExceptionInfo: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.Named
    data: {:file
           "/var/folders/15/ksxs2q354zqgytqvbydtw0q80000gn/T/boot.user5129302622791575400.clj",
           :line 45}
java.util.concurrent.ExecutionException: java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.Named
           java.lang.ClassCastException: clojure.lang.PersistentVector cannot be cast to clojure.lang.Named
                                clojure.core/name      core.clj: 1524
                    clojure.java.jdbc/as-sql-name      jdbc.clj:   67
clojure.java.jdbc/create-table-ddl/spec-to-string      jdbc.clj: 1133
                              clojure.core/map/fn      core.clj: 2624
                                              ...                    
                               clojure.core/first      core.clj:   55
                              clojure.string/join    string.clj:  185
               clojure.java.jdbc/create-table-ddl      jdbc.clj: 1137
                                              ...                    
                migratus.database/init-schema!/fn  database.clj:  225
                clojure.java.jdbc/db-transaction*      jdbc.clj:  602
                clojure.java.jdbc/db-transaction*      jdbc.clj:  587
                   migratus.database/init-schema!  database.clj:  220
               migratus.database.Database/connect  database.clj:  260
                                migratus.core/run      core.clj:   24
                            migratus.core/migrate      core.clj:   63
                              dre.task.migrate/up   migrate.clj:   20
                    dre.task.migrate/eval13103/fn   migrate.clj:   46
                                              ...                    
                               clojure.core/apply      core.clj:  630
                        boot.core/construct-tasks      core.clj:  760
                                              ...                    
                               clojure.core/apply      core.clj:  630
                                boot.core/boot/fn      core.clj:  805
              clojure.core/binding-conveyor-fn/fn      core.clj: 1916
                                              ...       

When I try to run migrate up.

Incorrect error message

I have observed that sometimes migratus does not print the correct error message when a migration fails. Specifically I had a syntax error in my SQL and the error reported was not the syntax error. I have created a repository that can be used to reproduce this issue. Notice in particular in the migration file that the third table create command is missing a comma between the two column types. Consistently, the error message is

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: relation "test_table" already exists

instead of the typical error for that sort of syntax error.

In order to reproduce this locally, you just need to checkout my repository and add a typical profiles.clj file with the database_url string defined.

If I can help in any other way, let me know. Thanks!

Document or warn when migrations contain INSERT statements

When using migrations combined with insert statements, an exception will be thrown. May be good to outline this in the documentation:

201506300001-create-table.up.sql

CREATE TABLE IF NOT EXISTS variance (
       id SERIAL PRIMARY KEY NOT NULL,
       is_exception boolean DEFAULT false,
       is_obsolete boolean DEFAULT false,
       is_disabled boolean DEFAULT false
);

INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (false, false, false);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (true, false, false);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (true, true, false);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (true, true, true);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (false, true, false);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (false, true, true);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (false, false, true);
INSERT INTO variance (is_exception, is_obsolete, is_disabled) VALUES (true, false, true);

Results in:

Exception in thread "main" org.postgresql.util.PSQLException: Too many update results were returned., compiling:(/private/var/folders/sq/0nk_x07s751gqtcxkj92bxjr0000gn/T/form-init5811083923084408417.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.postgresql.util.PSQLException: Too many update results were returned.
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleCommandStatus(AbstractJdbc2Statement.java:2714)
    at org.postgresql.core.v3.QueryExecutorImpl.interpretCommandStatus(QueryExecutorImpl.java:2252)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1884)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:405)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2892)
    at clojure.java.jdbc$execute_batch.invoke(jdbc.clj:401)
    at clojure.java.jdbc$db_do_commands$fn__24969.invoke(jdbc.clj:675)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:674)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:636)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:668)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_$fn__25194.invoke(database.clj:59)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_.invoke(database.clj:52)
    at clojure.lang.AFn.applyToHelper(AFn.java:165)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:630)
    at robert.bruce$try_try_again$fn__25180.invoke(bruce.clj:118)
    at robert.bruce$retry.invoke(bruce.clj:94)
    at robert.bruce$retry$fn__25173.invoke(bruce.clj:109)
    at clojure.core$trampoline.invoke(core.clj:6037)
    at clojure.core$trampoline.doInvoke(core.clj:6042)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at robert.bruce$try_try_again.doInvoke(bruce.clj:118)
    at clojure.lang.RestFn.invoke(RestFn.java:512)
    at migratus.database.Migration.up(database.clj:148)
    at migratus.core$up_STAR_.invoke(core.clj:47)
    at migratus.core$migrate_up_STAR_.invoke(core.clj:54)
    at migratus.core$migrate_STAR_.invoke(core.clj:58)
    at migratus.core$run.invoke(core.clj:25)
    at migratus.core$migrate.invoke(core.clj:63)
    at techstack.db.migrations$migrate.invoke(migrations.clj:14)
    at techstack.core$_main.doInvoke(core.clj:37)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:379)
    at user$eval58.invoke(form-init5811083923084408417.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more

`create` will put migrations in the root directory if the :migration-dir doesn't exist

When I have a config like

(def config {:store :database
             :migration-dir "this_is_a_directory_that_doesnt_exist/"
             :migration-table-name "migrations"
             :db "com.mysql.jdbc.Driver"
             :subprotocol "postgresql"
             :subname "//localhost/mydbi"})

running

(migratus.core/create config "my-migration") will put the migration file in the root directory of my project.

I'm willing to work on this, if you let me know what you think default behavior should be. Should we create the directory, or throw an error?

Migratus depends on deprecated clojure.java jdbc library

Migratus is depending on deprecated functions withing clojure java jdbc library
When running migrates 0.7.0 with org.clojure/java.jdbc "0.3.0-beta1" Migratus
fails with the following error.

(migratus.core/migrate db-config)
FileNotFoundException Could not locate clojure/java/jdbc/deprecated__init.class or clojure/java/jdbc/deprecated.clj on classpath: clojure.lang.RT.load (RT.java:443)

Dies on multiple SQL expressions

For some reason migratus dies when attempting to run migrations with multiple expressions in the file. For example having both a CREATE TABLE and a CREATE INDEX. Commenting out one of the two does not work; if I remove, say, the index then it works. I have tried running the migrations manually and there are no issues with the actual SQL.

Let me know if you need a stack trace or example migration.

Exception during migration creates some tables

I had a syntax error in my migration spanning multiple statements. When I ran (migratus/up config 2016...), Migratus threw an exception. After fixing the syntax error and re-ran migratus/up, it turns out half the tables were created, but nothing was written to the migrations table, leaving my DB in a dreadful state on the river styx.

Surely Migratus should rollback all previous statements in the event of an exception? Or am I doing something wrong?

Here was the exception:

clojure.lang.Compiler$CompilerException: org.postgresql.util.PSQLException: ERROR: relation "users" already exists, compiling:(/~/src/my-project/core/migrations.clj:33:3)
      org.postgresql.util.PSQLException: ERROR: relation "users" already exists

migrations failed but migratus gives me a useless stacktrace

Using migratus-0.5.0 I get this output while trying to run my migrations:


2012-11-24 10:10:57,082 | INFO  | migratus.database | creating migration table 'schema_migrations'
2012-11-24 10:10:57,152 | INFO  | migratus.core | Starting migrations
2012-11-24 10:10:57,445 | INFO  | migratus.core | Running up for [20121124100400]
2012-11-24 10:10:57,446 | INFO  | migratus.core | Up 20121124100400-add-everything
2012-11-24 10:11:01,811 | INFO  | migratus.core | Ending migrations
Exception in thread "main" java.sql.BatchUpdateException: Batch entry 1 <unknown> was aborted.  Call getNextException to see the cause.
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2621)
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleCommandStatus(AbstractJdbc2Statement.java:2592)
    at org.postgresql.core.v3.QueryExecutorImpl.interpretCommandStatus(QueryExecutorImpl.java:2150)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1804)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:407)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2754)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
    at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:298)
    at clojure.java.jdbc$execute_batch.invoke(jdbc.clj:418)
    at clojure.java.jdbc$do_commands$fn__973.invoke(jdbc.clj:430)
    at clojure.java.jdbc$transaction_STAR_.invoke(jdbc.clj:384)
    at clojure.java.jdbc$do_commands.doInvoke(jdbc.clj:429)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at migratus.database$up_STAR_$fn__13404.invoke(database.clj:50)
    at clojure.java.jdbc$transaction_STAR_.invoke(jdbc.clj:372)
    at migratus.database$up_STAR_.invoke(database.clj:44)
    at clojure.lang.AFn.applyToHelper(AFn.java:167)
    at clojure.lang.AFn.applyTo(AFn.java:151)
    at clojure.core$apply.invoke(core.clj:601)
    at robert.bruce$try_try_again$fn__13393.invoke(bruce.clj:118)
    at robert.bruce$retry.invoke(bruce.clj:94)
    at robert.bruce$retry$fn__13386.invoke(bruce.clj:109)
    at clojure.core$trampoline.invoke(core.clj:5575)
    at clojure.core$trampoline.doInvoke(core.clj:5580)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at robert.bruce$try_try_again.doInvoke(bruce.clj:118)
    at clojure.lang.RestFn.invoke(RestFn.java:482)
    at migratus.database.Migration.up(database.clj:71)
    at migratus.core$up_STAR_.invoke(core.clj:37)
    at migratus.core$migrate_STAR_.invoke(core.clj:44)
    at migratus.core$migrate$fn__1200.invoke(core.clj:57)
    at migratus.core$run.invoke(core.clj:23)
    at migratus.core$migrate.invoke(core.clj:57)
    at megatron.db$db_init.invoke(db.clj:16)
    at clojure.lang.Var.invoke(Var.java:411)
    at carousel.module$init$fn__175.invoke(module.clj:28)
    at carousel.registry$do_registered.doInvoke(registry.clj:45)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at carousel.module$init.invoke(module.clj:28)
    at megatron.main$main.invoke(main.clj:7)
    at user$eval13326.invoke(NO_SOURCE_FILE:1)
    at clojure.lang.Compiler.eval(Compiler.java:6511)
    at clojure.lang.Compiler.eval(Compiler.java:6501)
    at clojure.lang.Compiler.eval(Compiler.java:6477)
    at clojure.core$eval.invoke(core.clj:2797)
    at clojure.main$eval_opt.invoke(main.clj:297)
    at clojure.main$initialize.invoke(main.clj:316)
    at clojure.main$null_opt.invoke(main.clj:349)
    at clojure.main$main.doInvoke(main.clj:427)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:419)
    at clojure.lang.AFn.applyToHelper(AFn.java:163)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.main.main(main.java:37)

Failed to load class "org.slf4j.impl.StaticLoggerBinder".

Using

[migratus-lein "0.2.0"]

When running

lein migratus

I get

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

I tried adding a logging implementation to my :plugins list, i.e.

[ch.qos.logback/logback-classic "1.1.3"]

But still get the same error.

I tried adding to the :plugins list:

[org.slf4j/slf4j-log4j12 "1.7.9"]

Still same error.

Single-statement rollback migration failing with "Too many update results were returned"

Down file contains single statement DROP TABLE users;
Using org.postgresql/postgresql "9.4-1203-jdbc41"

When I remove semicolon - rollback completes successfully.

02:26:51.002 [main] INFO  migratus.core - Starting migrations
02:26:51.421 [main] INFO  migratus.core - Running down for [20151007011602]
02:26:51.422 [main] INFO  migratus.core - Down 20151007011602-add-users-table
02:26:51.436 [main] DEBUG migratus.database - found 1 down migrations
02:26:52.470 [main] DEBUG migratus.database - found 1 down migrations
02:26:55.204 [main] DEBUG migratus.database - found 1 down migrations
02:26:55.212 [main] INFO  migratus.core - Ending migrations
Exception in thread "main" org.postgresql.util.PSQLException: Too many update results were returned., compiling:(/tmp/form-init6425292863827031544.clj:1:73)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.postgresql.util.PSQLException: Too many update results were returned.
    at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleCommandStatus(AbstractJdbc2Statement.java:2688)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:338)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2898)
    at clojure.java.jdbc$execute_batch.invoke(jdbc.clj:401)
    at clojure.java.jdbc$db_do_commands$fn__807.invoke(jdbc.clj:675)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:674)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:636)
    at clojure.java.jdbc$db_do_commands.doInvoke(jdbc.clj:668)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$down_STAR_$fn__1276.invoke(database.clj:73)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:584)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$down_STAR_.invoke(database.clj:66)
    at clojure.lang.AFn.applyToHelper(AFn.java:165)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:630)
    at robert.bruce$try_try_again$fn__1018.invoke(bruce.clj:118)
    at robert.bruce$retry.invoke(bruce.clj:94)
    at robert.bruce$retry$fn__1011.invoke(bruce.clj:109)
    at clojure.core$trampoline.invoke(core.clj:6037)
    at clojure.core$trampoline.doInvoke(core.clj:6042)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at robert.bruce$try_try_again.doInvoke(bruce.clj:118)
    at clojure.lang.RestFn.invoke(RestFn.java:512)
    at migratus.database.Migration.down(database.clj:156)
    at migratus.core$run_down.invoke(core.clj:87)
    at migratus.core$rollback_STAR_.invoke(core.clj:96)
    at migratus.core$run.invoke(core.clj:25)
    at migratus.core$rollback.invoke(core.clj:106)
    at user$eval1567.invoke(form-init6425292863827031544.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more
Subprocess failed

Attempting to roll back multiple migrations raises an exception

The Luminus migratus documentation states that one can pass migration ids to rollback/migrate. Attempting to do so with rollback raises an exception:

$ lein run rollback 20150702130104 20150702123955
Exception in thread "main" clojure.lang.ArityException: Wrong number of args (3) passed to: core/rollback, compiling:(/private/var/folders/64/ckdtdxm14059n9wh8rhf1mvw0000gn/T/form-init5872681998558105682.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: clojure.lang.ArityException: Wrong number of args (3) passed to: core/rollback
    at clojure.lang.AFn.throwArity(AFn.java:429)
    at clojure.lang.AFn.invoke(AFn.java:40)
    at clojure.lang.AFn.applyToHelper(AFn.java:160)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:632)
    at appname.db.migrations$migrate.invoke(migrations.clj:17)
    at appname.core$_main.doInvoke(core.clj:37)
[...]

I haven't tried it with migrate to see if it does work on that case.

Null Pointer Exception when migration file contains invalid SQL

Thank you for working on migratus, it is pretty neat!

I had a migration file with some invalid SQL. I expect migratus to give me an exception related to the SQL being invalid. Instead I get a NullPointerException.

Here is a small example to reproduce the error:

;; in src/migratus_borked/core.clj
(ns migratus-borked.core
  (:require
    [migratus.core :as migratus]))

(def config {:store :database
             :migration-dir "migrations"
             :db {:connection-uri "jdbc:mysql://localhost:3306/cm_file_upload_dev?user=root&password=root"}})

(defn do-migrations []
  (migratus/migrate config))

Here is the invalid SQL file in resources/migrations/1-invalid-sql-file.sql:

SOME INVALID SQL;

I start a repl to produce the error:

^_^  ~/code/migratus-borked ฮป lein repl
nREPL server started on port 61660 on host 127.0.0.1 - nrepl://127.0.0.1:61660
REPL-y 0.3.5, nREPL 0.2.6
Clojure 1.6.0
Java HotSpot(TM) 64-Bit Server VM 1.8.0_25-b17
    Docs: (doc function-name-here)
          (find-doc "part-of-name-here")
  Source: (source function-name-here)
 Javadoc: (javadoc java-object-or-class-here)
    Exit: Control+D or (exit) or (quit)
 Results: Stored in vars *1, *2, *3, an exception in *e

user=> (require '[migratus-borked.core :as hello])
nil
user=> (hello/do-migrations)
Jul 01, 2015 1:12:45 PM clojure.tools.logging$eval406$fn__410 invoke
INFO: Starting migrations
Jul 01, 2015 1:12:46 PM clojure.tools.logging$eval406$fn__410 invoke
INFO: Running up for [1]
Jul 01, 2015 1:12:46 PM clojure.tools.logging$eval406$fn__410 invoke
INFO: Up 1-invalid-sql-file
Jul 01, 2015 1:12:49 PM clojure.tools.logging$eval406$fn__410 invoke
INFO: Ending migrations

NullPointerException   migratus.core/run (core.clj:27)
user=>

Here my my project.clj file.

;; my project.clj file
(defproject migratus-borked "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
            :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.6.0"]
                 [migratus "0.8.1"]
                 [org.clojure/java.jdbc "0.3.7"]
                 [mysql/mysql-connector-java "5.1.6"]
                 ])

The stack trace points to

(throw (.getNextException e)))
, which looks like it should be handing me back an exception related to my SQL being invalid, but is instead throwing a NullPointerException. This is on OS X 10.10.3.

When there's an syntax error, a partial migration is left applied

I recently experienced a problem in which I have an up migration that looks something like this:

DROP INDEX features_id
--;;
DROP INDEX features_name
--;;
DROP INDEX features_slug
--;;
ARBITRARY SYNTAX ERROR

when I tried running it, this is the error I got:

Exception in thread "main" org.postgresql.util.PSQLException: ERROR: index "features_id" does not exist, compiling:(/private/var/folders/k9/pgnpg2h92bv157mw70mhznk80000gn/T/form-init4702570188881465620.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.postgresql.util.PSQLException: ERROR: index "features_id" does not exist
    at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2198)
    at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1927)
    at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:255)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.execute(AbstractJdbc2Statement.java:561)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeWithFlags(AbstractJdbc2Statement.java:419)
    at org.postgresql.jdbc2.AbstractJdbc2Statement.executeUpdate(AbstractJdbc2Statement.java:365)
    at clojure.java.jdbc$db_do_execute_prepared_statement$fn__11756.invoke(jdbc.clj:753)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:595)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.java.jdbc$db_do_execute_prepared_statement.invoke(jdbc.clj:752)
    at clojure.java.jdbc$db_do_prepared.doInvoke(jdbc.clj:786)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:636)
    at clojure.java.jdbc$db_do_prepared.doInvoke(jdbc.clj:781)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_$fn__32126.invoke(database.clj:62)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:595)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_.invoke(database.clj:55)
    at clojure.lang.AFn.applyToHelper(AFn.java:165)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invoke(core.clj:630)
    at robert.bruce$try_try_again$fn__32112.invoke(bruce.clj:118)
    at robert.bruce$retry.invoke(bruce.clj:94)
    at robert.bruce$retry$fn__32105.invoke(bruce.clj:109)
    at clojure.core$trampoline.invoke(core.clj:6037)
    at clojure.core$trampoline.doInvoke(core.clj:6042)
    at clojure.lang.RestFn.invoke(RestFn.java:439)
    at robert.bruce$try_try_again.doInvoke(bruce.clj:118)
    at clojure.lang.RestFn.invoke(RestFn.java:512)
    at migratus.database.Migration.up(database.clj:151)
    at migratus.core$up_STAR_.invoke(core.clj:47)
    at migratus.core$migrate_up_STAR_.invoke(core.clj:54)
    at migratus.core$migrate_STAR_.invoke(core.clj:58)
    at migratus.core$run.invoke(core.clj:25)
    at migratus.core$migrate.invoke(core.clj:63)
    at ninjatools.db.migrations$migrate.invoke(migrations.clj:19)
    at ninjatools.core$_main.doInvoke(core.clj:40)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:379)
    at user$eval58.invoke(form-init4702570188881465620.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more

features_id definitely existed before running this migration and also there's no mention of the syntax error. If I look at the database now, I can see that features_id is indeed gone but in schema_migrations, this migration doesn't look like it was applied.

I turned on logging in PostgreSQL and this is what I found:

LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
LOG:  execute <unnamed>: SELECT * from schema_migrations WHERE id=$1
DETAIL:  parameters: $1 = '20151106134834'
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>:

        DROP INDEX features_id

LOG:  execute S_1: COMMIT
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
LOG:  execute <unnamed>: DROP INDEX features_name

LOG:  execute S_1: COMMIT
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
LOG:  execute <unnamed>: DROP INDEX features_slug

LOG:  execute S_1: COMMIT
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
ERROR:  syntax error at or near "ARBITRARY" at character 1
STATEMENT:  ARBITRARY SYNTAX ERROR

LOG:  execute S_2: ROLLBACK
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
LOG:  execute <unnamed>: SELECT * from schema_migrations WHERE id=$1
DETAIL:  parameters: $1 = '20151106134834'
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>:

        DROP INDEX features_id

ERROR:  index "features_id" does not exist
STATEMENT:

        DROP INDEX features_id

LOG:  execute S_2: ROLLBACK
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>: BEGIN
LOG:  execute <unnamed>: SELECT * from schema_migrations WHERE id=$1
DETAIL:  parameters: $1 = '20151106134834'
LOG:  execute <unnamed>: SHOW TRANSACTION ISOLATION LEVEL
LOG:  execute <unnamed>:

        DROP INDEX features_id

ERROR:  index "features_id" does not exist
STATEMENT:

        DROP INDEX features_id

LOG:  execute S_2: ROLLBACK

migratus is somehow trying to run the migration again and not properly rollbacking the whole migration.

NullPointerException With no Information

I create an empty folder, migrations2.

I have an empty database. I use the create method to make a new migration, it works. I put in the "up" a statement create table tests(); and in the "down" a drop table tests();.

I try to run migrate and get the following:

   AbstractJdbc2Statement.java:  829  org.postgresql.jdbc2.AbstractJdbc2Statement/replaceProcessing
   AbstractJdbc2Statement.java:  149  org.postgresql.jdbc2.AbstractJdbc2Statement/<init>
   AbstractJdbc3Statement.java:   42  org.postgresql.jdbc3.AbstractJdbc3Statement/<init>
  AbstractJdbc3gStatement.java:   28  org.postgresql.jdbc3g.AbstractJdbc3gStatement/<init>
   AbstractJdbc4Statement.java:   32  org.postgresql.jdbc4.AbstractJdbc4Statement/<init>
           Jdbc4Statement.java:   30  org.postgresql.jdbc4.Jdbc4Statement/<init>
   Jdbc4PreparedStatement.java:   23  org.postgresql.jdbc4.Jdbc4PreparedStatement/<init>
   Jdbc4PreparedStatement.java:   18  org.postgresql.jdbc4.Jdbc4PreparedStatement/<init>
          Jdbc4Connection.java:   39  org.postgresql.jdbc4.Jdbc4Connection/prepareStatement
  AbstractJdbc3Connection.java:  275  org.postgresql.jdbc3.AbstractJdbc3Connection/prepareStatement
  AbstractJdbc2Connection.java:  198  org.postgresql.jdbc2.AbstractJdbc2Connection/prepareStatement
                      jdbc.clj:  419  clojure.java.jdbc/prepare-statement
                   RestFn.java:  425  clojure.lang.RestFn/invoke
                      AFn.java:  156  clojure.lang.AFn/applyToHelper
                   RestFn.java:  132  clojure.lang.RestFn/applyTo
                      core.clj:  628  clojure.core/apply
                      jdbc.clj:  736  clojure.java.jdbc/db-query-with-resultset
                      jdbc.clj:  769  clojure.java.jdbc/query
                   RestFn.java:  425  clojure.lang.RestFn/invoke
                  database.clj:  177  migratus.database/completed-ids*/fn
                      jdbc.clj:  541  clojure.java.jdbc/db-transaction*

I've tried a half dozen config settings.

(defn mconfig []
  {:store                :database
   :migration-dir        "migrations2"
   :migration-table-name "swipes"
   :db "jdbc:postgresql://postgres:changeme@localhost:5432/swipes"
   })

(defn mconfig []
  {:store                :database
   :migration-dir        "migrations2"
   :migration-table-name "swipes"
   :db {:classname "org.postgresql.Driver",
        :subprotocol "postgresql",
        :user "postgres",
        :password "changeme",
        :subname "//localhost:5432/swipes"}
   })
(migratus/create (mconfig) "create-school-year")
(migratus/migrate (mconfig))

Neither of the above config options worked. The second is exactly how I connect using clojure.java.jdbc. Any ideas?

remove multiple commands support?

i've seen different complains/issues here about errors due to a migration with multiple commands.
it's good to be able to do it, but as migratus uses SQL commands, and not a DSL. One might add a command with a syntax error. Not a problem if the syntax error is on the first command. But it will leave the DB on a unstable state, if the syntax error is on the last command, because the first command will be applied, but the migration won't be marked as complete due to the failed last command.

Eg:

  • create migration with two commands, last one has a syntax error
  • run migrate, and only the first commands create the table, but i get an error and the migration was not marked as executed
  • fix the syntax error, and re-run migrate, get an error because the first command was already applied, the table is there already
  • try to rollback, but rollback the wrong migration because the one I wanted was not on schema_migrations
  • need to go into the database, delete the table by hand, and then be able to run the migration again

On the other side, we also can't mark the migration as completed if both commands haven't succeed, because it will break the rollback if i try to execute it.

I suggest we remove the support for multiple commands, and enforce having one command per migration. I can work on this change, but would like to know what others think about it first?

Unecessary dependency

Hi there,

Just started using your library and I have one concern: is camel-snake-kebab really needed as a dependency? Do you think it makes sense to remove it and re-implement functionality of one function that is used in this project? I can submit PR if you agree that this is ok thing to do.

Cheers,
Max

Migratus tries to execute foo.sql~ editor temp files

Is there some way to make Migratus ignore foo.sql~ files left by editors?

It seems to be very confused by them.

5-Nov-06 21:03:08 q400a INFO [slf4j-timbre.adapter] - Starting migrations
15-Nov-06 21:03:08 q400a WARN [slf4j-timbre.adapter] - '20151105234246-geocode-table.down.sql~' does not appear to be a valid migration
15-Nov-06 21:03:08 q400a WARN [slf4j-timbre.adapter] - '20151105234246-geocode-table.up.sql~' does not appear to be a valid migration
15-Nov-06 21:03:08 q400a INFO [slf4j-timbre.adapter] - Ending migrations

Some way to not have database passwords in project.clj

It'd be nice if there were a way to have the passwords and database logins not in project.clj, for example, so that they don't get committed to git (or published to github!).

One slightly-evil way would be to do a slurp and read-edn inside of the project.clj, but that feels wrong.

A better way would be to integrate something like the https://github.com/weavejester/environ package, which is pretty small, but not sure if you'd want that transitive dependency. But by integrating that, passwords maybe could be defined in env vars, in a .lein-env file that isn't comitted to git, or in JVM properties.

Cannot execute SELECT statements in migrations.

In this case, we're using a PostgreSQL extension (pg_partman) that partitions tables. When we try to do this:

user=> (migrate)

BatchUpdateException Batch entry 0 SELECT partman.create_parent(
        'public.transactions',
        'timestamp',            -- Field on which we'll partition
        'time-static',          --
        'daily',                -- Partitioning interval
        NULL,                   -- p_constraint_cols (not used)
        7,                      -- Number of future/past partitions the trigger can address
        TRUE                    -- run_maintenance() creates new partitions/uninherits old
        ) was aborted.  Call getNextException to see the cause.  org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError (AbstractJdbc2Statement.java:2743)
user=> (.getNextException *e)
#<PSQLException org.postgresql.util.PSQLException: A result was returned when none was expected.>
user=> (pst (.getNextException *e))
PSQLException A result was returned when none was expected.
        org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleResultRows (AbstractJdbc2Statement.java:2692)
        org.postgresql.core.v3.QueryExecutorImpl.processResults (QueryExecutorImpl.java:1853)
        org.postgresql.core.v3.QueryExecutorImpl.execute (QueryExecutorImpl.java:405)
        org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch (AbstractJdbc2Statement.java:2892)
        clojure.java.jdbc.deprecated/execute-batch (deprecated.clj:423)
        clojure.java.jdbc.deprecated/do-commands/fn--9265 (deprecated.clj:435)
        clojure.java.jdbc.deprecated/transaction* (deprecated.clj:389)
        clojure.java.jdbc.deprecated/do-commands (deprecated.clj:434)
        migratus.database/up*/fn--9377 (database.clj:50)
        clojure.java.jdbc.deprecated/transaction* (deprecated.clj:377)
        migratus.database/up* (database.clj:44)
        clojure.core/apply (core.clj:624)

To verify, I created a migration with just SELECT 42; in it and got the same error.

Migrations are created in the root project directory

Here is my migratus configuration:

  :migratus {:store :database
         :migration-dir "resources/migrations"
         :db ~(get (System/getenv) "DATABASE_URL")}

When I run lein migratus create (v 0.2.0) it creates the migration files in the project root instead

Unable to run migrations from uberjar

Hello.

I saw the previous issue on heroku that seemed to get closed out randomly, and a similar issue to the one I'm experiencing luminus-framework/luminus-template#171 on the luminus project.

I can't seem to get migrations to run on heroku.

lein migratus migrate

fails with

SEVERE: Error creating DB connection for
java.lang.IllegalArgumentException: db-spec null is missing a required parameter

but since I'm just using clojure with migratus and lein-migratus as dependencies instead of the full luminus framework, running

java -jar <app>.jar migrate

fails with

Exception in thread "main" java.io.FileNotFoundException: migrate (No such file or directory)

which makes sense since I don't have a migrate function or file.

What is the correct approach for a situation like this?

migrations failing on heroku

I've been working on an api server (ring/compojure based) and am using migratus for the database migrations (it's awesome!).

I'm having some trouble getting the migrations to run on heroku however, and am given an incredibly difficult to interpret error when attempting the migration.

heroku run lein migratus migrate --app myapp

Running lein migratus migrate attached to terminal... up, run.2813 

Exception in thread "main" java.lang.Exception: Too many arguments to def (impl.clj:35) at clojure.lang.Compiler.analyzeSeq(Compiler.java:5376) at clojure.lang.Compiler.analyze(Compiler.java:5190) at clojure.lang.Compiler.analyze(Compiler.java:5151) at clojure.lang.Compiler.eval(Compiler.java:5428) at clojure.lang.Compiler.load(Compiler.java:5857) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__4519.invoke(core.clj:4915) at clojure.core$load.doInvoke(core.clj:4914) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:4729) at clojure.core$load_lib.doInvoke(core.clj:4766) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:542) at clojure.core$load_libs.doInvoke(core.clj:4800) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:542) at clojure.core$require.doInvoke(core.clj:4881) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.tools.logging$eval80$loading__4414__auto____81.invoke(logging.clj:13) at clojure.tools.logging$eval80.invoke(logging.clj:13) at clojure.lang.Compiler.eval(Compiler.java:5424) at clojure.lang.Compiler.eval(Compiler.java:5415) at clojure.lang.Compiler.load(Compiler.java:5857) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__4519.invoke(core.clj:4915) at clojure.core$load.doInvoke(core.clj:4914) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:4729) at clojure.core$load_lib.doInvoke(core.clj:4766) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:542) at clojure.core$load_libs.doInvoke(core.clj:4800) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:542) at clojure.core$require.doInvoke(core.clj:4881) at clojure.lang.RestFn.invoke(RestFn.java:457) at migratus.core$eval74$loading__4414__auto____75.invoke(core.clj:14) at migratus.core$eval74.invoke(core.clj:14) at clojure.lang.Compiler.eval(Compiler.java:5424) at clojure.lang.Compiler.eval(Compiler.java:5415) at clojure.lang.Compiler.load(Compiler.java:5857) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__4519.invoke(core.clj:4915) at clojure.core$load.doInvoke(core.clj:4914) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:4729) at clojure.core$load_lib.doInvoke(core.clj:4766) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:542) at clojure.core$load_libs.doInvoke(core.clj:4800) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:542) at clojure.core$require.doInvoke(core.clj:4881) at clojure.lang.RestFn.invoke(RestFn.java:421) at leiningen.migratus$eval68$loading__4414__auto____69.invoke(migratus.clj:14) at leiningen.migratus$eval68.invoke(migratus.clj:14) at clojure.lang.Compiler.eval(Compiler.java:5424) at clojure.lang.Compiler.eval(Compiler.java:5415) at clojure.lang.Compiler.load(Compiler.java:5857) at clojure.lang.RT.loadResourceScript(RT.java:340) at clojure.lang.RT.loadResourceScript(RT.java:331) at clojure.lang.RT.load(RT.java:409) at clojure.lang.RT.load(RT.java:381) at clojure.core$load$fn__4519.invoke(core.clj:4915) at clojure.core$load.doInvoke(core.clj:4914) at clojure.lang.RestFn.invoke(RestFn.java:408) at clojure.core$load_one.invoke(core.clj:4729) at clojure.core$load_lib.doInvoke(core.clj:4766) at clojure.lang.RestFn.applyTo(RestFn.java:142) at clojure.core$apply.invoke(core.clj:542) at clojure.core$load_libs.doInvoke(core.clj:4800) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.core$apply.invoke(core.clj:542) at clojure.core$require.doInvoke(core.clj:4881) at clojure.lang.RestFn.invoke(RestFn.java:408) at leiningen.core$resolve_task.invoke(core.clj:208) at leiningen.core$apply_task.invoke(core.clj:258) at leiningen.core$_main.doInvoke(core.clj:329) at clojure.lang.RestFn.applyTo(RestFn.java:139) at clojure.core$apply.invoke(core.clj:542) at leiningen.core$_main.invoke(core.clj:332) at user$eval42.invoke(NO_SOURCE_FILE:1) at clojure.lang.Compiler.eval(Compiler.java:5424) at clojure.lang.Compiler.eval(Compiler.java:5391) at clojure.core$eval.invoke(core.clj:2382) at clojure.main$eval_opt.invoke(main.clj:235) at clojure.main$initialize.invoke(main.clj:254) at clojure.main$script_opt.invoke(main.clj:270) at clojure.main$main.doInvoke(main.clj:354) at clojure.lang.RestFn.invoke(RestFn.java:482) at clojure.lang.Var.invoke(Var.java:381) at clojure.lang.AFn.applyToHelper(AFn.java:178) at clojure.lang.Var.applyTo(Var.java:482) at clojure.main.main(main.java:37) Caused by: java.lang.Exception: Too many arguments to def at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:415) at clojure.lang.Compiler.analyzeSeq(Compiler.java:5369) ... 102 more

At first I thought it might be an issue with the way the connection string is formatted.

In my local profiles.clj (where it works fine), it looks like this:
:database-url "jdbc:postgresql://localhost:5432/my_db?user=myuser&password=mypass"
and the db string that heroku gives me is formatted like this:
postgres://myuser:[email protected]:5432/my_db

I made another environment variable using the credentials from the db that heroku gave me, but formatted in the same style as my local variable, but I still get the same error.

I'm completely baffled as to what the error might be.

Any ideas?

(migratus/create ...) returns true but does not create migration scripts

When I call (migratus/create config "my-migration"), the function returns true, but does not create any .sql files. The first call worked, but subsequent attempts fail. I have restarted my REPL, with no luck.

Here is my config:

(def config {:store                :database
             :migration-dir        "migrations/"
             :migration-table-name "migrations"
             :db                   "postgresql://localhost:5432/test-db"})

My migrations folder lives at ~/resources/migrations.

Why would migratus not create the new migration templates without an exception?

lein migratus create "migrationName" do not locate into correct migration folder

I run :

lein migratus create MigrationName

and it creates the migration file into the project folder ( not into the sub folder )
however i have

:migratus {:store :database
:migration-dir "migrations"
:db {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname ""
:user ""
:password ""}}

set into the project.clj , and i tried add the slashes to "migrations" but neither works..

is the project still being developed?

Looking at the activity, I was wondering if you're still planning to continue developing the lib going forward. I really like the approach that it takes and it seems to do everything I need aside from a few minor issues.

Specifically, for Luminus I'd like to take the approach of running migrations from the main as opposed to using a lein plugin. This way the packaged application could know how to apply its own migrations when deployed to the server. Migratus seems to be an excellent fit for that kind of workflow.

Migratus throws NullPointerException when database is down

Migratus throws a NullPointerException if target database is down. If you don't know your DB is down, you might think something is wrong with your connection string or migration. A clearer SQL-related exception would help to diagnose errors:

java.lang.NullPointerException:
                   migratus.database/connect*      database.clj:  194
           migratus.database.Database/connect      database.clj:  274
                            migratus.core/run          core.clj:   24
                           migratus.core/down          core.clj:   93
                                          ...

Disable transactions ala carte?

Some DDL commands are not able to be executed in transactions, although the database supports other DDL commands in transactions. An example is alter type ... add in Postgres. We need some way of disabling this per-module.

As a workaround, I think I could do:

-- this doesn't actually work...
commit;
--;;
alter type ... add ....;
--;;
begin;

But this seems like a gross hack. And doesn't work.

Insert in "compound" migration causes constraint violation

I have a migration that looks something like:

INSERT INTO users (id, ...) VALUES (1, ...);
--;;
SELECT nextval('users_id_seq');

With a completely empty database, this migration inserts the row then fails with ERROR: duplicate key value violates unique constraint "users_pkey" from attempting to insert the same row a second time. If I remove the second portion of the migration, it succeeds. Unfortunately, that leaves the database in an unusable state.

Feature Request: Parameterised Lein Migrations

It would be useful to be able to define multiple databases and migrate them from lein. For instance if the :migratus key in lein had multiple :db keys and you could call "lein migrate" on each independently to migrate that database.

Can show friendly error message that can point which sql file and line cause error?

I have several big migrate files, then when it's has error, it's hard to find out which cause errors.

oscardeiMac:migrations oscar$ lein migratus migrate
migrating all outstanding migrations
16-Feb-25 08:40:36 oscardeiMac.local INFO [slf4j-timbre.adapter] - Starting migrations
16-Feb-25 08:40:36 oscardeiMac.local INFO [slf4j-timbre.adapter] - creating migration table 'schema_migrations'
16-Feb-25 08:40:36 oscardeiMac.local WARN [slf4j-timbre.adapter] - '20150320103048417-update-trigger.clj' does not appear to be a valid migration
16-Feb-25 08:40:36 oscardeiMac.local INFO [slf4j-timbre.adapter] - Running up for [20150318161224442 20150811205628841 20150813161002387 20150814200402283 20160207072921680]
16-Feb-25 08:40:36 oscardeiMac.local INFO [slf4j-timbre.adapter] - Up 20150318161224442-base
16-Feb-25 08:40:36 oscardeiMac.local DEBUG [slf4j-timbre.adapter] - found 48 up migrations
16-Feb-25 08:40:36 oscardeiMac.local INFO [slf4j-timbre.adapter] - Ending migrations
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 11, compiling:(/private/var/folders/09/1sxxd1nn2mj3lnv6f90kstb40000gn/T/form-init5442890000147498866.clj:1:125)
    at clojure.lang.Compiler.load(Compiler.java:7239)
    at clojure.lang.Compiler.loadFile(Compiler.java:7165)
    at clojure.main$load_script.invoke(main.clj:275)
    at clojure.main$init_opt.invoke(main.clj:280)
    at clojure.main$initialize.invoke(main.clj:308)
    at clojure.main$null_opt.invoke(main.clj:343)
    at clojure.main$main.doInvoke(main.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')' at line 11
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:400)
    at com.mysql.jdbc.Util.getInstance(Util.java:383)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:980)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3847)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3783)
    at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2447)
    at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2594)
    at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2545)
    at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1901)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2113)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2049)
    at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2034)
    at clojure.java.jdbc$db_do_execute_prepared_statement$fn__367.invoke(jdbc.clj:753)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:595)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at clojure.java.jdbc$db_do_execute_prepared_statement.invoke(jdbc.clj:752)
    at clojure.java.jdbc$db_do_prepared.doInvoke(jdbc.clj:786)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:636)
    at clojure.java.jdbc$db_do_prepared.doInvoke(jdbc.clj:781)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_$fn__549.invoke(database.clj:61)
    at clojure.java.jdbc$db_transaction_STAR_.doInvoke(jdbc.clj:595)
    at clojure.lang.RestFn.invoke(RestFn.java:425)
    at migratus.database$up_STAR_.invoke(database.clj:54)
    at migratus.database.Migration.up(database.clj:163)
    at migratus.core$up_STAR_.invoke(core.clj:47)
    at migratus.core$migrate_up_STAR_.invoke(core.clj:54)
    at migratus.core$migrate_STAR_.invoke(core.clj:58)
    at migratus.core$run.invoke(core.clj:25)
    at migratus.core$migrate.invoke(core.clj:63)
    at user$eval90.invoke(form-init5442890000147498866.clj:1)
    at clojure.lang.Compiler.eval(Compiler.java:6782)
    at clojure.lang.Compiler.eval(Compiler.java:6772)
    at clojure.lang.Compiler.load(Compiler.java:7227)
    ... 11 more
Subprocess failed

Up migrations failing with org.postgresql/postgresql "9.4-1203-jdbc41"

They work fine with 9.4-1201-jdbc41 but with the latest JDBC driver version 9.4-1203-jdbc41 I get this error when running an up migration:

Exception in thread "main" org.postgresql.util.PSQLException: Too many update results were returned., compiling:(/private/var/folders/3s/ksknbjrd47jgbf95vzr_bx0w0000gn/T/form-init5347993960870637955.clj:1:124)
    at clojure.lang.Compiler.load(Compiler.java:7142)
    at clojure.lang.Compiler.loadFile(Compiler.java:7086)
    at clojure.main$load_script.invoke(main.clj:274)
    at clojure.main$init_opt.invoke(main.clj:279)
    at clojure.main$initialize.invoke(main.clj:307)
    at clojure.main$null_opt.invoke(main.clj:342)
    at clojure.main$main.doInvoke(main.clj:420)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at clojure.lang.Var.invoke(Var.java:383)
    at clojure.lang.AFn.applyToHelper(AFn.java:156)
    at clojure.lang.Var.applyTo(Var.java:700)
    at clojure.main.main(main.java:37)
Caused by: org.postgresql.util.PSQLException: Too many update results were returned.

release new version

can we release the new version with support to destroy?
I can bump the lein-plugin and luminus-template after it.

Can (m/up ..) and (m/down ...) return non-nil on success?

I noticed that (migratus/down config 2016...) returns nil whether a migration ran or not. This caught me when I made a typo in my manual call during my dev environment. It would be helpful to debug if it returned a non-nil value if the migration file was found and a statement was ran.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.