-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Crash when lastInsertRowId is negative #438
Comments
I'm not sure if any return value of sqlite3_last_inserted_rowid can be treated as an error condition. Lib's wrapper probably shouldn't return an optional value: |
1 ) "If no successful INSERTs into rowid tables have ever occurred on the database connection D, then sqlite3_last_insert_rowid(D) returns zero." |
I think it's zero initially, but changed only on successful inserts. |
Would you like to submit a PR that changes that line to the following? return rowid != 0 ? rowid : nil |
@stephencelis
So, I believe the correct fix would be simply returning rowid as non-optional Int64. This doesn't seem to break anything in the lib except this place:
where rowid was unconditionally dereferenced anyway. If it's ok, I'll submit a PR with these changes. |
While it's possible to insert a |
This function can't be used for error checking because it doesn't change last_insert_rowid on failed insert. It's return value is meaningful only after a successful insert. Returning nil from it can give a false impression that it can be used for error checking. Probably run() itself should fail, and it does by throwing an exception.
Trying to insert a duplicate value:
|
A possible way of reporting errors would be storing the result of sqlite3_step somewhere and returning nil if the last insert failed, or rowid (including 0) otherwise, but it will change the behavior of lastInsertRowId compared to the original sqlite function which could be confusing. |
One of my goals for the Swift wrapper was to reduce error, so the fact that a
is a confusion I'd like to solve. Could we use |
Probably yes, but it's very hard to implement properly. For example:
There are two problems with this implementation:
Another option is renaming the function to avoid confusion, something along the:
|
According to FMDB, they didn't check rowid at all. |
@jberkel @stephencelis Yes, FMDB handles this correctly, SQLite.swift doesn't. SQLite.swift implementation:
I'm trying to explain that there's NO reason to compare rowid with zero!
I believe the correct implementation is simply returning |
Consider, for example, the following statement:
Insert(template: "INSERT INTO \"sessions\" (\"owner_id\", \"started\", \"victim_name\", \"topic\", \"line\", \"chat_id\") VALUES (?, ?, ?, ?, ?, ?)", bindings: [Optional(230594948), Optional(1), Optional(""), Optional(""), Optional(0), Optional(-147636081)])
chat_id is INTEGER PRIMARY KEY and negative value is inserted.
sqlite3_last_insert_rowid() returns -147636081 (as expected)
Lib's lastInsertRowId turns it into nil:
The app crashes because Connection.run() dereferences nil.
The text was updated successfully, but these errors were encountered: