Skip to content

Commit 3c17a1a

Browse files
divangDivang Sharma
andauthored
Fixed TDS message severity handling (#2741)
* Fixed TDS meesage severity handling * Fixed test cases which were failed due to onDone method is rasing ErrorSeverity 20 --------- Co-authored-by: Divang Sharma <[email protected]>
1 parent 86cae8c commit 3c17a1a

File tree

4 files changed

+92
-0
lines changed

4 files changed

+92
-0
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerError.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,10 @@ public void setErrorNumber(int newErrorNumber) {
347347
this.errorNumber = newErrorNumber;
348348
}
349349

350+
public void setErrorMessage(String errorMessage) {
351+
this.errorMessage = errorMessage;
352+
}
353+
350354
@Override
351355
public SQLException toSqlExceptionOrSqlWarning() {
352356
return new SQLServerException(this);

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ protected Object[][] getContents() {
575575
{"R_vectorByteArrayLength", "Vector byte array length must be at least 8 bytes."},
576576
{"R_invalidVectorData", "The provided type of data is not supported for vector."},
577577
{"R_vectorByteArrayMultipleOfBytesPerDimension", "Byte array length must be a multiple of {0} for vector of type {1}."},
578+
{"R_severeError", "A severe error occurred on the current command. The results, if any, should be discarded."},
579+
578580
};
579581
}
580582
// @formatter:on

src/main/java/com/microsoft/sqlserver/jdbc/tdsparser.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,12 +245,20 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
245245
}
246246

247247
boolean onDone(TDSReader tdsReader) throws SQLServerException {
248+
short status = tdsReader.peekStatusFlag();
248249
StreamDone doneToken = new StreamDone();
249250
doneToken.setFromTDS(tdsReader);
250251
if (doneToken.isFinal()) {
251252
// Response is completely processed hence decrement unprocessed response count.
252253
tdsReader.getConnection().getSessionRecovery().decrementUnprocessedResponseCount();
253254
}
255+
256+
if ((status & TDS.DONE_SRVERROR) != 0) {
257+
SQLServerError syntheticError = new SQLServerError();
258+
syntheticError.setErrorMessage(SQLServerException.getErrString("R_severeError"));
259+
syntheticError.setErrorSeverity((byte) 20);
260+
addDatabaseError(syntheticError);
261+
}
254262
return true;
255263
}
256264

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.microsoft.sqlserver.jdbc;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
import static org.mockito.Mockito.*;
5+
6+
import org.junit.jupiter.api.Test;
7+
import org.junit.jupiter.api.BeforeEach;
8+
import org.mockito.Mock;
9+
import org.mockito.MockitoAnnotations;
10+
11+
/**
12+
* Unit test for TDSTokenHandler onDone method, specifically testing
13+
* severity 25 (fatal) error handling and SQLServerError generation.
14+
*/
15+
public class TDSTokenHandlerTest {
16+
17+
@Mock
18+
private TDSReader mockTdsReader;
19+
20+
@Mock
21+
private SQLServerConnection mockConnection;
22+
23+
@Mock
24+
private IdleConnectionResiliency mockSessionRecovery;
25+
26+
@Mock
27+
private TDSCommand mockCommand;
28+
29+
@BeforeEach
30+
void setUp() throws SQLServerException {
31+
MockitoAnnotations.openMocks(this);
32+
33+
// Setup basic mocks
34+
when(mockTdsReader.getConnection()).thenReturn(mockConnection);
35+
when(mockConnection.getSessionRecovery()).thenReturn(mockSessionRecovery);
36+
when(mockTdsReader.getCommand()).thenReturn(mockCommand);
37+
38+
// Mock the TDS data reading methods that StreamDone.setFromTDS() needs
39+
when(mockTdsReader.readUnsignedByte()).thenReturn(TDS.TDS_DONE); // token type
40+
when(mockTdsReader.readShort()).thenReturn((short) 0); // status and curCmd
41+
when(mockTdsReader.readLong()).thenReturn(0L); // rowCount
42+
}
43+
44+
/**
45+
* Simplified test case specifically for Severity 20 fatal error simulation.
46+
* This test mocks the TDS status flags to simulate a severity 20 error
47+
* and verifies that SQLServerError is properly generated.
48+
*/
49+
@Test
50+
void testSeverity20FatalErrorSimulation() throws SQLServerException {
51+
// Arrange - Simulate severity 20 fatal error with DONE_SRVERROR status
52+
short severity20ErrorStatus = (short) (TDS.DONE_SRVERROR);
53+
54+
// Mock TDSReader to return the error status that would be set for severity 20 errors
55+
when(mockTdsReader.peekStatusFlag()).thenReturn(severity20ErrorStatus);
56+
57+
// Override the readShort to return the error status for the StreamDone.setFromTDS() call
58+
// The first readShort call is for the status field in StreamDone
59+
when(mockTdsReader.readShort())
60+
.thenReturn(severity20ErrorStatus);
61+
62+
// Create token handler to test
63+
TDSTokenHandler handler = new TDSTokenHandler("Severity20Test");
64+
65+
// Act - Call onDone method which should detect the error status and create SQLServerError
66+
handler.onDone(mockTdsReader);
67+
68+
// Verify that SQLServerError was generated due to the error status
69+
SQLServerError generatedError = handler.getDatabaseError();
70+
assertNotNull(generatedError, "SQLServerError must be generated for severity 20 error condition");
71+
72+
// Verify the error message is the expected server error message
73+
String expectedErrorMessage = SQLServerException.getErrString("R_severeError");
74+
assertEquals(expectedErrorMessage, generatedError.getErrorMessage(),
75+
"Generated error should have R_severeError message for fatal errors");
76+
77+
}
78+
}

0 commit comments

Comments
 (0)