Обсуждение: DELETE ... RETURNING

Поиск
Список
Период
Сортировка

DELETE ... RETURNING

От
Thomas Kellerer
Дата:
Hi,

when using the RETURNING clause in a DELETE statement the driver throws an error:

org.postgresql.util.PSQLException: A result was returned when none was expected.

The code that I'm using is as follows:

Statement stmt = connection.createStatement();
stmt.executeUpdate("delete from person where firstname like 'A%' returning id");

Am I missing something or is the "RETURNING" feature not supported by the driver?

I'm using postgresql-8.4-701.jdbc3.jar with Java5

Regards
Thomas

Re: DELETE ... RETURNING

От
Dennis Brakhane
Дата:
On Mon, Jul 13, 2009 at 9:44 PM, Thomas Kellerer<spam_eater@gmx.net> wrote:
> Statement stmt = connection.createStatement();
> stmt.executeUpdate("delete from person where firstname like 'A%' returning
> id");
>
> Am I missing something or is the "RETURNING" feature not supported by the
> driver?

executeUpdate by definitionem can only return an int, the number of
rows affected.

You probably can use stmt.executeQuery instead

Re: DELETE ... RETURNING

От
Thomas Kellerer
Дата:
Dennis Brakhane wrote on 13.07.2009 21:51:
>> Am I missing something or is the "RETURNING" feature not supported by the
>> driver?
>
> executeUpdate by definitionem can only return an int, the number of
> rows affected.

True, but the JDBC API also defines Statement.getMoreResults() and
Statement.getResultSet() which could be used to return that information

At least executeUpdate() should not throw an exception.

> You probably can use stmt.executeQuery instead

Actually execute() works without throwing an exception, but getMoreResults() and
getResultSet() do not return the information about the deleted rows.

Additionally when using execute(), getUpdateCount() will return -1 even if rows
were deleted.

Thomas


Re: DELETE ... RETURNING

От
Oliver Jowett
Дата:
Thomas Kellerer wrote:

> At least executeUpdate() should not throw an exception.

Wrong, see the javadoc:

>     Throws:
>         SQLException - if a database access error occurs or the SQL statement returns a ResultSet object

Your SQL statement is returning a ResultSet object, so executeUpdate
correctly throws an exception.

Use executeQuery() or execute().

-O

Re: DELETE ... RETURNING

От
Thomas Kellerer
Дата:
Oliver Jowett wrote on 13.07.2009 23:42:
> Thomas Kellerer wrote:
>
>> At least executeUpdate() should not throw an exception.
>
> Wrong, see the javadoc:
Oops ;)

> Your SQL statement is returning a ResultSet object, so executeUpdate
> correctly throws an exception.
>
> Use executeQuery() or execute().

But execute() will not give the information about the returned IDs as
getMoreResults() always returns false.

And in my test getUpdateCount() returned -1 even though rows were deleted.

The following code will print "deleted: -1" and nothing more.

But my understanding is, that it should print "deleted: 3", and then iterate
over the returned ids (but at least show the correct update count)

Statement stmt = con.createStatement();

stmt.executeUpdate(
"CREATE TABLE test_delete (id integer primary key, some_data varchar(100))"
);
stmt.executeUpdate("insert into test_delete values (1, 'first row')");
stmt.executeUpdate("insert into test_delete values (2, 'second row')");
stmt.executeUpdate("insert into test_delete values (3, 'third row')");
con.commit();

stmt.execute("delete from test_delete returning id");
System.out.println("deleted: " + stmt.getUpdateCount());
if (stmt.getMoreResults())
{
   System.out.println("has result");
   rs = stmt.getResultSet();
   while (rs.next())
   {
     System.out.println(rs.getObject(1));
   }
}


Thomas

Re: DELETE ... RETURNING

От
Oliver Jowett
Дата:
Thomas Kellerer wrote:

> But my understanding is, that it should print "deleted: 3", and then
> iterate over the returned ids (but at least show the correct update count)

You might want to turn on logLevel=2 and see what the server's actually
telling us. The update count is usually just derived from the command
status string, maybe something odd is happening there with DELETE ..
RETURNING

-O

Re: DELETE ... RETURNING

От
Thomas Kellerer
Дата:
Oliver Jowett wrote on 13.07.2009 23:57:
> Thomas Kellerer wrote:
>
>> But my understanding is, that it should print "deleted: 3", and then
>> iterate over the returned ids (but at least show the correct update count)
>
> You might want to turn on logLevel=2 and see what the server's actually
> telling us. The update count is usually just derived from the command
> status string, maybe something odd is happening there with DELETE ..
> RETURNING


The log output looks fine as far as I can tell:

00:06:22.037 (1) simple execute,
handler=org.postgresql.jdbc2.AbstractJdbc2Statement$StatementResultHandler@a20892,
maxRows=0, fetchSize=0, flags=1
00:06:22.037 (1)  FE=> Bind(stmt=S_1,portal=null)
00:06:22.037 (1)  FE=> Execute(portal=null,limit=0)
00:06:22.037 (1)  FE=> Parse(stmt=null,query="delete from test_delete returning
id",oids={})
00:06:22.037 (1)  FE=> Bind(stmt=null,portal=null)
00:06:22.037 (1)  FE=> Describe(portal=null)
00:06:22.037 (1)  FE=> Execute(portal=null,limit=0)
00:06:22.037 (1)  FE=> Sync
00:06:22.053 (1)  <=BE BindComplete [null]
00:06:22.053 (1)  <=BE CommandStatus(BEGIN)
00:06:22.053 (1)  <=BE ParseComplete [null]
00:06:22.053 (1)  <=BE BindComplete [null]
00:06:22.053 (1)  <=BE RowDescription(1)
00:06:22.053 (1)  <=BE DataRow
00:06:22.053 (1)  <=BE DataRow
00:06:22.053 (1)  <=BE DataRow
00:06:22.053 (1)  <=BE CommandStatus(DELETE 3)
00:06:22.069 (1)  <=BE ReadyForQuery(T)

And it still doesn't explain why getMoreResults() is not working either.

Regards
Thomas

Re: DELETE ... RETURNING

От
Oliver Jowett
Дата:
Thomas Kellerer wrote:

> The following code will print "deleted: -1" and nothing more.

> stmt.execute("delete from test_delete returning id");
> System.out.println("deleted: " + stmt.getUpdateCount());
> if (stmt.getMoreResults())
> {
>   System.out.println("has result");
>   rs = stmt.getResultSet();
>   while (rs.next())
>   {
>     System.out.println(rs.getObject(1));
>   }
> }

I took another look at this, and your code assumes that the update count
is the first result. It's not. In the case where both a resultset and an
update count are present in a single query, the driver puts the
resultset result first (so that executeQuery() works nicely).

So your first call to getUpdateCount() returns -1 because the current
result is a resultset, not an update count (see the javadoc). Then you
call getMoreResults() which moves to the 2nd result (the update count)
and returns false because there's no resultset (again, see the javadoc).

If you want a general-purpose result processing loop, you want something
like this:

boolean hasResultSet = stmt.execute("...");
while (hasResultSet || stmt.getUpdateCount() != -1) {
  if (hasResultSet) {
    ResultSet rs = stmt.getResultSet();
    // .. process it ..
  } else {
    int updateCount = stmt.getUpdateCount();
    // .. process it ..
  }
  hasResultSet = stmt.getMoreResults();
}

-O

Re: DELETE ... RETURNING

От
Thomas Kellerer
Дата:
Oliver Jowett, 14.07.2009 00:35:
> I took another look at this, and your code assumes that the update count
> is the first result. It's not. In the case where both a resultset and an
> update count are present in a single query, the driver puts the
> resultset result first (so that executeQuery() works nicely).
>
> So your first call to getUpdateCount() returns -1 because the current
> result is a resultset, not an update count (see the javadoc). Then you
> call getMoreResults() which moves to the 2nd result (the update count)
> and returns false because there's no resultset (again, see the javadoc).
>
> If you want a general-purpose result processing loop

The perils of quick and dirty test programs...

I actually have that generic loop already, just failed to think it through completely before posting ;)

Sorry for the trouble and thanks for the help.

Regards
Thomas

Re: DELETE ... RETURNING

От
"Albe Laurenz"
Дата:
Thomas Kellerer wrote:
> when using the RETURNING clause in a DELETE statement the
> driver throws an error:
>
> org.postgresql.util.PSQLException: A result was returned when
> none was expected.
>
> The code that I'm using is as follows:
>
> Statement stmt = connection.createStatement();
> stmt.executeUpdate("delete from person where firstname like 'A%' returning id");
>
> Am I missing something or is the "RETURNING" feature not
> supported by the driver?
>
> I'm using postgresql-8.4-701.jdbc3.jar with Java5

That's easy; when you issue an SQL statement that returns a result,
you cannot use executeUpdate(java.lang.String).

Use executeQuery(java.lang.String) or execute(java.lang.String) and then getResultSet().

It does not matter whether the statement starts with SELECT or DELETE, the important
point is whether it returns a result set or not.

See for reference:
http://java.sun.com/j2se/1.5.0/docs/api/java/sql/Statement.html

Yours,
Laurenz Albe