-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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 issue #724 & #711 - two threads attempt to use the same database connection & prepared statements #728
base: master
Are you sure you want to change the base?
Conversation
…eaded access to database connection
I had a similar issue with GRDB. When SQLite statements are not reset and finalized when the user needs it, the user may end up with SQLite functions not called on the required dispatch queue (uncontrolled deallocation), or statements that retain database locks longer than needed (late statement reset, with unwanted errors SQLITE_ERROR "destination database is in use"). Of course, the user is not always aware of SQLite subtleties, so the user often does not know what he needs (namely, statement cleanup at a correct point in the lifetime of the program). This PR calls Now, I may want to suggest a change to this PR. FMDB users may use statement caching. In this case, finalizing statements is too much, but a reset would still be helpful. |
@crmo If you could make this problem occur in a unit test, that would be super helpful to me figuring out wether or not this should be fixed in FMDB. Not closing your result sets is a programmer error IMO, which we might be able to clean up, but calling -closeOpenResultSets seems a bit heavy handed. |
@ccgus Thanks for your attention, I added a unit test for this problem. When I readed the FMDB
FMResultSet *s = [db executeQuery:@"SELECT COUNT(*) FROM myTable"];
if ([s next]) {
int totalCount = [s intForColumnIndex:0];
}
So I used Usually we will use |
I don't consider this a bug. If a client is going to open up a result set, it should be closed. And FMDB even prints out: You're right that the documentation should be updated to reflect this. |
@crmo Do you have contact information, such as QQ? |
Cached Root cause maybe gcd autorelease pool pop is not invoked when finish block execution, so temp var is not guarantee released on the serial queue(not check the gcd source code). |
Maybe need to assert on the FMResultSet should dealloc on the private queue. |
I write a demo to recurrent issue #724 & #711:
I think the crash reason was if user traversed FMResultSet used
if ([FMResultSet next])
and not call[FMResultSet close]
. When FMResultSetdealloc
inAutoreleasePoolPage::pop()
, then[FMResultSet close]
andsqlite3_reset(_statement)
will be called, if user reading or writing to the database currently, the database connection and prepared statements was accessed by multi-threaded.I suggest to modify this like this, if the user did not close the FMResultSet after the block ends, we close it in current dispatch_queue_t.