Skip to content
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

Proper / secure way to receive last_insert_rowid #329

Closed
b3nn0 opened this issue Mar 2, 2018 · 10 comments
Closed

Proper / secure way to receive last_insert_rowid #329

b3nn0 opened this issue Mar 2, 2018 · 10 comments
Labels
bug Something isn't working enhancement:JDBC Enhancement specific to the JDBC standard released Issue has been released

Comments

@b3nn0
Copy link
Contributor

b3nn0 commented Mar 2, 2018

Hi,
right now there are multiple ways to retrieve the last inserted rowid of an insert.
None of them is very good.

  • Query for "SELECT last_insertrowid()":
    -> Doesn't work in multithreaded applications

  • Add the select statement directly behind the INSERT query, e.g.
    "INSERT INTO a VALUES('x'); SELECT last_insert_rowid()"
    -> Doesn't work when the insert is a prepared statement. SQLite will only respect the first statement.

  • Call stmt.getGeneratedKeys()
    -> Just as unreliable. It seems to do a lazy call to last_insert_rowid(), which is, in my opinion, a bug.

As SqliteJdbc seems to synchronize everything going to SQLite, it would be quite easy to fix.
To do so, the library simply would need to call sqlite3_last_insert_rowid() right after the query.
JDBC already provides the API, see Statement.RETURN_GENERATED_KEYS constant.

Implementing it should be quite simple...
I could potentially provide a patch, if it has the chance to be accepted.

@gotson
Copy link
Collaborator

gotson commented Jul 29, 2022

Is this still happening on the latest version?

@gotson gotson added the waiting for feedback Waiting for a feedback from the issue creator label Jul 29, 2022
@gotson
Copy link
Collaborator

gotson commented Sep 7, 2022

I was recently working to fix #330 and i stumbled upon this.

  • Call stmt.getGeneratedKeys()
    -> Just as unreliable. It seems to do a lazy call to last_insert_rowid(), which is, in my opinion, a bug.

I agree with you on this, the generated keys should be related to the Statement.

As SqliteJdbc seems to synchronize everything going to SQLite, it would be quite easy to fix.
To do so, the library simply would need to call sqlite3_last_insert_rowid() right after the query.

This is not as simple though, as you can insert multiple values, and getGeneratedKeys should return all of them, not just the last one. This has been raised in #468

I see a few possible options:

  1. disable support for retrieving generated keys entirely. That would imply having DatabaseMetaData#supportsGetGeneratedKeys() returning false.
  2. add a RETURNING clause when generated keys are requested, in order to get what we need. I'm not sure what should happen when the application passes a query already containing a RETURNING clause though.

@gotson gotson added bug Something isn't working enhancement:JDBC Enhancement specific to the JDBC standard and removed waiting for feedback Waiting for a feedback from the issue creator labels Sep 7, 2022
@gotson
Copy link
Collaborator

gotson commented Sep 11, 2022

I've been thinking about this, and I think option 2 would require to have a sql parser. We would need to be able to find out whether there is already a RETURNING clause, and also to find out what's the table name so that we can infer the generated keys too.

gotson added a commit that referenced this issue Aug 16, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
SQLite does not provide a good way to retrieve generated keys in a reliable way

BREAKING-CHANGE: getGeneratedKeys is not supported anymore

Closes: #329
@gotson
Copy link
Collaborator

gotson commented Aug 16, 2023

@b3nn0 in the next major version the driver will not support anymore getGeneratedKeys, as there is no reliable way to retrieve those. The good way would be to use the SQLite RETURNING clause.

@b3nn0
Copy link
Contributor Author

b3nn0 commented Aug 16, 2023

Alright, makes sense. Closing this then.

@b3nn0 b3nn0 closed this as completed Aug 16, 2023
@gotson gotson reopened this Aug 16, 2023
@gotson
Copy link
Collaborator

gotson commented Aug 16, 2023

This will be closed automatically once merged

@gotson gotson closed this as completed in 712a8a5 Aug 25, 2023
@github-actions github-actions bot added the released Issue has been released label Aug 29, 2023
@github-actions
Copy link
Contributor

🎉 This issue has been resolved in 3.43.0.0 (Release Notes)

@sproket
Copy link

sproket commented Sep 9, 2023

How is removing a feature resolved? Anyway it breaks Persism but I'm doing it the new way for SQLite and it's working so I'll put out an update soon.

gotson added a commit to gotson/sqlite-jdbc that referenced this issue Oct 18, 2023
SQLite does not provide a good way to retrieve generated keys in a reliable way

BREAKING-CHANGE: getGeneratedKeys is not supported anymore

Closes: xerial#329
velo added a commit to OpenFeign/querydsl that referenced this issue Nov 10, 2023
velo added a commit to OpenFeign/querydsl that referenced this issue Nov 10, 2023
* Bump org.xerial:sqlite-jdbc from 3.36.0 to 3.43.2.2

Bumps [org.xerial:sqlite-jdbc](https://github.com/xerial/sqlite-jdbc) from 3.36.0 to 3.43.2.2.
- [Release notes](https://github.com/xerial/sqlite-jdbc/releases)
- [Changelog](https://github.com/xerial/sqlite-jdbc/blob/master/CHANGELOG)
- [Commits](xerial/sqlite-jdbc@3.36.0...3.43.2.2)

---
updated-dependencies:
- dependency-name: org.xerial:sqlite-jdbc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* Exclude all databased from regular tests

* Disable upsert tests, as SQLite don't support it

xerial/sqlite-jdbc#329

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marvin Froeder <velobr@gmail.com>
@barrycaceres
Copy link

If I am reading this correctly, the ability to obtain the generated keys has been removed entirely with no "proper" way to do it?

Those of us who were managing our connections and atomically doing single inserts and then immediately obtaining the generated keys were having no problem with the existing functionality because we understood that using it meant doing a single insert and before letting any other thread get your Connection object you had to get the generated key.

Simply removing this functionality because it did not work for those who did not understand how to do it safely seems like a non-fix but like crippling access to SQLite via JDBC.

@barrycaceres
Copy link

How is removing a feature resolved? Anyway it breaks Persism but I'm doing it the new way for SQLite and it's working so I'll put out an update soon.

BINGO! You are so right. Somebody dropped the ball here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement:JDBC Enhancement specific to the JDBC standard released Issue has been released
Projects
None yet
Development

No branches or pull requests

4 participants