0001: /*
0002: Copyright (C) 2002-2007 MySQL AB
0003:
0004: This program is free software; you can redistribute it and/or modify
0005: it under the terms of version 2 of the GNU General Public License as
0006: published by the Free Software Foundation.
0007:
0008: There are special exceptions to the terms and conditions of the GPL
0009: as it is applied to this software. View the full text of the
0010: exception in file EXCEPTIONS-CONNECTOR-J in the directory of this
0011: software distribution.
0012:
0013: This program is distributed in the hope that it will be useful,
0014: but WITHOUT ANY WARRANTY; without even the implied warranty of
0015: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0016: GNU General Public License for more details.
0017:
0018: You should have received a copy of the GNU General Public License
0019: along with this program; if not, write to the Free Software
0020: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0021:
0022:
0023:
0024: */
0025: package testsuite.simple;
0026:
0027: import testsuite.BaseTestCase;
0028:
0029: import java.io.File;
0030: import java.io.FileInputStream;
0031: import java.io.FileWriter;
0032: import java.io.PrintStream;
0033: import java.net.InetAddress;
0034: import java.net.NetworkInterface;
0035: import java.sql.Connection;
0036: import java.sql.DatabaseMetaData;
0037: import java.sql.PreparedStatement;
0038: import java.sql.ResultSet;
0039: import java.sql.ResultSetMetaData;
0040: import java.sql.SQLException;
0041: import java.sql.Savepoint;
0042: import java.sql.Statement;
0043:
0044: import java.util.ArrayList;
0045: import java.util.Enumeration;
0046: import java.util.Iterator;
0047: import java.util.List;
0048: import java.util.Properties;
0049: import java.util.StringTokenizer;
0050:
0051: import com.mysql.jdbc.ConnectionPropertiesTransform;
0052: import com.mysql.jdbc.Driver;
0053: import com.mysql.jdbc.NonRegisteringDriver;
0054: import com.mysql.jdbc.SQLError;
0055: import com.mysql.jdbc.StringUtils;
0056: import com.mysql.jdbc.log.StandardLogger;
0057:
0058: /**
0059: * Tests java.sql.Connection functionality ConnectionTest.java,v 1.1 2002/12/06
0060: * 22:01:05 mmatthew Exp
0061: *
0062: * @author Mark Matthews
0063: */
0064: public class ConnectionTest extends BaseTestCase {
0065: /**
0066: * Constructor for ConnectionTest.
0067: *
0068: * @param name
0069: * the name of the test to run
0070: */
0071: public ConnectionTest(String name) {
0072: super (name);
0073: }
0074:
0075: /**
0076: * Runs all test cases in this test suite
0077: *
0078: * @param args
0079: */
0080: public static void main(String[] args) {
0081: junit.textui.TestRunner.run(ConnectionTest.class);
0082: }
0083:
0084: /**
0085: * Tests catalog functionality
0086: *
0087: * @throws Exception
0088: * if an error occurs
0089: */
0090: public void testCatalog() throws Exception {
0091: String currentCatalog = this .conn.getCatalog();
0092: this .conn.setCatalog(currentCatalog);
0093: assertTrue(currentCatalog.equals(this .conn.getCatalog()));
0094: }
0095:
0096: /**
0097: * Tests a cluster connection for failover, requires a two-node cluster URL
0098: * specfied in com.mysql.jdbc.testsuite.ClusterUrl system proeprty.
0099: *
0100: * @throws Exception
0101: * DOCUMENT ME!
0102: */
0103: public void testClusterConnection() throws Exception {
0104: String url = System
0105: .getProperty("com.mysql.jdbc.testsuite.ClusterUrl");
0106:
0107: if ((url != null) && (url.length() > 0)) {
0108: Object versionNumObj = getSingleValueWithQuery("SHOW VARIABLES LIKE 'version'");
0109:
0110: if ((versionNumObj != null)
0111: && (versionNumObj.toString().indexOf("cluster") != -1)) {
0112: Connection clusterConn = null;
0113: Statement clusterStmt = null;
0114:
0115: try {
0116: clusterConn = new NonRegisteringDriver().connect(
0117: url, null);
0118:
0119: clusterStmt = clusterConn.createStatement();
0120: clusterStmt
0121: .executeQuery("DROP TABLE IF EXISTS testClusterConn");
0122: clusterStmt
0123: .executeQuery("CREATE TABLE testClusterConn (field1 INT) TYPE=ndbcluster");
0124: clusterStmt
0125: .executeQuery("INSERT INTO testClusterConn VALUES (1)");
0126:
0127: clusterConn.setAutoCommit(false);
0128:
0129: clusterStmt
0130: .executeQuery("SELECT * FROM testClusterConn");
0131: clusterStmt
0132: .executeUpdate("UPDATE testClusterConn SET field1=4");
0133:
0134: // Kill the connection
0135: String connectionId = getSingleValueWithQuery(
0136: "SELECT CONNECTION_ID()").toString();
0137:
0138: System.out
0139: .println("Please kill the MySQL server now and press return...");
0140: System.in.read();
0141:
0142: System.out.println("Waiting for TCP/IP timeout...");
0143: Thread.sleep(10);
0144:
0145: System.out.println("Attempting auto reconnect");
0146:
0147: try {
0148: clusterConn.setAutoCommit(true);
0149: clusterConn.setAutoCommit(false);
0150: } catch (SQLException sqlEx) {
0151: System.out.println(sqlEx);
0152: }
0153:
0154: //
0155: // Test that this 'new' connection is not read-only
0156: //
0157: clusterStmt
0158: .executeUpdate("UPDATE testClusterConn SET field1=5");
0159:
0160: ResultSet rs = clusterStmt
0161: .executeQuery("SELECT * FROM testClusterConn WHERE field1=5");
0162:
0163: assertTrue("One row should be returned", rs.next());
0164: } finally {
0165: if (clusterStmt != null) {
0166: clusterStmt
0167: .executeQuery("DROP TABLE IF EXISTS testClusterConn");
0168: clusterStmt.close();
0169: }
0170:
0171: if (clusterConn != null) {
0172: clusterConn.close();
0173: }
0174: }
0175: }
0176: }
0177: }
0178:
0179: /**
0180: * DOCUMENT ME!
0181: *
0182: * @throws Exception
0183: * DOCUMENT ME!
0184: */
0185: public void testDeadlockDetection() throws Exception {
0186: try {
0187: this .rs = this .stmt
0188: .executeQuery("SHOW VARIABLES LIKE 'innodb_lock_wait_timeout'");
0189: this .rs.next();
0190:
0191: int timeoutSecs = this .rs.getInt(2);
0192:
0193: this .stmt.executeUpdate("DROP TABLE IF EXISTS t1");
0194: this .stmt
0195: .executeUpdate("CREATE TABLE t1 (id INTEGER, x INTEGER) TYPE=INNODB");
0196: this .stmt.executeUpdate("INSERT INTO t1 VALUES(0, 0)");
0197: this .conn.setAutoCommit(false);
0198: this .conn.createStatement().executeQuery(
0199: "SELECT * FROM t1 WHERE id=0 FOR UPDATE");
0200:
0201: Properties props = new Properties();
0202: props.setProperty(
0203: "includeInnodbStatusInDeadlockExceptions", "true");
0204:
0205: Connection deadlockConn = getConnectionWithProps(props);
0206: deadlockConn.setAutoCommit(false);
0207:
0208: // The following query should hang because con1 is locking the page
0209: deadlockConn.createStatement().executeUpdate(
0210: "UPDATE t1 SET x=2 WHERE id=0");
0211: deadlockConn.commit();
0212:
0213: Thread.sleep(timeoutSecs * 2 * 1000);
0214: } catch (SQLException sqlEx) {
0215: System.out
0216: .println("Caught SQLException due to deadlock/lock timeout");
0217: System.out.println("SQLState: " + sqlEx.getSQLState());
0218: System.out.println("Vendor error: " + sqlEx.getErrorCode());
0219: System.out.println("Message: " + sqlEx.getMessage());
0220:
0221: //
0222: // Check whether the driver thinks it really is deadlock...
0223: //
0224: assertTrue(SQLError.SQL_STATE_DEADLOCK.equals(sqlEx
0225: .getSQLState()));
0226: assertTrue(sqlEx.getErrorCode() == 1205);
0227: // Make sure INNODB Status is getting dumped into error message
0228: assertTrue(sqlEx.getMessage().indexOf("INNODB MONITOR") != -1);
0229: } finally {
0230: this .conn.setAutoCommit(true);
0231: this .stmt.executeUpdate("DROP TABLE IF EXISTS t1");
0232: }
0233: }
0234:
0235: /**
0236: * DOCUMENT ME!
0237: *
0238: * @throws Exception
0239: * DOCUMENT ME!
0240: */
0241: public void testCharsets() throws Exception {
0242: if (versionMeetsMinimum(4, 1)) {
0243: try {
0244: Properties props = new Properties();
0245: props.setProperty("useUnicode", "true");
0246: props.setProperty("characterEncoding", "UTF-8");
0247:
0248: Connection utfConn = getConnectionWithProps(props);
0249:
0250: this .stmt = utfConn.createStatement();
0251:
0252: this .stmt.executeUpdate("DROP TABLE IF EXISTS t1");
0253: // this.stmt.executeUpdate("SET CHARACTER SET latin1");
0254:
0255: this .stmt
0256: .executeUpdate("CREATE TABLE t1 ("
0257: + "comment CHAR(32) ASCII NOT NULL,"
0258: + "koi8_ru_f CHAR(32) CHARACTER SET koi8r NOT NULL"
0259: + ") CHARSET=latin5");
0260:
0261: this .stmt
0262: .executeUpdate("ALTER TABLE t1 CHANGE comment comment CHAR(32) CHARACTER SET latin2 NOT NULL");
0263: this .stmt
0264: .executeUpdate("ALTER TABLE t1 ADD latin5_f CHAR(32) NOT NULL");
0265: this .stmt
0266: .executeUpdate("ALTER TABLE t1 CHARSET=latin2");
0267: this .stmt
0268: .executeUpdate("ALTER TABLE t1 ADD latin2_f CHAR(32) NOT NULL");
0269: this .stmt
0270: .executeUpdate("ALTER TABLE t1 DROP latin2_f, DROP latin5_f");
0271:
0272: this .stmt
0273: .executeUpdate("INSERT INTO t1 (koi8_ru_f,comment) VALUES ('a','LAT SMALL A')");
0274: /*
0275: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0276: * VALUES ('b','LAT SMALL B')"); this.stmt.executeUpdate("INSERT
0277: * INTO t1 (koi8_ru_f,comment) VALUES ('c','LAT SMALL C')");
0278: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0279: * VALUES ('d','LAT SMALL D')"); this.stmt.executeUpdate("INSERT
0280: * INTO t1 (koi8_ru_f,comment) VALUES ('e','LAT SMALL E')");
0281: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0282: * VALUES ('f','LAT SMALL F')"); this.stmt.executeUpdate("INSERT
0283: * INTO t1 (koi8_ru_f,comment) VALUES ('g','LAT SMALL G')");
0284: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0285: * VALUES ('h','LAT SMALL H')"); this.stmt.executeUpdate("INSERT
0286: * INTO t1 (koi8_ru_f,comment) VALUES ('i','LAT SMALL I')");
0287: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0288: * VALUES ('j','LAT SMALL J')"); this.stmt.executeUpdate("INSERT
0289: * INTO t1 (koi8_ru_f,comment) VALUES ('k','LAT SMALL K')");
0290: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0291: * VALUES ('l','LAT SMALL L')"); this.stmt.executeUpdate("INSERT
0292: * INTO t1 (koi8_ru_f,comment) VALUES ('m','LAT SMALL M')");
0293: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0294: * VALUES ('n','LAT SMALL N')"); this.stmt.executeUpdate("INSERT
0295: * INTO t1 (koi8_ru_f,comment) VALUES ('o','LAT SMALL O')");
0296: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0297: * VALUES ('p','LAT SMALL P')"); this.stmt.executeUpdate("INSERT
0298: * INTO t1 (koi8_ru_f,comment) VALUES ('q','LAT SMALL Q')");
0299: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0300: * VALUES ('r','LAT SMALL R')"); this.stmt.executeUpdate("INSERT
0301: * INTO t1 (koi8_ru_f,comment) VALUES ('s','LAT SMALL S')");
0302: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0303: * VALUES ('t','LAT SMALL T')"); this.stmt.executeUpdate("INSERT
0304: * INTO t1 (koi8_ru_f,comment) VALUES ('u','LAT SMALL U')");
0305: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0306: * VALUES ('v','LAT SMALL V')"); this.stmt.executeUpdate("INSERT
0307: * INTO t1 (koi8_ru_f,comment) VALUES ('w','LAT SMALL W')");
0308: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0309: * VALUES ('x','LAT SMALL X')"); this.stmt.executeUpdate("INSERT
0310: * INTO t1 (koi8_ru_f,comment) VALUES ('y','LAT SMALL Y')");
0311: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0312: * VALUES ('z','LAT SMALL Z')"); this.stmt.executeUpdate("INSERT
0313: * INTO t1 (koi8_ru_f,comment) VALUES ('A','LAT CAPIT A')");
0314: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0315: * VALUES ('B','LAT CAPIT B')"); this.stmt.executeUpdate("INSERT
0316: * INTO t1 (koi8_ru_f,comment) VALUES ('C','LAT CAPIT C')");
0317: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0318: * VALUES ('D','LAT CAPIT D')"); this.stmt.executeUpdate("INSERT
0319: * INTO t1 (koi8_ru_f,comment) VALUES ('E','LAT CAPIT E')");
0320: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0321: * VALUES ('F','LAT CAPIT F')"); this.stmt.executeUpdate("INSERT
0322: * INTO t1 (koi8_ru_f,comment) VALUES ('G','LAT CAPIT G')");
0323: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0324: * VALUES ('H','LAT CAPIT H')"); this.stmt.executeUpdate("INSERT
0325: * INTO t1 (koi8_ru_f,comment) VALUES ('I','LAT CAPIT I')");
0326: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0327: * VALUES ('J','LAT CAPIT J')"); this.stmt.executeUpdate("INSERT
0328: * INTO t1 (koi8_ru_f,comment) VALUES ('K','LAT CAPIT K')");
0329: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0330: * VALUES ('L','LAT CAPIT L')"); this.stmt.executeUpdate("INSERT
0331: * INTO t1 (koi8_ru_f,comment) VALUES ('M','LAT CAPIT M')");
0332: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0333: * VALUES ('N','LAT CAPIT N')"); this.stmt.executeUpdate("INSERT
0334: * INTO t1 (koi8_ru_f,comment) VALUES ('O','LAT CAPIT O')");
0335: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0336: * VALUES ('P','LAT CAPIT P')"); this.stmt.executeUpdate("INSERT
0337: * INTO t1 (koi8_ru_f,comment) VALUES ('Q','LAT CAPIT Q')");
0338: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0339: * VALUES ('R','LAT CAPIT R')"); this.stmt.executeUpdate("INSERT
0340: * INTO t1 (koi8_ru_f,comment) VALUES ('S','LAT CAPIT S')");
0341: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0342: * VALUES ('T','LAT CAPIT T')"); this.stmt.executeUpdate("INSERT
0343: * INTO t1 (koi8_ru_f,comment) VALUES ('U','LAT CAPIT U')");
0344: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0345: * VALUES ('V','LAT CAPIT V')"); this.stmt.executeUpdate("INSERT
0346: * INTO t1 (koi8_ru_f,comment) VALUES ('W','LAT CAPIT W')");
0347: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0348: * VALUES ('X','LAT CAPIT X')"); this.stmt.executeUpdate("INSERT
0349: * INTO t1 (koi8_ru_f,comment) VALUES ('Y','LAT CAPIT Y')");
0350: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0351: * VALUES ('Z','LAT CAPIT Z')");
0352: */
0353:
0354: String cyrillicSmallA = "\u0430";
0355: this .stmt
0356: .executeUpdate("INSERT INTO t1 (koi8_ru_f,comment) VALUES ('"
0357: + cyrillicSmallA + "','CYR SMALL A')");
0358:
0359: /*
0360: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0361: * VALUES (_koi8r'?申','CYR SMALL BE')");
0362: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0363: * VALUES (_koi8r'?申','CYR SMALL VE')");
0364: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0365: * VALUES (_koi8r'?申','CYR SMALL GE')");
0366: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0367: * VALUES (_koi8r'?申','CYR SMALL DE')");
0368: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0369: * VALUES (_koi8r'?申','CYR SMALL IE')");
0370: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0371: * VALUES (_koi8r'?申','CYR SMALL IO')");
0372: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0373: * VALUES (_koi8r'?申','CYR SMALL ZHE')");
0374: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0375: * VALUES (_koi8r'?申','CYR SMALL ZE')");
0376: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0377: * VALUES (_koi8r'?申','CYR SMALL I')");
0378: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0379: * VALUES (_koi8r'?申','CYR SMALL KA')");
0380: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0381: * VALUES (_koi8r'?申','CYR SMALL EL')");
0382: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0383: * VALUES (_koi8r'?申','CYR SMALL EM')");
0384: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0385: * VALUES (_koi8r'?申','CYR SMALL EN')");
0386: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0387: * VALUES (_koi8r'?申','CYR SMALL O')");
0388: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0389: * VALUES (_koi8r'?申','CYR SMALL PE')");
0390: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0391: * VALUES (_koi8r'?申','CYR SMALL ER')");
0392: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0393: * VALUES (_koi8r'?申','CYR SMALL ES')");
0394: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0395: * VALUES (_koi8r'?申','CYR SMALL TE')");
0396: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0397: * VALUES (_koi8r'?申','CYR SMALL U')");
0398: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0399: * VALUES (_koi8r'?申','CYR SMALL EF')");
0400: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0401: * VALUES (_koi8r'?申','CYR SMALL HA')");
0402: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0403: * VALUES (_koi8r'?申','CYR SMALL TSE')");
0404: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0405: * VALUES (_koi8r'?申','CYR SMALL CHE')");
0406: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0407: * VALUES (_koi8r'?申','CYR SMALL SHA')");
0408: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0409: * VALUES (_koi8r'?申','CYR SMALL SCHA')");
0410: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0411: * VALUES (_koi8r'?申','CYR SMALL HARD SIGN')");
0412: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0413: * VALUES (_koi8r'?申','CYR SMALL YERU')");
0414: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0415: * VALUES (_koi8r'?申','CYR SMALL SOFT SIGN')");
0416: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0417: * VALUES (_koi8r'?申','CYR SMALL E')");
0418: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0419: * VALUES (_koi8r'?申','CYR SMALL YU')");
0420: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0421: * VALUES (_koi8r'?申','CYR SMALL YA')");
0422: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0423: * VALUES (_koi8r'?申','CYR CAPIT A')");
0424: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0425: * VALUES (_koi8r'?申','CYR CAPIT BE')");
0426: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0427: * VALUES (_koi8r'?申','CYR CAPIT VE')");
0428: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0429: * VALUES (_koi8r'?申','CYR CAPIT GE')");
0430: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0431: * VALUES (_koi8r'?申','CYR CAPIT DE')");
0432: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0433: * VALUES (_koi8r'?申','CYR CAPIT IE')");
0434: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0435: * VALUES (_koi8r'?申','CYR CAPIT IO')");
0436: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0437: * VALUES (_koi8r'?申','CYR CAPIT ZHE')");
0438: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0439: * VALUES (_koi8r'?申','CYR CAPIT ZE')");
0440: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0441: * VALUES (_koi8r'?申','CYR CAPIT I')");
0442: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0443: * VALUES (_koi8r'?申','CYR CAPIT KA')");
0444: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0445: * VALUES (_koi8r'?申','CYR CAPIT EL')");
0446: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0447: * VALUES (_koi8r'?申','CYR CAPIT EM')");
0448: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0449: * VALUES (_koi8r'?申','CYR CAPIT EN')");
0450: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0451: * VALUES (_koi8r'?申','CYR CAPIT O')");
0452: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0453: * VALUES (_koi8r'?申','CYR CAPIT PE')");
0454: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0455: * VALUES (_koi8r'?申','CYR CAPIT ER')");
0456: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0457: * VALUES (_koi8r'?申','CYR CAPIT ES')");
0458: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0459: * VALUES (_koi8r'?申','CYR CAPIT TE')");
0460: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0461: * VALUES (_koi8r'?申','CYR CAPIT U')");
0462: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0463: * VALUES (_koi8r'?申','CYR CAPIT EF')");
0464: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0465: * VALUES (_koi8r'?申','CYR CAPIT HA')");
0466: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0467: * VALUES (_koi8r'?申','CYR CAPIT TSE')");
0468: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0469: * VALUES (_koi8r'?申','CYR CAPIT CHE')");
0470: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0471: * VALUES (_koi8r'?申','CYR CAPIT SHA')");
0472: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0473: * VALUES (_koi8r'?申','CYR CAPIT SCHA')");
0474: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0475: * VALUES (_koi8r'?申','CYR CAPIT HARD SIGN')");
0476: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0477: * VALUES (_koi8r'?申','CYR CAPIT YERU')");
0478: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0479: * VALUES (_koi8r'?申','CYR CAPIT SOFT SIGN')");
0480: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0481: * VALUES (_koi8r'?申','CYR CAPIT E')");
0482: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0483: * VALUES (_koi8r'?申','CYR CAPIT YU')");
0484: * this.stmt.executeUpdate("INSERT INTO t1 (koi8_ru_f,comment)
0485: * VALUES (_koi8r'?申','CYR CAPIT YA')");
0486: */
0487:
0488: this .stmt
0489: .executeUpdate("ALTER TABLE t1 ADD utf8_f CHAR(32) CHARACTER SET utf8 NOT NULL");
0490: this .stmt
0491: .executeUpdate("UPDATE t1 SET utf8_f=CONVERT(koi8_ru_f USING utf8)");
0492: this .stmt.executeUpdate("SET CHARACTER SET koi8r");
0493: // this.stmt.executeUpdate("SET CHARACTER SET UTF8");
0494: this .rs = this .stmt.executeQuery("SELECT * FROM t1");
0495:
0496: ResultSetMetaData rsmd = this .rs.getMetaData();
0497:
0498: int numColumns = rsmd.getColumnCount();
0499:
0500: for (int i = 0; i < numColumns; i++) {
0501: System.out.print(rsmd.getColumnName(i + 1));
0502: System.out.print("\t\t");
0503: }
0504:
0505: System.out.println();
0506:
0507: while (this .rs.next()) {
0508: System.out.println(this .rs.getString(1) + "\t\t"
0509: + this .rs.getString(2) + "\t\t"
0510: + this .rs.getString(3));
0511:
0512: if (this .rs.getString(1).equals("CYR SMALL A")) {
0513: this .rs.getString(2);
0514: }
0515: }
0516:
0517: System.out.println();
0518:
0519: this .stmt.executeUpdate("SET NAMES utf8");
0520: this .rs = this .stmt.executeQuery("SELECT _koi8r 0xC1;");
0521:
0522: rsmd = this .rs.getMetaData();
0523:
0524: numColumns = rsmd.getColumnCount();
0525:
0526: for (int i = 0; i < numColumns; i++) {
0527: System.out.print(rsmd.getColumnName(i + 1));
0528: System.out.print("\t\t");
0529: }
0530:
0531: System.out.println();
0532:
0533: while (this .rs.next()) {
0534: System.out.println(this .rs.getString(1).equals(
0535: "\u0430")
0536: + "\t\t");
0537: System.out.println(new String(this .rs.getBytes(1),
0538: "KOI8_R"));
0539:
0540: }
0541:
0542: char[] c = new char[] { 0xd0b0 };
0543:
0544: System.out.println(new String(c));
0545: System.out.println("\u0430");
0546: } finally {
0547: // this.stmt.executeUpdate("DROP TABLE IF EXISTS t1");
0548: }
0549: }
0550: }
0551:
0552: /**
0553: * Tests isolation level functionality
0554: *
0555: * @throws Exception
0556: * if an error occurs
0557: */
0558: public void testIsolationLevel() throws Exception {
0559: if (versionMeetsMinimum(4, 0)) {
0560: String[] isoLevelNames = new String[] {
0561: "Connection.TRANSACTION_NONE",
0562: "Connection.TRANSACTION_READ_COMMITTED",
0563: "Connection.TRANSACTION_READ_UNCOMMITTED",
0564: "Connection.TRANSACTION_REPEATABLE_READ",
0565: "Connection.TRANSACTION_SERIALIZABLE" };
0566:
0567: int[] isolationLevels = new int[] {
0568: Connection.TRANSACTION_NONE,
0569: Connection.TRANSACTION_READ_COMMITTED,
0570: Connection.TRANSACTION_READ_UNCOMMITTED,
0571: Connection.TRANSACTION_REPEATABLE_READ,
0572: Connection.TRANSACTION_SERIALIZABLE };
0573:
0574: DatabaseMetaData dbmd = this .conn.getMetaData();
0575:
0576: for (int i = 0; i < isolationLevels.length; i++) {
0577: if (dbmd
0578: .supportsTransactionIsolationLevel(isolationLevels[i])) {
0579: this .conn
0580: .setTransactionIsolation(isolationLevels[i]);
0581:
0582: assertTrue(
0583: "Transaction isolation level that was set ("
0584: + isoLevelNames[i]
0585: + ") was not returned, nor was a more restrictive isolation level used by the server",
0586: this .conn.getTransactionIsolation() == isolationLevels[i]
0587: || this .conn
0588: .getTransactionIsolation() > isolationLevels[i]);
0589: }
0590: }
0591: }
0592: }
0593:
0594: /**
0595: * Tests the savepoint functionality in MySQL.
0596: *
0597: * @throws Exception
0598: * if an error occurs.
0599: */
0600: public void testSavepoint() throws Exception {
0601: if (!isRunningOnJdk131()) {
0602: DatabaseMetaData dbmd = this .conn.getMetaData();
0603:
0604: if (dbmd.supportsSavepoints()) {
0605: System.out.println("Testing SAVEPOINTs");
0606:
0607: try {
0608: this .conn.setAutoCommit(true);
0609:
0610: this .stmt
0611: .executeUpdate("DROP TABLE IF EXISTS testSavepoints");
0612: this .stmt
0613: .executeUpdate("CREATE TABLE testSavepoints (field1 int) TYPE=InnoDB");
0614:
0615: // Try with named save points
0616: this .conn.setAutoCommit(false);
0617: this .stmt
0618: .executeUpdate("INSERT INTO testSavepoints VALUES (1)");
0619:
0620: Savepoint afterInsert = this .conn
0621: .setSavepoint("afterInsert");
0622: this .stmt
0623: .executeUpdate("UPDATE testSavepoints SET field1=2");
0624:
0625: Savepoint afterUpdate = this .conn
0626: .setSavepoint("afterUpdate");
0627: this .stmt
0628: .executeUpdate("DELETE FROM testSavepoints");
0629:
0630: assertTrue("Row count should be 0",
0631: getRowCount("testSavepoints") == 0);
0632: this .conn.rollback(afterUpdate);
0633: assertTrue("Row count should be 1",
0634: getRowCount("testSavepoints") == 1);
0635: assertTrue("Value should be 2", "2"
0636: .equals(getSingleValue("testSavepoints",
0637: "field1", null).toString()));
0638: this .conn.rollback(afterInsert);
0639: assertTrue("Value should be 1", "1"
0640: .equals(getSingleValue("testSavepoints",
0641: "field1", null).toString()));
0642: this .conn.rollback();
0643: assertTrue("Row count should be 0",
0644: getRowCount("testSavepoints") == 0);
0645:
0646: // Try with 'anonymous' save points
0647: this .conn.rollback();
0648:
0649: this .stmt
0650: .executeUpdate("INSERT INTO testSavepoints VALUES (1)");
0651: afterInsert = this .conn.setSavepoint();
0652: this .stmt
0653: .executeUpdate("UPDATE testSavepoints SET field1=2");
0654: afterUpdate = this .conn.setSavepoint();
0655: this .stmt
0656: .executeUpdate("DELETE FROM testSavepoints");
0657:
0658: assertTrue("Row count should be 0",
0659: getRowCount("testSavepoints") == 0);
0660: this .conn.rollback(afterUpdate);
0661: assertTrue("Row count should be 1",
0662: getRowCount("testSavepoints") == 1);
0663: assertTrue("Value should be 2", "2"
0664: .equals(getSingleValue("testSavepoints",
0665: "field1", null).toString()));
0666: this .conn.rollback(afterInsert);
0667: assertTrue("Value should be 1", "1"
0668: .equals(getSingleValue("testSavepoints",
0669: "field1", null).toString()));
0670: this .conn.rollback();
0671:
0672: this .conn
0673: .releaseSavepoint(this .conn.setSavepoint());
0674: } finally {
0675: this .conn.setAutoCommit(true);
0676: this .stmt
0677: .executeUpdate("DROP TABLE IF EXISTS testSavepoints");
0678: }
0679: } else {
0680: System.out
0681: .println("MySQL version does not support SAVEPOINTs");
0682: }
0683: }
0684: }
0685:
0686: /**
0687: * Tests the ability to set the connection collation via properties.
0688: *
0689: * @throws Exception
0690: * if an error occurs or the test fails
0691: */
0692: public void testNonStandardConnectionCollation() throws Exception {
0693: if (versionMeetsMinimum(4, 1)) {
0694: String collationToSet = "utf8_bin";
0695: String characterSet = "utf-8";
0696:
0697: Properties props = new Properties();
0698: props.setProperty("connectionCollation", collationToSet);
0699: props.setProperty("characterEncoding", characterSet);
0700:
0701: Connection collConn = null;
0702: Statement collStmt = null;
0703: ResultSet collRs = null;
0704:
0705: try {
0706: collConn = getConnectionWithProps(props);
0707:
0708: collStmt = collConn.createStatement();
0709:
0710: collRs = collStmt
0711: .executeQuery("SHOW VARIABLES LIKE 'collation_connection'");
0712:
0713: assertTrue(collRs.next());
0714: assertTrue(collationToSet.equalsIgnoreCase(collRs
0715: .getString(2)));
0716: } finally {
0717: if (collConn != null) {
0718: collConn.close();
0719: }
0720: }
0721: }
0722: }
0723:
0724: public void testDumpQueriesOnException() throws Exception {
0725: Properties props = new Properties();
0726: props.setProperty("dumpQueriesOnException", "true");
0727: String bogusSQL = "SELECT 1 TO BAZ";
0728: Connection dumpConn = getConnectionWithProps(props);
0729:
0730: try {
0731: dumpConn.createStatement().executeQuery(bogusSQL);
0732: } catch (SQLException sqlEx) {
0733: assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
0734: }
0735:
0736: try {
0737: ((com.mysql.jdbc.Connection) dumpConn)
0738: .clientPrepareStatement(bogusSQL).executeQuery();
0739: } catch (SQLException sqlEx) {
0740: assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
0741: }
0742:
0743: try {
0744: this .stmt
0745: .executeUpdate("DROP TABLE IF EXISTS testDumpQueriesOnException");
0746: this .stmt
0747: .executeUpdate("CREATE TABLE testDumpQueriesOnException (field1 int UNIQUE)");
0748: this .stmt
0749: .executeUpdate("INSERT INTO testDumpQueriesOnException VALUES (1)");
0750:
0751: PreparedStatement pStmt = dumpConn
0752: .prepareStatement("INSERT INTO testDumpQueriesOnException VALUES (?)");
0753: pStmt.setInt(1, 1);
0754: pStmt.executeUpdate();
0755: } catch (SQLException sqlEx) {
0756: assertTrue(sqlEx.getMessage().indexOf(
0757: "INSERT INTO testDumpQueriesOnException") != -1);
0758: } finally {
0759: this .stmt
0760: .executeUpdate("DROP TABLE IF EXISTS testDumpQueriesOnException");
0761: }
0762:
0763: try {
0764: dumpConn.prepareStatement(bogusSQL);
0765: } catch (SQLException sqlEx) {
0766: assertTrue(sqlEx.getMessage().indexOf(bogusSQL) != -1);
0767: }
0768: }
0769:
0770: /**
0771: * Tests functionality of the ConnectionPropertiesTransform interface.
0772: *
0773: * @throws Exception
0774: * if the test fails.
0775: */
0776: public void testConnectionPropertiesTransform() throws Exception {
0777: String transformClassName = SimpleTransformer.class.getName();
0778:
0779: Properties props = new Properties();
0780:
0781: props.setProperty(
0782: NonRegisteringDriver.PROPERTIES_TRANSFORM_KEY,
0783: transformClassName);
0784:
0785: NonRegisteringDriver driver = new NonRegisteringDriver();
0786:
0787: Properties transformedProps = driver.parseURL(
0788: BaseTestCase.dbUrl, props);
0789:
0790: assertTrue("albequerque".equals(transformedProps
0791: .getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY)));
0792: }
0793:
0794: /**
0795: * Tests functionality of using URLs in 'LOAD DATA LOCAL INFILE' statements.
0796: *
0797: * @throws Exception
0798: * if the test fails.
0799: */
0800: public void testLocalInfileWithUrl() throws Exception {
0801: File infile = File.createTempFile("foo", "txt");
0802: infile.deleteOnExit();
0803: String url = infile.toURL().toExternalForm();
0804: FileWriter output = new FileWriter(infile);
0805: output.write("Test");
0806: output.flush();
0807: output.close();
0808:
0809: try {
0810: this .stmt
0811: .executeUpdate("DROP TABLE IF EXISTS testLocalInfileWithUrl");
0812: this .stmt
0813: .executeUpdate("CREATE TABLE testLocalInfileWithUrl (field1 LONGTEXT)");
0814:
0815: Properties props = new Properties();
0816: props.setProperty("allowUrlInLocalInfile", "true");
0817:
0818: Connection loadConn = getConnectionWithProps(props);
0819: Statement loadStmt = loadConn.createStatement();
0820:
0821: try {
0822: loadStmt.executeQuery("LOAD DATA LOCAL INFILE '" + url
0823: + "' INTO TABLE testLocalInfileWithUrl");
0824: } catch (SQLException sqlEx) {
0825: sqlEx.printStackTrace();
0826:
0827: throw sqlEx;
0828: }
0829:
0830: this .rs = this .stmt
0831: .executeQuery("SELECT * FROM testLocalInfileWithUrl");
0832: assertTrue(this .rs.next());
0833: assertTrue("Test".equals(this .rs.getString(1)));
0834: int count = this .stmt
0835: .executeUpdate("DELETE FROM testLocalInfileWithUrl");
0836: assertTrue(count == 1);
0837:
0838: StringBuffer escapedPath = new StringBuffer();
0839: String path = infile.getCanonicalPath();
0840:
0841: for (int i = 0; i < path.length(); i++) {
0842: char c = path.charAt(i);
0843:
0844: if (c == '\\') {
0845: escapedPath.append('\\');
0846: }
0847:
0848: escapedPath.append(c);
0849: }
0850:
0851: loadStmt.executeQuery("LOAD DATA LOCAL INFILE '"
0852: + escapedPath.toString()
0853: + "' INTO TABLE testLocalInfileWithUrl");
0854: this .rs = this .stmt
0855: .executeQuery("SELECT * FROM testLocalInfileWithUrl");
0856: assertTrue(this .rs.next());
0857: assertTrue("Test".equals(this .rs.getString(1)));
0858:
0859: try {
0860: loadStmt
0861: .executeQuery("LOAD DATA LOCAL INFILE 'foo:///' INTO TABLE testLocalInfileWithUrl");
0862: } catch (SQLException sqlEx) {
0863: assertTrue(sqlEx.getMessage() != null);
0864: assertTrue(sqlEx.getMessage().indexOf(
0865: "FileNotFoundException") != -1);
0866: }
0867:
0868: } finally {
0869: this .stmt
0870: .executeUpdate("DROP TABLE IF EXISTS testLocalInfileWithUrl");
0871: }
0872: }
0873:
0874: public void testLocalInfileDisabled() throws Exception {
0875: createTable("testLocalInfileDisabled", "(field1 varchar(255))");
0876:
0877: File infile = File.createTempFile("foo", "txt");
0878: infile.deleteOnExit();
0879: String url = infile.toURL().toExternalForm();
0880: FileWriter output = new FileWriter(infile);
0881: output.write("Test");
0882: output.flush();
0883: output.close();
0884:
0885: Connection loadConn = getConnectionWithProps(new Properties());
0886:
0887: try {
0888: // have to do this after connect, otherwise it's the server
0889: // that's enforcing it
0890: ((com.mysql.jdbc.Connection) loadConn)
0891: .setAllowLoadLocalInfile(false);
0892: try {
0893: loadConn
0894: .createStatement()
0895: .execute(
0896: "LOAD DATA LOCAL INFILE '"
0897: + infile.getCanonicalPath()
0898: + "' INTO TABLE testLocalInfileDisabled");
0899: fail("Should've thrown an exception.");
0900: } catch (SQLException sqlEx) {
0901: assertEquals(SQLError.SQL_STATE_GENERAL_ERROR, sqlEx
0902: .getSQLState());
0903: }
0904:
0905: assertFalse(loadConn.createStatement().executeQuery(
0906: "SELECT * FROM testLocalInfileDisabled").next());
0907: } finally {
0908: loadConn.close();
0909: }
0910: }
0911:
0912: public void testServerConfigurationCache() throws Exception {
0913: Properties props = new Properties();
0914:
0915: props.setProperty("cacheServerConfiguration", "true");
0916: props.setProperty("profileSQL", "true");
0917: props.setProperty("logFactory",
0918: "com.mysql.jdbc.log.StandardLogger");
0919:
0920: Connection conn1 = getConnectionWithProps(props);
0921:
0922: StandardLogger.saveLogsToBuffer();
0923:
0924: Connection conn2 = getConnectionWithProps(props);
0925:
0926: assertTrue("Configuration wasn't cached",
0927: StandardLogger.bufferedLog.toString().indexOf(
0928: "SHOW VARIABLES") == -1);
0929:
0930: if (versionMeetsMinimum(4, 1)) {
0931: assertTrue("Configuration wasn't cached",
0932: StandardLogger.bufferedLog.toString().indexOf(
0933: "SHOW COLLATION") == -1);
0934:
0935: }
0936: }
0937:
0938: /**
0939: * Tests whether or not the configuration 'useLocalSessionState' actually
0940: * prevents non-needed 'set autocommit=', 'set session transaction isolation
0941: * ...' and 'show variables like tx_isolation' queries.
0942: *
0943: * @throws Exception
0944: * if the test fails.
0945: */
0946: public void testUseLocalSessionState() throws Exception {
0947: Properties props = new Properties();
0948:
0949: props.setProperty("useLocalSessionState", "true");
0950: props.setProperty("profileSQL", "true");
0951: props.setProperty("logFactory",
0952: "com.mysql.jdbc.log.StandardLogger");
0953:
0954: Connection conn1 = getConnectionWithProps(props);
0955: conn1.setAutoCommit(true);
0956: conn1
0957: .setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
0958:
0959: StandardLogger.saveLogsToBuffer();
0960: StandardLogger.bufferedLog.setLength(0);
0961:
0962: conn1.setAutoCommit(true);
0963: conn1
0964: .setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
0965: conn1.getTransactionIsolation();
0966:
0967: String logAsString = StandardLogger.bufferedLog.toString();
0968:
0969: assertTrue(logAsString.indexOf("SET SESSION") == -1
0970: && logAsString
0971: .indexOf("SHOW VARIABLES LIKE 'tx_isolation'") == -1
0972: && logAsString.indexOf("SET autocommit=") == -1);
0973:
0974: }
0975:
0976: /**
0977: * Tests whether re-connect with non-read-only connection can happen.
0978: *
0979: * @throws Exception
0980: * if the test fails.
0981: */
0982: public void testFailoverConnection() throws Exception {
0983:
0984: if (!isServerRunningOnWindows()) { // windows sockets don't
0985: // work for this test
0986: Properties props = new Properties();
0987: props.setProperty("autoReconnect", "true");
0988: props.setProperty("failOverReadOnly", "false");
0989:
0990: // Re-build the connection information
0991: int firstIndexOfHost = BaseTestCase.dbUrl.indexOf("//") + 2;
0992: int lastIndexOfHost = BaseTestCase.dbUrl.indexOf("/",
0993: firstIndexOfHost);
0994:
0995: String hostPortPair = BaseTestCase.dbUrl.substring(
0996: firstIndexOfHost, lastIndexOfHost);
0997: System.out.println(hostPortPair);
0998:
0999: StringTokenizer st = new StringTokenizer(hostPortPair, ":");
1000:
1001: String host = null;
1002: String port = null;
1003:
1004: if (st.hasMoreTokens()) {
1005: String possibleHostOrPort = st.nextToken();
1006:
1007: if (Character.isDigit(possibleHostOrPort.charAt(0))
1008: && (possibleHostOrPort.indexOf(".") == -1 /* IPV4 */)
1009: && (possibleHostOrPort.indexOf("::") == -1 /* IPV6 */)) {
1010: port = possibleHostOrPort;
1011: host = "localhost";
1012: } else {
1013: host = possibleHostOrPort;
1014: }
1015: }
1016:
1017: if (host == null) {
1018: host = "localhost";
1019: }
1020:
1021: if (st.hasMoreTokens()) {
1022: port = st.nextToken();
1023: }
1024:
1025: StringBuffer newHostBuf = new StringBuffer();
1026: newHostBuf.append(host);
1027: if (port != null) {
1028: newHostBuf.append(":");
1029: newHostBuf.append(port);
1030: }
1031: newHostBuf.append(",");
1032: newHostBuf.append(host);
1033: if (port != null) {
1034: newHostBuf.append(":");
1035: newHostBuf.append(port);
1036: }
1037:
1038: props.put(NonRegisteringDriver.HOST_PROPERTY_KEY,
1039: newHostBuf.toString());
1040:
1041: Connection failoverConnection = null;
1042:
1043: try {
1044: failoverConnection = getConnectionWithProps(props);
1045:
1046: String originalConnectionId = getSingleIndexedValueWithQuery(
1047: failoverConnection, 1, "SELECT connection_id()")
1048: .toString();
1049: System.out.println("Original Connection Id = "
1050: + originalConnectionId);
1051:
1052: assertTrue(
1053: "Connection should not be in READ_ONLY state",
1054: !failoverConnection.isReadOnly());
1055:
1056: // Kill the connection
1057: this .stmt.executeUpdate("KILL " + originalConnectionId);
1058:
1059: // This takes a bit to occur
1060:
1061: Thread.sleep(3000);
1062:
1063: try {
1064: failoverConnection.createStatement().executeQuery(
1065: "SELECT 1");
1066: fail("We expect an exception here, because the connection should be gone until the reconnect code picks it up again");
1067: } catch (SQLException sqlEx) {
1068: ; // do-nothing
1069: }
1070:
1071: // Tickle re-connect
1072:
1073: failoverConnection.setAutoCommit(true);
1074:
1075: String newConnectionId = getSingleIndexedValueWithQuery(
1076: failoverConnection, 1, "SELECT connection_id()")
1077: .toString();
1078: System.out.println("new Connection Id = "
1079: + newConnectionId);
1080:
1081: assertTrue(
1082: "We should have a new connection to the server in this case",
1083: !newConnectionId.equals(originalConnectionId));
1084: assertTrue("Connection should not be read-only",
1085: !failoverConnection.isReadOnly());
1086: } finally {
1087: if (failoverConnection != null) {
1088: failoverConnection.close();
1089: }
1090: }
1091: }
1092: }
1093:
1094: public void testCannedConfigs() throws Exception {
1095: String url = "jdbc:mysql:///?useConfigs=clusterBase";
1096:
1097: Properties cannedProps = new NonRegisteringDriver().parseURL(
1098: url, null);
1099:
1100: assertTrue("true".equals(cannedProps
1101: .getProperty("autoReconnect")));
1102: assertTrue("false".equals(cannedProps
1103: .getProperty("failOverReadOnly")));
1104: assertTrue("true".equals(cannedProps
1105: .getProperty("roundRobinLoadBalance")));
1106:
1107: // this will fail, but we test that too
1108: url = "jdbc:mysql:///?useConfigs=clusterBase,clusterBase2";
1109:
1110: try {
1111: cannedProps = new NonRegisteringDriver()
1112: .parseURL(url, null);
1113: fail("should've bailed on that one!");
1114: } catch (SQLException sqlEx) {
1115: assertTrue(SQLError.SQL_STATE_INVALID_CONNECTION_ATTRIBUTE
1116: .equals(sqlEx.getSQLState()));
1117: }
1118: }
1119:
1120: public void testUseOldUTF8Behavior() throws Exception {
1121:
1122: Properties props = new Properties();
1123: props.setProperty("useOldUTF8Behavior", "true");
1124: props.setProperty("useUnicode", "true");
1125: props.setProperty("characterEncoding", "UTF-8");
1126: props.setProperty("logFactory",
1127: "com.mysql.jdbc.log.StandardLogger");
1128: props.setProperty("profileSQL", "true");
1129: StandardLogger.saveLogsToBuffer();
1130: StandardLogger.bufferedLog.setLength(0);
1131:
1132: try {
1133: getConnectionWithProps(props);
1134:
1135: assertTrue(StringUtils.indexOfIgnoreCase(
1136: StandardLogger.bufferedLog.toString(),
1137: "SET NAMES utf8") == -1);
1138: } finally {
1139: StandardLogger.bufferedLog = null;
1140: }
1141: }
1142:
1143: /**
1144: * Checks implementation of 'dontTrackOpenResources' property.
1145: *
1146: * @throws Exception
1147: * if the test fails.
1148: */
1149: public void testDontTrackOpenResources() throws Exception {
1150: Properties props = new Properties();
1151:
1152: props.setProperty("dontTrackOpenResources", "true");
1153: Connection noTrackConn = null;
1154: Statement noTrackStatement = null;
1155: PreparedStatement noTrackPstmt = null;
1156: ResultSet rs2 = null;
1157:
1158: try {
1159: noTrackConn = getConnectionWithProps(props);
1160: noTrackStatement = noTrackConn.createStatement();
1161: noTrackPstmt = noTrackConn.prepareStatement("SELECT 1");
1162: rs2 = noTrackPstmt.executeQuery();
1163: rs2.next();
1164:
1165: this .rs = noTrackStatement.executeQuery("SELECT 1");
1166: this .rs.next();
1167:
1168: noTrackConn.close();
1169:
1170: // Under 'strict' JDBC requirements, these calls should fail
1171: // (and _do_ if dontTrackOpenResources == false)
1172:
1173: this .rs.getString(1);
1174: rs2.getString(1);
1175: } finally {
1176: if (rs2 != null) {
1177: rs2.close();
1178: }
1179:
1180: if (noTrackStatement != null) {
1181: noTrackStatement.close();
1182: }
1183:
1184: if (noTrackConn != null && !noTrackConn.isClosed()) {
1185: noTrackConn.close();
1186: }
1187: }
1188: }
1189:
1190: public void testPing() throws SQLException {
1191: Connection conn2 = getConnectionWithProps((String) null);
1192:
1193: ((com.mysql.jdbc.Connection) conn2).ping();
1194: conn2.close();
1195:
1196: try {
1197: ((com.mysql.jdbc.Connection) conn2).ping();
1198: fail("Should have failed with an exception");
1199: } catch (SQLException sqlEx) {
1200: // ignore for now
1201: }
1202:
1203: //
1204: // This feature caused BUG#8975, so check for that too!
1205:
1206: Properties props = new Properties();
1207: props.setProperty("autoReconnect", "true");
1208:
1209: getConnectionWithProps(props);
1210: }
1211:
1212: public void testSessionVariables() throws Exception {
1213: String getInitialMaxAllowedPacket = getMysqlVariable("max_allowed_packet");
1214:
1215: int newMaxAllowedPacket = Integer
1216: .parseInt(getInitialMaxAllowedPacket) + 1024;
1217:
1218: Properties props = new Properties();
1219: props.setProperty("sessionVariables", "max_allowed_packet="
1220: + newMaxAllowedPacket);
1221: props.setProperty("profileSQL", "true");
1222:
1223: Connection varConn = getConnectionWithProps(props);
1224:
1225: assertTrue(!getInitialMaxAllowedPacket.equals(getMysqlVariable(
1226: varConn, "max_allowed_packet")));
1227: }
1228:
1229: /**
1230: * Tests setting profileSql on/off in the span of one connection.
1231: *
1232: * @throws Exception
1233: * if an error occurs.
1234: */
1235: public void testSetProfileSql() throws Exception {
1236: ((com.mysql.jdbc.Connection) this .conn).setProfileSql(false);
1237: stmt.executeQuery("SELECT 1");
1238: ((com.mysql.jdbc.Connection) this .conn).setProfileSql(true);
1239: stmt.executeQuery("SELECT 1");
1240: }
1241:
1242: public void testCreateDatabaseIfNotExist() throws Exception {
1243: if (isAdminConnectionConfigured()) {
1244: Properties props = new Properties();
1245: props.setProperty("createDatabaseIfNotExist", "true");
1246: props.setProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY,
1247: "testcreatedatabaseifnotexists");
1248:
1249: Connection newConn = getAdminConnectionWithProps(props);
1250: newConn.createStatement().executeUpdate(
1251: "DROP DATABASE testcreatedatabaseifnotexists");
1252: }
1253: }
1254:
1255: /**
1256: * Tests if gatherPerfMetrics works.
1257: *
1258: * @throws Exception if the test fails
1259: */
1260: public void testGatherPerfMetrics() throws Exception {
1261: if (versionMeetsMinimum(4, 1)) {
1262: try {
1263: Properties props = new Properties();
1264: props.put("autoReconnect", "true");
1265: props.put("relaxAutoCommit", "true");
1266: props.put("logSlowQueries", "true");
1267: props.put("slowQueryThresholdMillis", "2000");
1268: // these properties were reported as the cause of NullPointerException
1269: props.put("gatherPerfMetrics", "true");
1270: props.put("reportMetricsIntervalMillis", "3000");
1271:
1272: Connection conn1 = getConnectionWithProps(props);
1273: Statement stmt1 = conn1.createStatement();
1274: ResultSet rs1 = stmt1.executeQuery("SELECT 1");
1275: rs1.next();
1276: conn1.close();
1277: } catch (NullPointerException e) {
1278: e.printStackTrace();
1279: fail();
1280: }
1281: }
1282: }
1283:
1284: /**
1285: * Tests if useCompress works.
1286: *
1287: * @throws Exception if the test fails
1288: */
1289: public void testUseCompress() throws Exception {
1290: Properties props = new Properties();
1291: props.put("useCompression", "true");
1292: props.put("traceProtocol", "true");
1293: Connection conn1 = getConnectionWithProps(props);
1294: Statement stmt1 = conn1.createStatement();
1295: ResultSet rs1 = stmt1.executeQuery("SELECT VERSION()");
1296: rs1.next();
1297: rs1.getString(1);
1298: stmt1.close();
1299: conn1.close();
1300: }
1301:
1302: /**
1303: * Tests feature of "localSocketAddress", by enumerating local IF's and
1304: * trying each one in turn. This test might take a long time to run, since
1305: * we can't set timeouts if we're using localSocketAddress. We try and keep
1306: * the time down on the testcase by spawning the checking of each interface
1307: * off into separate threads.
1308: *
1309: * @throws Exception if the test can't use at least one of the local machine's
1310: * interfaces to make an outgoing connection to the server.
1311: */
1312: public void testLocalSocketAddress() throws Exception {
1313: if (isRunningOnJdk131()) {
1314: return;
1315: }
1316:
1317: Enumeration allInterfaces = NetworkInterface
1318: .getNetworkInterfaces();
1319:
1320: SpawnedWorkerCounter counter = new SpawnedWorkerCounter();
1321:
1322: List allChecks = new ArrayList();
1323:
1324: while (allInterfaces.hasMoreElements()) {
1325: NetworkInterface intf = (NetworkInterface) allInterfaces
1326: .nextElement();
1327:
1328: Enumeration allAddresses = intf.getInetAddresses();
1329:
1330: allChecks.add(new LocalSocketAddressCheckThread(
1331: allAddresses, counter));
1332: }
1333:
1334: counter.setWorkerCount(allChecks.size());
1335:
1336: for (Iterator it = allChecks.iterator(); it.hasNext();) {
1337: LocalSocketAddressCheckThread t = (LocalSocketAddressCheckThread) it
1338: .next();
1339: t.start();
1340: }
1341:
1342: // Wait for tests to complete....
1343: synchronized (counter) {
1344:
1345: while (counter.workerCount > 0 /* safety valve */) {
1346:
1347: counter.wait();
1348:
1349: if (counter.workerCount == 0) {
1350: System.out.println("Done!");
1351: break;
1352: }
1353: }
1354: }
1355:
1356: boolean didOneWork = false;
1357: boolean didOneFail = false;
1358:
1359: for (Iterator it = allChecks.iterator(); it.hasNext();) {
1360: LocalSocketAddressCheckThread t = (LocalSocketAddressCheckThread) it
1361: .next();
1362:
1363: if (t.atLeastOneWorked) {
1364: didOneWork = true;
1365:
1366: break;
1367: } else {
1368: if (!didOneFail) {
1369: didOneFail = true;
1370: }
1371: }
1372: }
1373:
1374: assertTrue(
1375: "At least one connection was made with the localSocketAddress set",
1376: didOneWork);
1377:
1378: NonRegisteringDriver d = new NonRegisteringDriver();
1379:
1380: String hostname = d.host(d.parseURL(dbUrl, null));
1381:
1382: if (!hostname.startsWith(":")
1383: && !hostname.startsWith("localhost")) {
1384:
1385: int indexOfColon = hostname.indexOf(":");
1386:
1387: if (indexOfColon != -1) {
1388: hostname = hostname.substring(0, indexOfColon);
1389: }
1390:
1391: boolean isLocalIf = false;
1392:
1393: isLocalIf = (null != NetworkInterface.getByName(hostname));
1394:
1395: if (!isLocalIf) {
1396: try {
1397: isLocalIf = (null != NetworkInterface
1398: .getByInetAddress(InetAddress
1399: .getByName(hostname)));
1400: } catch (Throwable t) {
1401: isLocalIf = false;
1402: }
1403: }
1404:
1405: if (!isLocalIf) {
1406: assertTrue(
1407: "At least one connection didn't fail with localSocketAddress set",
1408: didOneFail);
1409: }
1410: }
1411: }
1412:
1413: class SpawnedWorkerCounter {
1414: private int workerCount = 0;
1415:
1416: synchronized void setWorkerCount(int i) {
1417: workerCount = i;
1418: }
1419:
1420: synchronized void decrementWorkerCount() {
1421: workerCount--;
1422: notify();
1423: }
1424: }
1425:
1426: class LocalSocketAddressCheckThread extends Thread {
1427: boolean atLeastOneWorked = false;
1428: Enumeration allAddresses = null;
1429: SpawnedWorkerCounter counter = null;
1430:
1431: LocalSocketAddressCheckThread(Enumeration e,
1432: SpawnedWorkerCounter c) {
1433: allAddresses = e;
1434: counter = c;
1435: }
1436:
1437: public void run() {
1438:
1439: while (allAddresses.hasMoreElements()) {
1440: InetAddress addr = (InetAddress) allAddresses
1441: .nextElement();
1442:
1443: try {
1444: Properties props = new Properties();
1445: props.setProperty("localSocketAddress", addr
1446: .getHostAddress());
1447: props.setProperty("connectTimeout", "2000");
1448: getConnectionWithProps(props).close();
1449:
1450: atLeastOneWorked = true;
1451:
1452: break;
1453: } catch (SQLException sqlEx) {
1454: // ignore, we're only seeing if one of these tests succeeds
1455: }
1456: }
1457:
1458: counter.decrementWorkerCount();
1459: }
1460: }
1461:
1462: public void testUsageAdvisorTooLargeResultSet() throws Exception {
1463: Connection uaConn = null;
1464:
1465: PrintStream stderr = System.err;
1466:
1467: StringBuffer logBuf = new StringBuffer();
1468:
1469: StandardLogger.bufferedLog = logBuf;
1470:
1471: try {
1472: Properties props = new Properties();
1473: props.setProperty("useUsageAdvisor", "true");
1474: props.setProperty("resultSetSizeThreshold", "4");
1475: props.setProperty("logger", "StandardLogger");
1476:
1477: uaConn = getConnectionWithProps(props);
1478:
1479: assertTrue(
1480: "Result set threshold message not present",
1481: logBuf
1482: .toString()
1483: .indexOf(
1484: "larger than \"resultSetSizeThreshold\" of 4 rows") != -1);
1485: } finally {
1486: System.setErr(stderr);
1487:
1488: closeMemberJDBCResources();
1489:
1490: if (uaConn != null) {
1491: uaConn.close();
1492: }
1493: }
1494: }
1495:
1496: public void testUseLocalSessionStateRollback() throws Exception {
1497: if (!versionMeetsMinimum(5, 0, 0)) {
1498: return;
1499: }
1500:
1501: Properties props = new Properties();
1502: props.setProperty("useLocalSessionState", "true");
1503: props.setProperty("profileSQL", "true");
1504:
1505: StringBuffer buf = new StringBuffer();
1506: StandardLogger.bufferedLog = buf;
1507:
1508: createTable("testUseLocalSessionState",
1509: "(field1 varchar(32)) ENGINE=InnoDB");
1510:
1511: Connection localStateConn = null;
1512: Statement localStateStmt = null;
1513:
1514: try {
1515: localStateConn = getConnectionWithProps(props);
1516: localStateStmt = localStateConn.createStatement();
1517:
1518: localStateConn.setAutoCommit(false);
1519: localStateStmt
1520: .executeUpdate("INSERT INTO testUseLocalSessionState VALUES ('abc')");
1521: localStateConn.rollback();
1522: localStateConn.rollback();
1523: localStateStmt
1524: .executeUpdate("INSERT INTO testUseLocalSessionState VALUES ('abc')");
1525: localStateConn.commit();
1526: localStateConn.commit();
1527: localStateStmt.close();
1528: } finally {
1529: StandardLogger.bufferedLog = null;
1530:
1531: if (localStateStmt != null) {
1532: localStateStmt.close();
1533: }
1534:
1535: if (localStateConn != null) {
1536: localStateConn.close();
1537: }
1538: }
1539:
1540: int rollbackCount = 0;
1541: int rollbackPos = 0;
1542:
1543: String searchIn = buf.toString();
1544:
1545: while (rollbackPos != -1) {
1546: rollbackPos = searchIn.indexOf("rollback", rollbackPos);
1547:
1548: if (rollbackPos != -1) {
1549: rollbackPos += "rollback".length();
1550: rollbackCount++;
1551: }
1552: }
1553:
1554: assertEquals(1, rollbackCount);
1555:
1556: int commitCount = 0;
1557: int commitPos = 0;
1558:
1559: // space is important here, we don't want to count "autocommit"
1560: while (commitPos != -1) {
1561: commitPos = searchIn.indexOf(" commit", commitPos);
1562:
1563: if (commitPos != -1) {
1564: commitPos += " commit".length();
1565: commitCount++;
1566: }
1567: }
1568:
1569: assertEquals(1, commitCount);
1570: }
1571:
1572: /**
1573: * Checks if setting useCursorFetch to "true" automatically
1574: * enables server-side prepared statements.
1575: */
1576:
1577: public void testCouplingOfCursorFetch() throws Exception {
1578: if (!versionMeetsMinimum(5, 0)) {
1579: return;
1580: }
1581:
1582: Connection fetchConn = null;
1583:
1584: try {
1585: Properties props = new Properties();
1586: props.setProperty("useServerPrepStmts", "false"); // force the issue
1587: props.setProperty("useCursorFetch", "true");
1588: fetchConn = getConnectionWithProps(props);
1589: assertEquals("com.mysql.jdbc.ServerPreparedStatement",
1590: fetchConn.prepareStatement("SELECT 1").getClass()
1591: .getName());
1592: } finally {
1593: if (fetchConn != null) {
1594: fetchConn.close();
1595: }
1596: }
1597: }
1598: }
|