Re: invalid message format and I/O error while comunicating with backend - Mailing list pgsql-jdbc

From Kris Jurka
Subject Re: invalid message format and I/O error while comunicating with backend
Date
Msg-id 481901F4.1070302@ejurka.com
Whole thread Raw
In response to invalid message format and I/O error while comunicating with backend  (Sergi Vera <svera@emovilia.com>)
Responses Re: invalid message format and I/O error while comunicating with backend  (Sergi Vera <svera@emovilia.com>)
List pgsql-jdbc
This appears to be a thread safety related problem.  I believe your code
has one thread setting the parameter values and another thread executing
the prepared statement at the same time.  The executor does two passes
through the parameter list, once to calculate a total message length and
another time to send the values.  If the contents change between the
length calculation and the message sending we'll have the wrong length
and the whole client-server communication gets messed up.  The attached
test case demonstrates this failure mode.

I'm unsure how hard we should try to fix this, there are a couple of
approaches:

1) Do nothing.  It's really a client problem and they shouldn't be
setting and executing at the same time.

2) Just copy the parameters at execution time so we get a consistent
view of them.  This may not be exactly what the user wants though if the
order things actually execute is:  execute, set, copy instead of
execute, copy, set.

3) Go through all the PreparedStatement functions making most of them
synchronized so that you cannot set while an execute is running.

Kris Jurka

Sergi Vera wrote:
> Hi!
>
> I've been a little busy thoose days and was unable to work on this, but
> I've made the tcpdump session that you requested and
> here are the results
>
>
> Kris Jurka escribió:
>> Sergi Vera wrote:
>>> Thanks Kris for the help
>>>
>>> Adding loglevel=2 dind't add any more info on logs, and it will be
>>> not easy to make a self contained program, but I have attached the
>>> result of
>>
>> The loglevel=2 logging will go to the driver's System.out not into the
>> server error log.
>>
>>> tcpdump -vvv -i lo -w pgsqlerror2.dat
>>>
>>
>> This only captures the start of each packet so it doesn't have the
>> whole thing.  Could you recapture with:
>>
>> tcpdump -n -w pgsqlerror3.dat -s 1514 -i any tcp port 5432
>>
>> This ups the capture size (-s 1514) and also filters out the unrelated
>> UDP traffic you've got going on.
>>
>>> Browsing through the first failing pgsql data chunk, one can see that:
>>>
>>> http://img139.imageshack.us/my.php?image=pantallazolm8.png
>>>
>>> The last data has column lenght -1 which seems strange even if I
>>> don'k know anything of this particular protocol
>>>
>>
>> -1 length indicates a NULL value, so that's expected.
>>
>
>


import java.sql.*;

public class ThreadPS {

    public static void main(String args[]) throws Exception {
        Class.forName("org.postgresql.Driver");
        Connection conn = DriverManager.getConnection("jdbc:postgresql://localhost:5432/jurka","jurka","");

        Statement stmt = conn.createStatement();
        stmt.execute("CREATE TEMP TABLE threadps (a int, b text, c text)");
        stmt.close();

        PreparedStatement ps = conn.prepareStatement("INSERT INTO threadps VALUES (?,?,?)");
        ps.setInt(1,0);
        ps.setString(2, "0");
        ps.setString(3, "");

        Executor exec = new Executor(ps);
        new Thread(exec, "Exec").start();

        Setter set = new Setter(ps);
        new Thread(set, "Set").start();
    }

    static class Executor implements Runnable {
        private PreparedStatement ps;
        Executor(PreparedStatement ps) {
            this.ps = ps;
        }

        public void run() {
            while (true) {
                try {
                    ps.executeUpdate();
                } catch (SQLException sqle) {
                    sqle.printStackTrace();
                    System.exit(1);
                }
            }
        }
    }

    static class Setter implements Runnable {
        private PreparedStatement ps;
        Setter(PreparedStatement ps) {
            this.ps = ps;
        }

        public void run() {
            int count = 0;
            while (true) {
                try {
                    if (count++ % 2 == 0) {
                        ps.setInt(1,10);
                        ps.setString(2, "aa");
                        ps.setString(3, "bb");
                    } else {
                        ps.setInt(1, 1);
                        ps.setString(2, "a");
                        ps.setString(3, "b");
                    }
                } catch (SQLException sqle) {
                    sqle.printStackTrace();
                    System.exit(1);
                }
            }
        }
    }

}

pgsql-jdbc by date:

Previous
From: Andrew Perepelytsya
Date:
Subject: BLOB is read into memory instead of streaming (bug?)
Next
From: Kris Jurka
Date:
Subject: Re: BLOB is read into memory instead of streaming (bug?)