question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Foreign Key constraint is ignored inside transaction on iOS

See original GitHub issue

https://github.com/yshrsmz/sqldelight-fktest

I have these two tables.

CREATE TABLE author (
    id INTEGER NOT NULL PRIMARY KEY,
    name TEXT NOT NULL,
    birthday TEXT NOT NULL
);

CREATE TABLE book (
    id INTEGER NOT NULL PRIMARY KEY,
    name TEXT NOT NULL,
    author_id INTEGER NOT NULL,
    FOREIGN KEY (author_id) REFERENCES author(id) ON DELETE CASCADE
);

and I’m trying to write a repository class which takes a list of books and insert those in one transaction.

fun save(books:List<Book>) {
	bookQueries.transaction {
		books.forEach { book ->
			bookQueries.insertOrReplace(...)
		}
	}
}

It should work just fine if corresponding author records exist, and it works as intended on Android. On iOS, above code does not respect Foreign Key constraint.

After some investigation I found out that on iOS, foreign keys are not working inside transaction. Below test case illustrates this.

@Test
fun `should fail as FK constraint is not satisfied - transaction`() {
    database.pragmasQueries.foreignKeysOn() // PRAGMA foreign_keys=1;

    val books = database.bookQueries.count().executeAsOne()
    val authors = database.authorQueries.count().executeAsOne()

    assertEquals(0, books)
    assertEquals(0, authors)

    var failed = false

    try {
        database.transaction {
            database.bookQueries.insert(id = book3.id, name = book3.name, author_id = book3.author_id)
        }
    } catch (e: Throwable) {
        println(e)
        failed = true
    }


    val books2 = database.bookQueries.count().executeAsOne()
    println("books count after insertion attempt: $books2")

    if (!failed) {
        fail("should throw exception")
    }
}

This test case passes on Android, and fails on iOS. And if I call insert statement without transaction, it passes on both platform.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
yshrsmzcommented, Jul 12, 2019

Confirmed it’s working on v1.1.4 with the code below. Thanks!

// iOS
val dbConfig = DatabaseConfiguration(
        name = "database.db",
        version = Schema.version,
        foreignKeyConstraints = true,
        create = { connection ->
            wrapConnection(connection) { Schema.create(it) }
        },
        upgrade = { connection, oldVersion, newVersion ->
            wrapConnection(connection) { Schema.migrate(it, oldVersion, newVersion) }
        }
    )

val driver = NativeSqlDriver(dbConfig)
// Android
val driver = AndroidSqliteDriver(
        schema = Database.Schema,
        context = context,
        name = "database.db",
        callback = object : AndroidSqliteDriver.Callback(Database.Schema) {
            override fun onConfigure(db: SupportSQLiteDatabase) {
                super.onConfigure(db)
                db.setForeignKeyConstraintsEnabled(true)
            }
        }
    )
1reaction
kpgalligancommented, Jun 23, 2019

Some more info. Future versions of sqliter will have a db config flag for this. I also think I understand why fk pragma wasn’t working in transactions: https://stackoverflow.com/a/7360240/227313

Read more comments on GitHub >

github_iconTop Results From Across the Web

Swift with FMDB DELETE ignoring foreign key constraints ...
I'm relying to an extent on the database integrity to throw errors if there is a foreign key when a delete occurs. I've...
Read more >
ON CONFLICT IGNORE equivalent for foreign key constraints
I'm currently trying to do a bulk insert of many rows of new data into a set of tables with foreign key relations....
Read more >
SQLite Foreign Key Support
SQL foreign key constraints are used to enforce "exists" relationships ... If the current statement is not inside an explicit transaction (a ...
Read more >
sql - chromium/src.git - Git at Google
SQL foreign key constraints should not be used. All data validation should be performed using explicit SELECT statements (generally wrapped as helper ...
Read more >
How to ignore foreign key constraints in SQL - Quora
I will assume that the PP is asking how to avoid violating the constraint during a transaction when the referenced row will not...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found