From 31d085aecacb6e30f9fd9b154887b56608ced60b Mon Sep 17 00:00:00 2001 From: Magnus Persson <1431685+magnusp@users.noreply.github.com> Date: Sat, 31 Oct 2026 03:20:42 +0100 Subject: [PATCH] test(flyway): disable foreign keys in the DataSource Replace deprecated initSql with a DataSource that runs PRAGMA foreign_keys = OFF before returning each connection. An AFTER_CONNECT callback is not sufficient: Flyway has already disabled auto-commit when it runs, so the driver begins a transaction before the pragma and SQLite ignores it. Document the pool/DataSource connection-init setup instead. Closes #273. --- README.md | 22 +++++++++--------- .../libsql/jdbc/flyway/FlywayKnownGapsIT.java | 7 +++--- .../libsql/jdbc/flyway/FlywaySqldSupport.java | 23 ++++++++++++++++++- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 31643ad..f07ead3 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywayKnownGapsIT.java b/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywayKnownGapsIT.java index f521850..6bc2da2 100644 --- a/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywayKnownGapsIT.java +++ b/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywayKnownGapsIT.java @@ -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(); } diff --git a/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywaySqldSupport.java b/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywaySqldSupport.java index 23ca150..48639f1 100644 --- a/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywaySqldSupport.java +++ b/libsql-jdbc/src/test/java/io/github/magnusp/libsql/jdbc/flyway/FlywaySqldSupport.java @@ -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()); } @@ -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