Skip to content

Commit

Permalink
Merge branch 'hotfix/CONJ-407'
Browse files Browse the repository at this point in the history
  • Loading branch information
rusher committed Jan 12, 2017
2 parents 680f0b4 + e001e67 commit 6ab687a
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 46 deletions.
4 changes: 4 additions & 0 deletions documentation/changelog.creole
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
= Changelog
* [[https://github.com/MariaDB/mariadb-connector-j/documentation/changelog.creole#155|1.5.7]] not released
* [[https://github.com/MariaDB/mariadb-connector-j/documentation/changelog.creole#155|1.5.6]] Released on 21 Dec. 2016
* [[https://github.com/MariaDB/mariadb-connector-j/documentation/changelog.creole#155|1.5.5]] Released on 07 Nov. 2016
* [[https://github.com/MariaDB/mariadb-connector-j/documentation/changelog.creole#154|1.5.4]] Released on 10 Oct. 2016
Expand All @@ -15,6 +16,9 @@
* [[https://github.com/MariaDB/mariadb-connector-j/documentation/changelog.creole#140|1.4.0]] Released on 31 march 2016
---
== 1.5.7
* CONJ-407 : handling failover when packet > max_allowed_packet reset the connection state.
== 1.5.6
* CONJ-399 : resultSet getLong() for BIGINT column fails if value is Long.MIN_VALUE in Text protocol
* CONJ-395 : Aurora does not randomise selection of read replicas
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<artifactId>mariadb-java-client</artifactId>
<packaging>jar</packaging>
<name>mariadb-java-client</name>
<version>1.5.6</version>
<version>1.5.7-SNAPSHOT</version>
<description>JDBC driver for MariaDB and MySQL</description>
<url>https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/</url>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,10 @@ public Object invoke(Method method, Object[] args) throws Throwable {
public void syncConnection(Protocol from, Protocol to) throws QueryException {

if (from != null) {
proxy.lock.lock();

proxy.lock.lock();
try {
to.setMaxRows(from.getMaxRows());
to.setInternalMaxRows(from.getMaxRows());
if (from.getTransactionIsolationLevel() != 0) {
to.setTransactionIsolation(from.getTransactionIsolationLevel());
}
if (from.getDatabase() != null && !"".equals(from.getDatabase()) && !from.getDatabase().equals(to.getDatabase())) {
to.setCatalog(from.getDatabase());
}
if (from.getAutocommit() != to.getAutocommit()) {
to.executeQuery("set autocommit=" + (from.getAutocommit() ? "1" : "0"));
}
to.resetStateAfterFailover(from.getMaxRows(), from.getTransactionIsolationLevel(), from.getDatabase(), from.getAutocommit());
} finally {
proxy.lock.unlock();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
import java.util.ServiceLoader;
import java.util.concurrent.locks.ReentrantLock;

import static org.mariadb.jdbc.internal.util.SqlStates.CONNECTION_EXCEPTION;
import static org.mariadb.jdbc.internal.util.SqlStates.INTERRUPTED_EXCEPTION;
import static org.mariadb.jdbc.internal.util.SqlStates.FEATURE_NOT_SUPPORTED;
import static org.mariadb.jdbc.internal.util.SqlStates.*;


public class AbstractQueryProtocol extends AbstractConnectProtocol implements Protocol {
Expand Down Expand Up @@ -133,8 +131,7 @@ public void executeQuery(boolean mustExecuteOnMaster, Results results, final Str
} catch (QueryException queryException) {
throw addQueryInfo(sql, queryException);
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
}
Expand Down Expand Up @@ -166,8 +163,7 @@ public void executeQuery(boolean mustExecuteOnMaster, Results results, final Cli
} catch (QueryException queryException) {
throw throwErrorWithQuery(parameters, queryException, clientPrepareResult);
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
} finally {
Expand Down Expand Up @@ -306,8 +302,7 @@ public ServerPrepareResult prepare(String sql, boolean executeOnMaster) throws Q
ServerPrepareResult result = comStmtPrepare.read(packetFetcher);
return result;
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException(e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(),
e);
Expand Down Expand Up @@ -349,8 +344,7 @@ public void executeBatchMultiple(boolean mustExecuteOnMaster, Results results, f
if (!getOptions().continueBatchOnError) throw queryException;
if (exception == null) exception = queryException;
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
} finally {
Expand Down Expand Up @@ -392,8 +386,7 @@ public void executeBatchRewrite(boolean mustExecuteOnMaster, Results results,
} catch (QueryException queryException) {
throwErrorWithQuery(writer.buffer, queryException);
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
} finally {
Expand Down Expand Up @@ -540,8 +533,7 @@ public ServerPrepareResult prepareAndExecute(boolean mustExecuteOnMaster, Server
return serverPrepareResult;

} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
} finally {
Expand Down Expand Up @@ -581,8 +573,7 @@ public void executePreparedQuery(boolean mustExecuteOnMaster, ServerPrepareResul
} catch (QueryException qex) {
throw throwErrorWithQuery(parameters, qex, serverPrepareResult);
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
throw handleMaxAllowedFailover("Could not send query: " + e.getMessage(), e);
} catch (IOException e) {
throw new QueryException("Could not send query: " + e.getMessage(), -1, CONNECTION_EXCEPTION.getSqlState(), e);
} finally {
Expand Down Expand Up @@ -1124,16 +1115,6 @@ public void readLocalInfilePacket(Buffer buffer, Results results) throws QueryEx

try {
sendLocalFile(results, fileName);
} catch (MaxAllowedPacketException e) {
if (e.isMustReconnect()) connect();
try {
if (writer != null) {
writer.writeEmptyPacket(packetFetcher.getLastPacketSeq() + 1);
packetFetcher.getReusableBuffer();
}
} catch (IOException ee) {
}
throw new QueryException("Could not send query: " + e.getMessage(), -1, INTERRUPTED_EXCEPTION.getSqlState(), e);
} catch (IOException e) {
try {
if (writer != null) {
Expand Down Expand Up @@ -1251,4 +1232,62 @@ private void cmdPrologue() throws QueryException {
if (!this.connected) throw new QueryException("Connection is close", 1220, "08000");
}

/**
* Set current state after a failover.
*
* @param maxRows current Max rows
* @param transactionIsolationLevel current transactionIsolationLevel
* @param database current database
* @param autocommit current autocommit state
* @throws QueryException if any error occur.
*/
//TODO set all client affected variables when implementing CONJ-319
public void resetStateAfterFailover(int maxRows, int transactionIsolationLevel, String database, boolean autocommit) throws QueryException {
setMaxRows(maxRows);

if (transactionIsolationLevel != 0) {
setTransactionIsolation(transactionIsolationLevel);
}

if (database != null && !"".equals(database) && !getDatabase().equals(database)) {
setCatalog(database);
}

if (getAutocommit() != autocommit) {
executeQuery("set autocommit=" + (autocommit ? "1" : "0"));
}
}


/**
* Specific failover for MaxAllowedPacketException.
*
* That differ from other, since command cannot be relaunched.
*
* @param message exception message
* @param initialException initial MaxAllowedPacketException
* @return resulting exception to thrown.
*/
private QueryException handleMaxAllowedFailover(String message, MaxAllowedPacketException initialException) {
QueryException returningException = new QueryException(message, -1, UNDEFINED_SQLSTATE, initialException);

if (initialException.isMustReconnect()) {
try {
connect();
} catch (QueryException queryException) {
return new QueryException(message, -1, CONNECTION_EXCEPTION, initialException);
}

try {
resetStateAfterFailover(getMaxRows(), getTransactionIsolationLevel(), getDatabase(), getAutocommit());
} catch (QueryException queryException) {
returningException.setNextException(
new QueryException("reconnection succeed, but resetting previous state failed", -1,
UNDEFINED_SQLSTATE, queryException));
}
}

return returningException;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -252,4 +252,8 @@ void prologProxy(ServerPrepareResult serverPrepareResult, Results results, int m
void changeSocketSoTimeout(int setSoTimeout) throws SocketException;

void removeActiveStreamingResult();

void resetStateAfterFailover(int maxRows, int transactionIsolationLevel, String database, boolean autocommit)
throws QueryException;

}
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,6 @@ public MariaSelectResultSet(ColumnInformation[] columnInformation, List<byte[][]
int resultSetScrollType) {
this.statement = null;
this.isClosed = false;
this.protocol = protocol;
if (protocol != null) {
this.options = protocol.getOptions();
this.cal = protocol.getCalendar();
Expand All @@ -210,10 +209,11 @@ public MariaSelectResultSet(ColumnInformation[] columnInformation, List<byte[][]
this.dataTypeMappingFlags = 3;
this.returnTableAlias = false;
}
this.protocol = null;
this.columnsInformation = columnInformation;
this.columnNameMap = new ColumnNameMap(columnsInformation);
this.columnInformationLength = columnInformation.length;
this.isEof = false;
this.isEof = true;
this.isBinaryEncoded = false;
this.fetchSize = 1;
this.resultSetScrollType = resultSetScrollType;
Expand Down Expand Up @@ -1654,6 +1654,7 @@ private Timestamp getTimestamp(byte[] rawBytes, ColumnInformation columnInfo, Ca
Calendar calendar = options.useLegacyDatetimeCode ? Calendar.getInstance() : cal;

synchronized (calendar) {
calendar.clear();
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month - 1);
calendar.set(Calendar.DAY_OF_MONTH, day);
Expand Down Expand Up @@ -3525,6 +3526,7 @@ private Timestamp binaryTimestamp(byte[] rawBytes, ColumnInformation columnInfo,
Calendar calendar = options.useLegacyDatetimeCode ? Calendar.getInstance() : cal;
Timestamp tt;
synchronized (calendar) {
calendar.clear();
calendar.set(year, month - 1, day, hour, minutes, seconds);
tt = new Timestamp(calendar.getTimeInMillis());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ private static SQLException getException(QueryException exception, MariaDbConnec
message = "(conn:" + statement.getServerThreadId() + ") " + message;
}
SQLException sqlException = get(message, exception);
QueryException nextException = exception.getNextException();
if (nextException != null) {
sqlException.setNextException(get(nextException.getMessage(), nextException));
}

String sqlState = exception.getSqlState();
SqlStates state = SqlStates.fromString(sqlState);
if (connection != null) {
Expand Down
Original file line number Diff line number Diff line change
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.6";
public static final String version = "1.5.7-SNAPSHOT";
public static final int majorVersion = 1;
public static final int minorVersion = 5;
public static final int patchVersion = 6;
public static final String qualifier = "";
public static final int patchVersion = 7;
public static final String qualifier = "SNAPSHOT";

}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS
import org.mariadb.jdbc.internal.util.ExceptionCode;
import org.mariadb.jdbc.internal.util.SqlStates;

import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class QueryException extends Exception {
private static final long serialVersionUID = 974263994278018455L;
/**
Expand Down Expand Up @@ -202,4 +204,37 @@ public final String getSqlState() {
public void setSqlState(String sqlState) {
this.sqlState = sqlState;
}


/**
* Adds an <code>QueryException</code> object to the end of the chain.
*
* @param ex the new exception that will be added to the end of
* the <code>QueryException</code> chain
*/
public void setNextException(QueryException ex) {

QueryException current = this;
for (;;) {
QueryException next = current.next;
if (next != null) {
current = next;
continue;
}

if (nextUpdater.compareAndSet(current,null,ex)) {
return;
}
current = current.next;
}
}

public QueryException getNextException() {
return next;
}

private volatile QueryException next;

private static final AtomicReferenceFieldUpdater<QueryException,QueryException> nextUpdater =
AtomicReferenceFieldUpdater.newUpdater(QueryException.class,QueryException.class,"next");
}
43 changes: 43 additions & 0 deletions src/test/java/org/mariadb/jdbc/DateTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -609,4 +609,47 @@ public void getZeroDateString() throws SQLException {
}
}

private static final String TIMESTAMP_1 = "2015-05-13 08:15:14";
private static final String TIMESTAMP_YEAR_ZERO = "0000-11-15 10:15:22";

/**
* CONJ-405 : Calendar instance not cleared before being used in ResultSet.getTimestamp.
*
* @throws SQLException if error
*/
@Test
public void clearCalendar() throws SQLException {

try (Connection connection = setConnection("&useLegacyDatetimeCode=false&serverTimezone=UTC")) {

try (Statement statement = connection.createStatement()) {
try (ResultSet resultSet = statement.executeQuery(
"SELECT '" + TIMESTAMP_1 + "', '" + TIMESTAMP_YEAR_ZERO + "', '" + TIMESTAMP_1 + "'")) {
testResults(resultSet);
}
}

try (PreparedStatement preparedStatement = connection.prepareStatement(
"SELECT STR_TO_DATE('" + TIMESTAMP_1 + "', '%Y-%m-%d %H:%i:%s'), "
+ "STR_TO_DATE('" + TIMESTAMP_YEAR_ZERO + "', '%Y-%m-%d %H:%i:%s'), "
+ "STR_TO_DATE('" + TIMESTAMP_1 + "', '%Y-%m-%d %H:%i:%s')")) {
testResults(preparedStatement.executeQuery());
}
}
}

private void testResults(ResultSet resultSet) throws SQLException {
resultSet.next();
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
Timestamp timestamp1 = resultSet.getTimestamp(1, calendar);
Date date1 = resultSet.getDate(1, calendar);
resultSet.getTimestamp(2, calendar);

Timestamp timestamp3 = resultSet.getTimestamp(3, calendar);
Date date3 = resultSet.getDate(3, calendar);

Assert.assertEquals(date1.getTime(), date3.getTime());
Assert.assertEquals(timestamp1.getTime(), timestamp3.getTime());

}
}
Loading

0 comments on commit 6ab687a

Please sign in to comment.