Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 424
Boris Schegolev Avatar asked Jun 23 '17 12:06

Boris Schegolev


People also ask

What is a JDBC error?

JDBC connection errors. Connection errors are typically caused by incorrect or invalid connection string parameters, such as an invalid host name or database name. Verify that you are using correct and valid connection string parameters for the Gate.


1 Answers

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.

like image 77
Magnus Avatar answered Sep 20 '22 15:09

Magnus