How to collect warnings/notices while JDBC statement is being executed?

Boris Schegolev :

I am experiencing an issue with the latest version of PostgreSQL JDBC driver: I can not collect warnings/notices while the prepared statement is still being executed. Warning list only becomes available after the statement returns.

I used this feature with some previous driver version (I guess 9.1), but the implementation of PgPreparedStatement has probably changed since then.

What are my options to collect warnings before results are returned?

I created this simple test:

public class WarningTest {

    @Test
    public void readWarnings() throws Exception {
        Connection con = DriverManager.getConnection("jdbc:postgresql://localhost:5432/test_db", "test_user", "test_password");
        createTestFunction(con);

        PreparedStatement statement = con.prepareStatement("SELECT test_function();");
        SQLWarning[] warnings = new SQLWarning[1];
        new Timer().schedule(new TimerTask() {
            @Override public void run() {
                try {
                    warnings[0] = statement.getWarnings();
                } catch (SQLException e) {
                    Assert.fail("Exception thrown: " + e.getMessage());
                }
            }
        }, 3500);
        statement.executeQuery();
        Thread.sleep(1000);
        statement.close();

        Assert.assertNotNull(warnings[0]);
        Assert.assertFalse(warnings[0].getMessage().isEmpty());
    }

    private void createTestFunction(Connection con) throws SQLException {
        final PreparedStatement statement = con.prepareStatement(
            "CREATE OR REPLACE FUNCTION test_function() RETURNS VOID AS\n"
            + "$BODY$\n"
            + "BEGIN\n"
            + "\tFOR i IN 1..3 LOOP \n"
            + "\t\tRAISE NOTICE 'Tick %', i;\n"
            + "\t\tEXECUTE pg_sleep(1);\n"
            + "\tEND LOOP;\n"
            + "END\n"
            + "$BODY$\n"
            + "\tLANGUAGE plpgsql STABLE;");
        statement.execute();
        statement.close();
    }
}

It creates a function that runs for 3 seconds and writes a tick at the beginning of each second.

Test passes like this as the timer starts after result is returned. But if you decrease the timer delay from 3500 to 1500 the test will fail even though the database would have issued 2 notices by that time.

Magnus :

This issue was introduced with REL9.4.1210 versions REL9.4.1209 and below work as expected.

Line 244 of this commit is the reason why this no longer works, the warnings were previously added directly to the statement as soon as they were received, but it was re-factored and now they are only available after completion.

I have raised an issue for this, as well as a PR to address it.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=476016&siteId=1