Skip to content

Commit

Permalink
Fix for Bug#115265 (Bug#36843227), Second stored procedure call with …
Browse files Browse the repository at this point in the history
…cacheCallableStmts might fail.

Change-Id: I919d31e88db41e8893cadfb42c4dcd7d4f8a88a4
  • Loading branch information
Axyoan Marcelo committed Sep 5, 2024
1 parent db834bf commit 5a27bc4
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

Version 9.1.0

- Fix for Bug#115265 (Bug#36843227), Second stored procedure call with cacheCallableStmts might fail.

- Fix for Bug#36936407, PrepareCall method doesn't work as expected when DB name is involved.

- WL#16490, OpenID Connect authentication support.
Expand Down
45 changes: 24 additions & 21 deletions src/main/user-impl/java/com/mysql/cj/jdbc/CallableStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ public class CallableStatementParamInfo implements ParameterMetaData {

Map<String, CallableStatementParam> parameterMap;

int[] placeholderToParameterIndexMap;

boolean isReadOnlySafeProcedure = false;

boolean isReadOnlySafeChecked = false;
Expand All @@ -158,17 +160,15 @@ public class CallableStatementParamInfo implements ParameterMetaData {
this.dbInUse = getCurrentDatabase();
this.isFunctionCall = fullParamInfo.isFunctionCall;
this.fakeParameters = fullParamInfo.fakeParameters;
@SuppressWarnings("synthetic-access")
int[] localParameterMap = CallableStatement.this.placeholderToParameterIndexMap;
int parameterMapLength = localParameterMap.length;

this.isReadOnlySafeProcedure = fullParamInfo.isReadOnlySafeProcedure;
this.isReadOnlySafeChecked = fullParamInfo.isReadOnlySafeChecked;
this.parameterList = new ArrayList<>(fullParamInfo.numParameters);
this.parameterMap = new HashMap<>(fullParamInfo.numParameters);
setPlaceholderToParameterIndexMap(fullParamInfo.placeholderToParameterIndexMap);

for (int i = 0; i < parameterMapLength; i++) {
CallableStatementParam param = fullParamInfo.parameterList.get(localParameterMap[i]);
for (int i : this.placeholderToParameterIndexMap) {
CallableStatementParam param = fullParamInfo.parameterList.get(i);

this.parameterList.add(param);
this.parameterMap.put(param.paramName, param);
Expand Down Expand Up @@ -385,6 +385,10 @@ public <T> T unwrap(Class<T> iface) throws java.sql.SQLException {
}
}

void setPlaceholderToParameterIndexMap(int[] localPlaceholderToParameterIndexMap) {
this.placeholderToParameterIndexMap = localPlaceholderToParameterIndexMap.clone();
}

}

private final static int NOT_OUTPUT_PARAMETER_INDICATOR = Integer.MIN_VALUE;
Expand Down Expand Up @@ -489,8 +493,6 @@ protected static CallableStatement getInstance(JdbcConnection conn, CallableStat
return new CallableStatement(conn, paramInfo);
}

private int[] placeholderToParameterIndexMap;

private void generateParameterMap() throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
Expand All @@ -506,12 +508,12 @@ private void generateParameterMap() throws SQLException {
PreparedQuery q = (PreparedQuery) this.query;

if (this.paramInfo != null && !this.paramInfo.fakeParameters && q.getParameterCount() >= 0) {
this.placeholderToParameterIndexMap = new int[q.getParameterCount()];
int[] localPlaceholderToParameterIndexMap = new int[q.getParameterCount()];

int startIndex = 0;

if (this.callingStoredFunction) {
this.placeholderToParameterIndexMap[0] = 0;
localPlaceholderToParameterIndexMap[0] = 0;
startIndex = 1;
}

Expand Down Expand Up @@ -550,12 +552,13 @@ private void generateParameterMap() throws SQLException {
}
}
for (int j = 0; j < questionMarkCount; j++) {
this.placeholderToParameterIndexMap[placeholderCount++] = startIndex + i;
localPlaceholderToParameterIndexMap[placeholderCount++] = startIndex + i;
}
}
}
}
}
this.paramInfo.setPlaceholderToParameterIndexMap(localPlaceholderToParameterIndexMap);
}
} finally {
connectionLock.unlock();
Expand Down Expand Up @@ -629,8 +632,8 @@ private CallableStatementParam checkIsOutputParam(int paramIndex) throws SQLExce

int localParamIndex = paramIndex - 1;

if (this.placeholderToParameterIndexMap != null) {
localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
if (this.paramInfo.placeholderToParameterIndexMap != null) {
localParamIndex = this.paramInfo.placeholderToParameterIndexMap[localParamIndex];
}

CallableStatementParam paramDescriptor = this.paramInfo.getParameter(localParamIndex);
Expand Down Expand Up @@ -1529,12 +1532,12 @@ protected int getNamedParamIndex(String paramName, boolean forOut) throws SQLExc
MysqlErrorNumbers.SQLSTATE_CONNJ_ILLEGAL_ARGUMENT, getExceptionInterceptor());
}

if (this.placeholderToParameterIndexMap == null) {
if (this.paramInfo.placeholderToParameterIndexMap == null) {
return namedParamInfo.index + 1; // JDBC indices are 1-based
}

for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
if (this.placeholderToParameterIndexMap[i] == namedParamInfo.index) {
for (int i = 0; i < this.paramInfo.placeholderToParameterIndexMap.length; i++) {
if (this.paramInfo.placeholderToParameterIndexMap[i] == namedParamInfo.index) {
return i + 1;
}
}
Expand Down Expand Up @@ -1694,7 +1697,7 @@ public ParameterMetaData getParameterMetaData() throws SQLException {
Lock connectionLock = checkClosed().getConnectionLock();
connectionLock.lock();
try {
if (this.placeholderToParameterIndexMap == null) {
if (this.paramInfo.placeholderToParameterIndexMap == null) {
return this.paramInfo;
}

Expand Down Expand Up @@ -1988,8 +1991,8 @@ protected int mapOutputParameterIndexToRsIndex(int paramIndex) throws SQLExcepti

int localParamIndex = paramIndex - 1;

if (this.placeholderToParameterIndexMap != null) {
localParamIndex = this.placeholderToParameterIndexMap[localParamIndex];
if (this.paramInfo.placeholderToParameterIndexMap != null) {
localParamIndex = this.paramInfo.placeholderToParameterIndexMap[localParamIndex];
}

int rsIndex = this.parameterIndexToRsIndex[localParamIndex];
Expand Down Expand Up @@ -2374,14 +2377,14 @@ private void setOutParams() throws SQLException {

int outParamIndex = 0;

if (this.placeholderToParameterIndexMap == null) {
if (this.paramInfo.placeholderToParameterIndexMap == null) {
outParamIndex = outParamInfo.index + 1;
} else {
// Find it, todo: remove this linear search
boolean found = false;

for (int i = 0; i < this.placeholderToParameterIndexMap.length; i++) {
if (this.placeholderToParameterIndexMap[i] == outParamInfo.index) {
for (int i = 0; i < this.paramInfo.placeholderToParameterIndexMap.length; i++) {
if (this.paramInfo.placeholderToParameterIndexMap[i] == outParamInfo.index) {
outParamIndex = i + 1; /* JDBC is 1-based */
found = true;
break;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1906,4 +1906,46 @@ public void testBug36936407() throws Exception {
}
}

/**
* Tests fix for Bug#115265 (Bug#36843227), Second stored procedure call with cacheCallableStmts might fail.
*
* @throws Exception
*/
@Test
public void testBug115265() throws Exception {
createProcedure("testBug115265Procedure", "(IN a INT, IN b INT, OUT c INT) BEGIN SELECT a + b INTO c; END");
createFunction("testBug115265Function", "(a INT, b INT) RETURNS INT DETERMINISTIC RETURN a + b");
Properties props = new Properties();
props.setProperty(PropertyKey.cacheCallableStmts.getKeyName(), "true");
try (Connection testConn = getConnectionWithProps(props)) {
final String testProcedureQuery1 = "{CALL testBug115265Procedure(?,?,?)}";
final String testProcedureQuery2 = "{CALL testBug115265Procedure(1,?,?)}";
final String testFunctionQuery1 = "{? = CALL testBug115265Function(?,?)}";
final String testFunctionQuery2 = "{? = CALL testBug115265Function(1,?)}";

testBug115265RunTest(testConn, testProcedureQuery1, 3, true);
testBug115265RunTest(testConn, testProcedureQuery1, 3, true);

testBug115265RunTest(testConn, testProcedureQuery2, 2, true);
testBug115265RunTest(testConn, testProcedureQuery2, 2, true);

testBug115265RunTest(testConn, testFunctionQuery1, 3, false);
testBug115265RunTest(testConn, testFunctionQuery1, 3, false);

testBug115265RunTest(testConn, testFunctionQuery2, 2, false);
testBug115265RunTest(testConn, testFunctionQuery2, 2, false);
}
}

private void testBug115265RunTest(Connection testConn, String query, int placeholderCount, boolean isProcedure) throws SQLException {
CallableStatement testCstmt = testConn.prepareCall(query);
testCstmt.setInt("b", 10);
if (placeholderCount == 3) {
testCstmt.setInt("a", 1);
}
testCstmt.registerOutParameter(isProcedure ? placeholderCount : 1, Types.INTEGER);
testCstmt.execute();
assertEquals(11, isProcedure ? testCstmt.getInt("c") : testCstmt.getInt(1));
}

}

0 comments on commit 5a27bc4

Please sign in to comment.