/*
Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/J is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most MySQL Connectors.
There are special exceptions to the terms and conditions of the GPLv2 as it is applied to
this software, see the FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation; version 2
of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this
program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth
Floor, Boston, MA 02110-1301 USA
*/
package testsuite.regression;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Socket;
import java.net.SocketException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.DriverPropertyInfo;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.sql.XAConnection;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;
import testsuite.BaseTestCase;
import testsuite.UnreliableSocketFactory;
import com.mysql.jdbc.ConnectionImpl;
import com.mysql.jdbc.Driver;
import com.mysql.jdbc.LoadBalancingConnectionProxy;
import com.mysql.jdbc.Messages;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.MysqlDataTruncation;
import com.mysql.jdbc.NonRegisteringDriver;
import com.mysql.jdbc.RandomBalanceStrategy;
import com.mysql.jdbc.ReplicationConnection;
import com.mysql.jdbc.SQLError;
import com.mysql.jdbc.StandardSocketFactory;
import com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXADataSource;
import com.mysql.jdbc.jdbc2.optional.MysqlXid;
import com.mysql.jdbc.jdbc2.optional.SuspendableXAConnection;
import com.mysql.jdbc.log.StandardLogger;
/**
* Regression tests for Connections
*
* @author Mark Matthews
* @version $Id: ConnectionRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38
* mmatthews Exp $
*/
public class ConnectionRegressionTest extends BaseTestCase {
/**
* DOCUMENT ME!
*
* @param name
* the name of the testcase
*/
public ConnectionRegressionTest(String name) {
super(name);
}
/**
* Runs all test cases in this test suite
*
* @param args
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(ConnectionRegressionTest.class);
}
/**
* DOCUMENT ME!
*
* @throws Exception
* ...
*/
public void testBug1914() throws Exception {
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), BIGINT)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), BINARY)}"));
System.out
.println(this.conn.nativeSQL("{fn convert(foo(a,b,c), BIT)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), CHAR)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), DATE)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), DECIMAL)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), DOUBLE)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), FLOAT)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), INTEGER)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), LONGVARBINARY)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), LONGVARCHAR)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), TIME)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), TIMESTAMP)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), TINYINT)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), VARBINARY)}"));
System.out.println(this.conn
.nativeSQL("{fn convert(foo(a,b,c), VARCHAR)}"));
}
/**
* Tests fix for BUG#3554 - Not specifying database in URL causes
* MalformedURL exception.
*
* @throws Exception
* if an error ocurrs.
*/
public void testBug3554() throws Exception {
try {
new NonRegisteringDriver().connect(
"jdbc:mysql://localhost:3306/?user=root&password=root",
new Properties());
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf("Malformed") == -1);
}
}
/**
* DOCUMENT ME!
*
* @throws Exception
* ...
*/
public void testBug3790() throws Exception {
String field2OldValue = "foo";
String field2NewValue = "bar";
int field1OldValue = 1;
Connection conn1 = null;
Connection conn2 = null;
Statement stmt1 = null;
Statement stmt2 = null;
ResultSet rs2 = null;
Properties props = new Properties();
try {
createTable("testBug3790",
"(field1 INT NOT NULL PRIMARY KEY, field2 VARCHAR(32)) ",
"InnoDB");
this.stmt.executeUpdate("INSERT INTO testBug3790 VALUES ("
+ field1OldValue + ", '" + field2OldValue + "')");
conn1 = getConnectionWithProps(props); // creates a new connection
conn2 = getConnectionWithProps(props); // creates another new
// connection
conn1.setAutoCommit(false);
conn2.setAutoCommit(false);
stmt1 = conn1.createStatement();
stmt1.executeUpdate("UPDATE testBug3790 SET field2 = '"
+ field2NewValue + "' WHERE field1=" + field1OldValue);
conn1.commit();
stmt2 = conn2.createStatement();
rs2 = stmt2.executeQuery("SELECT field1, field2 FROM testBug3790");
assertTrue(rs2.next());
assertTrue(rs2.getInt(1) == field1OldValue);
assertTrue(rs2.getString(2).equals(field2NewValue));
} finally {
if (rs2 != null) {
rs2.close();
}
if (stmt2 != null) {
stmt2.close();
}
if (stmt1 != null) {
stmt1.close();
}
if (conn1 != null) {
conn1.close();
}
if (conn2 != null) {
conn2.close();
}
}
}
/**
* Tests if the driver configures character sets correctly for 4.1.x
* servers. Requires that the 'admin connection' is configured, as this test
* needs to create/drop databases.
*
* @throws Exception
* if an error occurs
*/
public void testCollation41() throws Exception {
if (versionMeetsMinimum(4, 1) && isAdminConnectionConfigured()) {
Map charsetsAndCollations = getCharacterSetsAndCollations();
charsetsAndCollations.remove("latin7"); // Maps to multiple Java
// charsets
charsetsAndCollations.remove("ucs2"); // can't be used as a
// connection charset
Iterator charsets = charsetsAndCollations.keySet().iterator();
while (charsets.hasNext()) {
Connection charsetConn = null;
Statement charsetStmt = null;
try {
String charsetName = charsets.next().toString();
String collationName = charsetsAndCollations.get(
charsetName).toString();
Properties props = new Properties();
props.put("characterEncoding", charsetName);
System.out.println("Testing character set " + charsetName);
charsetConn = getAdminConnectionWithProps(props);
charsetStmt = charsetConn.createStatement();
charsetStmt
.executeUpdate("DROP DATABASE IF EXISTS testCollation41");
charsetStmt
.executeUpdate("DROP TABLE IF EXISTS testCollation41");
charsetStmt
.executeUpdate("CREATE DATABASE testCollation41 DEFAULT CHARACTER SET "
+ charsetName);
charsetConn.setCatalog("testCollation41");
// We've switched catalogs, so we need to recreate the
// statement to pick this up...
charsetStmt = charsetConn.createStatement();
StringBuffer createTableCommand = new StringBuffer(
"CREATE TABLE testCollation41"
+ "(field1 VARCHAR(255), field2 INT)");
charsetStmt.executeUpdate(createTableCommand.toString());
charsetStmt
.executeUpdate("INSERT INTO testCollation41 VALUES ('abc', 0)");
int updateCount = charsetStmt
.executeUpdate("UPDATE testCollation41 SET field2=1 WHERE field1='abc'");
assertTrue(updateCount == 1);
} finally {
if (charsetStmt != null) {
charsetStmt
.executeUpdate("DROP TABLE IF EXISTS testCollation41");
charsetStmt
.executeUpdate("DROP DATABASE IF EXISTS testCollation41");
charsetStmt.close();
}
if (charsetConn != null) {
charsetConn.close();
}
}
}
}
}
/**
* Tests setReadOnly() being reset during failover
*
* @throws Exception
* if an error occurs.
*/
public void testSetReadOnly() throws Exception {
Properties props = new Properties();
props.put("autoReconnect", "true");
String sepChar = "?";
if (BaseTestCase.dbUrl.indexOf("?") != -1) {
sepChar = "&";
}
Connection reconnectableConn = DriverManager.getConnection(
BaseTestCase.dbUrl + sepChar + "autoReconnect=true", props);
this.rs = reconnectableConn.createStatement().executeQuery(
"SELECT CONNECTION_ID()");
this.rs.next();
String connectionId = this.rs.getString(1);
reconnectableConn.setReadOnly(true);
boolean isReadOnly = reconnectableConn.isReadOnly();
Connection killConn = getConnectionWithProps((Properties) null);
killConn.createStatement().executeUpdate("KILL " + connectionId);
Thread.sleep(2000);
SQLException caughtException = null;
int numLoops = 8;
while (caughtException == null && numLoops > 0) {
numLoops--;
try {
reconnectableConn.createStatement().executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
caughtException = sqlEx;
}
}
System.out
.println("Executing statement on reconnectable connection...");
this.rs = reconnectableConn.createStatement().executeQuery(
"SELECT CONNECTION_ID()");
this.rs.next();
assertTrue("Connection is not a reconnected-connection",
!connectionId.equals(this.rs.getString(1)));
try {
reconnectableConn.createStatement().executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
; // ignore
}
reconnectableConn.createStatement().executeQuery("SELECT 1");
assertTrue(reconnectableConn.isReadOnly() == isReadOnly);
}
private Map getCharacterSetsAndCollations() throws Exception {
Map charsetsToLoad = new HashMap();
try {
this.rs = this.stmt.executeQuery("SHOW character set");
while (this.rs.next()) {
charsetsToLoad.put(this.rs.getString("Charset"),
this.rs.getString("Default collation"));
}
//
// These don't have mappings in Java...
//
charsetsToLoad.remove("swe7");
charsetsToLoad.remove("hp8");
charsetsToLoad.remove("dec8");
charsetsToLoad.remove("koi8u");
charsetsToLoad.remove("keybcs2");
charsetsToLoad.remove("geostd8");
charsetsToLoad.remove("armscii8");
} finally {
if (this.rs != null) {
this.rs.close();
}
}
return charsetsToLoad;
}
/**
* Tests fix for BUG#4334, port #'s not being picked up for
* failover/autoreconnect.
*
* @throws Exception
* if an error occurs.
*/
public void testBug4334() throws Exception {
if (isAdminConnectionConfigured()) {
Connection adminConnection = null;
try {
adminConnection = getAdminConnection();
int bogusPortNumber = 65534;
NonRegisteringDriver driver = new NonRegisteringDriver();
Properties oldProps = driver.parseURL(BaseTestCase.dbUrl, null);
String host = driver.host(oldProps);
int port = driver.port(oldProps);
String database = oldProps
.getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
String user = oldProps
.getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
String password = oldProps
.getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
StringBuffer newUrlToTestPortNum = new StringBuffer(
"jdbc:mysql://");
if (host != null) {
newUrlToTestPortNum.append(host);
}
newUrlToTestPortNum.append(":").append(port);
newUrlToTestPortNum.append(",");
if (host != null) {
newUrlToTestPortNum.append(host);
}
newUrlToTestPortNum.append(":").append(bogusPortNumber);
newUrlToTestPortNum.append("/");
if (database != null) {
newUrlToTestPortNum.append(database);
}
if ((user != null) || (password != null)) {
newUrlToTestPortNum.append("?");
if (user != null) {
newUrlToTestPortNum.append("user=").append(user);
if (password != null) {
newUrlToTestPortNum.append("&");
}
}
if (password != null) {
newUrlToTestPortNum.append("password=")
.append(password);
}
}
Properties autoReconnectProps = new Properties();
autoReconnectProps.put("autoReconnect", "true");
System.out.println(newUrlToTestPortNum);
//
// First test that port #'s are being correctly picked up
//
// We do this by looking at the error message that is returned
//
Connection portNumConn = DriverManager.getConnection(
newUrlToTestPortNum.toString(), autoReconnectProps);
Statement portNumStmt = portNumConn.createStatement();
this.rs = portNumStmt.executeQuery("SELECT connection_id()");
this.rs.next();
killConnection(adminConnection, this.rs.getString(1));
try {
portNumStmt.executeQuery("SELECT connection_id()");
} catch (SQLException sqlEx) {
// we expect this one
}
try {
portNumStmt.executeQuery("SELECT connection_id()");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().toLowerCase()
.indexOf("connection refused") != -1);
}
//
// Now make sure failover works
//
StringBuffer newUrlToTestFailover = new StringBuffer(
"jdbc:mysql://");
if (host != null) {
newUrlToTestFailover.append(host);
}
newUrlToTestFailover.append(":").append(port);
newUrlToTestFailover.append(",");
if (host != null) {
newUrlToTestFailover.append(host);
}
newUrlToTestFailover.append(":").append(bogusPortNumber);
newUrlToTestFailover.append("/");
if (database != null) {
newUrlToTestFailover.append(database);
}
if ((user != null) || (password != null)) {
newUrlToTestFailover.append("?");
if (user != null) {
newUrlToTestFailover.append("user=").append(user);
if (password != null) {
newUrlToTestFailover.append("&");
}
}
if (password != null) {
newUrlToTestFailover.append("password=").append(
password);
}
}
Connection failoverConn = DriverManager.getConnection(
newUrlToTestFailover.toString(), autoReconnectProps);
Statement failoverStmt = portNumConn.createStatement();
this.rs = failoverStmt.executeQuery("SELECT connection_id()");
this.rs.next();
killConnection(adminConnection, this.rs.getString(1));
try {
failoverStmt.executeQuery("SELECT connection_id()");
} catch (SQLException sqlEx) {
// we expect this one
}
failoverStmt.executeQuery("SELECT connection_id()");
} finally {
if (adminConnection != null) {
adminConnection.close();
}
}
}
}
private static void killConnection(Connection adminConn, String threadId)
throws SQLException {
adminConn.createStatement().execute("KILL " + threadId);
}
/**
* Tests fix for BUG#6966, connections starting up failed-over (due to down
* master) never retry master.
*
* @throws Exception
* if the test fails...Note, test is timing-dependent, but
* should work in most cases.
*/
public void testBug6966() throws Exception {
Properties props = new Driver().parseURL(BaseTestCase.dbUrl, null);
props.setProperty("autoReconnect", "true");
props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
Properties urlProps = new NonRegisteringDriver().parseURL(this.dbUrl,
null);
String host = urlProps.getProperty(Driver.HOST_PROPERTY_KEY);
String port = urlProps.getProperty(Driver.PORT_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY);
props.remove(Driver.NUM_HOSTS_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY + ".1");
props.remove(Driver.PORT_PROPERTY_KEY + ".1");
props.setProperty("queriesBeforeRetryMaster", "50");
props.setProperty("maxReconnects", "1");
UnreliableSocketFactory.mapHost("master", host);
UnreliableSocketFactory.mapHost("slave", host);
UnreliableSocketFactory.downHost("master");
Connection failoverConnection = null;
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://master:"
+ port + ",slave:" + port + "/", props);
failoverConnection.setAutoCommit(false);
String originalConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
for (int i = 0; i < 50; i++) {
failoverConnection.createStatement().executeQuery("SELECT 1");
}
((com.mysql.jdbc.Connection) failoverConnection)
.clearHasTriedMaster();
UnreliableSocketFactory.dontDownHost("master");
failoverConnection.setAutoCommit(true);
String newConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
assertTrue(((com.mysql.jdbc.Connection) failoverConnection)
.hasTriedMaster());
assertTrue(!newConnectionId.equals(originalConnectionId));
failoverConnection.createStatement().executeQuery("SELECT 1");
} finally {
UnreliableSocketFactory.flushAllHostLists();
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
/**
* Test fix for BUG#7952 -- Infinite recursion when 'falling back' to master
* in failover configuration.
*
* @throws Exception
* if the tests fails.
*/
public void testBug7952() throws Exception {
Properties props = new Driver().parseURL(BaseTestCase.dbUrl, null);
props.setProperty("autoReconnect", "true");
String host = props.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
if (!NonRegisteringDriver.isHostPropertiesList(host)) {
String port = props.getProperty(
NonRegisteringDriver.PORT_PROPERTY_KEY, "3306");
host = host + ":" + port;
}
host = host + "," + host;
props.remove("PORT");
props.remove("HOST");
props.setProperty("queriesBeforeRetryMaster", "10");
props.setProperty("maxReconnects", "1");
Connection failoverConnection = null;
Connection killerConnection = getConnectionWithProps((String) null);
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://" + host
+ "/", props);
((com.mysql.jdbc.Connection) failoverConnection)
.setPreferSlaveDuringFailover(true);
failoverConnection.setAutoCommit(false);
String failoverConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
System.out.println("Connection id: " + failoverConnectionId);
killConnection(killerConnection, failoverConnectionId);
Thread.sleep(3000); // This can take some time....
try {
failoverConnection.createStatement().executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
assertTrue("08S01".equals(sqlEx.getSQLState()));
}
((com.mysql.jdbc.Connection) failoverConnection)
.setPreferSlaveDuringFailover(false);
((com.mysql.jdbc.Connection) failoverConnection)
.setFailedOver(true);
failoverConnection.setAutoCommit(true);
String failedConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
System.out.println("Failed over connection id: "
+ failedConnectionId);
((com.mysql.jdbc.Connection) failoverConnection)
.setPreferSlaveDuringFailover(false);
((com.mysql.jdbc.Connection) failoverConnection)
.setFailedOver(true);
for (int i = 0; i < 30; i++) {
failoverConnection.setAutoCommit(true);
System.out.println(getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()"));
// failoverConnection.createStatement().executeQuery("SELECT
// 1");
failoverConnection.setAutoCommit(true);
}
String fallbackConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
System.out.println("fallback connection id: "
+ fallbackConnectionId);
/*
* long begin = System.currentTimeMillis();
*
* failoverConnection.setAutoCommit(true);
*
* long end = System.currentTimeMillis();
*
* assertTrue("Probably didn't try failing back to the
* master....check test", (end - begin) > 500);
*
* failoverConnection.createStatement().executeQuery("SELECT 1");
*/
} finally {
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
/**
* Tests fix for BUG#7607 - MS932, SHIFT_JIS and Windows_31J not recog. as
* aliases for sjis.
*
* @throws Exception
* if the test fails.
*/
public void testBug7607() throws Exception {
if (versionMeetsMinimum(4, 1)) {
Connection ms932Conn = null, cp943Conn = null, shiftJisConn = null, windows31JConn = null;
try {
Properties props = new Properties();
props.setProperty("characterEncoding", "MS932");
ms932Conn = getConnectionWithProps(props);
this.rs = ms932Conn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'character_set_client'");
assertTrue(this.rs.next());
String encoding = this.rs.getString(2);
if (!versionMeetsMinimum(5, 0, 3)
&& !versionMeetsMinimum(4, 1, 11)) {
assertEquals("sjis", encoding.toLowerCase(Locale.ENGLISH));
} else {
assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
}
this.rs = ms932Conn.createStatement().executeQuery(
"SELECT 'abc'");
assertTrue(this.rs.next());
String charsetToCheck = "ms932";
if (versionMeetsMinimum(5, 0, 3)
|| versionMeetsMinimum(4, 1, 11)) {
charsetToCheck = "windows-31j";
}
assertEquals(charsetToCheck,
((com.mysql.jdbc.ResultSetMetaData) this.rs
.getMetaData()).getColumnCharacterSet(1)
.toLowerCase(Locale.ENGLISH));
try {
ms932Conn.createStatement().executeUpdate(
"drop table if exists testBug7607");
ms932Conn
.createStatement()
.executeUpdate(
"create table testBug7607 (sortCol int, col1 varchar(100) ) character set sjis");
ms932Conn.createStatement().executeUpdate(
"insert into testBug7607 values(1, 0x835C)"); // standard
// sjis
ms932Conn.createStatement().executeUpdate(
"insert into testBug7607 values(2, 0x878A)"); // NEC
// kanji
this.rs = ms932Conn
.createStatement()
.executeQuery(
"SELECT col1 FROM testBug7607 ORDER BY sortCol ASC");
assertTrue(this.rs.next());
String asString = this.rs.getString(1);
assertTrue("\u30bd".equals(asString));
// Can't be fixed unless server is fixed,
// this is fixed in 4.1.7.
assertTrue(this.rs.next());
asString = this.rs.getString(1);
assertEquals("\u3231", asString);
} finally {
ms932Conn.createStatement().executeUpdate(
"drop table if exists testBug7607");
}
props = new Properties();
props.setProperty("characterEncoding", "SHIFT_JIS");
shiftJisConn = getConnectionWithProps(props);
this.rs = shiftJisConn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'character_set_client'");
assertTrue(this.rs.next());
encoding = this.rs.getString(2);
assertTrue("sjis".equalsIgnoreCase(encoding));
this.rs = shiftJisConn.createStatement().executeQuery(
"SELECT 'abc'");
assertTrue(this.rs.next());
String charSetUC = ((com.mysql.jdbc.ResultSetMetaData) this.rs
.getMetaData()).getColumnCharacterSet(1).toUpperCase(
Locale.US);
if (isRunningOnJdk131()) {
assertEquals("WINDOWS-31J", charSetUC);
} else {
// assertEquals("SHIFT_JIS", charSetUC);
}
props = new Properties();
props.setProperty("characterEncoding", "WINDOWS-31J");
windows31JConn = getConnectionWithProps(props);
this.rs = windows31JConn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'character_set_client'");
assertTrue(this.rs.next());
encoding = this.rs.getString(2);
if (!versionMeetsMinimum(5, 0, 3)
&& !versionMeetsMinimum(4, 1, 11)) {
assertEquals("sjis", encoding.toLowerCase(Locale.ENGLISH));
} else {
assertEquals("cp932", encoding.toLowerCase(Locale.ENGLISH));
}
this.rs = windows31JConn.createStatement().executeQuery(
"SELECT 'abc'");
assertTrue(this.rs.next());
if (!versionMeetsMinimum(4, 1, 11)) {
assertEquals("sjis".toLowerCase(Locale.ENGLISH),
((com.mysql.jdbc.ResultSetMetaData) this.rs
.getMetaData()).getColumnCharacterSet(1)
.toLowerCase(Locale.ENGLISH));
} else {
assertEquals("windows-31j".toLowerCase(Locale.ENGLISH),
((com.mysql.jdbc.ResultSetMetaData) this.rs
.getMetaData()).getColumnCharacterSet(1)
.toLowerCase(Locale.ENGLISH));
}
props = new Properties();
props.setProperty("characterEncoding", "CP943");
cp943Conn = getConnectionWithProps(props);
this.rs = cp943Conn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'character_set_client'");
assertTrue(this.rs.next());
encoding = this.rs.getString(2);
assertTrue("sjis".equalsIgnoreCase(encoding));
this.rs = cp943Conn.createStatement().executeQuery(
"SELECT 'abc'");
assertTrue(this.rs.next());
charSetUC = ((com.mysql.jdbc.ResultSetMetaData) this.rs
.getMetaData()).getColumnCharacterSet(1).toUpperCase(
Locale.US);
if (isRunningOnJdk131()) {
assertEquals("WINDOWS-31J", charSetUC);
} else {
assertEquals("CP943", charSetUC);
}
} finally {
if (ms932Conn != null) {
ms932Conn.close();
}
if (shiftJisConn != null) {
shiftJisConn.close();
}
if (windows31JConn != null) {
windows31JConn.close();
}
if (cp943Conn != null) {
cp943Conn.close();
}
}
}
}
/**
* In some case Connector/J's round-robin function doesn't work.
*
* I had 2 mysqld, node1 "localhost:3306" and node2 "localhost:3307".
*
* 1. node1 is up, node2 is up
*
* 2. java-program connect to node1 by using properties
* "autoRecconect=true",
* "roundRobinLoadBalance=true","failOverReadOnly=false".
*
* 3. node1 is down, node2 is up
*
* 4. java-program execute a query and fail, but Connector/J's round-robin
* fashion failover work and if java-program retry a query it can succeed
* (connection is change to node2 by Connector/j)
*
* 5. node1 is up, node2 is up
*
* 6. node1 is up, node2 is down
*
* 7. java-program execute a query, but this time Connector/J doesn't work
* althought node1 is up and usable.
*
*
* @throws Exception
*/
/*
* FIXME: This test is no longer valid with random selection of hosts public
* void testBug8643() throws Exception { if (runMultiHostTests()) {
* Properties defaultProps = getMasterSlaveProps();
*
* defaultProps.remove(NonRegisteringDriver.HOST_PROPERTY_KEY);
* defaultProps.remove(NonRegisteringDriver.PORT_PROPERTY_KEY);
*
* defaultProps.put("autoReconnect", "true");
* defaultProps.put("roundRobinLoadBalance", "true");
* defaultProps.put("failOverReadOnly", "false");
*
* Connection con = null; try { con =
* DriverManager.getConnection(getMasterSlaveUrl(), defaultProps); Statement
* stmt1 = con.createStatement();
*
* ResultSet rs1 = stmt1 .executeQuery("show variables like 'port'");
* rs1.next();
*
* rs1 = stmt1.executeQuery("select connection_id()"); rs1.next(); String
* originalConnectionId = rs1.getString(1); this.stmt.executeUpdate("kill "
* + originalConnectionId);
*
* int numLoops = 8;
*
* SQLException caughtException = null;
*
* while (caughtException == null && numLoops > 0) { numLoops--;
*
* try { rs1 = stmt1.executeQuery("show variables like 'port'"); } catch
* (SQLException sqlEx) { caughtException = sqlEx; } }
*
* assertNotNull(caughtException);
*
* // failover and retry rs1 =
* stmt1.executeQuery("show variables like 'port'");
*
* rs1.next(); assertTrue(!((com.mysql.jdbc.Connection) con)
* .isMasterConnection());
*
* rs1 = stmt1.executeQuery("select connection_id()"); rs1.next(); String
* nextConnectionId = rs1.getString(1);
* assertTrue(!nextConnectionId.equals(originalConnectionId));
*
* this.stmt.executeUpdate("kill " + nextConnectionId);
*
* numLoops = 8;
*
* caughtException = null;
*
* while (caughtException == null && numLoops > 0) { numLoops--;
*
* try { rs1 = stmt1.executeQuery("show variables like 'port'"); } catch
* (SQLException sqlEx) { caughtException = sqlEx; } }
*
* assertNotNull(caughtException);
*
* // failover and retry rs1 =
* stmt1.executeQuery("show variables like 'port'");
*
* rs1.next(); assertTrue(((com.mysql.jdbc.Connection) con)
* .isMasterConnection());
*
* } finally { if (con != null) { try { con.close(); } catch (Exception e) {
* e.printStackTrace(); } } } } }
*/
/**
* Tests fix for BUG#9206, can not use 'UTF-8' for characterSetResults
* configuration property.
*/
public void testBug9206() throws Exception {
Properties props = new Properties();
props.setProperty("characterSetResults", "UTF-8");
getConnectionWithProps(props).close();
}
/**
* These two charsets have different names depending on version of MySQL
* server.
*
* @throws Exception
* if the test fails.
*/
public void testNewCharsetsConfiguration() throws Exception {
Properties props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "EUC_KR");
getConnectionWithProps(props).close();
props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "KOI8_R");
getConnectionWithProps(props).close();
}
/**
* Tests fix for BUG#10144 - Memory leak in ServerPreparedStatement if
* serverPrepare() fails.
*/
public void testBug10144() throws Exception {
if (versionMeetsMinimum(4, 1)) {
Properties props = new Properties();
props.setProperty("emulateUnsupportedPstmts", "false");
props.setProperty("useServerPrepStmts", "true");
Connection bareConn = getConnectionWithProps(props);
int currentOpenStatements = ((com.mysql.jdbc.Connection) bareConn)
.getActiveStatementCount();
try {
bareConn.prepareStatement("Boo!");
fail("Should not've been able to prepare that one!");
} catch (SQLException sqlEx) {
assertEquals(currentOpenStatements,
((com.mysql.jdbc.Connection) bareConn)
.getActiveStatementCount());
} finally {
if (bareConn != null) {
bareConn.close();
}
}
}
}
/**
* Tests fix for BUG#10496 - SQLException is thrown when using property
* "characterSetResults"
*/
public void testBug10496() throws Exception {
if (versionMeetsMinimum(5, 0, 3)) {
Properties props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "WINDOWS-31J");
props.setProperty("characterSetResults", "WINDOWS-31J");
getConnectionWithProps(props).close();
props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "EUC_JP");
props.setProperty("characterSetResults", "EUC_JP");
getConnectionWithProps(props).close();
}
}
/**
* Tests fix for BUG#11259, autoReconnect ping causes exception on
* connection startup.
*
* @throws Exception
* if the test fails.
*/
public void testBug11259() throws Exception {
Connection dsConn = null;
try {
Properties props = new Properties();
props.setProperty("autoReconnect", "true");
dsConn = getConnectionWithProps(props);
} finally {
if (dsConn != null) {
dsConn.close();
}
}
}
/**
* Tests fix for BUG#11879 -- ReplicationConnection won't switch to slave,
* throws "Catalog can't be null" exception.
*
* @throws Exception
* if the test fails
*/
public void testBug11879() throws Exception {
if (runMultiHostTests()) {
Connection replConn = null;
try {
replConn = getMasterSlaveReplicationConnection();
replConn.setReadOnly(true);
replConn.setReadOnly(false);
} finally {
if (replConn != null) {
replConn.close();
}
}
}
}
/**
* Tests fix for BUG#11976 - maxPerformance.properties mis-spells
* "elideSetAutoCommits".
*
* @throws Exception
* if the test fails.
*/
public void testBug11976() throws Exception {
if (isRunningOnJdk131()) {
return; // test not valid on JDK-1.3.1
}
if (!versionMeetsMinimum(6, 0)) {
return; // server status is broken until MySQL-6.0
}
Properties props = new Properties();
props.setProperty("useConfigs", "maxPerformance");
Connection maxPerfConn = getConnectionWithProps(props);
assertEquals(true,
((com.mysql.jdbc.Connection) maxPerfConn)
.getElideSetAutoCommits());
}
/**
* Tests fix for BUG#12218, properties shared between master and slave with
* replication connection.
*
* @throws Exception
* if the test fails.
*/
public void testBug12218() throws Exception {
if (runMultiHostTests()) {
Connection replConn = null;
try {
replConn = getMasterSlaveReplicationConnection();
assertTrue(!((MySQLConnection) ((ReplicationConnection) replConn)
.getMasterConnection())
.hasSameProperties(((ReplicationConnection) replConn)
.getSlavesConnection()));
} finally {
if (replConn != null) {
replConn.close();
}
}
}
}
/**
* Tests fix for BUG#12229 - explainSlowQueries hangs with server-side
* prepared statements.
*
* @throws Exception
* if the test fails.
*/
public void testBug12229() throws Exception {
createTable("testBug12229", "(`int_field` integer )");
this.stmt.executeUpdate("insert into testBug12229 values (123456),(1)");
Properties props = new Properties();
props.put("profileSQL", "true");
props.put("slowQueryThresholdMillis", "0");
props.put("logSlowQueries", "true");
props.put("explainSlowQueries", "true");
props.put("useServerPrepStmts", "true");
Connection explainConn = getConnectionWithProps(props);
this.pstmt = explainConn
.prepareStatement("SELECT `int_field` FROM `testBug12229` WHERE `int_field` = ?");
this.pstmt.setInt(1, 1);
this.rs = this.pstmt.executeQuery();
assertTrue(this.rs.next());
this.rs = this.pstmt.executeQuery();
assertTrue(this.rs.next());
this.rs = this.pstmt.executeQuery();
assertTrue(this.rs.next());
}
/**
* Tests fix for BUG#12752 - Cp1251 incorrectly mapped to win1251 for
* servers newer than 4.0.x.
*
* @throws Exception
* if the test fails.
*/
public void testBug12752() throws Exception {
Properties props = new Properties();
props.setProperty("characterEncoding", "Cp1251");
getConnectionWithProps(props).close();
}
/**
* Tests fix for BUG#12753, sessionVariables=....=...., doesn't work as it's
* tokenized incorrectly.
*
* @throws Exception
* if the test fails.
*/
public void testBug12753() throws Exception {
if (versionMeetsMinimum(4, 1)) {
Properties props = new Properties();
props.setProperty("sessionVariables", "sql_mode=ansi");
Connection sessionConn = null;
try {
sessionConn = getConnectionWithProps(props);
String sqlMode = getMysqlVariable(sessionConn, "sql_mode");
assertTrue(sqlMode.indexOf("ANSI") != -1);
} finally {
if (sessionConn != null) {
sessionConn.close();
sessionConn = null;
}
}
}
}
/**
* Tests fix for BUG#13048 - maxQuerySizeToLog is not respected.
*
* @throws Exception
* if the test fails
*/
public void testBug13048() throws Exception {
Connection profileConn = null;
PrintStream oldErr = System.err;
try {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
System.setErr(new PrintStream(bOut));
Properties props = new Properties();
props.setProperty("profileSQL", "true");
props.setProperty("maxQuerySizeToLog", "2");
props.setProperty("logger", "com.mysql.jdbc.log.StandardLogger");
profileConn = getConnectionWithProps(props);
StringBuffer queryBuf = new StringBuffer("SELECT '");
for (int i = 0; i < 500; i++) {
queryBuf.append("a");
}
queryBuf.append("'");
this.rs = profileConn.createStatement().executeQuery(
queryBuf.toString());
this.rs.close();
String logString = new String(bOut.toString("ISO8859-1"));
assertTrue(logString.indexOf("... (truncated)") != -1);
bOut = new ByteArrayOutputStream();
System.setErr(new PrintStream(bOut));
this.rs = profileConn.prepareStatement(queryBuf.toString())
.executeQuery();
logString = new String(bOut.toString("ISO8859-1"));
assertTrue(logString.indexOf("... (truncated)") != -1);
} finally {
System.setErr(oldErr);
if (profileConn != null) {
profileConn.close();
}
if (this.rs != null) {
ResultSet toClose = this.rs;
this.rs = null;
toClose.close();
}
}
}
/**
* Tests fix for BUG#13453 - can't use & or = in URL configuration values
* (we now allow you to use www-form-encoding).
*
* @throws Exception
* if the test fails
*/
public void testBug13453() throws Exception {
StringBuffer urlBuf = new StringBuffer(dbUrl);
if (dbUrl.indexOf('?') == -1) {
urlBuf.append('?');
} else {
urlBuf.append('&');
}
urlBuf.append("sessionVariables=@testBug13453='%25%26+%3D'");
Connection encodedConn = null;
try {
encodedConn = DriverManager.getConnection(urlBuf.toString(), null);
this.rs = encodedConn.createStatement().executeQuery(
"SELECT @testBug13453");
assertTrue(this.rs.next());
assertEquals("%& =", this.rs.getString(1));
} finally {
if (this.rs != null) {
this.rs.close();
this.rs = null;
}
if (encodedConn != null) {
encodedConn.close();
}
}
}
/**
* Tests fix for BUG#15065 - Usage advisor complains about unreferenced
* columns, even though they've been referenced.
*
* @throws Exception
* if the test fails.
*/
public void testBug15065() throws Exception {
if (isRunningOnJdk131()) {
return; // test not valid on JDK-1.3.1
}
createTable("testBug15065", "(field1 int)");
this.stmt.executeUpdate("INSERT INTO testBug15065 VALUES (1)");
Connection advisorConn = null;
Statement advisorStmt = null;
try {
Properties props = new Properties();
props.setProperty("useUsageAdvisor", "true");
props.setProperty("logger", "com.mysql.jdbc.log.StandardLogger");
advisorConn = getConnectionWithProps(props);
advisorStmt = advisorConn.createStatement();
Method[] getMethods = ResultSet.class.getMethods();
PrintStream oldErr = System.err;
try {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
System.setErr(new PrintStream(bOut));
HashMap methodsToSkipMap = new HashMap();
// Needs an actual URL
methodsToSkipMap.put("getURL", null);
// Java6 JDBC4.0 methods we don't implement
methodsToSkipMap.put("getNCharacterStream", null);
methodsToSkipMap.put("getNClob", null);
methodsToSkipMap.put("getNString", null);
methodsToSkipMap.put("getRowId", null);
methodsToSkipMap.put("getSQLXML", null);
for (int j = 0; j < 2; j++) {
for (int i = 0; i < getMethods.length; i++) {
String methodName = getMethods[i].getName();
if (methodName.startsWith("get")
&& !methodsToSkipMap.containsKey(methodName)) {
Class[] parameterTypes = getMethods[i]
.getParameterTypes();
if (parameterTypes.length == 1
&& parameterTypes[0] == Integer.TYPE) {
if (j == 0) {
this.rs = advisorStmt
.executeQuery("SELECT COUNT(*) FROM testBug15065");
} else {
this.rs = advisorConn
.prepareStatement(
"SELECT COUNT(*) FROM testBug15065")
.executeQuery();
}
this.rs.next();
try {
getMethods[i].invoke(this.rs,
new Object[] { new Integer(1) });
} catch (InvocationTargetException invokeEx) {
// we don't care about bad values, just that
// the
// column gets "touched"
if (!invokeEx
.getCause()
.getClass()
.isAssignableFrom(
java.sql.SQLException.class)
&& !invokeEx
.getCause()
.getClass()
.getName()
.equals("com.mysql.jdbc.NotImplemented")
&& !invokeEx
.getCause()
.getClass()
.getName()
.equals("java.sql.SQLFeatureNotSupportedException")) {
throw invokeEx;
}
}
this.rs.close();
this.rs = null;
}
}
}
}
String logOut = bOut.toString("ISO8859-1");
if (logOut.indexOf(".Level") != -1) {
return; // we ignore for warnings
}
assertTrue("Usage advisor complained about columns:\n\n"
+ logOut, logOut.indexOf("columns") == -1);
} finally {
System.setErr(oldErr);
}
} finally {
if (advisorConn != null) {
advisorConn.close();
}
}
}
/**
* Tests fix for BUG#15544, no "dos" character set in MySQL > 4.1.0
*
* @throws Exception
* if the test fails
*/
public void testBug15544() throws Exception {
Properties props = new Properties();
props.setProperty("characterEncoding", "Cp437");
Connection dosConn = null;
try {
dosConn = getConnectionWithProps(props);
} finally {
if (dosConn != null) {
dosConn.close();
}
}
}
public void testCSC5765() throws Exception {
if (isRunningOnJdk131()) {
return; // test not valid on JDK-1.3.1
}
Properties props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "utf8");
props.setProperty("characterSetResults", "utf8");
props.setProperty("connectionCollation", "utf8_bin");
Connection utf8Conn = null;
try {
utf8Conn = getConnectionWithProps(props);
this.rs = utf8Conn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'character_%'");
while (this.rs.next()) {
System.out.println(this.rs.getString(1) + " = "
+ this.rs.getString(2));
}
this.rs = utf8Conn.createStatement().executeQuery(
"SHOW VARIABLES LIKE 'collation_%'");
while (this.rs.next()) {
System.out.println(this.rs.getString(1) + " = "
+ this.rs.getString(2));
}
} finally {
if (utf8Conn != null) {
utf8Conn.close();
}
}
}
/**
* Tests fix for BUG#15570 - ReplicationConnection incorrectly copies state,
* doesn't transfer connection context correctly when transitioning between
* the same read-only states.
*
* (note, this test will fail if the test user doesn't have permission to
* "USE 'mysql'".
*
* @throws Exception
* if the test fails.
*/
public void testBug15570() throws Exception {
Connection replConn = null;
try {
replConn = getMasterSlaveReplicationConnection();
int masterConnectionId = Integer
.parseInt(getSingleIndexedValueWithQuery(replConn, 1,
"SELECT CONNECTION_ID()").toString());
replConn.setReadOnly(false);
assertEquals(
masterConnectionId,
Integer.parseInt(getSingleIndexedValueWithQuery(replConn,
1, "SELECT CONNECTION_ID()").toString()));
String currentCatalog = replConn.getCatalog();
replConn.setCatalog(currentCatalog);
assertEquals(currentCatalog, replConn.getCatalog());
replConn.setReadOnly(true);
int slaveConnectionId = Integer
.parseInt(getSingleIndexedValueWithQuery(replConn, 1,
"SELECT CONNECTION_ID()").toString());
// The following test is okay for now, as the chance
// of MySQL wrapping the connection id counter during our
// testsuite is very small.
assertTrue("Slave id " + slaveConnectionId
+ " is not newer than master id " + masterConnectionId,
slaveConnectionId > masterConnectionId);
assertEquals(currentCatalog, replConn.getCatalog());
String newCatalog = "mysql";
replConn.setCatalog(newCatalog);
assertEquals(newCatalog, replConn.getCatalog());
replConn.setReadOnly(true);
assertEquals(newCatalog, replConn.getCatalog());
replConn.setReadOnly(false);
assertEquals(
masterConnectionId,
Integer.parseInt(getSingleIndexedValueWithQuery(replConn,
1, "SELECT CONNECTION_ID()").toString()));
} finally {
if (replConn != null) {
replConn.close();
}
}
}
/**
* Tests bug where downed slave caused round robin load balance not to cycle
* back to first host in the list.
*
* @throws Exception
* if the test fails...Note, test is timing-dependent, but
* should work in most cases.
*/
public void testBug23281() throws Exception {
Properties props = new Driver().parseURL(BaseTestCase.dbUrl, null);
props.setProperty("autoReconnect", "false");
props.setProperty("roundRobinLoadBalance", "true");
props.setProperty("failoverReadOnly", "false");
if (!isRunningOnJdk131()) {
props.setProperty("connectTimeout", "5000");
}
String host = props.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
if (!NonRegisteringDriver.isHostPropertiesList(host)) {
String port = props.getProperty(
NonRegisteringDriver.PORT_PROPERTY_KEY, "3306");
host = host + ":" + port;
}
props.remove("PORT");
props.remove("HOST");
StringBuffer newHostBuf = new StringBuffer();
newHostBuf.append(host);
newHostBuf.append(",");
// newHostBuf.append(host);
newHostBuf.append("192.0.2.1"); // non-exsitent machine from RFC3330
// test network
newHostBuf.append(":65532"); // make sure the slave fails
props.remove("PORT");
props.remove("HOST");
Connection failoverConnection = null;
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://"
+ newHostBuf.toString() + "/", props);
String originalConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT CONNECTION_ID()").toString();
System.out.println(originalConnectionId);
Connection nextConnection = getConnectionWithProps("jdbc:mysql://"
+ newHostBuf.toString() + "/", props);
String nextId = getSingleIndexedValueWithQuery(nextConnection, 1,
"SELECT CONNECTION_ID()").toString();
System.out.println(nextId);
} finally {
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
/**
* Tests to insure proper behavior for BUG#24706.
*
* @throws Exception
* if the test fails.
*/
public void testBug24706() throws Exception {
if (!versionMeetsMinimum(6, 0)) {
return; // server status isn't there to support this feature
}
Properties props = new Properties();
props.setProperty("elideSetAutoCommits", "true");
props.setProperty("logger", "StandardLogger");
props.setProperty("profileSQL", "true");
Connection c = null;
StringBuffer logBuf = new StringBuffer();
StandardLogger.bufferedLog = logBuf;
try {
c = getConnectionWithProps(props);
c.setAutoCommit(true);
c.createStatement().execute("SELECT 1");
c.setAutoCommit(true);
c.setAutoCommit(false);
c.createStatement().execute("SELECT 1");
c.setAutoCommit(false);
// We should only see _one_ "set autocommit=" sent to the server
String log = logBuf.toString();
int searchFrom = 0;
int count = 0;
int found = 0;
while ((found = log.indexOf("SET autocommit=", searchFrom)) != -1) {
searchFrom = found + 1;
count++;
}
// The SELECT doesn't actually start a transaction, so being
// pedantic the
// driver issues SET autocommit=0 again in this case.
assertEquals(2, count);
} finally {
StandardLogger.bufferedLog = null;
if (c != null) {
c.close();
}
}
}
/**
* Tests fix for BUG#25514 - Timer instance used for
* Statement.setQueryTimeout() created per-connection, rather than per-VM,
* causing memory leak.
*
* @throws Exception
* if the test fails.
*/
public void testBug25514() throws Exception {
for (int i = 0; i < 10; i++) {
getConnectionWithProps((Properties) null).close();
}
ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
while (root.getParent() != null) {
root = root.getParent();
}
int numThreadsNamedTimer = findNamedThreadCount(root, "Timer");
if (numThreadsNamedTimer == 0) {
numThreadsNamedTimer = findNamedThreadCount(root,
"MySQL Statement Cancellation Timer");
}
// Notice that this seems impossible to test on JDKs prior to 1.5, as
// there is no
// reliable way to find the TimerThread, so we have to rely on new JDKs
// for this
// test.
assertTrue("More than one timer for cancel was created",
numThreadsNamedTimer <= 1);
}
private int findNamedThreadCount(ThreadGroup group, String nameStart) {
int count = 0;
int numThreads = group.activeCount();
Thread[] threads = new Thread[numThreads * 2];
numThreads = group.enumerate(threads, false);
for (int i = 0; i < numThreads; i++) {
if (threads[i].getName().startsWith(nameStart)) {
count++;
}
}
int numGroups = group.activeGroupCount();
ThreadGroup[] groups = new ThreadGroup[numGroups * 2];
numGroups = group.enumerate(groups, false);
for (int i = 0; i < numGroups; i++) {
count += findNamedThreadCount(groups[i], nameStart);
}
return count;
}
/**
* Ensures that we don't miss getters/setters for driver properties in
* ConnectionProperties so that names given in documentation work with
* DataSources which will use JavaBean-style names and reflection to set the
* values (and often fail silently! when the method isn't available).
*
* @throws Exception
*/
public void testBug23626() throws Exception {
Class clazz = this.conn.getClass();
DriverPropertyInfo[] dpi = new NonRegisteringDriver().getPropertyInfo(
dbUrl, null);
StringBuffer missingSettersBuf = new StringBuffer();
StringBuffer missingGettersBuf = new StringBuffer();
Class[][] argTypes = { new Class[] { String.class },
new Class[] { Integer.TYPE }, new Class[] { Long.TYPE },
new Class[] { Boolean.TYPE } };
for (int i = 0; i < dpi.length; i++) {
String propertyName = dpi[i].name;
if (propertyName.equals("HOST") || propertyName.equals("PORT")
|| propertyName.equals("DBNAME")
|| propertyName.equals("user")
|| propertyName.equals("password")) {
continue;
}
StringBuffer mutatorName = new StringBuffer("set");
mutatorName.append(Character.toUpperCase(propertyName.charAt(0)));
mutatorName.append(propertyName.substring(1));
StringBuffer accessorName = new StringBuffer("get");
accessorName.append(Character.toUpperCase(propertyName.charAt(0)));
accessorName.append(propertyName.substring(1));
try {
clazz.getMethod(accessorName.toString(), (Class[]) null);
} catch (NoSuchMethodException nsme) {
missingGettersBuf.append(accessorName.toString());
missingGettersBuf.append("\n");
}
boolean foundMethod = false;
for (int j = 0; j < argTypes.length; j++) {
try {
clazz.getMethod(mutatorName.toString(), argTypes[j]);
foundMethod = true;
break;
} catch (NoSuchMethodException nsme) {
}
}
if (!foundMethod) {
missingSettersBuf.append(mutatorName);
missingSettersBuf.append("\n");
}
}
assertEquals("Missing setters for listed configuration properties.",
"", missingSettersBuf.toString());
assertEquals("Missing getters for listed configuration properties.",
"", missingSettersBuf.toString());
}
/**
* Tests fix for BUG#25545 - Client flags not sent correctly during
* handshake when using SSL.
*
* Requires test certificates from testsuite/ssl-test-certs to be installed
* on the server being tested.
*
* @throws Exception
* if the test fails.
*/
public void testBug25545() throws Exception {
if (!versionMeetsMinimum(5, 0)) {
return;
}
if (isRunningOnJdk131()) {
return;
}
createProcedure("testBug25545", "() BEGIN SELECT 1; END");
String trustStorePath = "src/testsuite/ssl-test-certs/test-cert-store";
System.setProperty("javax.net.ssl.keyStore", trustStorePath);
System.setProperty("javax.net.ssl.keyStorePassword", "password");
System.setProperty("javax.net.ssl.trustStore", trustStorePath);
System.setProperty("javax.net.ssl.trustStorePassword", "password");
Connection sslConn = null;
try {
Properties props = new Properties();
props.setProperty("useSSL", "true");
props.setProperty("requireSSL", "true");
sslConn = getConnectionWithProps(props);
sslConn.prepareCall("{ call testBug25545()}").execute();
} finally {
if (sslConn != null) {
sslConn.close();
}
}
}
/**
* Tests fix for BUG#27655 - getTransactionIsolation() uses
* "SHOW VARIABLES LIKE" which is very inefficient on MySQL-5.0+
*
* @throws Exception
*/
public void testBug27655() throws Exception {
StringBuffer logBuf = new StringBuffer();
Properties props = new Properties();
props.setProperty("profileSQL", "true");
props.setProperty("logger", "StandardLogger");
StandardLogger.bufferedLog = logBuf;
Connection loggedConn = null;
try {
loggedConn = getConnectionWithProps(props);
loggedConn.getTransactionIsolation();
if (versionMeetsMinimum(4, 0, 3)) {
assertEquals(
-1,
logBuf.toString().indexOf(
"SHOW VARIABLES LIKE 'tx_isolation'"));
}
} finally {
if (loggedConn != null) {
loggedConn.close();
}
}
}
/**
* Tests fix for issue where a failed-over connection would let an
* application call setReadOnly(false), when that call should be ignored
* until the connection is reconnected to a writable master.
*
* @throws Exception
* if the test fails.
*/
public void testFailoverReadOnly() throws Exception {
Properties props = getMasterSlaveProps();
props.setProperty("autoReconnect", "true");
Connection failoverConn = null;
Statement failoverStmt = null;
try {
failoverConn = getConnectionWithProps(getMasterSlaveUrl(), props);
((com.mysql.jdbc.Connection) failoverConn)
.setPreferSlaveDuringFailover(true);
failoverStmt = failoverConn.createStatement();
String masterConnectionId = getSingleIndexedValueWithQuery(
failoverConn, 1, "SELECT connection_id()").toString();
this.stmt.execute("KILL " + masterConnectionId);
// die trying, so we get the next host
for (int i = 0; i < 100; i++) {
try {
failoverStmt.executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
break;
}
}
String slaveConnectionId = getSingleIndexedValueWithQuery(
failoverConn, 1, "SELECT connection_id()").toString();
assertTrue("Didn't get a new physical connection",
!masterConnectionId.equals(slaveConnectionId));
failoverConn.setReadOnly(false); // this should be ignored
assertTrue(failoverConn.isReadOnly());
((com.mysql.jdbc.Connection) failoverConn)
.setPreferSlaveDuringFailover(false);
this.stmt.execute("KILL " + slaveConnectionId); // we can't issue
// this on our own
// connection :p
// die trying, so we get the next host
for (int i = 0; i < 100; i++) {
try {
failoverStmt.executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
break;
}
}
String newMasterId = getSingleIndexedValueWithQuery(failoverConn,
1, "SELECT connection_id()").toString();
assertTrue("Didn't get a new physical connection",
!slaveConnectionId.equals(newMasterId));
failoverConn.setReadOnly(false);
assertTrue(!failoverConn.isReadOnly());
} finally {
if (failoverStmt != null) {
failoverStmt.close();
}
if (failoverConn != null) {
failoverConn.close();
}
}
}
public void testPropertiesDescriptionsKeys() throws Exception {
DriverPropertyInfo[] dpi = new NonRegisteringDriver().getPropertyInfo(
dbUrl, null);
for (int i = 0; i < dpi.length; i++) {
String description = dpi[i].description;
String propertyName = dpi[i].name;
if (description.indexOf("Missing error message for key '") != -1
|| description.startsWith("!")) {
fail("Missing message for configuration property "
+ propertyName);
}
if (description.length() < 10) {
fail("Suspiciously short description for configuration property "
+ propertyName);
}
}
}
public void testBug29106() throws Exception {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class checkerClass = cl
.loadClass("com.mysql.jdbc.integration.jboss.MysqlValidConnectionChecker");
((MysqlValidConnectionChecker) checkerClass.newInstance())
.isValidConnection(this.conn);
}
public void testBug29852() throws Exception {
Connection lbConn = getLoadBalancedConnection();
assertTrue(!lbConn.getClass().getName().startsWith("com.mysql.jdbc"));
lbConn.close();
}
/**
* Test of a new feature to fix BUG 22643, specifying a "validation query"
* in your connection pool that starts with "slash-star ping slash-star"
* _exactly_ will cause the driver to " + instead send a ping to the server
* (much lighter weight), and when using a ReplicationConnection or a
* LoadBalancedConnection, will send the ping across all active connections.
*
* @throws Exception
*/
public void testBug22643() throws Exception {
checkPingQuery(this.conn);
Connection replConnection = getMasterSlaveReplicationConnection();
try {
checkPingQuery(replConnection);
} finally {
if (replConnection != null) {
replConnection.close();
}
}
Connection lbConn = getLoadBalancedConnection();
try {
checkPingQuery(lbConn);
} finally {
if (lbConn != null) {
lbConn.close();
}
}
}
private void checkPingQuery(Connection c) throws SQLException {
// Yes, I know we're sending 2, and looking for 1
// that's part of the test, since we don't _really_
// send the query to the server!
String aPingQuery = "/* ping */ SELECT 2";
Statement pingStmt = c.createStatement();
PreparedStatement pingPStmt = null;
this.rs = pingStmt.executeQuery(aPingQuery);
assertTrue(this.rs.next());
assertEquals(this.rs.getInt(1), 1);
assertTrue(pingStmt.execute(aPingQuery));
this.rs = pingStmt.getResultSet();
assertTrue(this.rs.next());
assertEquals(this.rs.getInt(1), 1);
pingPStmt = c.prepareStatement(aPingQuery);
assertTrue(pingPStmt.execute());
this.rs = pingPStmt.getResultSet();
assertTrue(this.rs.next());
assertEquals(this.rs.getInt(1), 1);
this.rs = pingPStmt.executeQuery();
assertTrue(this.rs.next());
assertEquals(this.rs.getInt(1), 1);
}
public void testBug31053() throws Exception {
Properties props = new Properties();
props.setProperty("connectTimeout", "2000");
props.setProperty("loadBalanceStrategy", "random");
Connection lbConn = getLoadBalancedConnection(2, "localhost:23", props);
lbConn.setAutoCommit(false);
for (int i = 0; i < 10; i++) {
lbConn.commit();
}
}
public void testBug32877() throws Exception {
Properties props = new Properties();
props.setProperty("connectTimeout", "2000");
props.setProperty("loadBalanceStrategy", "bestResponseTime");
Connection lbConn = getLoadBalancedConnection(1, "localhost:23", props);
lbConn.setAutoCommit(false);
long begin = System.currentTimeMillis();
for (int i = 0; i < 4; i++) {
lbConn.commit();
}
assertTrue(System.currentTimeMillis() - begin < 10000);
}
/**
* Tests fix for BUG#33734 - NullPointerException when using client-side
* prepared statements and enabling caching of prepared statements (only
* present in nightly builds of 5.1).
*
* @throws Exception
*/
public void testBug33734() throws Exception {
Connection testConn = getConnectionWithProps("cachePrepStmts=true,useServerPrepStmts=false");
try {
testConn.prepareStatement("SELECT 1");
} finally {
testConn.close();
}
}
/** 34703 [NEW]: isValild() aborts Connection on timeout */
public void testBug34703() throws Exception {
if (!com.mysql.jdbc.Util.isJdbc4()) {
return;
}
Method isValid = java.sql.Connection.class.getMethod("isValid",
new Class[] { Integer.TYPE });
Connection newConn = getConnectionWithProps((Properties) null);
isValid.invoke(newConn, new Object[] { new Integer(1) });
Thread.sleep(2000);
assertTrue(((Boolean) isValid.invoke(newConn,
new Object[] { new Integer(0) })).booleanValue());
}
public void testBug34937() throws Exception {
com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource ds = new com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource();
StringBuffer urlBuf = new StringBuffer();
urlBuf.append(getMasterSlaveUrl());
urlBuf.append("?");
Properties props = getMasterSlaveProps();
String key = null;
Enumeration keyEnum = props.keys();
while (keyEnum.hasMoreElements()) {
key = (String) keyEnum.nextElement();
urlBuf.append(key);
urlBuf.append("=");
urlBuf.append(props.get(key));
urlBuf.append("&");
}
String url = urlBuf.toString();
url = "jdbc:mysql:replication:"
+ url.substring(url.indexOf("jdbc:mysql:")
+ "jdbc:mysql:".length());
ds.setURL(url);
Connection replConn = ds.getPooledConnection().getConnection();
boolean readOnly = false;
for (int i = 0; i < 10; i++) {
this.rs = replConn.createStatement().executeQuery("SELECT 1");
assertTrue(this.rs.next());
this.rs = replConn.prepareStatement("SELECT 1").executeQuery();
assertTrue(this.rs.next());
readOnly = !readOnly;
replConn.setReadOnly(readOnly);
}
}
public void testBug35660() throws Exception {
Connection lbConn = getLoadBalancedConnection(null);
Connection lbConn2 = getLoadBalancedConnection(null);
try {
assertEquals(this.conn, this.conn);
assertEquals(lbConn, lbConn);
assertFalse(lbConn.equals(this.conn));
assertFalse(lbConn.equals(lbConn2));
} finally {
lbConn.close();
lbConn2.close();
}
}
public void testBug37570() throws Exception {
Properties props = new Properties();
props.setProperty("characterEncoding", "utf-8");
props.setProperty("passwordCharacterEncoding", "utf-8");
Connection adminConn = getAdminConnectionWithProps(props);
if (adminConn != null) {
String unicodePassword = "\u0430\u0431\u0432"; // Cyrillic string
String user = "bug37570";
Statement adminStmt = adminConn.createStatement();
adminStmt.executeUpdate("grant usage on *.* to '" + user
+ "'@'127.0.0.1' identified by 'foo'");
adminStmt.executeUpdate("update mysql.user set password=PASSWORD('"
+ unicodePassword + "') where user = '" + user + "'");
adminStmt.executeUpdate("flush privileges");
try {
((MySQLConnection) adminConn).changeUser(user, unicodePassword);
} catch (SQLException sqle) {
assertTrue("Connection with non-latin1 password failed", false);
}
}
}
public void testUnreliableSocketFactory() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy", "bestResponseTime");
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
assertNotNull("Connection should not be null", conn);
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
// both connections are live now
UnreliableSocketFactory.downHost("first");
UnreliableSocketFactory.downHost("second");
try {
conn2.createStatement().execute("SELECT 1");
fail("Should hang here.");
} catch (SQLException sqlEx) {
assertEquals("08S01", sqlEx.getSQLState());
}
}
public void testBug43421() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy", "bestResponseTime");
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
assertNotNull("Connection should not be null", conn2);
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
// both connections are live now
UnreliableSocketFactory.downHost("second");
UnreliableSocketFactory.downHost("first");
try {
conn2.createStatement().execute("/* ping */");
fail("Pings will not succeed when one host is down and using loadbalance w/o global blacklist.");
} catch (SQLException sqlEx) {
}
UnreliableSocketFactory.flushAllHostLists();
props = new Properties();
props.setProperty("globalBlacklistTimeout", "200");
props.setProperty("loadBalanceStrategy", "bestResponseTime");
conn2 = this.getUnreliableLoadBalancedConnection(new String[] {
"first", "second" }, props);
assertNotNull("Connection should not be null", conn);
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
// both connections are live now
UnreliableSocketFactory.downHost("second");
try {
conn2.createStatement().execute("/* ping */");
} catch (SQLException sqlEx) {
fail("Pings should succeed even though host is down.");
}
}
public void testBug48442() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy", "random");
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
assertNotNull("Connection should not be null", conn2);
conn2.setAutoCommit(false);
UnreliableSocketFactory.downHost("second");
int hc = 0;
try {
conn2.createStatement().execute("SELECT 1");
} catch (SQLException e) {
conn2.createStatement().execute("SELECT 1");
}
hc = conn2.hashCode();
conn2.commit();
UnreliableSocketFactory.dontDownHost("second");
UnreliableSocketFactory.downHost("first");
try {
conn2.commit();
} catch (SQLException e) {
}
assertTrue(hc == conn2.hashCode());
}
public void testBug45171() throws Exception {
List statementsToTest = new LinkedList();
statementsToTest.add(this.conn.createStatement());
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.clientPrepareStatement("SELECT 1"));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.clientPrepareStatement("SELECT 1",
Statement.RETURN_GENERATED_KEYS));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.clientPrepareStatement("SELECT 1", new int[0]));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.clientPrepareStatement("SELECT 1", new String[0]));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.serverPrepareStatement("SELECT 1"));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.serverPrepareStatement("SELECT 1",
Statement.RETURN_GENERATED_KEYS));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.serverPrepareStatement("SELECT 1", new int[0]));
statementsToTest.add(((com.mysql.jdbc.Connection) this.conn)
.serverPrepareStatement("SELECT 1", new String[0]));
Iterator iter = statementsToTest.iterator();
while (iter.hasNext()) {
Statement toTest = (Statement) iter.next();
assertEquals(toTest.getResultSetType(), ResultSet.TYPE_FORWARD_ONLY);
assertEquals(toTest.getResultSetConcurrency(),
ResultSet.CONCUR_READ_ONLY);
}
}
/**
* Tests fix for BUG#44587, provide last packet sent/received timing in all
* connection failure errors.
*/
public void testBug44587() throws Exception {
Exception e = null;
String msg = SQLError.createLinkFailureMessageBasedOnHeuristics(
(MySQLConnection) this.conn, System.currentTimeMillis() - 1000,
System.currentTimeMillis() - 2000, e, false);
assertTrue(containsMessage(msg,
"CommunicationsException.ServerPacketTimingInfo"));
}
/**
* Tests fix for BUG#45419, ensure that time is not converted to seconds
* before being reported as milliseconds.
*/
public void testBug45419() throws Exception {
Exception e = null;
String msg = SQLError.createLinkFailureMessageBasedOnHeuristics(
(MySQLConnection) this.conn, System.currentTimeMillis() - 1000,
System.currentTimeMillis() - 2000, e, false);
Matcher m = Pattern.compile("([\\d\\,\\.]+)", Pattern.MULTILINE)
.matcher(msg);
assertTrue(m.find());
assertTrue(Long.parseLong(m.group(0).replaceAll("[,.]", "")) >= 2000);
assertTrue(Long.parseLong(m.group(1).replaceAll("[,.]", "")) >= 1000);
}
public static boolean containsMessage(String msg, String key) {
String[] expectedFragments = Messages.getString(key).split("\\{\\d\\}");
for (int i = 0; i < expectedFragments.length; i++) {
if (msg.indexOf(expectedFragments[i]) < 0) {
return false;
}
}
return true;
}
public void testBug46637() throws Exception {
NonRegisteringDriver driver = new NonRegisteringDriver();
Properties props = new Properties();
copyBasePropertiesIntoProps(props, driver);
String hostname = getPortFreeHostname(props, driver);
UnreliableSocketFactory.flushAllHostLists();
UnreliableSocketFactory.downHost(hostname);
try {
Connection noConn = getConnectionWithProps("socketFactory=testsuite.UnreliableSocketFactory");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf("has not received") != -1);
} finally {
UnreliableSocketFactory.flushAllHostLists();
}
}
public void testBug32216() throws Exception {
checkBug32216("www.mysql.com", "12345", "my_database");
checkBug32216("www.mysql.com", null, "my_database");
}
private void checkBug32216(String host, String port, String dbname)
throws SQLException {
NonRegisteringDriver driver = new NonRegisteringDriver();
StringBuffer url = new StringBuffer("jdbc:mysql://");
url.append(host);
if (port != null) {
url.append(':');
url.append(port);
}
url.append('/');
url.append(dbname);
Properties result = driver.parseURL(url.toString(), new Properties());
assertEquals("hostname not equal", host,
result.getProperty(Driver.HOST_PROPERTY_KEY));
if (port != null) {
assertEquals("port not equal", port,
result.getProperty(Driver.PORT_PROPERTY_KEY));
} else {
assertEquals("port default incorrect", "3306",
result.getProperty(Driver.PORT_PROPERTY_KEY));
}
assertEquals("dbname not equal", dbname,
result.getProperty(Driver.DBNAME_PROPERTY_KEY));
}
public void testBug44324() throws Exception {
createTable(
"bug44324",
"(Id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, SomeVChar VARCHAR(10)) ENGINE=MyISAM;");
try {
this.stmt
.executeUpdate("INSERT INTO bug44324 values (null, 'Some text much longer than 10 characters')");
} catch (MysqlDataTruncation sqlEx) {
assertTrue(0 != sqlEx.getErrorCode());
}
}
public void testBug46925() throws Exception {
MysqlXADataSource xads1 = new MysqlXADataSource();
MysqlXADataSource xads2 = new MysqlXADataSource();
Xid txid = new MysqlXid(new byte[] { 0x1 }, new byte[] { 0xf }, 3306);
xads1.setPinGlobalTxToPhysicalConnection(true);
xads1.setUrl(dbUrl);
xads2.setPinGlobalTxToPhysicalConnection(true);
xads2.setUrl(dbUrl);
XAConnection c1 = xads1.getXAConnection();
assertTrue(c1 instanceof SuspendableXAConnection);
// start a transaction on one connection
c1.getXAResource().start(txid, XAResource.TMNOFLAGS);
c1.getXAResource().end(txid, XAResource.TMSUCCESS);
XAConnection c2 = xads2.getXAConnection();
assertTrue(c2 instanceof SuspendableXAConnection);
// prepare on another one. Since we are using a "pinned" connection
// we should have the same "currentXAConnection" for both
// SuspendableXAConnection
c2.getXAResource().prepare(txid); // this will fail without the fix.
c2.getXAResource().commit(txid, false);
}
public void testBug47494() throws Exception {
try {
getConnectionWithProps("jdbc:mysql://localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
getConnectionWithProps("jdbc:mysql://:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
getConnectionWithProps("jdbc:mysql://:9999,:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
try {
getConnectionWithProps("jdbc:mysql://localhost:9999,localhost:9999/test?socketFactory=testsuite.regression.ConnectionRegressionTest$PortNumberSocketFactory");
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getCause() instanceof IOException);
}
}
public static class PortNumberSocketFactory extends StandardSocketFactory {
public PortNumberSocketFactory() {
}
public Socket connect(String hostname, int portNumber, Properties props)
throws SocketException, IOException {
assertEquals(9999, portNumber);
throw new IOException();
}
}
public void testBug48486() throws Exception {
Properties props = new NonRegisteringDriver().parseURL(dbUrl, null);
String host = props.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY,
"localhost");
String port = props.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY,
"3306");
String hostSpec = host;
if (!NonRegisteringDriver.isHostPropertiesList(host)) {
hostSpec = host + ":" + port;
}
String database = props
.getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
removeHostRelatedProps(props);
props.remove(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
StringBuilder configs = new StringBuilder();
for (@SuppressWarnings("rawtypes")
Map.Entry entry : props.entrySet()) {
configs.append(entry.getKey());
configs.append("=");
configs.append(entry.getValue());
configs.append("&");
}
String newUrl = String.format("jdbc:mysql:loadbalance://%s,%s/%s?%s",
hostSpec, hostSpec, database, configs.toString());
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setUrl(newUrl);
Connection c = ds.getPooledConnection().getConnection();
c.createStatement().executeQuery("SELECT 1");
c.prepareStatement("SELECT 1").executeQuery();
}
public void testBug48605() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy", "random");
props.setProperty("selfDestructOnPingMaxOperations", "5");
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
assertNotNull("Connection should not be null", conn2);
conn2.setAutoCommit(false);
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 1");
conn2.commit();
try {
conn2.createStatement().execute("/* ping */ SELECT 1");
// don't care about this - we want the SQLExceptions passed up early
// for ping failures, rather
// than waiting until commit/rollback and pickNewConnection().
} catch (SQLException e) {
}
assertTrue(conn2.isClosed());
try {
conn2.createStatement().execute("SELECT 1");
fail("Should throw Exception, connection is closed.");
} catch (SQLException e) {
}
}
public void testBug49700() throws Exception {
Connection c = getConnectionWithProps("sessionVariables=@foo='bar'");
assertEquals("bar", getSingleIndexedValueWithQuery(c, 1, "SELECT @foo"));
((com.mysql.jdbc.Connection) c).resetServerState();
assertEquals("bar", getSingleIndexedValueWithQuery(c, 1, "SELECT @foo"));
}
public void testBug51266() throws Exception {
Properties props = new Properties();
props.setProperty("roundRobinLoadBalance", "true"); // shouldn't be
// needed, but used
// in reported bug,
// it's removed by
// the driver
Set downedHosts = new HashSet();
downedHosts.add("first");
// this loop will hang on the first unreliable host if the bug isn't
// fixed.
for (int i = 0; i < 20; i++) {
getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props, downedHosts)
.close();
}
}
// Tests fix for Bug#51643 - connection chosen by load balancer "sticks" to
// statements
// that live past commit()/rollback().
public void testBug51643() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy",
"com.mysql.jdbc.SequentialBalanceStrategy");
Connection lbConn = getUnreliableLoadBalancedConnection(new String[] {
"first", "second" }, props);
try {
PreparedStatement cPstmt = lbConn
.prepareStatement("SELECT connection_id()");
PreparedStatement serverPstmt = lbConn
.prepareStatement("SELECT connection_id()");
Statement plainStmt = lbConn.createStatement();
lbConn.setAutoCommit(false);
this.rs = cPstmt.executeQuery();
this.rs.next();
String cPstmtConnId = this.rs.getString(1);
this.rs = serverPstmt.executeQuery();
this.rs.next();
String serverPstmtConnId = this.rs.getString(1);
this.rs = plainStmt.executeQuery("SELECT connection_id()");
this.rs.next();
String plainStmtConnId = this.rs.getString(1);
lbConn.commit();
lbConn.setAutoCommit(false);
this.rs = cPstmt.executeQuery();
this.rs.next();
String cPstmtConnId2 = this.rs.getString(1);
assertFalse(cPstmtConnId2.equals(cPstmtConnId));
this.rs = serverPstmt.executeQuery();
this.rs.next();
String serverPstmtConnId2 = this.rs.getString(1);
assertFalse(serverPstmtConnId2.equals(serverPstmtConnId));
this.rs = plainStmt.executeQuery("SELECT connection_id()");
this.rs.next();
String plainStmtConnId2 = this.rs.getString(1);
assertFalse(plainStmtConnId2.equals(plainStmtConnId));
} finally {
lbConn.close();
}
}
public void testBug51783() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy",
ForcedLoadBalanceStrategy.class.getName());
props.setProperty("loadBalanceBlacklistTimeout", "5000");
props.setProperty("loadBalancePingTimeout", "100");
props.setProperty("loadBalanceValidateConnectionOnSwapServer", "true");
String portNumber = new NonRegisteringDriver().parseURL(dbUrl, null)
.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY);
if (portNumber == null) {
portNumber = "3306";
}
ForcedLoadBalanceStrategy.forceFutureServer("first:" + portNumber, -1);
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
conn2.setAutoCommit(false);
conn2.createStatement().execute("SELECT 1");
ForcedLoadBalanceStrategy.forceFutureServer("second:" + portNumber, -1);
UnreliableSocketFactory.downHost("second");
try {
conn2.commit(); // will be on second after this
assertTrue("Connection should be closed", conn2.isClosed());
} catch (SQLException e) {
fail("Should not error because failure to get another server.");
}
conn2.close();
props = new Properties();
props.setProperty("loadBalanceStrategy",
ForcedLoadBalanceStrategy.class.getName());
props.setProperty("loadBalanceBlacklistTimeout", "5000");
props.setProperty("loadBalancePingTimeout", "100");
props.setProperty("loadBalanceValidateConnectionOnSwapServer", "false");
ForcedLoadBalanceStrategy.forceFutureServer("first:" + portNumber, -1);
conn2 = this.getUnreliableLoadBalancedConnection(new String[] {
"first", "second" }, props);
conn2.setAutoCommit(false);
conn2.createStatement().execute("SELECT 1");
ForcedLoadBalanceStrategy.forceFutureServer("second:" + portNumber, 1);
UnreliableSocketFactory.downHost("second");
try {
conn2.commit(); // will be on second after this
assertFalse(
"Connection should not be closed, should be able to connect to first",
conn2.isClosed());
} catch (SQLException e) {
fail("Should not error because failure to get another server.");
}
}
public static class ForcedLoadBalanceStrategy extends RandomBalanceStrategy {
private static String forcedFutureServer = null;
private static int forceFutureServerTimes = 0;
public static void forceFutureServer(String host, int times) {
forcedFutureServer = host;
forceFutureServerTimes = times;
}
public com.mysql.jdbc.ConnectionImpl pickConnection(
LoadBalancingConnectionProxy proxy, List configuredHosts,
Map liveConnections, long[] responseTimes, int numRetries)
throws SQLException {
if (forcedFutureServer == null || forceFutureServerTimes == 0) {
return super.pickConnection(proxy, configuredHosts,
liveConnections, responseTimes, numRetries);
}
if (forceFutureServerTimes > 0) {
forceFutureServerTimes--;
}
ConnectionImpl conn = (ConnectionImpl) liveConnections
.get(forcedFutureServer);
if (conn == null) {
conn = proxy.createConnectionForHost(forcedFutureServer);
}
return conn;
}
public void destroy() {
super.destroy();
}
public void init(com.mysql.jdbc.Connection conn, Properties props)
throws SQLException {
super.init(conn, props);
}
}
public void testAutoCommitLB() throws Exception {
Properties props = new Properties();
props.setProperty("loadBalanceStrategy",
CountingReBalanceStrategy.class.getName());
props.setProperty("loadBalanceAutoCommitStatementThreshold", "3");
String portNumber = new NonRegisteringDriver().parseURL(dbUrl, null)
.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY);
if (portNumber == null) {
portNumber = "3306";
}
Connection conn2 = this.getUnreliableLoadBalancedConnection(
new String[] { "first", "second" }, props);
conn2.setAutoCommit(true);
CountingReBalanceStrategy.resetTimesRebalanced();
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 2");
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.createStatement().execute("SELECT 3");
assertEquals(1, CountingReBalanceStrategy.getTimesRebalanced());
conn2.setAutoCommit(false);
CountingReBalanceStrategy.resetTimesRebalanced();
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 2");
conn2.createStatement().execute("SELECT 3");
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.close();
props.remove("loadBalanceAutoCommitStatementThreshold");
conn2 = this.getUnreliableLoadBalancedConnection(new String[] {
"first", "second" }, props);
conn2.setAutoCommit(true);
CountingReBalanceStrategy.resetTimesRebalanced();
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 2");
conn2.createStatement().execute("SELECT 3");
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.setAutoCommit(false);
CountingReBalanceStrategy.resetTimesRebalanced();
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 2");
conn2.createStatement().execute("SELECT 3");
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.close();
props.setProperty("loadBalanceAutoCommitStatementThreshold", "3");
props.setProperty("loadBalanceAutoCommitStatementRegex", ".*2.*");
conn2 = this.getUnreliableLoadBalancedConnection(new String[] {
"first", "second" }, props);
conn2.setAutoCommit(true);
CountingReBalanceStrategy.resetTimesRebalanced();
conn2.createStatement().execute("SELECT 1");
conn2.createStatement().execute("SELECT 2");
conn2.createStatement().execute("SELECT 3");
conn2.createStatement().execute("SELECT 2");
assertEquals(0, CountingReBalanceStrategy.getTimesRebalanced());
conn2.createStatement().execute("SELECT 2");
assertEquals(1, CountingReBalanceStrategy.getTimesRebalanced());
conn2.close();
}
public static class CountingReBalanceStrategy extends RandomBalanceStrategy {
private static int rebalancedTimes = 0;
public static int getTimesRebalanced() {
return rebalancedTimes;
}
public static void resetTimesRebalanced() {
rebalancedTimes = 0;
}
public com.mysql.jdbc.ConnectionImpl pickConnection(
LoadBalancingConnectionProxy proxy, List configuredHosts,
Map liveConnections, long[] responseTimes, int numRetries)
throws SQLException {
rebalancedTimes++;
return super.pickConnection(proxy, configuredHosts,
liveConnections, responseTimes, numRetries);
}
public void destroy() {
super.destroy();
}
public void init(com.mysql.jdbc.Connection conn, Properties props)
throws SQLException {
super.init(conn, props);
}
}
public void testBug56429() throws Exception {
Properties props = new Driver().parseURL(BaseTestCase.dbUrl, null);
props.setProperty("autoReconnect", "true");
props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
Properties urlProps = new NonRegisteringDriver().parseURL(
BaseTestCase.dbUrl, null);
String host = urlProps.getProperty(Driver.HOST_PROPERTY_KEY);
String port = urlProps.getProperty(Driver.PORT_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY);
props.remove(Driver.NUM_HOSTS_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY + ".1");
props.remove(Driver.PORT_PROPERTY_KEY + ".1");
props.setProperty("queriesBeforeRetryMaster", "50");
props.setProperty("maxReconnects", "1");
UnreliableSocketFactory.mapHost("master", host);
UnreliableSocketFactory.mapHost("slave", host);
Connection failoverConnection = null;
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://master:"
+ port + ",slave:" + port + "/", props);
String userHost = getSingleIndexedValueWithQuery(1, "SELECT USER()")
.toString();
String[] userParts = userHost.split("@");
this.rs = this.stmt.executeQuery("SHOW PROCESSLIST");
int startConnCount = 0;
while (this.rs.next()) {
if (this.rs.getString("User").equals(userParts[0])
&& this.rs.getString("Host").equals(userParts[1])) {
startConnCount++;
}
}
assert (startConnCount > 0);
failoverConnection.setAutoCommit(false); // this will fail if state
// not copied over
for (int i = 0; i < 20; i++) {
failoverConnection.commit();
}
this.rs = this.stmt.executeQuery("SHOW PROCESSLIST");
int endConnCount = 0;
while (this.rs.next()) {
if (this.rs.getString("User").equals(userParts[0])
&& this.rs.getString("Host").equals(userParts[1])) {
endConnCount++;
}
}
assert (endConnCount > 0);
if (endConnCount - startConnCount >= 20) { // this may be bogus if
// run on a real system,
// we should probably
// look to see they're
// coming from this
// testsuite?
fail("We're leaking connections even when not failed over");
}
} finally {
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
public void testBug56955() throws Exception {
assertEquals("JKS",
((com.mysql.jdbc.Connection) this.conn)
.getTrustCertificateKeyStoreType());
assertEquals("JKS",
((com.mysql.jdbc.Connection) this.conn)
.getClientCertificateKeyStoreType());
}
public void testBug57262() throws Exception {
Properties props = new Properties();
props.setProperty("characterEncoding", "utf-8");
props.setProperty("useUnicode", "true");
props.setProperty("useOldUTF8Behavior", "true");
Connection c = getConnectionWithProps(props);
ResultSet rs = c.createStatement().executeQuery(
"SHOW SESSION VARIABLES LIKE 'character_set_connection'");
rs.next();
assertEquals("latin1", rs.getString(2));
}
public void testBug58706() throws Exception {
Properties props = new Driver().parseURL(BaseTestCase.dbUrl, null);
props.setProperty("autoReconnect", "true");
props.setProperty("socketFactory", "testsuite.UnreliableSocketFactory");
Properties urlProps = new NonRegisteringDriver().parseURL(this.dbUrl,
null);
String host = urlProps.getProperty(Driver.HOST_PROPERTY_KEY);
String port = urlProps.getProperty(Driver.PORT_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY);
props.remove(Driver.NUM_HOSTS_PROPERTY_KEY);
props.remove(Driver.HOST_PROPERTY_KEY + ".1");
props.remove(Driver.PORT_PROPERTY_KEY + ".1");
props.setProperty("queriesBeforeRetryMaster", "0");
props.setProperty("failOverReadOnly", "false");
props.setProperty("secondsBeforeRetryMaster", "1");
UnreliableSocketFactory.mapHost("master", host);
UnreliableSocketFactory.mapHost("slave", host);
Connection failoverConnection = null;
try {
failoverConnection = getConnectionWithProps("jdbc:mysql://master:"
+ port + ",slave:" + port + "/", props);
failoverConnection.setAutoCommit(false);
assertTrue(((com.mysql.jdbc.Connection)failoverConnection).isMasterConnection());
for (int i = 0; i < 50; i++) {
failoverConnection.createStatement().executeQuery("SELECT 1");
}
UnreliableSocketFactory.downHost("master");
try {
failoverConnection.createStatement().executeQuery("SELECT 1"); // this should fail and trigger failover
fail("Expected exception");
} catch (SQLException sqlEx) {
assertEquals("08S01", sqlEx.getSQLState());
}
failoverConnection.setAutoCommit(true);
assertTrue(!((com.mysql.jdbc.Connection)failoverConnection).isMasterConnection());
assertTrue(!failoverConnection.isReadOnly());
failoverConnection.createStatement().executeQuery("SELECT 1");
failoverConnection.createStatement().executeQuery("SELECT 1");
UnreliableSocketFactory.dontDownHost("master");
Thread.sleep(2000);
failoverConnection.setAutoCommit(true);
failoverConnection.createStatement().executeQuery("SELECT 1");
assertTrue(((com.mysql.jdbc.Connection)failoverConnection).isMasterConnection());
failoverConnection.createStatement().executeQuery("SELECT 1");
} finally {
UnreliableSocketFactory.flushAllHostLists();
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
public void testStatementComment() throws Exception {
Connection c = getConnectionWithProps("autoGenerateTestcaseScript=true,logger=StandardLogger");
PrintStream oldErr = System.err;
try {
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(bOut);
System.setErr(printStream);
((com.mysql.jdbc.Connection)c).setStatementComment("Hi there");
c.setAutoCommit(false);
c.createStatement().execute("SELECT 1");
c.commit();
c.rollback();
Pattern pattern = Pattern.compile("Hi");
String loggedData = new String(bOut.toByteArray());
Matcher matcher = pattern.matcher(loggedData);
int count = 0;
while (matcher.find()) {
count++;
}
assertEquals(4, count);
} finally {
System.setErr(oldErr);
}
}
public void testReconnectWithCachedConfig() throws Exception {
Connection rConn = getConnectionWithProps("autoReconnect=true,initialTimeout=2,maxReconnects=3,cacheServerConfiguration=true,elideSetAutoCommits=true");
String threadId = getSingleIndexedValueWithQuery(rConn, 1, "select connection_id()").toString();
killConnection(this.conn, threadId);
boolean detectedDeadConn = false;
for (int i = 0; i < 100; i++) {
try {
rConn.createStatement().executeQuery("SELECT 1");
} catch (SQLException sqlEx) {
detectedDeadConn = true;
break;
}
}
assertTrue(detectedDeadConn);
rConn.prepareStatement("SELECT 1").executeQuery();
Connection rConn2 = getConnectionWithProps("autoReconnect=true,initialTimeout=2,maxReconnects=3,cacheServerConfiguration=true,elideSetAutoCommits=true");
rConn2.prepareStatement("SELECT 1").executeQuery();
}
}