Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,23 +245,23 @@ driver=io.github.magnusp.libsql.jdbc.LibsqlDriver
`jdbc:libsql:` cannot be used with URL-based configuration at all, even with an
explicit driver, because the plugin lookup fails first.

Auto-commit statements on one JDBC connection share a Hrana stream, so `initSql` and
`afterConnect` statements that set session state such as `PRAGMA foreign_keys` apply
to the migrations that follow on that connection.
Auto-commit statements on one JDBC connection share a Hrana stream, so a
connection-init statement that sets session state such as `PRAGMA foreign_keys`
applies to the migrations that follow on that connection.

Flyway wraps `clean()` in a transaction, and SQLite ignores `PRAGMA foreign_keys`
inside a transaction. Set the pragma when the connection is initialized, before
Flyway begins that transaction:
inside a transaction. Run the pragma when the DataSource hands over the connection,
before Flyway begins that transaction:

```properties
# flyway.properties
initSql=PRAGMA foreign_keys = OFF
# HikariCP / Spring Boot
spring.datasource.hikari.connection-init-sql=PRAGMA foreign_keys = OFF
```

```properties
# Spring Boot
spring.flyway.init-sqls=PRAGMA foreign_keys = OFF
```
For a programmatic `DataSource`, run the same statement in `getConnection()` before
returning the connection. Do not use an `AFTER_CONNECT` callback for this: Flyway has
already disabled auto-commit by then, so the driver starts a transaction before the
pragma and SQLite ignores it.

The driver splits Flyway's `PRAGMA foreign_keys = OFF; DROP TABLE ...; PRAGMA
foreign_keys = ON` scripts and runs every statement on the connection's stream (see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ private static Flyway flyway() {
/**
* Flyway wraps {@code clean()} in a transaction. SQLite ignores
* {@code PRAGMA foreign_keys} inside a transaction, so the pragma must run when the
* connection is initialized, before Flyway begins its transaction. The driver's
* connection-scoped auto-commit stream keeps that session state for the later statements.
* DataSource hands over the connection, before Flyway begins any transaction. The
* driver's connection-scoped auto-commit stream keeps that state for the later statements.
*/
private static Flyway flywayWithForeignKeysDisabled() {
return Flyway.configure()
.dataSource(dataSource())
.dataSource(dataSourceWithForeignKeysDisabled())
.locations("classpath:flyway/migration")
.cleanDisabled(false)
.initSql("PRAGMA foreign_keys = OFF")
.load();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ static DataSource dataSource() {
return new DriverManagerDataSource(jdbcUrl());
}

/** A DataSource that disables foreign keys before handing the connection to Flyway. */
static DataSource dataSourceWithForeignKeysDisabled() {
return new DriverManagerDataSource(jdbcUrl(), true);
}

static Connection connect() throws SQLException {
return DriverManager.getConnection(jdbcUrl());
}
Expand Down Expand Up @@ -138,14 +143,30 @@ private static String requireLibsqlImage() {
static final class DriverManagerDataSource implements DataSource {

private final String url;
private final boolean disableForeignKeys;

DriverManagerDataSource(String url) {
this(url, false);
}

DriverManagerDataSource(String url, boolean disableForeignKeys) {
this.url = url;
this.disableForeignKeys = disableForeignKeys;
}

@Override
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url);
Connection connection = DriverManager.getConnection(url);
if (!disableForeignKeys) {
return connection;
}
try (Statement statement = connection.createStatement()) {
statement.execute("PRAGMA foreign_keys = OFF");
return connection;
} catch (SQLException e) {
connection.close();
throw e;
}
}

@Override
Expand Down
Loading