/*
Copyright (c) 2002, 2013, 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.simple;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import testsuite.BaseTestCase;
import com.mysql.jdbc.CharsetMapping;
import com.mysql.jdbc.Driver;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.NonRegisteringDriver;
import com.mysql.jdbc.SQLError;
import com.mysql.jdbc.StringUtils;
import com.mysql.jdbc.Util;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import com.mysql.jdbc.log.StandardLogger;
/**
* Tests java.sql.Connection functionality ConnectionTest.java,v 1.1 2002/12/06
* 22:01:05 mmatthew Exp
*
* @author Mark Matthews
*/
public class ConnectionTest extends BaseTestCase {
/**
* Constructor for ConnectionTest.
*
* @param name
* the name of the test to run
*/
public ConnectionTest(String name) {
super(name);
}
/**
* Runs all test cases in this test suite
*
* @param args
*/
public static void main(String[] args) {
junit.textui.TestRunner.run(ConnectionTest.class);
}
/**
* Tests catalog functionality
*
* @throws Exception
* if an error occurs
*/
public void testCatalog() throws Exception {
String currentCatalog = this.conn.getCatalog();
this.conn.setCatalog(currentCatalog);
assertTrue(currentCatalog.equals(this.conn.getCatalog()));
}
/**
* Tests a cluster connection for failover, requires a two-node cluster URL
* specfied in com.mysql.jdbc.testsuite.ClusterUrl system proeprty.
*
* @throws Exception
* DOCUMENT ME!
*/
public void testClusterConnection() throws Exception {
String url = System.getProperty("com.mysql.jdbc.testsuite.ClusterUrl");
if ((url != null) && (url.length() > 0)) {
Object versionNumObj = getSingleValueWithQuery("SHOW VARIABLES LIKE 'version'");
if ((versionNumObj != null)
&& (versionNumObj.toString().indexOf("cluster") != -1)) {
Connection clusterConn = null;
Statement clusterStmt = null;
try {
clusterConn = new NonRegisteringDriver().connect(url, null);
clusterStmt = clusterConn.createStatement();
clusterStmt
.executeQuery("DROP TABLE IF EXISTS testClusterConn");
clusterStmt
.executeQuery("CREATE TABLE testClusterConn (field1 INT) "
+ getTableTypeDecl() + " =ndbcluster");
clusterStmt
.executeQuery("INSERT INTO testClusterConn VALUES (1)");
clusterConn.setAutoCommit(false);
clusterStmt.executeQuery("SELECT * FROM testClusterConn");
clusterStmt
.executeUpdate("UPDATE testClusterConn SET field1=4");
// Kill the connection
@SuppressWarnings("unused")
String connectionId = getSingleValueWithQuery(
"SELECT CONNECTION_ID()").toString();
System.out
.println("Please kill the MySQL server now and press return...");
System.in.read();
System.out.println("Waiting for TCP/IP timeout...");
Thread.sleep(10);
System.out.println("Attempting auto reconnect");
try {
clusterConn.setAutoCommit(true);
clusterConn.setAutoCommit(false);
} catch (SQLException sqlEx) {
System.out.println(sqlEx);
}
//
// Test that this 'new' connection is not read-only
//
clusterStmt
.executeUpdate("UPDATE testClusterConn SET field1=5");
ResultSet rset = clusterStmt
.executeQuery("SELECT * FROM testClusterConn WHERE field1=5");
assertTrue("One row should be returned", rset.next());
} finally {
if (clusterStmt != null) {
clusterStmt
.executeQuery("DROP TABLE IF EXISTS testClusterConn");
clusterStmt.close();
}
if (clusterConn != null) {
clusterConn.close();
}
}
}
}
}
/**
* DOCUMENT ME!
*
* @throws Exception
* Old test was passing due to
* http://bugs.mysql.com/bug.php?id=989 which is fixed for 5.5+
*/
public void testDeadlockDetection() throws Exception {
try {
this.rs = this.stmt
.executeQuery("SHOW VARIABLES LIKE 'innodb_lock_wait_timeout'");
this.rs.next();
int timeoutSecs = this.rs.getInt(2);
createTable("t1", "(id INTEGER, x INTEGER) ", "INNODB");
this.stmt.executeUpdate("INSERT INTO t1 VALUES(0, 0)");
this.conn.setAutoCommit(false);
Properties props = new Properties();
props.setProperty("includeInnodbStatusInDeadlockExceptions", "true");
props.setProperty("includeThreadDumpInDeadlockExceptions", "true");
Connection deadlockConn = getConnectionWithProps(props);
deadlockConn.setAutoCommit(false);
try {
this.conn.createStatement().executeQuery(
"SELECT * FROM t1 WHERE id=0 FOR UPDATE");
// The following query should hang because con1 is locking the
// page
deadlockConn.createStatement().executeUpdate(
"UPDATE t1 SET x=2 WHERE id=0");
} finally {
if (versionMeetsMinimum(5, 5)) {
this.conn.commit();
deadlockConn.commit();
}
}
Thread.sleep(timeoutSecs * 2 * 1000);
} catch (SQLException sqlEx) {
System.out
.println("Caught SQLException due to deadlock/lock timeout");
System.out.println("SQLState: " + sqlEx.getSQLState());
System.out.println("Vendor error: " + sqlEx.getErrorCode());
System.out.println("Message: " + sqlEx.getMessage());
//
// Check whether the driver thinks it really is deadlock...
//
assertTrue(SQLError.SQL_STATE_DEADLOCK.equals(sqlEx.getSQLState()));
assertTrue(sqlEx.getErrorCode() == 1205);
// Make sure INNODB Status is getting dumped into error message
if (sqlEx.getMessage().indexOf("PROCESS privilege") != -1) {
fail("This test requires user with process privilege");
}
assertTrue(
"Can't find INNODB MONITOR in:\n\n" + sqlEx.getMessage(),
sqlEx.getMessage().indexOf("INNODB MONITOR") != -1);
assertTrue(
"Can't find thread dump in:\n\n" + sqlEx.getMessage(),
sqlEx.getMessage().indexOf("testsuite.simple.ConnectionTest.testDeadlockDetection") != -1);
} finally {
this.conn.setAutoCommit(true);
}
}
/**
* DOCUMENT ME!
*
* @throws Exception
* DOCUMENT ME!
*/
public void testCharsets() throws Exception {
if (versionMeetsMinimum(4, 1)) {
Properties props = new Properties();
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "UTF-8");
Connection utfConn = getConnectionWithProps(props);
this.stmt = utfConn.createStatement();
createTable("t1", "(" + "comment CHAR(32) ASCII NOT NULL,"
+ "koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL"
+ ") CHARSET=latin5");
this.stmt
.executeUpdate("ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL");
this.stmt
.executeUpdate("ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL");
this.stmt.executeUpdate("ALTER TABLE t1 CHARSET=latin2");
this.stmt
.executeUpdate("ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL");
this.stmt
.executeUpdate("ALTER TABLE t1 DROP latin2_f, DROP latin5_f");
this.stmt
.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A')");
/*
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('b','LAT SMALL B')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('c','LAT SMALL C')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('d','LAT SMALL D')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('e','LAT SMALL E')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('f','LAT SMALL F')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('g','LAT SMALL G')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('h','LAT SMALL H')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('i','LAT SMALL I')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('j','LAT SMALL J')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('k','LAT SMALL K')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('l','LAT SMALL L')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('m','LAT SMALL M')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('n','LAT SMALL N')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('o','LAT SMALL O')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('p','LAT SMALL P')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('q','LAT SMALL Q')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('r','LAT SMALL R')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('s','LAT SMALL S')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('t','LAT SMALL T')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('u','LAT SMALL U')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('v','LAT SMALL V')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('w','LAT SMALL W')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('x','LAT SMALL X')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('y','LAT SMALL Y')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('z','LAT SMALL Z')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('A','LAT CAPIT A')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('B','LAT CAPIT B')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('C','LAT CAPIT C')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('D','LAT CAPIT D')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('E','LAT CAPIT E')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('F','LAT CAPIT F')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('G','LAT CAPIT G')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('H','LAT CAPIT H')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('I','LAT CAPIT I')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('J','LAT CAPIT J')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('K','LAT CAPIT K')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('L','LAT CAPIT L')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('M','LAT CAPIT M')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('N','LAT CAPIT N')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('O','LAT CAPIT O')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('P','LAT CAPIT P')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('Q','LAT CAPIT Q')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('R','LAT CAPIT R')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('S','LAT CAPIT S')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('T','LAT CAPIT T')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('U','LAT CAPIT U')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('V','LAT CAPIT V')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('W','LAT CAPIT W')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('X','LAT CAPIT X')"); this.stmt.executeUpdate("INSERT
* INTO t1 (koi8_ru_f,comment) VALUES ('Y','LAT CAPIT Y')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES ('Z','LAT CAPIT Z')");
*/
String cyrillicSmallA = "\u0430";
this.stmt
.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment) VALUES ('"
+ cyrillicSmallA + "','CYR SMALL A')");
/*
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL BE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL VE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL GE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL DE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL IE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL IO')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL ZHE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL ZE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL I')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL KA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL EL')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL EM')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL EN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL O')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL PE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL ER')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL ES')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL TE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL U')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL EF')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL HA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL TSE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL CHE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL SHA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL SCHA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL HARD SIGN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL YERU')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL SOFT SIGN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL E')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL YU')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR SMALL YA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT A')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT BE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT VE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT GE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT DE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT IE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT IO')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT ZHE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT ZE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT I')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT KA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT EL')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT EM')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT EN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT O')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT PE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT ER')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT ES')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT TE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT U')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT EF')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT HA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT TSE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT CHE')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT SHA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT SCHA')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT HARD SIGN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT YERU')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT SOFT SIGN')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT E')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT YU')");
* this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
* VALUES (_koi8r'?��','CYR CAPIT YA')");
*/
this.stmt
.executeUpdate("ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL");
this.stmt
.executeUpdate("UPDATE t1 SET utf8_f=CONVERT(koi8_ru_f USING utf8)");
this.stmt.executeUpdate("SET CHARACTER SET koi8r");
// this.stmt.executeUpdate("SET CHARACTER SET UTF8");
this.rs = this.stmt.executeQuery("SELECT * FROM t1");
ResultSetMetaData rsmd = this.rs.getMetaData();
int numColumns = rsmd.getColumnCount();
for (int i = 0; i < numColumns; i++) {
System.out.print(rsmd.getColumnName(i + 1));
System.out.print("\t\t");
}
System.out.println();
while (this.rs.next()) {
System.out.println(this.rs.getString(1) + "\t\t"
+ this.rs.getString(2) + "\t\t" + this.rs.getString(3));
if (this.rs.getString(1).equals("CYR SMALL A")) {
this.rs.getString(2);
}
}
System.out.println();
this.stmt.executeUpdate("SET NAMES utf8");
this.rs = this.stmt.executeQuery("SELECT _koi8r 0xC1;");
rsmd = this.rs.getMetaData();
numColumns = rsmd.getColumnCount();
for (int i = 0; i < numColumns; i++) {
System.out.print(rsmd.getColumnName(i + 1));
System.out.print("\t\t");
}
System.out.println();
while (this.rs.next()) {
System.out.println(this.rs.getString(1).equals("\u0430")
+ "\t\t");
System.out.println(new String(this.rs.getBytes(1), "KOI8_R"));
}
char[] c = new char[] { 0xd0b0 };
System.out.println(new String(c));
System.out.println("\u0430");
}
}
/**
* Tests isolation level functionality
*
* @throws Exception
* if an error occurs
*/
public void testIsolationLevel() throws Exception {
if (versionMeetsMinimum(4, 0)) {
String[] isoLevelNames = new String[] {
"Connection.TRANSACTION_NONE",
"Connection.TRANSACTION_READ_COMMITTED",
"Connection.TRANSACTION_READ_UNCOMMITTED",
"Connection.TRANSACTION_REPEATABLE_READ",
"Connection.TRANSACTION_SERIALIZABLE" };
int[] isolationLevels = new int[] { Connection.TRANSACTION_NONE,
Connection.TRANSACTION_READ_COMMITTED,
Connection.TRANSACTION_READ_UNCOMMITTED,
Connection.TRANSACTION_REPEATABLE_READ,
Connection.TRANSACTION_SERIALIZABLE };
DatabaseMetaData dbmd = this.conn.getMetaData();
for (int i = 0; i < isolationLevels.length; i++) {
if (dbmd.supportsTransactionIsolationLevel(isolationLevels[i])) {
this.conn.setTransactionIsolation(isolationLevels[i]);
assertTrue(
"Transaction isolation level that was set ("
+ isoLevelNames[i]
+ ") was not returned, nor was a more restrictive isolation level used by the server",
this.conn.getTransactionIsolation() == isolationLevels[i]
|| this.conn.getTransactionIsolation() > isolationLevels[i]);
}
}
}
}
/**
* Tests the savepoint functionality in MySQL.
*
* @throws Exception
* if an error occurs.
*/
public void testSavepoint() throws Exception {
if (!isRunningOnJdk131()) {
DatabaseMetaData dbmd = this.conn.getMetaData();
if (dbmd.supportsSavepoints()) {
System.out.println("Testing SAVEPOINTs");
try {
this.conn.setAutoCommit(true);
createTable("testSavepoints", "(field1 int)", "InnoDB");
// Try with named save points
this.conn.setAutoCommit(false);
this.stmt
.executeUpdate("INSERT INTO testSavepoints VALUES (1)");
Savepoint afterInsert = this.conn
.setSavepoint("afterInsert");
this.stmt
.executeUpdate("UPDATE testSavepoints SET field1=2");
Savepoint afterUpdate = this.conn
.setSavepoint("afterUpdate");
this.stmt.executeUpdate("DELETE FROM testSavepoints");
assertTrue("Row count should be 0",
getRowCount("testSavepoints") == 0);
this.conn.rollback(afterUpdate);
assertTrue("Row count should be 1",
getRowCount("testSavepoints") == 1);
assertTrue(
"Value should be 2",
"2".equals(getSingleValue("testSavepoints",
"field1", null).toString()));
this.conn.rollback(afterInsert);
assertTrue(
"Value should be 1",
"1".equals(getSingleValue("testSavepoints",
"field1", null).toString()));
this.conn.rollback();
assertTrue("Row count should be 0",
getRowCount("testSavepoints") == 0);
// Try with 'anonymous' save points
this.conn.rollback();
this.stmt
.executeUpdate("INSERT INTO testSavepoints VALUES (1)");
afterInsert = this.conn.setSavepoint();
this.stmt
.executeUpdate("UPDATE testSavepoints SET field1=2");
afterUpdate = this.conn.setSavepoint();
this.stmt.executeUpdate("DELETE FROM testSavepoints");
assertTrue("Row count should be 0",
getRowCount("testSavepoints") == 0);
this.conn.rollback(afterUpdate);
assertTrue("Row count should be 1",
getRowCount("testSavepoints") == 1);
assertTrue(
"Value should be 2",
"2".equals(getSingleValue("testSavepoints",
"field1", null).toString()));
this.conn.rollback(afterInsert);
assertTrue(
"Value should be 1",
"1".equals(getSingleValue("testSavepoints",
"field1", null).toString()));
this.conn.rollback();
this.conn.releaseSavepoint(this.conn.setSavepoint());
} finally {
this.conn.setAutoCommit(true);
}
} else {
System.out.println("MySQL version does not support SAVEPOINTs");
}
}
}
/**
* Tests the ability to set the connection collation via properties.
*
* @throws Exception
* if an error occurs or the test fails
*/
public void testNonStandardConnectionCollation() throws Exception {
if (versionMeetsMinimum(4, 1)) {
String collationToSet = "utf8_bin";
String characterSet = "utf-8";
Properties props = new Properties();
props.setProperty("connectionCollation", collationToSet);
props.setProperty("characterEncoding", characterSet);
Connection collConn = null;
Statement collStmt = null;
ResultSet collRs = null;
try {
collConn = getConnectionWithProps(props);
collStmt = collConn.createStatement();
collRs = collStmt
.executeQuery("SHOW VARIABLES LIKE 'collation_connection'");
assertTrue(collRs.next());
assertTrue(collationToSet.equalsIgnoreCase(collRs.getString(2)));
} finally {
if (collConn != null) {
collConn.close();
}
}
}
}
public void testDumpQueriesOnException() throws Exception {
Properties props = new Properties();
props.setProperty("dumpQueriesOnException", "true");
String bogusSQL = "SELECT 1 TO BAZ";
Connection dumpConn = getConnectionWithProps(props);
try {
dumpConn.createStatement().executeQuery(bogusSQL);
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
}
try {
((com.mysql.jdbc.Connection) dumpConn).clientPrepareStatement(
bogusSQL).executeQuery();
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
}
try {
createTable("testDumpQueriesOnException", "(field1 int UNIQUE)");
this.stmt
.executeUpdate("INSERT INTO testDumpQueriesOnException VALUES (1)");
PreparedStatement pStmt = dumpConn
.prepareStatement("INSERT INTO testDumpQueriesOnException VALUES (?)");
pStmt.setInt(1, 1);
pStmt.executeUpdate();
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf(
"INSERT INTO testDumpQueriesOnException") != -1);
}
try {
dumpConn.prepareStatement(bogusSQL);
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
}
}
/**
* Tests functionality of the ConnectionPropertiesTransform interface.
*
* @throws Exception
* if the test fails.
*/
public void testConnectionPropertiesTransform() throws Exception {
String transformClassName = SimpleTransformer.class.getName();
Properties props = new Properties();
props.setProperty(NonRegisteringDriver.PROPERTIES_TRANSFORM_KEY,
transformClassName);
NonRegisteringDriver driver = new NonRegisteringDriver();
Properties transformedProps = driver
.parseURL(BaseTestCase.dbUrl, props);
assertTrue("albequerque".equals(transformedProps
.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY)));
}
/**
* Tests functionality of using URLs in 'LOAD DATA LOCAL INFILE' statements.
*
* @throws Exception
* if the test fails.
*/
public void testLocalInfileWithUrl() throws Exception {
File infile = File.createTempFile("foo", "txt");
infile.deleteOnExit();
String url = infile.toURL().toExternalForm();
FileWriter output = new FileWriter(infile);
output.write("Test");
output.flush();
output.close();
createTable("testLocalInfileWithUrl", "(field1 LONGTEXT)");
Properties props = new Properties();
props.setProperty("allowUrlInLocalInfile", "true");
Connection loadConn = getConnectionWithProps(props);
Statement loadStmt = loadConn.createStatement();
String charset = " CHARACTER SET " + CharsetMapping.getMysqlEncodingForJavaEncoding(((MySQLConnection)loadConn).getEncoding(), (com.mysql.jdbc.Connection) loadConn);
try {
loadStmt.executeQuery("LOAD DATA LOCAL INFILE '" + url
+ "' INTO TABLE testLocalInfileWithUrl" + charset);
} catch (SQLException sqlEx) {
sqlEx.printStackTrace();
throw sqlEx;
}
this.rs = this.stmt
.executeQuery("SELECT * FROM testLocalInfileWithUrl");
assertTrue(this.rs.next());
assertTrue("Test".equals(this.rs.getString(1)));
int count = this.stmt
.executeUpdate("DELETE FROM testLocalInfileWithUrl");
assertTrue(count == 1);
StringBuffer escapedPath = new StringBuffer();
String path = infile.getCanonicalPath();
for (int i = 0; i < path.length(); i++) {
char c = path.charAt(i);
if (c == '\\') {
escapedPath.append('\\');
}
escapedPath.append(c);
}
loadStmt.executeQuery("LOAD DATA LOCAL INFILE '"
+ escapedPath.toString()
+ "' INTO TABLE testLocalInfileWithUrl" + charset);
this.rs = this.stmt
.executeQuery("SELECT * FROM testLocalInfileWithUrl");
assertTrue(this.rs.next());
assertTrue("Test".equals(this.rs.getString(1)));
try {
loadStmt.executeQuery("LOAD DATA LOCAL INFILE 'foo:///' INTO TABLE testLocalInfileWithUrl" + charset);
} catch (SQLException sqlEx) {
assertTrue(sqlEx.getMessage() != null);
assertTrue(sqlEx.getMessage().indexOf("FileNotFoundException") != -1);
}
}
public void testLocalInfileDisabled() throws Exception {
createTable("testLocalInfileDisabled", "(field1 varchar(255))");
File infile = File.createTempFile("foo", "txt");
infile.deleteOnExit();
//String url = infile.toURL().toExternalForm();
FileWriter output = new FileWriter(infile);
output.write("Test");
output.flush();
output.close();
Connection loadConn = getConnectionWithProps(new Properties());
try {
// have to do this after connect, otherwise it's the server
// that's enforcing it
((com.mysql.jdbc.Connection) loadConn)
.setAllowLoadLocalInfile(false);
try {
loadConn.createStatement().execute(
"LOAD DATA LOCAL INFILE '" + infile.getCanonicalPath()
+ "' INTO TABLE testLocalInfileDisabled");
fail("Should've thrown an exception.");
} catch (SQLException sqlEx) {
assertEquals(SQLError.SQL_STATE_GENERAL_ERROR,
sqlEx.getSQLState());
}
assertFalse(loadConn.createStatement()
.executeQuery("SELECT * FROM testLocalInfileDisabled")
.next());
} finally {
loadConn.close();
}
}
public void testServerConfigurationCache() throws Exception {
Properties props = new Properties();
props.setProperty("cacheServerConfiguration", "true");
props.setProperty("profileSQL", "true");
props.setProperty("logFactory", "com.mysql.jdbc.log.StandardLogger");
Connection conn1 = getConnectionWithProps(props);
try {
// eliminate side-effects when not run in isolation
StandardLogger.bufferedLog = new StringBuffer();
Connection conn2 = getConnectionWithProps(props);
StandardLogger.saveLogsToBuffer();
assertTrue("Configuration wasn't cached", StandardLogger.bufferedLog
.toString().indexOf("SHOW VARIABLES") == -1);
if (versionMeetsMinimum(4, 1)) {
assertTrue(
"Configuration wasn't cached",
StandardLogger.bufferedLog.toString().indexOf(
"SHOW COLLATION") == -1);
}
} finally {
StandardLogger.bufferedLog = null;
}
}
/**
* Tests whether or not the configuration 'useLocalSessionState' actually
* prevents non-needed 'set autocommit=', 'set session transaction isolation
* ...' and 'show variables like tx_isolation' queries.
*
* @throws Exception
* if the test fails.
*/
public void testUseLocalSessionState() throws Exception {
Properties props = new Properties();
props.setProperty("useLocalSessionState", "true");
props.setProperty("profileSQL", "true");
props.setProperty("logFactory", "com.mysql.jdbc.log.StandardLogger");
Connection conn1 = getConnectionWithProps(props);
conn1.setAutoCommit(true);
conn1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
StandardLogger.saveLogsToBuffer();
StandardLogger.bufferedLog.setLength(0);
conn1.setAutoCommit(true);
conn1.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
conn1.getTransactionIsolation();
String logAsString = StandardLogger.bufferedLog.toString();
assertTrue(logAsString.indexOf("SET SESSION") == -1
&& logAsString.indexOf("SHOW VARIABLES LIKE 'tx_isolation'") == -1
&& logAsString.indexOf("SET autocommit=") == -1);
}
/**
* Tests whether re-connect with non-read-only connection can happen.
*
* @throws Exception
* if the test fails.
*/
public void testFailoverConnection() throws Exception {
if (!isServerRunningOnWindows()) { // windows sockets don't
// work for this test
Properties props = new Properties();
props.setProperty("autoReconnect", "true");
props.setProperty("failOverReadOnly", "false");
Properties urlProps = new NonRegisteringDriver().parseURL(
dbUrl, null);
String host = urlProps.getProperty(Driver.HOST_PROPERTY_KEY);
String port = urlProps.getProperty(Driver.PORT_PROPERTY_KEY);
props.setProperty(Driver.HOST_PROPERTY_KEY + ".1", host);
props.setProperty(Driver.PORT_PROPERTY_KEY + ".1", port);
props.setProperty(Driver.HOST_PROPERTY_KEY + ".2", host);
props.setProperty(Driver.PORT_PROPERTY_KEY + ".2", port);
props.setProperty(Driver.NUM_HOSTS_PROPERTY_KEY, "2");
Connection failoverConnection = null;
try {
failoverConnection = getConnectionWithProps(props);
String originalConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT connection_id()")
.toString();
System.out.println("Original Connection Id = "
+ originalConnectionId);
assertTrue("Connection should not be in READ_ONLY state",
!failoverConnection.isReadOnly());
// Kill the connection
this.stmt.executeUpdate("KILL " + originalConnectionId);
// This takes a bit to occur
Thread.sleep(3000);
try {
failoverConnection.createStatement().executeQuery(
"SELECT 1");
fail("We expect an exception here, because the connection should be gone until the reconnect code picks it up again");
} catch (SQLException sqlEx) {
; // do-nothing
}
// Tickle re-connect
failoverConnection.setAutoCommit(true);
String newConnectionId = getSingleIndexedValueWithQuery(
failoverConnection, 1, "SELECT connection_id()")
.toString();
System.out.println("new Connection Id = " + newConnectionId);
assertTrue(
"We should have a new connection to the server in this case",
!newConnectionId.equals(originalConnectionId));
assertTrue("Connection should not be read-only",
!failoverConnection.isReadOnly());
} finally {
if (failoverConnection != null) {
failoverConnection.close();
}
}
}
}
public void testCannedConfigs() throws Exception {
String url = "jdbc:mysql:///?useConfigs=clusterBase";
Properties cannedProps = new NonRegisteringDriver().parseURL(url, null);
assertTrue("true".equals(cannedProps.getProperty("autoReconnect")));
assertTrue("false".equals(cannedProps.getProperty("failOverReadOnly")));
assertTrue("true".equals(cannedProps
.getProperty("roundRobinLoadBalance")));
// this will fail, but we test that too
url = "jdbc:mysql:///?useConfigs=clusterBase,clusterBase2";
try {
cannedProps = new NonRegisteringDriver().parseURL(url, null);
fail("should've bailed on that one!");
} catch (SQLException sqlEx) {
assertTrue(SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE
.equals(sqlEx.getSQLState()));
}
}
public void testUseOldUTF8Behavior() throws Exception {
Properties props = new Properties();
props.setProperty("useOldUTF8Behavior", "true");
props.setProperty("useUnicode", "true");
props.setProperty("characterEncoding", "UTF-8");
props.setProperty("logFactory", "com.mysql.jdbc.log.StandardLogger");
props.setProperty("profileSQL", "true");
StandardLogger.saveLogsToBuffer();
StandardLogger.bufferedLog.setLength(0);
try {
getConnectionWithProps(props);
assertTrue(StringUtils.indexOfIgnoreCase(
StandardLogger.bufferedLog.toString(), "SET NAMES utf8") == -1);
} finally {
StandardLogger.bufferedLog = null;
}
}
/**
* Checks implementation of 'dontTrackOpenResources' property.
*
* @throws Exception
* if the test fails.
*/
public void testDontTrackOpenResources() throws Exception {
Properties props = new Properties();
props.setProperty("dontTrackOpenResources", "true");
Connection noTrackConn = null;
Statement noTrackStatement = null;
PreparedStatement noTrackPstmt = null;
ResultSet rs2 = null;
try {
noTrackConn = getConnectionWithProps(props);
noTrackStatement = noTrackConn.createStatement();
noTrackPstmt = noTrackConn.prepareStatement("SELECT 1");
rs2 = noTrackPstmt.executeQuery();
rs2.next();
this.rs = noTrackStatement.executeQuery("SELECT 1");
this.rs.next();
noTrackConn.close();
// Under 'strict' JDBC requirements, these calls should fail
// (and _do_ if dontTrackOpenResources == false)
this.rs.getString(1);
rs2.getString(1);
} finally {
if (rs2 != null) {
rs2.close();
}
if (noTrackStatement != null) {
noTrackStatement.close();
}
if (noTrackConn != null && !noTrackConn.isClosed()) {
noTrackConn.close();
}
}
}
public void testPing() throws SQLException {
Connection conn2 = getConnectionWithProps((String) null);
((com.mysql.jdbc.Connection) conn2).ping();
conn2.close();
try {
((com.mysql.jdbc.Connection) conn2).ping();
fail("Should have failed with an exception");
} catch (SQLException sqlEx) {
// ignore for now
}
//
// This feature caused BUG#8975, so check for that too!
Properties props = new Properties();
props.setProperty("autoReconnect", "true");
getConnectionWithProps(props);
}
public void testSessionVariables() throws Exception {
String getInitialWaitTimeout = getMysqlVariable("wait_timeout");
int newWaitTimeout = Integer.parseInt(getInitialWaitTimeout) + 10000;
Properties props = new Properties();
props.setProperty("sessionVariables", "wait_timeout=" + newWaitTimeout);
props.setProperty("profileSQL", "true");
Connection varConn = getConnectionWithProps(props);
assertTrue(!getInitialWaitTimeout.equals(getMysqlVariable(varConn,
"wait_timeout")));
}
/**
* Tests setting profileSql on/off in the span of one connection.
*
* @throws Exception
* if an error occurs.
*/
public void testSetProfileSql() throws Exception {
((com.mysql.jdbc.Connection) this.conn).setProfileSql(false);
stmt.executeQuery("SELECT 1");
((com.mysql.jdbc.Connection) this.conn).setProfileSql(true);
stmt.executeQuery("SELECT 1");
}
public void testCreateDatabaseIfNotExist() throws Exception {
if (isAdminConnectionConfigured()) {
Properties props = new Properties();
props.setProperty("createDatabaseIfNotExist", "true");
props.setProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY,
"testcreatedatabaseifnotexists");
Connection newConn = getAdminConnectionWithProps(props);
newConn.createStatement().executeUpdate(
"DROP DATABASE testcreatedatabaseifnotexists");
}
}
/**
* Tests if gatherPerfMetrics works.
*
* @throws Exception
* if the test fails
*/
public void testGatherPerfMetrics() throws Exception {
if (versionMeetsMinimum(4, 1)) {
try {
Properties props = new Properties();
props.put("autoReconnect", "true");
props.put("relaxAutoCommit", "true");
props.put("logSlowQueries", "true");
props.put("slowQueryThresholdMillis", "2000");
// these properties were reported as the cause of
// NullPointerException
props.put("gatherPerfMetrics", "true");
props.put("reportMetricsIntervalMillis", "3000");
Connection conn1 = getConnectionWithProps(props);
Statement stmt1 = conn1.createStatement();
ResultSet rs1 = stmt1.executeQuery("SELECT 1");
rs1.next();
conn1.close();
} catch (NullPointerException e) {
e.printStackTrace();
fail();
}
}
}
/**
* Tests if useCompress works.
*
* @throws Exception
* if the test fails
*/
public void testUseCompress() throws Exception {
// Get real value
this.rs = this.stmt.executeQuery("SHOW VARIABLES LIKE 'max_allowed_packet'");
this.rs.next();
if (this.rs.getInt(2) < 4+1024*1024*16-1) {
fail("You need to increase max_allowed_packet to at least "+(4+1024*1024*16-1)+" before running this test!");
}
testCompressionWith("false", 1024*1024*16-2); // no split
testCompressionWith("false", 1024*1024*16-1); // split with additional empty packet
testCompressionWith("false", 1024*1024*32); // big payload
testCompressionWith("true", 1024*1024*16-2-3); // no split, one compressed packet
testCompressionWith("true", 1024*1024*16-2-2); // no split, two compressed packets
testCompressionWith("true", 1024*1024*16-1); // split with additional empty packet, two compressed packets
testCompressionWith("true", 1024*1024*32); // big payload
}
/**
*
* @param useCompression
* @param maxUncompressedPacketSize mysql header + payload
* @throws Exception
*/
private void testCompressionWith(String useCompression, int maxPayloadSize) throws Exception {
String sqlToSend = "INSERT INTO BLOBTEST(blobdata) VALUES (?)";
int requiredSize = maxPayloadSize - sqlToSend.length() - "_binary''".length();
File testBlobFile = File.createTempFile("cmj-testblob", ".dat");
testBlobFile.deleteOnExit();
cleanupTempFiles(testBlobFile, "cmj-testblob");
BufferedOutputStream bOut = new BufferedOutputStream(
new FileOutputStream(testBlobFile));
int dataRange = Byte.MAX_VALUE - Byte.MIN_VALUE;
for (int i = 0; i < requiredSize; i++) {
bOut.write((byte) ((Math.random() * dataRange) + Byte.MIN_VALUE));
}
bOut.flush();
bOut.close();
Properties props = new Properties();
props.put("useCompression", useCompression);
Connection conn1 = getConnectionWithProps(props);
Statement stmt1 = conn1.createStatement();
createTable("BLOBTEST", "(pos int PRIMARY KEY auto_increment, blobdata LONGBLOB)");
BufferedInputStream bIn = new BufferedInputStream(new FileInputStream(testBlobFile));
this.pstmt = conn1.prepareStatement(sqlToSend);
this.pstmt.setBinaryStream(1, bIn, (int) testBlobFile.length());
this.pstmt.execute();
this.pstmt.clearParameters();
this.rs = stmt1.executeQuery("SELECT blobdata from BLOBTEST LIMIT 1");
this.rs.next();
InputStream is = this.rs.getBinaryStream(1);
bIn.close();
bIn = new BufferedInputStream(new FileInputStream(testBlobFile));
int blobbyte = 0;
int count = 0;
while ((blobbyte = is.read()) > -1) {
int filebyte = bIn.read();
if (filebyte < 0 || filebyte != blobbyte) {
fail("Blob is not identical to initial data.");
}
count++;
}
assertEquals(requiredSize, count);
if (is != null) {
is.close();
}
if (bIn != null) {
bIn.close();
}
}
/**
* Tests feature of "localSocketAddress", by enumerating local IF's and
* trying each one in turn. This test might take a long time to run, since
* we can't set timeouts if we're using localSocketAddress. We try and keep
* the time down on the testcase by spawning the checking of each interface
* off into separate threads.
*
* @throws Exception
* if the test can't use at least one of the local machine's
* interfaces to make an outgoing connection to the server.
*/
public void testLocalSocketAddress() throws Exception {
if (isRunningOnJdk131()) {
return;
}
Enumeration<NetworkInterface> allInterfaces = NetworkInterface.getNetworkInterfaces();
SpawnedWorkerCounter counter = new SpawnedWorkerCounter();
List<LocalSocketAddressCheckThread> allChecks = new ArrayList<LocalSocketAddressCheckThread>();
while (allInterfaces.hasMoreElements()) {
NetworkInterface intf = allInterfaces.nextElement();
Enumeration<InetAddress> allAddresses = intf.getInetAddresses();
allChecks.add(new LocalSocketAddressCheckThread(allAddresses,
counter));
}
counter.setWorkerCount(allChecks.size());
for (LocalSocketAddressCheckThread t : allChecks) {
t.start();
}
// Wait for tests to complete....
synchronized (counter) {
while (counter.workerCount > 0 /* safety valve */) {
counter.wait();
if (counter.workerCount == 0) {
System.out.println("Done!");
break;
}
}
}
boolean didOneWork = false;
boolean didOneFail = false;
for (LocalSocketAddressCheckThread t : allChecks) {
if (t.atLeastOneWorked) {
didOneWork = true;
break;
}
if (!didOneFail) {
didOneFail = true;
}
}
assertTrue(
"At least one connection was made with the localSocketAddress set",
didOneWork);
NonRegisteringDriver d = new NonRegisteringDriver();
String hostname = d.host(d.parseURL(dbUrl, null));
if (!hostname.startsWith(":") && !hostname.startsWith("localhost")) {
int indexOfColon = hostname.indexOf(":");
if (indexOfColon != -1) {
hostname = hostname.substring(0, indexOfColon);
}
boolean isLocalIf = false;
isLocalIf = (null != NetworkInterface.getByName(hostname));
if (!isLocalIf) {
try {
isLocalIf = (null != NetworkInterface
.getByInetAddress(InetAddress.getByName(hostname)));
} catch (Throwable t) {
isLocalIf = false;
}
}
if (!isLocalIf) {
assertTrue(
"At least one connection didn't fail with localSocketAddress set",
didOneFail);
}
}
}
class SpawnedWorkerCounter {
protected int workerCount = 0;
synchronized void setWorkerCount(int i) {
workerCount = i;
}
synchronized void decrementWorkerCount() {
workerCount--;
notify();
}
}
class LocalSocketAddressCheckThread extends Thread {
boolean atLeastOneWorked = false;
Enumeration<InetAddress> allAddresses = null;
SpawnedWorkerCounter counter = null;
LocalSocketAddressCheckThread(Enumeration<InetAddress> e, SpawnedWorkerCounter c) {
allAddresses = e;
counter = c;
}
public void run() {
while (allAddresses.hasMoreElements()) {
InetAddress addr = allAddresses.nextElement();
try {
Properties props = new Properties();
props.setProperty("localSocketAddress",
addr.getHostAddress());
props.setProperty("connectTimeout", "2000");
getConnectionWithProps(props).close();
atLeastOneWorked = true;
break;
} catch (SQLException sqlEx) {
// ignore, we're only seeing if one of these tests succeeds
}
}
counter.decrementWorkerCount();
}
}
public void testUsageAdvisorTooLargeResultSet() throws Exception {
Connection uaConn = null;
PrintStream stderr = System.err;
StringBuffer logBuf = new StringBuffer();
StandardLogger.bufferedLog = logBuf;
try {
Properties props = new Properties();
props.setProperty("useUsageAdvisor", "true");
props.setProperty("resultSetSizeThreshold", "4");
props.setProperty("logger", "StandardLogger");
uaConn = getConnectionWithProps(props);
assertTrue(
"Result set threshold message not present",
logBuf.toString().indexOf(
"larger than \"resultSetSizeThreshold\" of 4 rows") != -1);
} finally {
System.setErr(stderr);
if (uaConn != null) {
uaConn.close();
}
}
}
public void testUseLocalSessionStateRollback() throws Exception {
if (!versionMeetsMinimum(6, 0, 0)) {
return;
}
Properties props = new Properties();
props.setProperty("useLocalSessionState", "true");
props.setProperty("useLocalTransactionState", "true");
props.setProperty("profileSQL", "true");
StringBuffer buf = new StringBuffer();
StandardLogger.bufferedLog = buf;
createTable("testUseLocalSessionState", "(field1 varchar(32))",
"InnoDB");
Connection localStateConn = null;
Statement localStateStmt = null;
try {
localStateConn = getConnectionWithProps(props);
localStateStmt = localStateConn.createStatement();
localStateConn.setAutoCommit(false);
localStateStmt
.executeUpdate("INSERT INTO testUseLocalSessionState VALUES ('abc')");
localStateConn.rollback();
localStateConn.rollback();
localStateStmt
.executeUpdate("INSERT INTO testUseLocalSessionState VALUES ('abc')");
localStateConn.commit();
localStateConn.commit();
localStateStmt.close();
} finally {
StandardLogger.bufferedLog = null;
if (localStateStmt != null) {
localStateStmt.close();
}
if (localStateConn != null) {
localStateConn.close();
}
}
int rollbackCount = 0;
int rollbackPos = 0;
String searchIn = buf.toString();
while (rollbackPos != -1) {
rollbackPos = searchIn.indexOf("rollback", rollbackPos);
if (rollbackPos != -1) {
rollbackPos += "rollback".length();
rollbackCount++;
}
}
assertEquals(1, rollbackCount);
int commitCount = 0;
int commitPos = 0;
// space is important here, we don't want to count "autocommit"
while (commitPos != -1) {
commitPos = searchIn.indexOf(" commit", commitPos);
if (commitPos != -1) {
commitPos += " commit".length();
commitCount++;
}
}
assertEquals(1, commitCount);
}
/**
* Checks if setting useCursorFetch to "true" automatically enables
* server-side prepared statements.
*/
public void testCouplingOfCursorFetch() throws Exception {
if (!versionMeetsMinimum(5, 0)) {
return;
}
Connection fetchConn = null;
try {
Properties props = new Properties();
props.setProperty("useServerPrepStmts", "false"); // force the issue
props.setProperty("useCursorFetch", "true");
fetchConn = getConnectionWithProps(props);
String classname = "com.mysql.jdbc.ServerPreparedStatement";
if (Util.isJdbc4()) {
classname = "com.mysql.jdbc.JDBC4ServerPreparedStatement";
}
assertEquals(classname, fetchConn.prepareStatement("SELECT 1")
.getClass().getName());
} finally {
if (fetchConn != null) {
fetchConn.close();
}
}
}
public void testInterfaceImplementation() throws Exception {
testInterfaceImplementation(getConnectionWithProps((Properties) null));
MysqlConnectionPoolDataSource cpds = new MysqlConnectionPoolDataSource();
cpds.setUrl(dbUrl);
testInterfaceImplementation(cpds.getPooledConnection().getConnection());
}
private void testInterfaceImplementation(Connection connToCheck)
throws Exception {
Method[] dbmdMethods = java.sql.DatabaseMetaData.class.getMethods();
// can't do this statically, as we return different
// implementations depending on JDBC version
DatabaseMetaData dbmd = connToCheck.getMetaData();
checkInterfaceImplemented(dbmdMethods, dbmd.getClass(), dbmd);
Statement stmtToCheck = connToCheck.createStatement();
checkInterfaceImplemented(java.sql.Statement.class.getMethods(),
stmtToCheck.getClass(), stmtToCheck);
PreparedStatement pStmtToCheck = connToCheck
.prepareStatement("SELECT 1");
ParameterMetaData paramMd = pStmtToCheck.getParameterMetaData();
checkInterfaceImplemented(
java.sql.PreparedStatement.class.getMethods(),
pStmtToCheck.getClass(), pStmtToCheck);
checkInterfaceImplemented(
java.sql.ParameterMetaData.class.getMethods(),
paramMd.getClass(), paramMd);
pStmtToCheck = ((com.mysql.jdbc.Connection) connToCheck)
.serverPrepareStatement("SELECT 1");
checkInterfaceImplemented(
java.sql.PreparedStatement.class.getMethods(),
pStmtToCheck.getClass(), pStmtToCheck);
ResultSet toCheckRs = connToCheck.createStatement().executeQuery(
"SELECT 1");
checkInterfaceImplemented(java.sql.ResultSet.class.getMethods(),
toCheckRs.getClass(), toCheckRs);
toCheckRs = connToCheck.createStatement().executeQuery("SELECT 1");
checkInterfaceImplemented(
java.sql.ResultSetMetaData.class.getMethods(), toCheckRs
.getMetaData().getClass(), toCheckRs.getMetaData());
if (versionMeetsMinimum(5, 0, 0)) {
createProcedure("interfaceImpl",
"(IN p1 INT)\nBEGIN\nSELECT 1;\nEND");
CallableStatement cstmt = connToCheck
.prepareCall("{CALL interfaceImpl(?)}");
checkInterfaceImplemented(
java.sql.CallableStatement.class.getMethods(),
cstmt.getClass(), cstmt);
}
checkInterfaceImplemented(java.sql.Connection.class.getMethods(),
connToCheck.getClass(), connToCheck);
}
private void checkInterfaceImplemented(Method[] interfaceMethods,
Class<?> implementingClass, Object invokeOn)
throws NoSuchMethodException {
for (int i = 0; i < interfaceMethods.length; i++) {
Method toFind = interfaceMethods[i];
Method toMatch = implementingClass.getMethod(toFind.getName(),
toFind.getParameterTypes());
assertNotNull(toFind.toString(), toMatch);
Class<?> paramTypes[] = toFind.getParameterTypes();
Object[] args = new Object[paramTypes.length];
fillPrimitiveDefaults(paramTypes, args, paramTypes.length);
try {
toMatch.invoke(invokeOn, args);
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
} catch (java.lang.AbstractMethodError e) {
throw e;
}
}
}
public void testNonVerifyServerCert() throws Exception {
getConnectionWithProps("useSSL=true,verifyServerCertificate=false,requireSSL=true");
}
public void testSelfDestruct() throws Exception {
Connection selfDestructingConn = getConnectionWithProps("selfDestructOnPingMaxOperations=2");
boolean failed = false;
for (int i = 0; i < 20; i++) {
selfDestructingConn.createStatement().executeQuery("SELECT 1");
try {
selfDestructingConn.createStatement().executeQuery(
"/* ping */ SELECT 1");
} catch (SQLException sqlEx) {
String sqlState = sqlEx.getSQLState();
assertEquals("08S01", sqlState);
failed = true;
break;
}
}
if (!failed) {
fail("Connection should've self-destructed");
}
failed = false;
selfDestructingConn = getConnectionWithProps("selfDestructOnPingSecondsLifetime=1");
for (int i = 0; i < 20; i++) {
selfDestructingConn.createStatement().executeQuery(
"SELECT SLEEP(1)");
try {
selfDestructingConn.createStatement().executeQuery(
"/* ping */ SELECT 1");
} catch (SQLException sqlEx) {
String sqlState = sqlEx.getSQLState();
assertEquals("08S01", sqlState);
failed = true;
break;
}
}
if (!failed) {
fail("Connection should've self-destructed");
}
}
public void testLifecyleInterceptor() throws Exception {
createTable("testLifecycleInterceptor", "(field1 int)", "InnoDB");
Connection liConn = null;
try {
liConn = getConnectionWithProps("connectionLifecycleInterceptors=testsuite.simple.TestLifecycleInterceptor");
liConn.setAutoCommit(false);
liConn.createStatement().executeUpdate(
"INSERT INTO testLifecycleInterceptor VALUES (1)");
liConn.commit();
assertEquals(TestLifecycleInterceptor.transactionsBegun, 1);
assertEquals(TestLifecycleInterceptor.transactionsCompleted, 1);
liConn.createStatement().executeQuery(
"SELECT * FROM testLifecycleInterceptor");
assertEquals(TestLifecycleInterceptor.transactionsBegun, 2);
// implicit commit
liConn.createStatement().executeUpdate(
"CREATE TABLE testLifecycleFoo (field1 int)");
assertEquals(TestLifecycleInterceptor.transactionsCompleted, 2);
} finally {
if (liConn != null) {
liConn.createStatement().executeUpdate(
"DROP TABLE IF EXISTS testLifecycleFoo");
liConn.close();
}
}
}
public void testNewHostParsing() throws Exception {
Properties parsedProps = new NonRegisteringDriver().parseURL(dbUrl,
null);
String host = parsedProps
.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
String port = parsedProps
.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY);
String user = parsedProps
.getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
String password = parsedProps
.getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
String database = parsedProps
.getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
String newUrl = String
.format("jdbc:mysql://address=(protocol=tcp)(host=%s)(port=%s)(user=%s)(password=%s)/%s",
host, port, user != null ? user : "",
password != null ? password : "", database);
try {
getConnectionWithProps(newUrl, new Properties());
} catch (SQLException sqlEx) {
throw new RuntimeException("Failed to connect with URL " + newUrl,
sqlEx);
}
}
public void testCompression() throws Exception {
Connection compressedConn = getConnectionWithProps("useCompression=true,maxAllowedPacket=33554432");
Statement compressedStmt = compressedConn.createStatement();
compressedStmt.setFetchSize(Integer.MIN_VALUE);
this.rs = compressedStmt
.executeQuery("select repeat('a', 256 * 256 * 256 - 5)");
this.rs.next();
String str = rs.getString(1);
assertEquals((256 * 256 * 256 - 5), str.length());
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) != 'a') {
fail();
}
}
}
public void testIsLocal() throws Exception {
Properties parsedProps = new NonRegisteringDriver().parseURL(dbUrl, null);
String host = parsedProps.getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY, "localhost");
if (host.equals("localhost") || host.equals("127.0.0.1")) {
// we can actually test this
assertTrue(((com.mysql.jdbc.ConnectionImpl) this.conn).isServerLocal());
}
}
public void testReadOnly56() throws Exception {
if (versionMeetsMinimum(5, 6, 5)) {
try {
Connection notLocalState = getConnectionWithProps("profileSql=true");
for (int i = 0; i < 2; i++) {
StandardLogger.bufferedLog = new StringBuffer();
StandardLogger.saveLogsToBuffer();
notLocalState.setReadOnly(true);
assertTrue(StandardLogger.bufferedLog.toString().indexOf("set session transaction read only") != -1);
notLocalState.createStatement().execute("set session transaction read write");
assertFalse(notLocalState.isReadOnly());
}
for (int i = 0; i < 2; i++) {
StandardLogger.bufferedLog = new StringBuffer();
StandardLogger.saveLogsToBuffer();
notLocalState.setReadOnly(false);
assertTrue(StandardLogger.bufferedLog.toString().indexOf("set session transaction read write") != -1);
notLocalState.createStatement().execute("set session transaction read only");
assertTrue(notLocalState.isReadOnly());
}
Connection localState = getConnectionWithProps("profileSql=true,useLocalSessionState=true");
for (int i = 0; i < 2; i++) {
StandardLogger.bufferedLog = new StringBuffer();
StandardLogger.saveLogsToBuffer();
localState.setReadOnly(true);
if (i == 0) {
assertTrue(StandardLogger.bufferedLog.toString().indexOf("set session transaction read only") != -1);
} else {
assertTrue(StandardLogger.bufferedLog.toString().indexOf("set session transaction read only") == -1);
}
StandardLogger.bufferedLog = new StringBuffer();
StandardLogger.saveLogsToBuffer();
localState.isReadOnly();
assertTrue(StandardLogger.bufferedLog.toString().indexOf("select @@session.tx_read_only") == -1);
}
} finally {
StandardLogger.bufferedLog = null;
}
}
}
}