/* 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; } } } }