When a statement is reading a result set, issuing close on it results could incorrectly return empty result set to the caller. This does not raise any exception.
When a statement is triggered to execute a query, jTDS parses the response TDS packet only till “column metadata” part, and gives the buffer pointer back to the caller to stream result set each row at a time. Whenever caller requests for new row, call comes back to jTDS to parse next one row from the input buffer - and this goes on until it reaches the DONE token, which signals end-of-results.
Problem arises when a typical connection pool issues a close() on the statement from a parallel thread, but the statement is still in use by the caller.
As part of the close() API implementation of jTDS statement:
1. BufferPointer is moved to the end of the buffer until the DONE token
2. Result set is marcked as closed
Now, if any statement just started to read rows between (1) and (2) - It assumes that there are no more rows (Since it sees DONE token) and it does not fail either since statement is still open. This ends up returning empty result set to the caller, assuming there are no rows to read.
Note: If statement reads during (1) - it fails to understand the packet and complains saying “TDS protocol error, Invalid byte XX”
If it reads after (2) - It fails saying “Statement is already closed. Failed to fetch column XXXX”
Attaching reproducer.