Skip to content

Commit d4bcee9

Browse files
committed
Fix for Bug#44791 (Bug#11753361), Setting/getting holdability on connection does not work properly.
Change-Id: If8a8b9d54683b2c5b9b54b125718c12c48fc35d9
1 parent f87653d commit d4bcee9

File tree

5 files changed

+176
-35
lines changed

5 files changed

+176
-35
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 9.4.0
55

6+
- Fix for Bug#44791 (Bug#11753361), Setting/getting holdability on connection does not work properly.
7+
68
- Fix for Bug#21294134, DBMD.GETPROCEDURECOLUMNS() IS UNABLE TO DEAL WITH PROCEDURE COLUMNS WITH SPACES.
79

810
- Fix for Bug#77658 (Bug#21946136), Incorrect java.sql.Statement.cancel() behavior.

src/main/resources/com/mysql/cj/LocalizedErrorMessages.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,8 @@ Connection.12=Could not map transaction isolation ''{0}'' to a valid JDBC level.
134134
Connection.13=Could not retrieve transaction isolation level from server
135135
Connection.15=Connection setting too low for ''maxAllowedPacket''. When ''useServerPrepStmts=true'', ''maxAllowedPacket'' must be higher than {0}. Check also ''max_allowed_packet'' in MySQL configuration files.
136136
Connection.16=Could not retrieve transaction read-only status from server
137-
Connection.17=HOLD_CUSRORS_OVER_COMMIT is only supported holdability level
137+
Connection.17.1=Holdability ''{0}'' is not supported
138+
Connection.17.2=Unknown holdability constant ''{0}''
138139
Connection.18=Connection implicitly closed by Driver. You should call Connection.close() from your code to free resources more efficiently and avoid resource leaks.
139140
Connection.19=Connection lifetime of < .5 seconds. You might be un-necessarily creating short-lived connections and should investigate connection pooling to be more efficient.
140141
Connection.20=Can''t call rollback when autocommit=true

src/main/user-impl/java/com/mysql/cj/jdbc/ConnectionImpl.java

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,28 @@ public void cleanup(Throwable whyCleanedUp) {
613613

614614
@Override
615615
public void clearWarnings() throws SQLException {
616-
// firstWarning = null;
616+
// this.warningChain = null;
617+
}
618+
619+
/**
620+
* Validates the specified holdability value against the supported values.
621+
*
622+
* @param holdability
623+
* The holdability value to check.
624+
* @throws SQLException
625+
* If the specified holdability value is unknown or not supported.
626+
*/
627+
private void checkResultSetHoldability(int holdability) throws SQLException {
628+
if (this.pedantic.getValue()) {
629+
if (holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) {
630+
throw SQLError.createSQLFeatureNotSupportedException(
631+
Messages.getString("Connection.17.1", new Object[] { "ResultSet.CLOSE_CURSORS_AT_COMMIT" }),
632+
MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, getExceptionInterceptor());
633+
} else if (holdability != ResultSet.HOLD_CURSORS_OVER_COMMIT) {
634+
throw SQLError.createSQLException(Messages.getString("Connection.17.2", new Object[] { holdability }),
635+
MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, getExceptionInterceptor());
636+
}
637+
}
617638
}
618639

619640
@Override
@@ -682,6 +703,7 @@ public java.sql.PreparedStatement clientPrepareStatement(String sql, String[] au
682703
@Override
683704
public java.sql.PreparedStatement clientPrepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
684705
throws SQLException {
706+
checkResultSetHoldability(resultSetHoldability);
685707
return clientPrepareStatement(sql, resultSetType, resultSetConcurrency, true);
686708
}
687709

@@ -1074,13 +1096,7 @@ public java.sql.Statement createStatement(int resultSetType, int resultSetConcur
10741096

10751097
@Override
10761098
public java.sql.Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
1077-
if (this.pedantic.getValue()) {
1078-
if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
1079-
throw SQLError.createSQLException("HOLD_CUSRORS_OVER_COMMIT is only supported holdability level",
1080-
MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, getExceptionInterceptor());
1081-
}
1082-
}
1083-
1099+
checkResultSetHoldability(resultSetHoldability);
10841100
return createStatement(resultSetType, resultSetConcurrency);
10851101
}
10861102

@@ -1124,7 +1140,7 @@ public String getCharacterSetMetadata() {
11241140

11251141
@Override
11261142
public int getHoldability() throws SQLException {
1127-
return java.sql.ResultSet.CLOSE_CURSORS_AT_COMMIT;
1143+
return java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT;
11281144
}
11291145

11301146
@Override
@@ -1567,15 +1583,8 @@ public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int
15671583

15681584
@Override
15691585
public java.sql.CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
1570-
if (this.pedantic.getValue()) {
1571-
if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
1572-
throw SQLError.createSQLException(Messages.getString("Connection.17"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT,
1573-
getExceptionInterceptor());
1574-
}
1575-
}
1576-
1586+
checkResultSetHoldability(resultSetHoldability);
15771587
CallableStatement cStmt = (com.mysql.cj.jdbc.CallableStatement) prepareCall(sql, resultSetType, resultSetConcurrency);
1578-
15791588
return cStmt;
15801589
}
15811590

@@ -1696,13 +1705,7 @@ public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType
16961705

16971706
@Override
16981707
public java.sql.PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
1699-
if (this.pedantic.getValue()) {
1700-
if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
1701-
throw SQLError.createSQLException(Messages.getString("Connection.17"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT,
1702-
getExceptionInterceptor());
1703-
}
1704-
}
1705-
1708+
checkResultSetHoldability(resultSetHoldability);
17061709
return prepareStatement(sql, resultSetType, resultSetConcurrency);
17071710
}
17081711

@@ -2061,13 +2064,7 @@ public java.sql.PreparedStatement serverPrepareStatement(String sql, int resultS
20612064
@Override
20622065
public java.sql.PreparedStatement serverPrepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
20632066
throws SQLException {
2064-
if (this.pedantic.getValue()) {
2065-
if (resultSetHoldability != java.sql.ResultSet.HOLD_CURSORS_OVER_COMMIT) {
2066-
throw SQLError.createSQLException(Messages.getString("Connection.17"), MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT,
2067-
getExceptionInterceptor());
2068-
}
2069-
}
2070-
2067+
checkResultSetHoldability(resultSetHoldability);
20712068
return serverPrepareStatement(sql, resultSetType, resultSetConcurrency);
20722069
}
20732070

@@ -2243,8 +2240,8 @@ public void setFailedOver(boolean flag) {
22432240
}
22442241

22452242
@Override
2246-
public void setHoldability(int arg0) throws SQLException {
2247-
// do nothing
2243+
public void setHoldability(int holdability) throws SQLException {
2244+
checkResultSetHoldability(holdability);
22482245
}
22492246

22502247
@Override

src/main/user-impl/java/com/mysql/cj/jdbc/result/ResultSetImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2690,7 +2690,7 @@ protected ExceptionInterceptor getExceptionInterceptor() {
26902690

26912691
@Override
26922692
public int getHoldability() throws SQLException {
2693-
throw SQLError.createSQLFeatureNotSupportedException();
2693+
return HOLD_CURSORS_OVER_COMMIT;
26942694
}
26952695

26962696
@Override

src/test/java/testsuite/regression/ConnectionRegressionTest.java

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@
5858
import java.nio.charset.Charset;
5959
import java.security.Security;
6060
import java.security.cert.CertificateException;
61+
import java.sql.CallableStatement;
6162
import java.sql.Connection;
63+
import java.sql.DatabaseMetaData;
6264
import java.sql.DriverManager;
6365
import java.sql.DriverPropertyInfo;
6466
import java.sql.PreparedStatement;
@@ -12354,4 +12356,143 @@ void testBug19948601() throws Exception {
1235412356
});
1235512357
}
1235612358

12359+
/**
12360+
* Tests fix for Bug#44791 (Bug#11753361), Setting/getting holdability on connection does not work properly.
12361+
*
12362+
* @throws Exception
12363+
*/
12364+
@Test
12365+
void testBug44791() throws Exception {
12366+
createProcedure("testBug44791", "() BEGIN SELECT 1; END");
12367+
final int fakeResultSetHoldability = 99;
12368+
Properties props = new Properties();
12369+
12370+
/*
12371+
* Pedantic off.
12372+
*/
12373+
props.setProperty(PropertyKey.pedantic.getKeyName(), "false");
12374+
12375+
try (Connection testConn = getConnectionWithProps(props)) {
12376+
DatabaseMetaData testDbmd = testConn.getMetaData();
12377+
assertTrue(testDbmd.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT));
12378+
assertFalse(testDbmd.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT));
12379+
assertFalse(testDbmd.supportsResultSetHoldability(fakeResultSetHoldability));
12380+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testDbmd.getResultSetHoldability());
12381+
12382+
testConn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
12383+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12384+
12385+
testConn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
12386+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12387+
12388+
testConn.setHoldability(fakeResultSetHoldability);
12389+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12390+
}
12391+
12392+
boolean useSPS = false;
12393+
do {
12394+
try (Connection testConn = getConnectionWithProps(props)) {
12395+
for (int h : new int[] { ResultSet.HOLD_CURSORS_OVER_COMMIT, ResultSet.CLOSE_CURSORS_AT_COMMIT, fakeResultSetHoldability }) {
12396+
Statement testStmt = testConn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, h);
12397+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testStmt.getResultSetHoldability());
12398+
ResultSet testRs = testStmt.executeQuery("SELECT 1");
12399+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12400+
12401+
PreparedStatement testPstmt = testConn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, h);
12402+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testPstmt.getResultSetHoldability());
12403+
testRs = testPstmt.executeQuery();
12404+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12405+
12406+
CallableStatement testCstmt = testConn.prepareCall("{ CALL testBug44791() }", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, h);
12407+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testCstmt.getResultSetHoldability());
12408+
testRs = testCstmt.executeQuery();
12409+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12410+
}
12411+
}
12412+
} while (useSPS = !useSPS);
12413+
12414+
/*
12415+
* Pedantic on.
12416+
*/
12417+
props.setProperty(PropertyKey.pedantic.getKeyName(), "true");
12418+
12419+
try (Connection testConn = getConnectionWithProps(props)) {
12420+
DatabaseMetaData testDbmd = testConn.getMetaData();
12421+
assertTrue(testDbmd.supportsResultSetHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT));
12422+
assertFalse(testDbmd.supportsResultSetHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT));
12423+
assertFalse(testDbmd.supportsResultSetHoldability(fakeResultSetHoldability));
12424+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testDbmd.getResultSetHoldability());
12425+
12426+
testConn.setHoldability(ResultSet.HOLD_CURSORS_OVER_COMMIT);
12427+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12428+
12429+
assertThrows(SQLFeatureNotSupportedException.class, "Holdability 'ResultSet.CLOSE_CURSORS_AT_COMMIT' is not supported", () -> {
12430+
testConn.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT);
12431+
return null;
12432+
});
12433+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12434+
12435+
assertThrows(SQLException.class, "Unknown holdability constant '99'", () -> {
12436+
testConn.setHoldability(fakeResultSetHoldability);
12437+
return null;
12438+
});
12439+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testConn.getHoldability());
12440+
}
12441+
12442+
useSPS = false;
12443+
do {
12444+
try (Connection testConn = getConnectionWithProps(props)) {
12445+
// ResultSet.HOLD_CURSORS_OVER_COMMIT: works correctly.
12446+
Statement testStmt = testConn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.HOLD_CURSORS_OVER_COMMIT);
12447+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testStmt.getResultSetHoldability());
12448+
ResultSet testRs = testStmt.executeQuery("SELECT 1");
12449+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12450+
12451+
PreparedStatement testPstmt = testConn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
12452+
ResultSet.HOLD_CURSORS_OVER_COMMIT);
12453+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testPstmt.getResultSetHoldability());
12454+
testRs = testPstmt.executeQuery();
12455+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12456+
12457+
CallableStatement testCstmt = testConn.prepareCall("{ CALL testBug44791() }", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
12458+
ResultSet.HOLD_CURSORS_OVER_COMMIT);
12459+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testCstmt.getResultSetHoldability());
12460+
testRs = testCstmt.executeQuery();
12461+
assertEquals(ResultSet.HOLD_CURSORS_OVER_COMMIT, testRs.getHoldability());
12462+
12463+
// ResultSet.CLOSE_CURSORS_AT_COMMIT: not supported - throws SQLFeatureNotSupportedException.
12464+
assertThrows(SQLFeatureNotSupportedException.class, "Holdability 'ResultSet.CLOSE_CURSORS_AT_COMMIT' is not supported", () -> {
12465+
testConn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
12466+
return null;
12467+
});
12468+
12469+
assertThrows(SQLFeatureNotSupportedException.class, "Holdability 'ResultSet.CLOSE_CURSORS_AT_COMMIT' is not supported", () -> {
12470+
testConn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
12471+
return null;
12472+
});
12473+
12474+
assertThrows(SQLFeatureNotSupportedException.class, "Holdability 'ResultSet.CLOSE_CURSORS_AT_COMMIT' is not supported", () -> {
12475+
testConn.prepareCall("{ CALL testBug44791() }", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_AT_COMMIT);
12476+
return null;
12477+
});
12478+
12479+
// fakeResultSetHoldability: unknown holdability - throws SQLException.
12480+
assertThrows(SQLException.class, "Unknown holdability constant '99'", () -> {
12481+
testConn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, fakeResultSetHoldability);
12482+
return null;
12483+
});
12484+
12485+
assertThrows(SQLException.class, "Unknown holdability constant '99'", () -> {
12486+
testConn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, fakeResultSetHoldability);
12487+
return null;
12488+
});
12489+
12490+
assertThrows(SQLException.class, "Unknown holdability constant '99'", () -> {
12491+
testConn.prepareCall("{ CALL testBug44791() }", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, fakeResultSetHoldability);
12492+
return null;
12493+
});
12494+
}
12495+
} while (useSPS = !useSPS);
12496+
}
12497+
1235712498
}

0 commit comments

Comments
 (0)