Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix use of transactions to apply migrations #86

Merged
merged 1 commit into from
Jan 31, 2023

Conversation

z64
Copy link
Contributor

@z64 z64 commented Jan 31, 2023

This patch fixes an issue that has apparently existed for a very long time: application of migrations in a transaction has not been working as intended!

Currently, if you apply a migration like the following:

-- +micrate Up
CREATE TABLE foo (x int);
invalid_sql;
-- +micrate Down
DROP TABLE foo;

This will:

  1. Create table foo
  2. Crash on parsing invalid_sql

When this happens, the database will be left in a partially migrated state, with foo created and the migration marked as applied, essentially "bricking" micrate until you manually resolve it.

  • The migration will not be marked as applied
  • If you try to run up again, it will complain foo already exists, so you need to add IF NOT EXISTS or manually DROP TABLE foo;.
  • Hopefully there are no more errors, or you'll have to do it again!

The reason this happens was just because of the misuse of the transaction API. Opening a tx with db.transaction checks out a connection from the pool, and issues BEGIN for you. From there, you must issue queries against tx.connection - where the tx is taking place - in order for them to be applied.

Instead, db is used again, which instead pull another connection from the DB pool; meaning the tx does not get any of the migration statements.

With this fix, failed migrations will be fully rolled back as intended, allowing you to make fixes & run up again without issue.

This patch fixes an issue that has apparently existed for a very long
time: application of migrations in a transaction has not been working as
intended!

Currently, if you apply a migration like the following:

```sql
-- +micrate Up
CREATE TABLE foo (x int);
invalid_sql;
-- +micrate Down
DROP TABLE foo;
```

This will:

1. Create table `foo`
2. Crash on parsing `invalid_sql`

When this happens, the database will be left in a partially migrated
state, with `foo` created and the migration marked as applied,
essentially "bricking" micrate until you manually resolve it.

- The migration will not be marked as applied
- If you try to run `up` again, it will complain `foo` already exists,
  so you need to add `IF NOT EXISTS` or manually `DROP TABLE foo;`.
- Hopefully there are no more errors, or you'll have to do it again!

The reason this happens was just because of the misuse of the
transaction API. Opening a tx with `db.transaction` checks out a
connection from the pool, and issues `BEGIN` for you. From there, you
must issue queries against `tx.connection` - where the tx is taking
place - in order for them to be applied.

Instead, `db` is used again, which instead pull *another* connection
from the DB pool; meaning the tx does not get *any* of the migration
statements.

With this fix, failed migrations will be fully rolled back as intended,
allowing you to make fixes & run `up` again without issue.
Copy link

@drujensen-happymoney drujensen-happymoney left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding and fixing this. 💯

@drujensen drujensen merged commit 7e4496f into amberframework:master Jan 31, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants