Skip to content

Commit

Permalink
Fix for Bug#84365 (33425867), INSERT..VALUE with VALUES function lead to
Browse files Browse the repository at this point in the history
a StringIndexOutOfBoundsException.
  • Loading branch information
soklakov committed Nov 18, 2021
1 parent a82104b commit 97b5d11
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 3 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 8.0.28

- Fix for Bug#84365 (33425867), INSERT..VALUE with VALUES function lead to a StringIndexOutOfBoundsException.

- Fix for Bug#105211 (33468860), class java.time.LocalDate cannot be cast to class java.sql.Date.

- Fix for Bug#101389 (32089018), GETWARNINGS SHOULD CHECK WARNING COUNT BEFORE SENDING SHOW.
Expand Down
13 changes: 10 additions & 3 deletions src/main/core-api/java/com/mysql/cj/ParseInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,12 +244,19 @@ private String extractValuesClause(String sql, String quoteCharStr) {
int indexOfValues = -1;
int valuesSearchStart = this.statementStartPos;

int indexOfFirstEqualsChar = StringUtils.indexOfIgnoreCase(valuesSearchStart, sql, "=", quoteCharStr, quoteCharStr, SearchMode.__MRK_COM_MYM_HNT_WS);

while (indexOfValues == -1) {
// TODO: also support "VALUE" clause
// "VALUE" is a synonym of "VALUES" clause, so checking for the first one
if (quoteCharStr.length() > 0) {
indexOfValues = StringUtils.indexOfIgnoreCase(valuesSearchStart, sql, "VALUES", quoteCharStr, quoteCharStr, SearchMode.__MRK_COM_MYM_HNT_WS);
indexOfValues = StringUtils.indexOfIgnoreCase(valuesSearchStart, sql, "VALUE", quoteCharStr, quoteCharStr, SearchMode.__MRK_COM_MYM_HNT_WS);
} else {
indexOfValues = StringUtils.indexOfIgnoreCase(valuesSearchStart, sql, "VALUES");
indexOfValues = StringUtils.indexOfIgnoreCase(valuesSearchStart, sql, "VALUE");
}

if (indexOfFirstEqualsChar > 0 && indexOfValues > indexOfFirstEqualsChar) {
// VALUES clause always precedes the first '=' occurrence, otherwise it's a values() function
indexOfValues = -1;
}

// TODO: this doesn't support queries like "INSERT INTO t /* foo */VALUES/* bar */(...)" although its valid. Replace by StringInspector.
Expand Down
47 changes: 47 additions & 0 deletions src/test/java/testsuite/regression/StatementRegressionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -11826,4 +11826,51 @@ public void testBug105211() throws Exception {
con.close();
} while (useSPS = !useSPS);
}

/**
* Test fix for Bug#84365 (33425867), INSERT..VALUE with VALUES function lead to a StringIndexOutOfBoundsException.
*
* @throws Exception
*/
@Test
public void testBug84365() throws Exception {
createTable("testBug84365", "(id int(11) NOT NULL, name varchar(25) DEFAULT NULL, PRIMARY KEY (id)) ENGINE=InnoDB DEFAULT CHARSET=latin1");

Properties props = new Properties();
props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), "true");

for (boolean useSSPS : new boolean[] { false, true }) {

this.stmt.executeUpdate("truncate table testBug84365");

props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "" + useSSPS);
Connection testConn = getConnectionWithProps(props);

PreparedStatement st = testConn.prepareStatement("insert into testBug84365(id, name) VALUES(?,?) on duplicate key update id = values(id) + 1");
st.setInt(1, 1);
st.setString(2, "Name1");
st.execute();
st.close();

st = testConn.prepareStatement("insert into testBug84365(id, name) VALUE(?,?) on duplicate key update id = values(id) + 1");
st.setInt(1, 2);
st.setString(2, "Name2");
st.execute();
st.close();

st = testConn.prepareStatement("insert into testBug84365 set id = 2 on duplicate key update id = values(id) + 1");
st.execute();

this.rs = testConn.createStatement().executeQuery("select * from testBug84365 order by id");
assertTrue(this.rs.next());
assertEquals(1, this.rs.getInt("id"));
assertEquals("Name1", this.rs.getString("name"));
assertTrue(this.rs.next());
assertEquals(3, this.rs.getInt("id"));
assertEquals("Name2", this.rs.getString("name"));
assertFalse(this.rs.next());
}
}
}

0 comments on commit 97b5d11

Please sign in to comment.