Skip to content

Implementation of getGeneratedKeys() - #1067

Closed
prrvchr wants to merge 5 commits into
xerial:masterfrom
prrvchr:master
Closed

Implementation of getGeneratedKeys()#1067
prrvchr wants to merge 5 commits into
xerial:masterfrom
prrvchr:master

Conversation

@prrvchr

@prrvchr prrvchr commented Feb 6, 2024

Copy link
Copy Markdown
Contributor

No description provided.

@gotson

gotson commented Feb 6, 2024

Copy link
Copy Markdown
Collaborator

we would need some unit test coverage

Comment on lines +428 to +432
int pos = sql.lastIndexOf(';');
int index = pos != -1 ? pos : sql.length();
String prefix = sql.substring(0, index);
String suffix = sql.substring(index);
sql = prefix + " RETURNING " + keys + suffix;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is quite dangerous to perform such changes on the fly on the query. There is no query manipulation in this driver, and if we were to add it, it would need a proper sql parser.

My understanding from your issue was that if the user submits a query with RETURNING, the keys would be made available, else they would be ignored.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is quite dangerous to perform such changes on the fly on the query. There is no query manipulation in this driver, and if we were to add it, it would need a proper sql parser.

Simply add (before a possible ;) the word RETURNING and a * for all the columns or columns chosen by their name. I don't think a parser is needed to make such simple changes.
This may seem a bit ugly but I believe it is the right way to get as close as possible to the JDBC API.

My understanding from your issue was that if the user submits a query with RETURNING, the keys would be made available, else they would be ignored.

No more precisely if the user submits a query with:

  • execute(String sql, int autoGeneratedKeys) or executeUpdate(String sql, int autoGeneratedKeys) with autoGeneratedKeys == RETURN_GENERATED_KEYS
  • execute(String sql, String[] colnames)
  • executeUpdate(String sql, String[] colnames)
  • executeLargeUpdate(String sql, String[] colnames)
    Then all the keys or the one requested will be available in the getGeneratedKeys() method.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may seem a bit ugly

you got the gist of it. I am not keen on proceeding on merging this PR in that state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK what do you suggest?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as i said, if a statement contains RETURNING, the driver could return the generated keys.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can parse it like this:

int pos = sql.indexOf(';');
int index = pos != -1 ? pos : sql.length();
StringBuilder buffer = new StringBuilder(sql.substring(0, index));
buffer.append(" RETURNING ");
buffer.append(keys);
buffer.append(sql.substring(index));
sql = buffer.toString();

In any case, any parser won't do much different than that?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

as i said, if a statement contains RETURNING, the driver could return the generated keys.

I understood that well, but why ask me to do PR if it's to answer me that?

Your solution does not follow the JDBC API for two reasons:

  • an executeUpdate cannot return a resultset.
  • SQL INSERT commands must be carried out using the executeUpdate() method.

As a result, software following JDBC specifications will not work with sqlite-jdbc. It's really a shame...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a result, software following JDBC specifications will not work with sqlite-jdbc. It's really a shame...

compromises have to be made, SQLite is very different from other DB engines.

@gotson

gotson commented Feb 6, 2024

Copy link
Copy Markdown
Collaborator

I think there was some misunderstanding about the issue you raised, and the PR you created.

  • Getting multiple generated keys for a multi-insert statement is not possible in SQLite, unless you use a RETURNING clause
  • this project will not add query modification on the fly. Doing so in a safe manner would require a parser, and at the moment this project does not include one.
  • checking whether a provided query contains some keywords is fine, even without a parser. It could be wrong, but the risk is small.

A possible solution would be to detect whether the query contains a RETURNING keyword, and if that is the case, provide the returned keys from the statement inside getGeneratedKeys. I believe that is what sqlite-jna does.

However, i believe that in your particular use case, you do not control the queries, and as such you would not be able to use a RETURNING clause.

@prrvchr

prrvchr commented Feb 6, 2024

Copy link
Copy Markdown
Contributor Author

However, i believe that in your particular use case, you do not control the queries, and as such you would not be able to use a RETURNING clause.

This is exactly my problem, it's LibreOffice Base which controls my driver.
On the other hand, I have just implemented this operating mode in my driver and it works quite well.
Is it complicated to compile sqlite-jdbc?

@gotson

gotson commented Feb 7, 2024

Copy link
Copy Markdown
Collaborator

Feel free to use your own fork if you need. I will not merge this PR.

Is it complicated to compile sqlite-jdbc?

It is not, if you read the documentation. What is it you are struggling with ?

@gotson gotson added the wontfix label Feb 7, 2024
@gotson gotson closed this Feb 7, 2024
@prrvchr

prrvchr commented Feb 7, 2024

Copy link
Copy Markdown
Contributor Author

Feel free to use your own fork if you need. I will not merge this PR.

The job of a driver is to follow a standard here JDBC.
Its developer must do everything possible to follow this standard (cache of results, deferred loading, rewriting of queries).
But you seem determined not to modify the queries and therefore not to be able to follow the JDBC specifications .
I repeat, but under JDBC the INSERT, UPDATE and DELETE SQL command are done by the java.sql.Statement.executeUpdate() methode and not java.sql.Statement.execute() which is reserved for obtaining java.sql.ResultSet and obtaining dynamic keys following an INSERT or an UPDATE is done by the java.sql.getGeneratedKeys() method and for JDBC if the getGenratedKeys() method is not present then the management of records in writing (INSERT) can only be done record by record (goodbye performance).

You are free to do what you want, but do not ask the other to produce PRs if in the end they are refused without even being tested.

And I think it would be good if you put a link to my archive with an explanation to make it available to those who need to follow the JDBC specifications.

@gotson

gotson commented Feb 8, 2024

Copy link
Copy Markdown
Collaborator

honestly you start to be annoying. I already stated the position of this project, if you are not happy, move along, or fork the project. It's open source after all.

Repository owner locked as too heated and limited conversation to collaborators Feb 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants