Skip to content

Commit

Permalink
[CONJ-329] & [CONJ-330] rewriteBatchedStatements single query correction
Browse files Browse the repository at this point in the history
  • Loading branch information
rusher committed Aug 15, 2016
1 parent 4b1f278 commit fc156f5
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 67 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -6,7 +6,7 @@
<artifactId>mariadb-java-client</artifactId>
<packaging>jar</packaging>
<name>mariadb-java-client</name>
<version>1.5.0-RC2-SNAPSHOT</version>
<version>1.5.1-RC2-SNAPSHOT</version>
<description>JDBC driver for MariaDB and MySQL</description>
<url>https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/</url>

Expand Down
Expand Up @@ -303,9 +303,9 @@ public int[] executeBatch() throws SQLException {
} finally {
if (exception != null) {
if (options.rewriteBatchedStatements) {
if (prepareResult.isRewritableValuesQuery()) {
if (prepareResult.isQueryMultiValuesRewritable()) {
internalExecutionResult.updateResultsForRewrite(size, true);
} else if (prepareResult.isRewritableMultipleQuery()) {
} else if (prepareResult.isQueryMultipleRewritable()) {
internalExecutionResult.updateResultsMultiple(size, true);
}
}
Expand Down Expand Up @@ -336,14 +336,14 @@ public int[] executeBatch() throws SQLException {
private void executeInternalBatch(MultiExecutionResult internalExecutionResult, int size) throws QueryException {

if (options.rewriteBatchedStatements) {
if (prepareResult.isRewritableValuesQuery()) {
if (prepareResult.isQueryMultiValuesRewritable()) {
//values rewritten in one query :
// INSERT INTO X(a,b) VALUES (1,2), (3,4), ...
protocol.executeBatchRewrite(protocol.isMasterConnection(), internalExecutionResult, prepareResult,
parameterList, resultSetScrollType, true);
internalExecutionResult.updateResultsForRewrite(size, false);
return;
} else if (prepareResult.isRewritableMultipleQuery()) {
} else if (prepareResult.isQueryMultipleRewritable()) {
//multi rewritten in one query :
// INSERT INTO X(a,b) VALUES (1,2);INSERT INTO X(a,b) VALUES (3,4); ...
protocol.executeBatchRewrite(protocol.isMasterConnection(), internalExecutionResult, prepareResult,
Expand Down
44 changes: 18 additions & 26 deletions src/main/java/org/mariadb/jdbc/MariaDbConnection.java
Expand Up @@ -403,9 +403,24 @@ public PreparedStatement prepareStatement(final String sql, final String[] colum
public PreparedStatement internalPrepareStatement(final String sql, final int resultSetScrollType)
throws SQLException {
checkConnection();
if (!options.rewriteBatchedStatements
&& options.useServerPrepStmts
&& checkIfPreparable(sql)) {

boolean canUsePrepareStatement = false;
if (options.rewriteBatchedStatements) {
//in case of CALL statement, handling INOUT parameter is better with Prepare protocol
String cleanSql = sql.toUpperCase().trim();
canUsePrepareStatement = cleanSql.contains("CALL");
} else if (options.useServerPrepStmts && sql != null) {
String cleanSql = sql.toUpperCase().trim();
canUsePrepareStatement = (cleanSql.contains("SELECT")
|| cleanSql.contains("CALL")
|| cleanSql.contains("UPDATE")
|| cleanSql.contains("INSERT")
|| cleanSql.contains("DELETE")
|| cleanSql.contains("REPLACE")
|| cleanSql.contains("DO"));
}

if (canUsePrepareStatement) {
try {
return new MariaDbServerPreparedStatement(this, sql, resultSetScrollType, false);
} catch (SQLNonTransientConnectionException e) {
Expand All @@ -419,29 +434,6 @@ && checkIfPreparable(sql)) {
return new MariaDbClientPreparedStatement(this, sql, resultSetScrollType);
}


/**
* Check if SQL request is "preparable" and has parameter.
*
* @param sql sql query
* @return true if preparable
*/
private boolean checkIfPreparable(String sql) {
if (sql == null) {
return true;
}

String cleanSql = sql.toUpperCase().trim();
return (cleanSql.contains("SELECT")
|| cleanSql.contains("CALL")
|| cleanSql.contains("UPDATE")
|| cleanSql.contains("INSERT")
|| cleanSql.contains("DELETE")
|| cleanSql.contains("REPLACE")
|| cleanSql.contains("DO"));

}

/**
* Creates a <code>CallableStatement</code> object for calling
* database stored procedures.
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/org/mariadb/jdbc/MariaDbStatement.java
Expand Up @@ -733,15 +733,15 @@ public ResultSet getGeneratedKeys() throws SQLException {
data[i] = ((SingleExecutionResult) executionResult).getInsertId() + i * autoIncrementIncrement;
}
} else {
MultiVariableIntExecutionResult multiExecution = (MultiVariableIntExecutionResult) executionResult;
MultiExecutionResult multiExecution = (MultiExecutionResult) executionResult;
int size = 0;
int affectedRowslength = multiExecution.getAffectedRows().length;
for (int i = 0; i < affectedRowslength; i++) {
size += multiExecution.getAffectedRows()[i];
}
data = new long[size];
for (int affectedRows = 0; affectedRows < affectedRowslength; affectedRows++) {
for (int i = 0; i < affectedRows; i++) {
for (int i = 0; i < multiExecution.getAffectedRows()[affectedRows]; i++) {
data[i] = multiExecution.getInsertIds()[affectedRows] + i * autoIncrementIncrement;
}
}
Expand Down Expand Up @@ -832,7 +832,7 @@ public int getUpdateCount() throws SQLException {
if (executionResult.isSingleExecutionResult()) {
return (int) ((SingleExecutionResult) executionResult).getAffectedRows();
} else {
return ((MultiExecutionResult) executionResult).getAffectedRows()[0];
return ((MultiExecutionResult) executionResult).getFirstAffectedRows();
}
}

Expand Down
Expand Up @@ -51,7 +51,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS

import org.mariadb.jdbc.internal.packet.dao.parameters.ParameterHolder;
import org.mariadb.jdbc.internal.stream.PacketOutputStream;
import org.mariadb.jdbc.internal.util.ExceptionMapper;
import org.mariadb.jdbc.internal.util.dao.ClientPrepareResult;
import org.mariadb.jdbc.internal.util.dao.QueryException;

Expand All @@ -74,7 +73,7 @@ public static void sendSubCmd(final PacketOutputStream writer, final ClientPrepa
throws IOException {
writer.buffer.put(Packet.COM_QUERY);

if (clientPrepareResult.isRewritableValuesQuery()) {
if (clientPrepareResult.isRewriteType()) {

writer.write(clientPrepareResult.getQueryParts().get(0));
writer.write(clientPrepareResult.getQueryParts().get(1));
Expand Down
Expand Up @@ -154,7 +154,7 @@ public void executeQuery(boolean mustExecuteOnMaster, ExecutionResult executionR
int resultSetScrollType) throws QueryException {
cmdPrologue();
try {
if (clientPrepareResult.getParamCount() == 0 && !clientPrepareResult.isRewritableValuesQuery()) {
if (clientPrepareResult.getParamCount() == 0 && !clientPrepareResult.isQueryMultiValuesRewritable()) {
ComExecute.sendDirect(writer, clientPrepareResult.getQueryParts().get(0));
} else {
writer.startPacket(0);
Expand Down Expand Up @@ -982,7 +982,7 @@ private QueryException throwErrorWithQuery(ParameterHolder[] parameters, QueryEx
String sql = serverPrepareResult.getSql();
if (serverPrepareResult.getParamCount() > 0) {
sql += ", parameters [";
if (parameters.length > 1) {
if (parameters.length > 0) {
for (int i = 0; i < Math.min(parameters.length, serverPrepareResult.getParamCount()); i++) {
sql += parameters[i].toString() + ",";
}
Expand Down
Expand Up @@ -7,5 +7,7 @@ public interface MultiExecutionResult extends ExecutionResult {
void updateResultsMultiple(int waitedSize, boolean hasException);

int[] getAffectedRows();

int getFirstAffectedRows();
}

Expand Up @@ -1409,9 +1409,13 @@ private Date getDate(byte[] rawBytes, ColumnInformation columnInfo, Calendar cal
switch (columnInfo.getType()) {
case TIMESTAMP:
case DATETIME:
return new Date(getTimestamp(rawBytes, columnInfo, cal).getTime());
Timestamp timestamp = getTimestamp(rawBytes, columnInfo, cal);
if (timestamp == null) return null;
return new Date(timestamp.getTime());
case TIME:
return new Date(getTime(rawBytes, columnInfo, cal).getTime());
Time time = getTime(rawBytes, columnInfo, cal);
if (time == null) return null;
return new Date(time.getTime());
case DATE:
return new Date(
Integer.parseInt(rawValue.substring(0, 4)) - 1900,
Expand Down Expand Up @@ -1502,7 +1506,8 @@ private Time getTime(byte[] rawBytes, ColumnInformation columnInfo, Calendar cal

if (!this.isBinaryEncoded) {
if (columnInfo.getType() == MariaDbType.TIMESTAMP || columnInfo.getType() == MariaDbType.DATETIME) {
return new Time(getTimestamp(rawBytes, columnInfo, cal).getTime());
Timestamp timestamp = getTimestamp(rawBytes, columnInfo, cal);
return (timestamp == null) ? null : new Time(timestamp.getTime());
} else if (columnInfo.getType() == MariaDbType.DATE) {
Calendar zeroCal = Calendar.getInstance();
zeroCal.set(1970, 0, 1, 0, 0, 0);
Expand Down Expand Up @@ -1594,10 +1599,8 @@ private Timestamp getTimestamp(byte[] rawBytes, ColumnInformation columnInfo, Ca
}
if (!this.isBinaryEncoded) {
String rawValue = new String(rawBytes, StandardCharsets.UTF_8);
String zeroTimestamp = "0000-00-00 00:00:00";
if (rawValue.equals(zeroTimestamp)) {
return null;
}
if (rawValue.startsWith("0000-00-00 00:00:00")) return null;

switch (columnInfo.getType()) {
case TIME:
//time does not go after millisecond
Expand Down
Expand Up @@ -51,10 +51,10 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
package org.mariadb.jdbc.internal.util.constant;

public final class Version {
public static final String version = "1.5.0-RC2-SNAPSHOT";
public static final String version = "1.5.1-RC2-SNAPSHOT";
public static final int majorVersion = 1;
public static final int minorVersion = 5;
public static final int patchVersion = 0;
public static final int patchVersion = 1;
public static final String qualifier = "RC2-SNAPSHOT";

}
Expand Up @@ -56,17 +56,19 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
public class ClientPrepareResult implements PrepareResult {
private String sql;
private List<byte[]> queryParts;
private boolean rewritableValuesQuery = true;
private boolean rewritableMultipleQuery = true;
private boolean isQueryMultiValuesRewritable = true;
private boolean isQueryMultipleRewritable = true;
private boolean rewriteType;
private int paramCount;

private ClientPrepareResult(String sql, List<byte[]> queryParts, boolean rewritableValuesQuery,
boolean rewritableMultipleQuery, boolean isRewritePart) {
private ClientPrepareResult(String sql, List<byte[]> queryParts, boolean isQueryMultiValuesRewritable,
boolean isQueryMultipleRewritable, boolean rewriteType) {
this.sql = sql;
this.queryParts = queryParts;
this.rewritableValuesQuery = rewritableValuesQuery;
this.rewritableMultipleQuery = rewritableMultipleQuery;
this.paramCount = queryParts.size() - (isRewritePart ? 3 : 1);
this.isQueryMultiValuesRewritable = isQueryMultiValuesRewritable;
this.isQueryMultipleRewritable = isQueryMultipleRewritable;
this.paramCount = queryParts.size() - (rewriteType ? 3 : 1);
this.rewriteType = rewriteType;
}

public String getSql() {
Expand All @@ -77,22 +79,26 @@ public List<byte[]> getQueryParts() {
return queryParts;
}

public boolean isRewritableValuesQuery() {
return rewritableValuesQuery;
public boolean isQueryMultiValuesRewritable() {
return isQueryMultiValuesRewritable;
}

public boolean isRewritableMultipleQuery() {
return rewritableMultipleQuery;
public boolean isQueryMultipleRewritable() {
return isQueryMultipleRewritable;
}

public boolean isRewriteType() {
return rewriteType;
}

public int getParamCount() {
return paramCount;
}

/**
* Separate query in a String list and set flag rewritableMultipleQuery.
* Separate query in a String list and set flag isQueryMultipleRewritable.
* The resulting string list is separed by ? that are not in comments.
* rewritableMultipleQuery flag is set if query can be rewrite in one query
* isQueryMultipleRewritable flag is set if query can be rewrite in one query
* (all case but if using "-- comment").
* example for query :
* "INSERT INTO tableName(id, name) VALUES (?, ?)"
Expand Down Expand Up @@ -320,7 +326,7 @@ public static boolean isRewritableBatch(String queryString, boolean noBackslashE
}

/**
* Separate query in a String list and set flag rewritableValuesQuery
* Separate query in a String list and set flag isQueryMultiValuesRewritable
* The parameters "?" (not in comments) emplacements are to be known.
*
* The only rewritten queries follow these notation:
Expand Down Expand Up @@ -555,12 +561,20 @@ public static ClientPrepareResult createRewritableParts(String queryString, bool
}
}

partList.add(0, (preValuePart1 == null) ? new byte[0] : preValuePart1.getBytes("UTF-8"));
if (!hasParam) {
//permit to have rewrite without parameter
partList.add(1, sb.toString().getBytes("UTF-8"));
if (preValuePart1 == null) {
partList.add(0, sb.toString().getBytes("UTF-8"));
partList.add(1, new byte[0]);
} else {
partList.add(0, preValuePart1.getBytes("UTF-8"));
partList.add(1, sb.toString().getBytes("UTF-8"));
}
sb.setLength(0);
} else partList.add(1, (preValuePart2 == null) ? new byte[0] : preValuePart2.getBytes("UTF-8"));
} else {
partList.add(0, (preValuePart1 == null) ? new byte[0] : preValuePart1.getBytes("UTF-8"));
partList.add(1, (preValuePart2 == null) ? new byte[0] : preValuePart2.getBytes("UTF-8"));
}

if (!isInsert) reWritablePrepare = false;

Expand Down
Expand Up @@ -23,12 +23,12 @@ private void checkParsing(String sql, int paramNumber, boolean rewritable, boole
for (int i = 0; i < partsRewrite.length; i++) {
Assert.assertEquals(partsRewrite[i], new String(statement.getPrepareResult().getQueryParts().get(i)));
}
assertEquals(rewritable, statement.getPrepareResult().isRewritableValuesQuery());
assertEquals(rewritable, statement.getPrepareResult().isQueryMultiValuesRewritable());
} else {
for (int i = 0; i < partsMulti.length; i++) {
Assert.assertEquals(partsMulti[i], new String(statement.getPrepareResult().getQueryParts().get(i)));
}
assertEquals(allowMultiqueries, statement.getPrepareResult().isRewritableMultipleQuery());
assertEquals(allowMultiqueries, statement.getPrepareResult().isQueryMultipleRewritable());

}
}
Expand Down Expand Up @@ -269,6 +269,16 @@ public void testLineCommentFinished() throws Exception {
")"});
}

@Test
public void testSelect1() throws Exception {
checkParsing("SELECT 1",
0, false, true,
new String[] {
"SELECT 1",
"",
""},
new String[] {"SELECT 1"});
}

@Test
public void rewriteBatchedError() throws Exception {
Expand Down

0 comments on commit fc156f5

Please sign in to comment.