brettwooldridge / HikariCP

光 HikariCP・A solid, high-performance, JDBC connection pool at last.
Apache License 2.0
19.63k stars 2.9k forks source link

Connection schema is not recovered to settings value when setSchema is used (underline connection is Postgres). #2170

Open hondogo opened 4 months ago

hondogo commented 4 months ago

Reproduction code with explanations in comments:

public static void main(String[] args) throws Exception {
        try (HikariDataSource dataSource = new HikariDataSource()) {
            // configuring connection settings for Postgres
            dataSource.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres"); // change to your Postgres connection settings
            dataSource.setUsername("postgres"); // change to your Postgres connection settings
            dataSource.setPassword("postgres"); // change to your Postgres connection settings
            //
            dataSource.setAutoCommit(false);
            dataSource.setSchema("public");
            dataSource.setMinimumIdle(1); // to be ensured we take the same connection from pool
            dataSource.setMaximumPoolSize(1); // to be ensured we take the same connection from pool
            // preparing for test (creating schema schema1 if not exists)
            try (Connection connection = dataSource.getConnection()) {
                connection.setSchema("schema1");
                if (connection.getSchema() == null) {
                    try (PreparedStatement stm = connection.prepareStatement("create schema schema1")) {
                        stm.executeUpdate();
                    }
                }
                connection.setSchema("public"); 
                connection.commit();
            }
            // start of test
            try (Connection connection = dataSource.getConnection()) {
                if (!"public".equals(connection.getSchema())) { // OK (skip if)
                    throw new AssertionError(connection.getSchema());
                }
                connection.setSchema("schema1");
                if (!"schema1".equals(connection.getSchema())) { // OK (skip if)
                    throw new AssertionError(connection.getSchema());
                }
                connection.commit(); // Postgres save default schema in session scope on commit
                connection.setSchema("public");
                connection.rollback(); // Postgres restore default schema in session from last commit (schema1) but com.zaxxer.hikari.pool.ProxyConnection::dbschema is still equals to "public" schema
                if ("public".equals(connection.getSchema())) { // OK (skip if) ProxyConnection.getSchema is directly calling Postgres connection getSchema() that is schema1 after rollback
                    throw new AssertionError(connection.getSchema());
                }
            } // while on close there is code in com.zaxxer.hikari.pool.PoolBase :
            /*
                // This if statement will be skipped case proxyConnection.getSchemaState() will return not actual schema from variable com.zaxxer.hikari.pool.ProxyConnection::dbschema, so schema in settings is equals to not actual value
                if ((dirtyBits & 32) != 0 && this.schema != null && !this.schema.equals(proxyConnection.getSchemaState())) {
                    connection.setSchema(this.schema);
                    resetBits |= 32;
                }
                // proposed solution is to change call to proxyConnection.getSchemaState() to connection.getSchema()
                // or may be needed to assign actual schema to com.zaxxer.hikari.pool.ProxyConnection::dbschema after rollback to make it sync (if default schema is specified in settings)
             */
            try (Connection connection = dataSource.getConnection()) {
                if (!"public".equals(connection.getSchema())) { // FAIL (execute if body) cause actual Postgres connection schema is "schema1" (it was not reset on previous ProxyConnection::close)
                    throw new AssertionError(connection.getSchema());
                }
            }
        }
    }