Package testsuite.simple

Source Code of testsuite.simple.ConnectionTest$LocalSocketAddressCheckThread

/*
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.DriverManager;
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;
      }
    }
  }
 
  /**
   * IPv6 Connection test.
   *
   * @throws SQLException
   */
  public void testIPv6() throws Exception {

    if (!versionMeetsMinimum(5, 6)) {
      return;
      // this test could work with MySQL 5.5 but requires specific server configuration, e.g. "--bind-address=::"
    }

    Properties connProps = getPropertiesFromTestsuiteUrl();

    String host = "::1"; // IPv6 loopback
    int port = Integer.parseInt(connProps.getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY));
    String username = connProps.getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
    String password = connProps.getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);

    String ipv6Url = String.format("jdbc:mysql://address=(protocol=tcp)(host=%s)(port=%d)", host, port);

    Connection testConn = null;
    Statement testStmt = null;
    ResultSet testRS = null;
   
    testConn = DriverManager.getConnection(ipv6Url, username, password);
    testStmt = testConn.createStatement();
    testRS = testStmt.executeQuery("SELECT USER()");

    assertTrue(testRS.next());
    assertTrue(testRS.getString(1).startsWith(username));
   
    testRS.close();
    testStmt.close();
    testConn.close();
  }
}
TOP

Related Classes of testsuite.simple.ConnectionTest$LocalSocketAddressCheckThread

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.