xerial / sqlite-jdbc

SQLite JDBC Driver
Apache License 2.0
2.86k stars 619 forks source link

getGeneratedKeys no longer working after calling executeBatch #1109

Closed aaime closed 6 months ago

aaime commented 6 months ago

Describe the bug We have a generic library that connects to a variety of JDBC data sources. Among the other things, it has code paths that perform addBatch/executeBatch, and then fetch generated keys. This used to work fine in 3.41.2.2, but is now broken in 3.45.3.0, the resultset of generated keys is empty. For the Sqlite case we limit the batch size to 1.

To Reproduce

Here is a sample program:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQLiteJDBCExample {

    public static void main(String[] args) throws SQLException, ClassNotFoundException {
        Class.forName("org.sqlite.JDBC");

        try (Connection connection = DriverManager.getConnection("jdbc:sqlite:test.db")) {
            connection.setAutoCommit(false);

            // Create a table
            try (Statement statement = connection.createStatement()) {
                statement.executeUpdate("CREATE TABLE IF NOT EXISTS Records (id INTEGER PRIMARY " +
                        "KEY " +
                        "AUTOINCREMENT, name TEXT)");
            }

            // Prepare a statement to insert records
            try (PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " +
                    "Records (name) VALUES (?)", Statement.RETURN_GENERATED_KEYS)) {

                // Insert 3 records using batch processing
                preparedStatement.setString(1, "John");
                preparedStatement.addBatch();
                preparedStatement.executeBatch();

                // Fetch the generated keys
                try (ResultSet generatedKeys = preparedStatement.getGeneratedKeys()) {
                    System.out.println("Generated keys:");
                    while (generatedKeys.next()) {
                        System.out.println("Key: " + generatedKeys.getInt(1));
                    }
                }

                // Commit the transaction
                connection.commit();
            }
        }
    }
}

With the old driver, the generated keys were returned, with the new version, the set is empty. I've noticed that even with the old version, trying to add two items in the batch, would result in only one key returned (and this is likely why Sqlite is limited to 1 entry in the batch).

Would it be possible to restore key fetching for single-entry batches? (the alternative would be to make an exception for sqlite, which would make the current generic code a bit hairy).

gotson commented 6 months ago

Sqlite cannot return multiple generated values. https://github.com/xerial/sqlite-jdbc/pull/1035 reintroduced support for single value insert.