jaybird icon indicating copy to clipboard operation
jaybird copied to clipboard

Current statement has no data to return. [JDBC605]

Open firebird-automations opened this issue 5 years ago • 3 comments

Submitted by: Attila Molnár (e_pluribus_unum)

Hi Mark!

The "test" proc is selectable, but executed via EXECUTE PROCEDRURE/CallableStatement. Reading out parameter cause "Current statement has no data to return." exception. I think in this case null value should be returned The resultset is empty beacuse of no suspend is actually called in "test", but it was not executed via SELECT.

try(Connection conn = ds.getConnection()) { String create = "create or alter procedure test\n" + "returns (msg varchar(1000))\n" + "as\n" + "begin\n" + " msg = '';\n" + " if (msg <> '') then suspend;\n" + "end"; conn.setAutoCommit(false); conn.setReadOnly(false); conn.createStatement().execute(create); conn.commit(); CallableStatement cs = conn.prepareCall("EXECUTE PROCEDURE test (?)"); cs.registerOutParameter(1, java.sql.Types.VARCHAR); cs.execute(); String msg = cs.getString("MSG");//Current statement has no data to return. }

firebird-automations avatar Dec 10 '19 17:12 firebird-automations

Modified by: Attila Molnár (e_pluribus_unum)

priority: Major [ 3 ] => Minor [ 4 ]

firebird-automations avatar Dec 10 '19 17:12 firebird-automations

Commented by: @mrotteveel

Jaybird will automatically convert this to `SELECT * FROM test(?)` because the presence of SUSPEND in the code will make the procedure selectable. Using `CallableStatement.getXXX` is not advisable for selectable procedures. This specific case is explicitly handled in the code (see https://github.com/FirebirdSQL/jaybird/blob/master/src/main/org/firebirdsql/jdbc/AbstractCallableStatement.java#L1012), and has been this way for years (eg see in Branch_1_0: https://github.com/FirebirdSQL/jaybird/blob/Branch_1_0/src/main/org/firebirdsql/jdbc/FBCallableStatement.java#L1284)

If you don't want the automatic conversion, you can either specify connection property `ignoreProcedureType=true`, or for this specific case use `cs.unwrap(FirebirdCallableStatement.class).setSelectableProcedure(false);`. This will then work because an `execute procedure` will always have a result.

The first option (`ignoreProcedureType=true`) will have effect for all statements on the connection, and will result in call escapes to also always use `EXECUTE PROCEDURE`, which may not be what you want.

Alternatively, use `executeQuery()` and iterate over the result set.

firebird-automations avatar Dec 14 '19 13:12 firebird-automations

Commented by: @mrotteveel

I am considering expanding the ignoreProcedureType property to allow a little bit more fine-grained control (eg to not perform the transformation of EXECUTE PROCEDURE, but do perform it for the call-escape).

To be honest, I'm not really happy with how stored procedures work in Jaybird currently, but with nearly two decades of history in the current behaviour, I also don't want to break existing applications.

firebird-automations avatar Dec 14 '19 14:12 firebird-automations

I added a test asserting the existing behaviour.

mrotteveel avatar Jan 20 '23 15:01 mrotteveel

I'm going to leave the existing behaviour as is.

mrotteveel avatar Jan 20 '23 15:01 mrotteveel