Thread: CallableStatement and getUpdateCount

CallableStatement and getUpdateCount

From
Sam Lawrence
Date:
Hi,

I have a query about using CallableStatement with functions that return
a SETOF. I know the "Calling Stored Functions" documentation says use a
Statement or a PreparedStatement - I'm in the process of porting over a
database and would like to leave my calling code the same - that means
CallableStatement (more in a moment).

First, an example. A simple function (I know the SETOF is redundant in
this example, normally it wouldn't be) -

    CREATE OR REPLACE FUNCTION cstest()
    RETURNS SETOF integer AS
    $$
        SELECT 1;
    $$
    LANGUAGE 'sql' VOLATILE;

The calling code -

    Class.forName("org.postgresql.Driver");
    Connection con = DriverManager.getConnection("...");

    CallableStatement cs = con.prepareCall("{call cstest()}");
    cs.execute();

    System.out.println("update count - should be -1? " +
cs.getUpdateCount());

    ResultSet rs = cs.getResultSet();
    while(rs.next())
    {
        System.out.println(rs.getInt(1));
    }
    rs.close();
    cs.close();
    con.close();

The code works fine and returns the record correctly. My problem is the
getUpdateCount after the execute - from the java.sql.Statement
documentation "if the result is a ResultSet object or there are no more
results, -1 is returned". It actually comes back as 1. Is this a bug or
have I missed something?

I found this problem via Spring's
org.springframework.jdbc.object.StoredProcedure class - it doesn't find
any ResultSets because it relies on the value of getUpdateCount.

I'm running PostgreSQL 8.3.0 with postgresql-8.3-603.jdbc4.

Thanks in advance.

Sam.



Re: CallableStatement and getUpdateCount

From
"Albe Laurenz"
Date:
Sam Lawrence wrote:
> I have a query about using CallableStatement with functions that return
> a SETOF. I know the "Calling Stored Functions" documentation says use a
> Statement or a PreparedStatement - I'm in the process of porting over a
> database and would like to leave my calling code the same - that means
> CallableStatement (more in a moment).
>
> First, an example. A simple function (I know the SETOF is redundant in
> this example, normally it wouldn't be) -
>
>     CREATE OR REPLACE FUNCTION cstest()
>     RETURNS SETOF integer AS
>     $$
>         SELECT 1;
>     $$
>     LANGUAGE 'sql' VOLATILE;
>
> The calling code -
>
>     Class.forName("org.postgresql.Driver");
>     Connection con = DriverManager.getConnection("...");
>
>     CallableStatement cs = con.prepareCall("{call cstest()}");
>     cs.execute();
>
>     System.out.println("update count - should be -1? " + cs.getUpdateCount());
>
>     ResultSet rs = cs.getResultSet();
>     while(rs.next())
>     {
>         System.out.println(rs.getInt(1));
>     }
>     rs.close();
>     cs.close();
>     con.close();
>
> The code works fine and returns the record correctly. My problem is the
> getUpdateCount after the execute - from the java.sql.Statement
> documentation "if the result is a ResultSet object or there are no more
> results, -1 is returned". It actually comes back as 1. Is this a bug or
> have I missed something?
>
> I'm running PostgreSQL 8.3.0 with postgresql-8.3-603.jdbc4.

Hmmm. getUpdateCount() is defined in
org/postgresql/jdbc2/AbstractJdbc2Statement.java as

    public int getUpdateCount() throws SQLException
    {
[...]
        if (isFunction)
            return 1;
[...]
    }

So it will always return 1 for a callable statement.

There is no comment in the source. Does anybody know why that is?

Yours,
Laurenz Albe

Re: CallableStatement and getUpdateCount

From
Kris Jurka
Date:

On Tue, 1 Apr 2008, Albe Laurenz wrote:

> Hmmm. getUpdateCount() is defined in
> org/postgresql/jdbc2/AbstractJdbc2Statement.java as
>
>        if (isFunction)
>            return 1;
>

I would guess that this code was conceived without regard to returning
sets.  For code that does {? = call f()} you expect the caller to fetch
the result using CallableStatement.getXXX() so that's why the code isn't
indicating that a ResultSet is returned even though there is one under the
hood.  The JDBC driver has no idea whether the function it's calling is
returning a SETOF or not, so it can't use that to determine what to return
for getUpdateCount.

Perhaps we can differentiate between calls of the form {call f()} and {? =
call f()} ?

Kris Jurka

Re: CallableStatement and getUpdateCount

From
"Albe Laurenz"
Date:
Kris Jurka wrote:
> > Hmmm. getUpdateCount() is defined in
> > org/postgresql/jdbc2/AbstractJdbc2Statement.java as
> >
> >        if (isFunction)
> >            return 1;
>
> I would guess that this code was conceived without regard to returning
> sets.  For code that does {? = call f()} you expect the caller to fetch
> the result using CallableStatement.getXXX() so that's why the code isn't
> indicating that a ResultSet is returned even though there is one under the
> hood.  The JDBC driver has no idea whether the function it's calling is
> returning a SETOF or not, so it can't use that to determine what to return
> for getUpdateCount.
>
> Perhaps we can differentiate between calls of the form {call f()} and {? =
> call f()} ?

If I understood correctly then there *is* a result set in the case mentioned.

Would it work as desired if the two checks in getUpdateCount were reversed?

        if (result.getResultSet() != null)
            return -1;

        if (isFunction)
            return 1;

Or is there a problem I do not see?

Yours,
Laurenz Albe

Re: CallableStatement and getUpdateCount

From
Kris Jurka
Date:

On Wed, 2 Apr 2008, Albe Laurenz wrote:

> If I understood correctly then there *is* a result set in the case mentioned.
>
> Would it work as desired if the two checks in getUpdateCount were reversed?
>
>        if (result.getResultSet() != null)
>            return -1;
>
>        if (isFunction)
>            return 1;
>

Reading some more, the whole "if (isFunction)" line is bogus.  I was
thinking that the current situation was that all function calls returned
an update count of 1, but that's not true.  If you look at the code in
AbstractJdbc2Statement.executeWithFlags(int) you can see that if someone
has registered an output parameter (returnTypeSet), then it extracts the
results out of the underlying ResultSet and discards it (sets it to null).
So when getUpdateCount is called, the first result == null check is hit so
we return -1.

So right now the only case we're returning 1 is when we actually do have a
ResultSet which is exactly the opposite of what we want.  I've applied the
attached patch to CVS and backpatched to 8.0.

Kris Jurka

Attachment

Re: CallableStatement and getUpdateCount

From
Sam Lawrence
Date:
Kris Jurka wrote:
> So right now the only case we're returning 1 is when we actually do
> have a ResultSet which is exactly the opposite of what we want.  I've
> applied the attached patch to CVS and backpatched to 8.0.
>
> Kris Jurka
Many thanks Kris - that fixes it. I can also confirm that Spring's
org.springframework.jdbc.object.StoredProcedure now behaves as expected.

Sam.


Re: CallableStatement and getUpdateCount

From
"Albe Laurenz"
Date:
Kris Jurka wrote:
> So right now the only case we're returning 1 is when we actually do have a
> ResultSet which is exactly the opposite of what we want. I've applied the
> attached patch to CVS and backpatched to 8.0.

Cool, thanks!

Laurenz Albe