ccgus / fmdb

A Cocoa / Objective-C wrapper around SQLite
Other
13.84k stars 2.76k forks source link

Allow to access sqliteHandle on queue or implement interrupt #325

Open stoprocent opened 9 years ago

stoprocent commented 9 years ago

Hi I'm running long search queries and I wanted to be able to cancel a query with sqlite3_interrupt. All my database operations are runing on FBDatabaseQueue because of the nature my code is structured. Thing is if I run a sqlite3_interrupt([db sqliteHandle]) inside inDatabase block it will wait until long query is done.

I can develop this feature and create pull request but I didnt dig deep enough in fmdb code to see if it will have impact in other places like transactions etc.

From SQLite Docs it looks like its safe: https://www.sqlite.org/c3ref/interrupt.html An SQL operation that is interrupted will return SQLITE_INTERRUPT. If the interrupted SQL operation is an INSERT, UPDATE, or DELETE that is inside an explicit transaction, then the entire transaction will be rolled back automatically.

For now i have a very DIRTY solution :)

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
    // Cancel long running query
    // Needs a hack as FMDB is not allowing me to access sqliteHandle outside synchronus queue
    FMDatabase *db = [self.dbQueue performSelector:NSSelectorFromString(@"database")];
    sqlite3_interrupt([db sqliteHandle]);
#pragma clang diagnostic pop
ccgus commented 9 years ago

Does your solution actually work better than sqlite3_interrupt([db sqliteHandle]), inside a block? Something like this:

_q = [FMDatabaseQueue databaseQueueWithPath:nil];

__block sqlite3 *dbHandle;
[_q inDatabase:^(FMDatabase *db) {
    dbHandle = [db sqliteHandle];
}];

// do stuff with dbHandle later on, which of course will not be thread safe unless it's inside a fmdatabasequeue block
stoprocent commented 9 years ago

Problem with that "inDatabase" will runs block with dispatch_sync on a private queue and if one query is taking very long to run and you just want to cancel it from outside inDatabase block you cant do it :(

With your solution what will happen is that long running query will finish and you will have nothing to cancel :)

ccgus commented 9 years ago

I see. Can you add a test to your pull request, so I can see how it's used, as well as making sure it doesn't break in future updates (assuming I add it). Sounds like a reasonable idea- I just want to make sure I understand everything completely.

stoprocent commented 9 years ago

Sure thing

evands commented 9 years ago

stoprocent, have you continued to use this (which I see you submitted in pull request [cbc418841115f05358a676ded83c85cb2a6eb7b2]) with success?