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.regression;
0026:
0027: import java.io.ByteArrayOutputStream;
0028: import java.io.PrintStream;
0029: import java.lang.reflect.Field;
0030: import java.lang.reflect.InvocationTargetException;
0031: import java.lang.reflect.Method;
0032: import java.sql.Connection;
0033: import java.sql.DriverManager;
0034: import java.sql.DriverPropertyInfo;
0035: import java.sql.PreparedStatement;
0036: import java.sql.ResultSet;
0037: import java.sql.SQLException;
0038: import java.sql.Statement;
0039: import java.util.HashMap;
0040: import java.util.Iterator;
0041: import java.util.Locale;
0042: import java.util.Map;
0043: import java.util.Properties;
0044: import java.util.StringTokenizer;
0045:
0046: import testsuite.BaseTestCase;
0047:
0048: import com.mysql.jdbc.ConnectionImpl;
0049: import com.mysql.jdbc.Driver;
0050: import com.mysql.jdbc.NonRegisteringDriver;
0051: import com.mysql.jdbc.ReplicationConnection;
0052: import com.mysql.jdbc.ReplicationDriver;
0053: import com.mysql.jdbc.log.StandardLogger;
0054:
0055: /**
0056: * Regression tests for Connections
0057: *
0058: * @author Mark Matthews
0059: * @version $Id: ConnectionRegressionTest.java,v 1.1.2.1 2005/05/13 18:58:38
0060: * mmatthews Exp $
0061: */
0062: public class ConnectionRegressionTest extends BaseTestCase {
0063: /**
0064: * DOCUMENT ME!
0065: *
0066: * @param name
0067: * the name of the testcase
0068: */
0069: public ConnectionRegressionTest(String name) {
0070: super (name);
0071: }
0072:
0073: /**
0074: * Runs all test cases in this test suite
0075: *
0076: * @param args
0077: */
0078: public static void main(String[] args) {
0079: junit.textui.TestRunner.run(ConnectionRegressionTest.class);
0080: }
0081:
0082: /**
0083: * DOCUMENT ME!
0084: *
0085: * @throws Exception
0086: * ...
0087: */
0088: public void testBug1914() throws Exception {
0089: System.out.println(this .conn
0090: .nativeSQL("{fn convert(foo(a,b,c), BIGINT)}"));
0091: System.out.println(this .conn
0092: .nativeSQL("{fn convert(foo(a,b,c), BINARY)}"));
0093: System.out.println(this .conn
0094: .nativeSQL("{fn convert(foo(a,b,c), BIT)}"));
0095: System.out.println(this .conn
0096: .nativeSQL("{fn convert(foo(a,b,c), CHAR)}"));
0097: System.out.println(this .conn
0098: .nativeSQL("{fn convert(foo(a,b,c), DATE)}"));
0099: System.out.println(this .conn
0100: .nativeSQL("{fn convert(foo(a,b,c), DECIMAL)}"));
0101: System.out.println(this .conn
0102: .nativeSQL("{fn convert(foo(a,b,c), DOUBLE)}"));
0103: System.out.println(this .conn
0104: .nativeSQL("{fn convert(foo(a,b,c), FLOAT)}"));
0105: System.out.println(this .conn
0106: .nativeSQL("{fn convert(foo(a,b,c), INTEGER)}"));
0107: System.out.println(this .conn
0108: .nativeSQL("{fn convert(foo(a,b,c), LONGVARBINARY)}"));
0109: System.out.println(this .conn
0110: .nativeSQL("{fn convert(foo(a,b,c), LONGVARCHAR)}"));
0111: System.out.println(this .conn
0112: .nativeSQL("{fn convert(foo(a,b,c), TIME)}"));
0113: System.out.println(this .conn
0114: .nativeSQL("{fn convert(foo(a,b,c), TIMESTAMP)}"));
0115: System.out.println(this .conn
0116: .nativeSQL("{fn convert(foo(a,b,c), TINYINT)}"));
0117: System.out.println(this .conn
0118: .nativeSQL("{fn convert(foo(a,b,c), VARBINARY)}"));
0119: System.out.println(this .conn
0120: .nativeSQL("{fn convert(foo(a,b,c), VARCHAR)}"));
0121: }
0122:
0123: /**
0124: * Tests fix for BUG#3554 - Not specifying database in URL causes
0125: * MalformedURL exception.
0126: *
0127: * @throws Exception
0128: * if an error ocurrs.
0129: */
0130: public void testBug3554() throws Exception {
0131: try {
0132: new NonRegisteringDriver()
0133: .connect(
0134: "jdbc:mysql://localhost:3306/?user=root&password=root",
0135: new Properties());
0136: } catch (SQLException sqlEx) {
0137: assertTrue(sqlEx.getMessage().indexOf("Malformed") == -1);
0138: }
0139: }
0140:
0141: /**
0142: * DOCUMENT ME!
0143: *
0144: * @throws Exception
0145: * ...
0146: */
0147: public void testBug3790() throws Exception {
0148: String field2OldValue = "foo";
0149: String field2NewValue = "bar";
0150: int field1OldValue = 1;
0151:
0152: Connection conn1 = null;
0153: Connection conn2 = null;
0154: Statement stmt1 = null;
0155: Statement stmt2 = null;
0156: ResultSet rs2 = null;
0157:
0158: Properties props = new Properties();
0159:
0160: try {
0161: this .stmt.executeUpdate("DROP TABLE IF EXISTS testBug3790");
0162: this .stmt
0163: .executeUpdate("CREATE TABLE testBug3790 (field1 INT NOT NULL PRIMARY KEY, field2 VARCHAR(32)) TYPE=InnoDB");
0164: this .stmt.executeUpdate("INSERT INTO testBug3790 VALUES ("
0165: + field1OldValue + ", '" + field2OldValue + "')");
0166:
0167: conn1 = getConnectionWithProps(props); // creates a new connection
0168: conn2 = getConnectionWithProps(props); // creates another new
0169: // connection
0170: conn1.setAutoCommit(false);
0171: conn2.setAutoCommit(false);
0172:
0173: stmt1 = conn1.createStatement();
0174: stmt1.executeUpdate("UPDATE testBug3790 SET field2 = '"
0175: + field2NewValue + "' WHERE field1="
0176: + field1OldValue);
0177: conn1.commit();
0178:
0179: stmt2 = conn2.createStatement();
0180:
0181: rs2 = stmt2
0182: .executeQuery("SELECT field1, field2 FROM testBug3790");
0183:
0184: assertTrue(rs2.next());
0185: assertTrue(rs2.getInt(1) == field1OldValue);
0186: assertTrue(rs2.getString(2).equals(field2NewValue));
0187: } finally {
0188: this .stmt.executeUpdate("DROP TABLE IF EXISTS testBug3790");
0189:
0190: if (rs2 != null) {
0191: rs2.close();
0192: }
0193:
0194: if (stmt2 != null) {
0195: stmt2.close();
0196: }
0197:
0198: if (stmt1 != null) {
0199: stmt1.close();
0200: }
0201:
0202: if (conn1 != null) {
0203: conn1.close();
0204: }
0205:
0206: if (conn2 != null) {
0207: conn2.close();
0208: }
0209: }
0210: }
0211:
0212: /**
0213: * Tests if the driver configures character sets correctly for 4.1.x
0214: * servers. Requires that the 'admin connection' is configured, as this test
0215: * needs to create/drop databases.
0216: *
0217: * @throws Exception
0218: * if an error occurs
0219: */
0220: public void testCollation41() throws Exception {
0221: if (versionMeetsMinimum(4, 1) && isAdminConnectionConfigured()) {
0222: Map charsetsAndCollations = getCharacterSetsAndCollations();
0223: charsetsAndCollations.remove("latin7"); // Maps to multiple Java
0224: // charsets
0225: charsetsAndCollations.remove("ucs2"); // can't be used as a
0226: // connection charset
0227:
0228: Iterator charsets = charsetsAndCollations.keySet()
0229: .iterator();
0230:
0231: while (charsets.hasNext()) {
0232: Connection charsetConn = null;
0233: Statement charsetStmt = null;
0234:
0235: try {
0236: String charsetName = charsets.next().toString();
0237: String collationName = charsetsAndCollations.get(
0238: charsetName).toString();
0239: Properties props = new Properties();
0240: props.put("characterEncoding", charsetName);
0241:
0242: System.out.println("Testing character set "
0243: + charsetName);
0244:
0245: charsetConn = getAdminConnectionWithProps(props);
0246:
0247: charsetStmt = charsetConn.createStatement();
0248:
0249: charsetStmt
0250: .executeUpdate("DROP DATABASE IF EXISTS testCollation41");
0251: charsetStmt
0252: .executeUpdate("DROP TABLE IF EXISTS testCollation41");
0253:
0254: charsetStmt
0255: .executeUpdate("CREATE DATABASE testCollation41 DEFAULT CHARACTER SET "
0256: + charsetName);
0257: charsetConn.setCatalog("testCollation41");
0258:
0259: // We've switched catalogs, so we need to recreate the
0260: // statement to pick this up...
0261: charsetStmt = charsetConn.createStatement();
0262:
0263: StringBuffer createTableCommand = new StringBuffer(
0264: "CREATE TABLE testCollation41"
0265: + "(field1 VARCHAR(255), field2 INT)");
0266:
0267: charsetStmt.executeUpdate(createTableCommand
0268: .toString());
0269:
0270: charsetStmt
0271: .executeUpdate("INSERT INTO testCollation41 VALUES ('abc', 0)");
0272:
0273: int updateCount = charsetStmt
0274: .executeUpdate("UPDATE testCollation41 SET field2=1 WHERE field1='abc'");
0275: assertTrue(updateCount == 1);
0276: } finally {
0277: if (charsetStmt != null) {
0278: charsetStmt
0279: .executeUpdate("DROP TABLE IF EXISTS testCollation41");
0280: charsetStmt
0281: .executeUpdate("DROP DATABASE IF EXISTS testCollation41");
0282: charsetStmt.close();
0283: }
0284:
0285: if (charsetConn != null) {
0286: charsetConn.close();
0287: }
0288: }
0289: }
0290: }
0291: }
0292:
0293: /**
0294: * Tests setReadOnly() being reset during failover
0295: *
0296: * @throws Exception
0297: * if an error occurs.
0298: */
0299: public void testSetReadOnly() throws Exception {
0300: Properties props = new Properties();
0301: props.put("autoReconnect", "true");
0302:
0303: String sepChar = "?";
0304:
0305: if (BaseTestCase.dbUrl.indexOf("?") != -1) {
0306: sepChar = "&";
0307: }
0308:
0309: Connection reconnectableConn = DriverManager.getConnection(
0310: BaseTestCase.dbUrl + sepChar + "autoReconnect=true",
0311: props);
0312:
0313: this .rs = reconnectableConn.createStatement().executeQuery(
0314: "SELECT CONNECTION_ID()");
0315: this .rs.next();
0316:
0317: String connectionId = this .rs.getString(1);
0318:
0319: reconnectableConn.setReadOnly(true);
0320:
0321: boolean isReadOnly = reconnectableConn.isReadOnly();
0322:
0323: Connection killConn = getConnectionWithProps((Properties) null);
0324:
0325: killConn.createStatement()
0326: .executeUpdate("KILL " + connectionId);
0327: Thread.sleep(2000);
0328:
0329: SQLException caughtException = null;
0330:
0331: int numLoops = 8;
0332:
0333: while (caughtException == null && numLoops > 0) {
0334: numLoops--;
0335:
0336: try {
0337: reconnectableConn.createStatement().executeQuery(
0338: "SELECT 1");
0339: } catch (SQLException sqlEx) {
0340: caughtException = sqlEx;
0341: }
0342: }
0343:
0344: System.out
0345: .println("Executing statement on reconnectable connection...");
0346:
0347: this .rs = reconnectableConn.createStatement().executeQuery(
0348: "SELECT CONNECTION_ID()");
0349: this .rs.next();
0350: assertTrue("Connection is not a reconnected-connection",
0351: !connectionId.equals(this .rs.getString(1)));
0352:
0353: try {
0354: reconnectableConn.createStatement()
0355: .executeQuery("SELECT 1");
0356: } catch (SQLException sqlEx) {
0357: ; // ignore
0358: }
0359:
0360: reconnectableConn.createStatement().executeQuery("SELECT 1");
0361:
0362: assertTrue(reconnectableConn.isReadOnly() == isReadOnly);
0363: }
0364:
0365: private Map getCharacterSetsAndCollations() throws Exception {
0366: Map charsetsToLoad = new HashMap();
0367:
0368: try {
0369: this .rs = this .stmt.executeQuery("SHOW character set");
0370:
0371: while (this .rs.next()) {
0372: charsetsToLoad.put(this .rs.getString("Charset"),
0373: this .rs.getString("Default collation"));
0374: }
0375:
0376: //
0377: // These don't have mappings in Java...
0378: //
0379: charsetsToLoad.remove("swe7");
0380: charsetsToLoad.remove("hp8");
0381: charsetsToLoad.remove("dec8");
0382: charsetsToLoad.remove("koi8u");
0383: charsetsToLoad.remove("keybcs2");
0384: charsetsToLoad.remove("geostd8");
0385: charsetsToLoad.remove("armscii8");
0386: } finally {
0387: if (this .rs != null) {
0388: this .rs.close();
0389: }
0390: }
0391:
0392: return charsetsToLoad;
0393: }
0394:
0395: /**
0396: * Tests fix for BUG#4334, port #'s not being picked up for
0397: * failover/autoreconnect.
0398: *
0399: * @throws Exception
0400: * if an error occurs.
0401: */
0402: public void testBug4334() throws Exception {
0403: if (isAdminConnectionConfigured()) {
0404: Connection adminConnection = null;
0405:
0406: try {
0407: adminConnection = getAdminConnection();
0408:
0409: int bogusPortNumber = 65534;
0410:
0411: NonRegisteringDriver driver = new NonRegisteringDriver();
0412:
0413: Properties oldProps = driver.parseURL(
0414: BaseTestCase.dbUrl, null);
0415:
0416: String host = driver.host(oldProps);
0417: int port = driver.port(oldProps);
0418: String database = oldProps
0419: .getProperty(NonRegisteringDriver.DBNAME_PROPERTY_KEY);
0420: String user = oldProps
0421: .getProperty(NonRegisteringDriver.USER_PROPERTY_KEY);
0422: String password = oldProps
0423: .getProperty(NonRegisteringDriver.PASSWORD_PROPERTY_KEY);
0424:
0425: StringBuffer newUrlToTestPortNum = new StringBuffer(
0426: "jdbc:mysql://");
0427:
0428: if (host != null) {
0429: newUrlToTestPortNum.append(host);
0430: }
0431:
0432: newUrlToTestPortNum.append(":").append(port);
0433: newUrlToTestPortNum.append(",");
0434:
0435: if (host != null) {
0436: newUrlToTestPortNum.append(host);
0437: }
0438:
0439: newUrlToTestPortNum.append(":").append(bogusPortNumber);
0440: newUrlToTestPortNum.append("/");
0441:
0442: if (database != null) {
0443: newUrlToTestPortNum.append(database);
0444: }
0445:
0446: if ((user != null) || (password != null)) {
0447: newUrlToTestPortNum.append("?");
0448:
0449: if (user != null) {
0450: newUrlToTestPortNum.append("user=")
0451: .append(user);
0452:
0453: if (password != null) {
0454: newUrlToTestPortNum.append("&");
0455: }
0456: }
0457:
0458: if (password != null) {
0459: newUrlToTestPortNum.append("password=").append(
0460: password);
0461: }
0462: }
0463:
0464: Properties autoReconnectProps = new Properties();
0465: autoReconnectProps.put("autoReconnect", "true");
0466:
0467: System.out.println(newUrlToTestPortNum);
0468:
0469: //
0470: // First test that port #'s are being correctly picked up
0471: //
0472: // We do this by looking at the error message that is returned
0473: //
0474: Connection portNumConn = DriverManager.getConnection(
0475: newUrlToTestPortNum.toString(),
0476: autoReconnectProps);
0477: Statement portNumStmt = portNumConn.createStatement();
0478: this .rs = portNumStmt
0479: .executeQuery("SELECT connection_id()");
0480: this .rs.next();
0481:
0482: killConnection(adminConnection, this .rs.getString(1));
0483:
0484: try {
0485: portNumStmt.executeQuery("SELECT connection_id()");
0486: } catch (SQLException sqlEx) {
0487: // we expect this one
0488: }
0489:
0490: try {
0491: portNumStmt.executeQuery("SELECT connection_id()");
0492: } catch (SQLException sqlEx) {
0493: assertTrue(sqlEx.getMessage().toLowerCase()
0494: .indexOf("connection refused") != -1);
0495: }
0496:
0497: //
0498: // Now make sure failover works
0499: //
0500: StringBuffer newUrlToTestFailover = new StringBuffer(
0501: "jdbc:mysql://");
0502:
0503: if (host != null) {
0504: newUrlToTestFailover.append(host);
0505: }
0506:
0507: newUrlToTestFailover.append(":").append(port);
0508: newUrlToTestFailover.append(",");
0509:
0510: if (host != null) {
0511: newUrlToTestFailover.append(host);
0512: }
0513:
0514: newUrlToTestFailover.append(":")
0515: .append(bogusPortNumber);
0516: newUrlToTestFailover.append("/");
0517:
0518: if (database != null) {
0519: newUrlToTestFailover.append(database);
0520: }
0521:
0522: if ((user != null) || (password != null)) {
0523: newUrlToTestFailover.append("?");
0524:
0525: if (user != null) {
0526: newUrlToTestFailover.append("user=").append(
0527: user);
0528:
0529: if (password != null) {
0530: newUrlToTestFailover.append("&");
0531: }
0532: }
0533:
0534: if (password != null) {
0535: newUrlToTestFailover.append("password=")
0536: .append(password);
0537: }
0538: }
0539:
0540: Connection failoverConn = DriverManager.getConnection(
0541: newUrlToTestFailover.toString(),
0542: autoReconnectProps);
0543: Statement failoverStmt = portNumConn.createStatement();
0544: this .rs = failoverStmt
0545: .executeQuery("SELECT connection_id()");
0546: this .rs.next();
0547:
0548: killConnection(adminConnection, this .rs.getString(1));
0549:
0550: try {
0551: failoverStmt.executeQuery("SELECT connection_id()");
0552: } catch (SQLException sqlEx) {
0553: // we expect this one
0554: }
0555:
0556: failoverStmt.executeQuery("SELECT connection_id()");
0557: } finally {
0558: if (adminConnection != null) {
0559: adminConnection.close();
0560: }
0561: }
0562: }
0563: }
0564:
0565: private static void killConnection(Connection adminConn,
0566: String threadId) throws SQLException {
0567: adminConn.createStatement().execute("KILL " + threadId);
0568: }
0569:
0570: /**
0571: * Tests fix for BUG#6966, connections starting up failed-over (due to down
0572: * master) never retry master.
0573: *
0574: * @throws Exception
0575: * if the test fails...Note, test is timing-dependent, but
0576: * should work in most cases.
0577: */
0578: public void testBug6966() throws Exception {
0579: Properties props = new Driver().parseURL(BaseTestCase.dbUrl,
0580: null);
0581: props.setProperty("autoReconnect", "true");
0582:
0583: // Re-build the connection information
0584: int firstIndexOfHost = BaseTestCase.dbUrl.indexOf("//") + 2;
0585: int lastIndexOfHost = BaseTestCase.dbUrl.indexOf("/",
0586: firstIndexOfHost);
0587:
0588: String hostPortPair = BaseTestCase.dbUrl.substring(
0589: firstIndexOfHost, lastIndexOfHost);
0590:
0591: StringTokenizer st = new StringTokenizer(hostPortPair, ":");
0592:
0593: String host = null;
0594: String port = null;
0595:
0596: if (st.hasMoreTokens()) {
0597: String possibleHostOrPort = st.nextToken();
0598:
0599: if (Character.isDigit(possibleHostOrPort.charAt(0))
0600: && (possibleHostOrPort.indexOf(".") == -1 /* IPV4 */)
0601: && (possibleHostOrPort.indexOf("::") == -1 /* IPV6 */)) {
0602: port = possibleHostOrPort;
0603: host = "localhost";
0604: } else {
0605: host = possibleHostOrPort;
0606: }
0607: }
0608:
0609: if (st.hasMoreTokens()) {
0610: port = st.nextToken();
0611: }
0612:
0613: if (host == null) {
0614: host = "";
0615: }
0616:
0617: if (port == null) {
0618: port = "3306";
0619: }
0620:
0621: StringBuffer newHostBuf = new StringBuffer();
0622: newHostBuf.append(host);
0623: newHostBuf.append(":65532"); // make sure the master fails
0624: newHostBuf.append(",");
0625: newHostBuf.append(host);
0626: if (port != null) {
0627: newHostBuf.append(":");
0628: newHostBuf.append(port);
0629: }
0630:
0631: props.remove("PORT");
0632:
0633: props.setProperty("HOST", newHostBuf.toString());
0634: props.setProperty("queriesBeforeRetryMaster", "50");
0635: props.setProperty("maxReconnects", "1");
0636:
0637: Connection failoverConnection = null;
0638:
0639: try {
0640: failoverConnection = getConnectionWithProps("jdbc:mysql://"
0641: + newHostBuf.toString() + "/", props);
0642: failoverConnection.setAutoCommit(false);
0643:
0644: String originalConnectionId = getSingleIndexedValueWithQuery(
0645: failoverConnection, 1, "SELECT CONNECTION_ID()")
0646: .toString();
0647:
0648: for (int i = 0; i < 49; i++) {
0649: failoverConnection.createStatement().executeQuery(
0650: "SELECT 1");
0651: }
0652:
0653: ((com.mysql.jdbc.Connection) failoverConnection)
0654: .clearHasTriedMaster();
0655:
0656: failoverConnection.setAutoCommit(true);
0657:
0658: String newConnectionId = getSingleIndexedValueWithQuery(
0659: failoverConnection, 1, "SELECT CONNECTION_ID()")
0660: .toString();
0661:
0662: assertTrue(((com.mysql.jdbc.Connection) failoverConnection)
0663: .hasTriedMaster());
0664:
0665: assertTrue(!newConnectionId.equals(originalConnectionId));
0666:
0667: failoverConnection.createStatement().executeQuery(
0668: "SELECT 1");
0669: } finally {
0670: if (failoverConnection != null) {
0671: failoverConnection.close();
0672: }
0673: }
0674: }
0675:
0676: /**
0677: * Test fix for BUG#7952 -- Infinite recursion when 'falling back' to master
0678: * in failover configuration.
0679: *
0680: * @throws Exception
0681: * if the tests fails.
0682: */
0683: public void testBug7952() throws Exception {
0684: Properties props = new Driver().parseURL(BaseTestCase.dbUrl,
0685: null);
0686: props.setProperty("autoReconnect", "true");
0687:
0688: // Re-build the connection information
0689: int firstIndexOfHost = BaseTestCase.dbUrl.indexOf("//") + 2;
0690: int lastIndexOfHost = BaseTestCase.dbUrl.indexOf("/",
0691: firstIndexOfHost);
0692:
0693: String hostPortPair = BaseTestCase.dbUrl.substring(
0694: firstIndexOfHost, lastIndexOfHost);
0695:
0696: StringTokenizer st = new StringTokenizer(hostPortPair, ":");
0697:
0698: String host = null;
0699: String port = null;
0700:
0701: if (st.hasMoreTokens()) {
0702: String possibleHostOrPort = st.nextToken();
0703:
0704: if (possibleHostOrPort.indexOf(".") == -1
0705: && Character.isDigit(possibleHostOrPort.charAt(0))) {
0706: port = possibleHostOrPort;
0707: host = "localhost";
0708: } else {
0709: host = possibleHostOrPort;
0710: }
0711: }
0712:
0713: if (st.hasMoreTokens()) {
0714: port = st.nextToken();
0715: }
0716:
0717: if (host == null) {
0718: host = "";
0719: }
0720:
0721: if (port == null) {
0722: port = "3306";
0723: }
0724:
0725: StringBuffer newHostBuf = new StringBuffer();
0726: newHostBuf.append(host);
0727: newHostBuf.append(":");
0728: newHostBuf.append(port);
0729: newHostBuf.append(",");
0730: newHostBuf.append(host);
0731: if (port != null) {
0732: newHostBuf.append(":");
0733: newHostBuf.append(port);
0734: }
0735:
0736: props.remove("PORT");
0737:
0738: props.setProperty("HOST", newHostBuf.toString());
0739: props.setProperty("queriesBeforeRetryMaster", "10");
0740: props.setProperty("maxReconnects", "1");
0741:
0742: Connection failoverConnection = null;
0743: Connection killerConnection = getConnectionWithProps((String) null);
0744:
0745: try {
0746: failoverConnection = getConnectionWithProps("jdbc:mysql://"
0747: + newHostBuf + "/", props);
0748: ((com.mysql.jdbc.Connection) failoverConnection)
0749: .setPreferSlaveDuringFailover(true);
0750: failoverConnection.setAutoCommit(false);
0751:
0752: String failoverConnectionId = getSingleIndexedValueWithQuery(
0753: failoverConnection, 1, "SELECT CONNECTION_ID()")
0754: .toString();
0755:
0756: System.out
0757: .println("Connection id: " + failoverConnectionId);
0758:
0759: killConnection(killerConnection, failoverConnectionId);
0760:
0761: Thread.sleep(3000); // This can take some time....
0762:
0763: try {
0764: failoverConnection.createStatement().executeQuery(
0765: "SELECT 1");
0766: } catch (SQLException sqlEx) {
0767: assertTrue("08S01".equals(sqlEx.getSQLState()));
0768: }
0769:
0770: ((com.mysql.jdbc.Connection) failoverConnection)
0771: .setPreferSlaveDuringFailover(false);
0772: ((com.mysql.jdbc.Connection) failoverConnection)
0773: .setFailedOver(true);
0774:
0775: failoverConnection.setAutoCommit(true);
0776:
0777: String failedConnectionId = getSingleIndexedValueWithQuery(
0778: failoverConnection, 1, "SELECT CONNECTION_ID()")
0779: .toString();
0780: System.out.println("Failed over connection id: "
0781: + failedConnectionId);
0782:
0783: ((com.mysql.jdbc.Connection) failoverConnection)
0784: .setPreferSlaveDuringFailover(false);
0785: ((com.mysql.jdbc.Connection) failoverConnection)
0786: .setFailedOver(true);
0787:
0788: for (int i = 0; i < 30; i++) {
0789: failoverConnection.setAutoCommit(true);
0790: System.out
0791: .println(getSingleIndexedValueWithQuery(
0792: failoverConnection, 1,
0793: "SELECT CONNECTION_ID()"));
0794: // failoverConnection.createStatement().executeQuery("SELECT
0795: // 1");
0796: failoverConnection.setAutoCommit(true);
0797: }
0798:
0799: String fallbackConnectionId = getSingleIndexedValueWithQuery(
0800: failoverConnection, 1, "SELECT CONNECTION_ID()")
0801: .toString();
0802: System.out.println("fallback connection id: "
0803: + fallbackConnectionId);
0804:
0805: /*
0806: * long begin = System.currentTimeMillis();
0807: *
0808: * failoverConnection.setAutoCommit(true);
0809: *
0810: * long end = System.currentTimeMillis();
0811: *
0812: * assertTrue("Probably didn't try failing back to the
0813: * master....check test", (end - begin) > 500);
0814: *
0815: * failoverConnection.createStatement().executeQuery("SELECT 1");
0816: */
0817: } finally {
0818: if (failoverConnection != null) {
0819: failoverConnection.close();
0820: }
0821: }
0822: }
0823:
0824: /**
0825: * Tests fix for BUG#7607 - MS932, SHIFT_JIS and Windows_31J not recog. as
0826: * aliases for sjis.
0827: *
0828: * @throws Exception
0829: * if the test fails.
0830: */
0831: public void testBug7607() throws Exception {
0832: if (versionMeetsMinimum(4, 1)) {
0833: Connection ms932Conn = null, cp943Conn = null, shiftJisConn = null, windows31JConn = null;
0834:
0835: try {
0836: Properties props = new Properties();
0837: props.setProperty("characterEncoding", "MS932");
0838:
0839: ms932Conn = getConnectionWithProps(props);
0840:
0841: this .rs = ms932Conn.createStatement().executeQuery(
0842: "SHOW VARIABLES LIKE 'character_set_client'");
0843: assertTrue(this .rs.next());
0844: String encoding = this .rs.getString(2);
0845: if (!versionMeetsMinimum(5, 0, 3)
0846: && !versionMeetsMinimum(4, 1, 11)) {
0847: assertEquals("sjis", encoding
0848: .toLowerCase(Locale.ENGLISH));
0849: } else {
0850: assertEquals("cp932", encoding
0851: .toLowerCase(Locale.ENGLISH));
0852: }
0853:
0854: this .rs = ms932Conn.createStatement().executeQuery(
0855: "SELECT 'abc'");
0856: assertTrue(this .rs.next());
0857:
0858: String charsetToCheck = "ms932";
0859:
0860: if (versionMeetsMinimum(5, 0, 3)
0861: || versionMeetsMinimum(4, 1, 11)) {
0862: charsetToCheck = "windows-31j";
0863: }
0864:
0865: assertEquals(charsetToCheck,
0866: ((com.mysql.jdbc.ResultSetMetaData) this .rs
0867: .getMetaData())
0868: .getColumnCharacterSet(1).toLowerCase(
0869: Locale.ENGLISH));
0870:
0871: try {
0872: ms932Conn.createStatement().executeUpdate(
0873: "drop table if exists testBug7607");
0874: ms932Conn
0875: .createStatement()
0876: .executeUpdate(
0877: "create table testBug7607 (sortCol int, col1 varchar(100) ) character set sjis");
0878: ms932Conn
0879: .createStatement()
0880: .executeUpdate(
0881: "insert into testBug7607 values(1, 0x835C)"); // standard
0882: // sjis
0883: ms932Conn
0884: .createStatement()
0885: .executeUpdate(
0886: "insert into testBug7607 values(2, 0x878A)"); // NEC
0887: // kanji
0888:
0889: this .rs = ms932Conn
0890: .createStatement()
0891: .executeQuery(
0892: "SELECT col1 FROM testBug7607 ORDER BY sortCol ASC");
0893: assertTrue(this .rs.next());
0894: String asString = this .rs.getString(1);
0895: assertTrue("\u30bd".equals(asString));
0896:
0897: // Can't be fixed unless server is fixed,
0898: // this is fixed in 4.1.7.
0899:
0900: assertTrue(this .rs.next());
0901: asString = this .rs.getString(1);
0902: assertEquals("\u3231", asString);
0903: } finally {
0904: ms932Conn.createStatement().executeUpdate(
0905: "drop table if exists testBug7607");
0906: }
0907:
0908: props = new Properties();
0909: props.setProperty("characterEncoding", "SHIFT_JIS");
0910:
0911: shiftJisConn = getConnectionWithProps(props);
0912:
0913: this .rs = shiftJisConn.createStatement().executeQuery(
0914: "SHOW VARIABLES LIKE 'character_set_client'");
0915: assertTrue(this .rs.next());
0916: encoding = this .rs.getString(2);
0917: assertTrue("sjis".equalsIgnoreCase(encoding));
0918:
0919: this .rs = shiftJisConn.createStatement().executeQuery(
0920: "SELECT 'abc'");
0921: assertTrue(this .rs.next());
0922:
0923: String charSetUC = ((com.mysql.jdbc.ResultSetMetaData) this .rs
0924: .getMetaData()).getColumnCharacterSet(1)
0925: .toUpperCase(Locale.US);
0926:
0927: if (isRunningOnJdk131()) {
0928: assertEquals("WINDOWS-31J", charSetUC);
0929: } else {
0930: // assertEquals("SHIFT_JIS", charSetUC);
0931: }
0932:
0933: props = new Properties();
0934: props.setProperty("characterEncoding", "WINDOWS-31J");
0935:
0936: windows31JConn = getConnectionWithProps(props);
0937:
0938: this .rs = windows31JConn
0939: .createStatement()
0940: .executeQuery(
0941: "SHOW VARIABLES LIKE 'character_set_client'");
0942: assertTrue(this .rs.next());
0943: encoding = this .rs.getString(2);
0944:
0945: if (!versionMeetsMinimum(5, 0, 3)
0946: && !versionMeetsMinimum(4, 1, 11)) {
0947: assertEquals("sjis", encoding
0948: .toLowerCase(Locale.ENGLISH));
0949: } else {
0950: assertEquals("cp932", encoding
0951: .toLowerCase(Locale.ENGLISH));
0952: }
0953:
0954: this .rs = windows31JConn.createStatement()
0955: .executeQuery("SELECT 'abc'");
0956: assertTrue(this .rs.next());
0957:
0958: if (!versionMeetsMinimum(4, 1, 11)) {
0959: assertEquals("sjis".toLowerCase(Locale.ENGLISH),
0960: ((com.mysql.jdbc.ResultSetMetaData) this .rs
0961: .getMetaData())
0962: .getColumnCharacterSet(1)
0963: .toLowerCase(Locale.ENGLISH));
0964: } else {
0965: assertEquals("windows-31j"
0966: .toLowerCase(Locale.ENGLISH),
0967: ((com.mysql.jdbc.ResultSetMetaData) this .rs
0968: .getMetaData())
0969: .getColumnCharacterSet(1)
0970: .toLowerCase(Locale.ENGLISH));
0971: }
0972:
0973: props = new Properties();
0974: props.setProperty("characterEncoding", "CP943");
0975:
0976: cp943Conn = getConnectionWithProps(props);
0977:
0978: this .rs = cp943Conn.createStatement().executeQuery(
0979: "SHOW VARIABLES LIKE 'character_set_client'");
0980: assertTrue(this .rs.next());
0981: encoding = this .rs.getString(2);
0982: assertTrue("sjis".equalsIgnoreCase(encoding));
0983:
0984: this .rs = cp943Conn.createStatement().executeQuery(
0985: "SELECT 'abc'");
0986: assertTrue(this .rs.next());
0987:
0988: charSetUC = ((com.mysql.jdbc.ResultSetMetaData) this .rs
0989: .getMetaData()).getColumnCharacterSet(1)
0990: .toUpperCase(Locale.US);
0991:
0992: if (isRunningOnJdk131()) {
0993: assertEquals("WINDOWS-31J", charSetUC);
0994: } else {
0995: assertEquals("CP943", charSetUC);
0996: }
0997:
0998: } finally {
0999: if (ms932Conn != null) {
1000: ms932Conn.close();
1001: }
1002:
1003: if (shiftJisConn != null) {
1004: shiftJisConn.close();
1005: }
1006:
1007: if (windows31JConn != null) {
1008: windows31JConn.close();
1009: }
1010:
1011: if (cp943Conn != null) {
1012: cp943Conn.close();
1013: }
1014: }
1015: }
1016: }
1017:
1018: /**
1019: * In some case Connector/J's round-robin function doesn't work.
1020: *
1021: * I had 2 mysqld, node1 "localhost:3306" and node2 "localhost:3307".
1022: *
1023: * 1. node1 is up, node2 is up
1024: *
1025: * 2. java-program connect to node1 by using properties
1026: * "autoRecconect=true","roundRobinLoadBalance=true","failOverReadOnly=false".
1027: *
1028: * 3. node1 is down, node2 is up
1029: *
1030: * 4. java-program execute a query and fail, but Connector/J's round-robin
1031: * fashion failover work and if java-program retry a query it can succeed
1032: * (connection is change to node2 by Connector/j)
1033: *
1034: * 5. node1 is up, node2 is up
1035: *
1036: * 6. node1 is up, node2 is down
1037: *
1038: * 7. java-program execute a query, but this time Connector/J doesn't work
1039: * althought node1 is up and usable.
1040: *
1041: *
1042: * @throws Exception
1043: */
1044: public void testBug8643() throws Exception {
1045: if (runMultiHostTests()) {
1046: Properties defaultProps = getMasterSlaveProps();
1047:
1048: defaultProps.remove(NonRegisteringDriver.HOST_PROPERTY_KEY);
1049: defaultProps.remove(NonRegisteringDriver.PORT_PROPERTY_KEY);
1050:
1051: defaultProps.put("autoReconnect", "true");
1052: defaultProps.put("roundRobinLoadBalance", "true");
1053: defaultProps.put("failOverReadOnly", "false");
1054:
1055: Connection con = null;
1056: try {
1057: con = DriverManager.getConnection(getMasterSlaveUrl(),
1058: defaultProps);
1059: Statement stmt1 = con.createStatement();
1060:
1061: ResultSet rs1 = stmt1
1062: .executeQuery("show variables like 'port'");
1063: rs1.next();
1064:
1065: rs1 = stmt1.executeQuery("select connection_id()");
1066: rs1.next();
1067: String originalConnectionId = rs1.getString(1);
1068: this .stmt.executeUpdate("kill " + originalConnectionId);
1069:
1070: int numLoops = 8;
1071:
1072: SQLException caughtException = null;
1073:
1074: while (caughtException == null && numLoops > 0) {
1075: numLoops--;
1076:
1077: try {
1078: rs1 = stmt1
1079: .executeQuery("show variables like 'port'");
1080: } catch (SQLException sqlEx) {
1081: caughtException = sqlEx;
1082: }
1083: }
1084:
1085: assertNotNull(caughtException);
1086:
1087: // failover and retry
1088: rs1 = stmt1.executeQuery("show variables like 'port'");
1089:
1090: rs1.next();
1091: assertTrue(!((com.mysql.jdbc.Connection) con)
1092: .isMasterConnection());
1093:
1094: rs1 = stmt1.executeQuery("select connection_id()");
1095: rs1.next();
1096: String nextConnectionId = rs1.getString(1);
1097: assertTrue(!nextConnectionId
1098: .equals(originalConnectionId));
1099:
1100: this .stmt.executeUpdate("kill " + nextConnectionId);
1101:
1102: numLoops = 8;
1103:
1104: caughtException = null;
1105:
1106: while (caughtException == null && numLoops > 0) {
1107: numLoops--;
1108:
1109: try {
1110: rs1 = stmt1
1111: .executeQuery("show variables like 'port'");
1112: } catch (SQLException sqlEx) {
1113: caughtException = sqlEx;
1114: }
1115: }
1116:
1117: assertNotNull(caughtException);
1118:
1119: // failover and retry
1120: rs1 = stmt1.executeQuery("show variables like 'port'");
1121:
1122: rs1.next();
1123: assertTrue(((com.mysql.jdbc.Connection) con)
1124: .isMasterConnection());
1125:
1126: } finally {
1127: if (con != null) {
1128: try {
1129: con.close();
1130: } catch (Exception e) {
1131: e.printStackTrace();
1132: }
1133: }
1134: }
1135: }
1136: }
1137:
1138: /**
1139: * Tests fix for BUG#9206, can not use 'UTF-8' for characterSetResults
1140: * configuration property.
1141: */
1142: public void testBug9206() throws Exception {
1143: Properties props = new Properties();
1144: props.setProperty("characterSetResults", "UTF-8");
1145: getConnectionWithProps(props).close();
1146: }
1147:
1148: /**
1149: * These two charsets have different names depending on version of MySQL
1150: * server.
1151: *
1152: * @throws Exception
1153: * if the test fails.
1154: */
1155: public void testNewCharsetsConfiguration() throws Exception {
1156: Properties props = new Properties();
1157: props.setProperty("useUnicode", "true");
1158: props.setProperty("characterEncoding", "EUC_KR");
1159: getConnectionWithProps(props).close();
1160:
1161: props = new Properties();
1162: props.setProperty("useUnicode", "true");
1163: props.setProperty("characterEncoding", "KOI8_R");
1164: getConnectionWithProps(props).close();
1165: }
1166:
1167: /**
1168: * Tests fix for BUG#10144 - Memory leak in ServerPreparedStatement if
1169: * serverPrepare() fails.
1170: */
1171:
1172: public void testBug10144() throws Exception {
1173: if (versionMeetsMinimum(4, 1)) {
1174: Properties props = new Properties();
1175: props.setProperty("emulateUnsupportedPstmts", "false");
1176: props.setProperty("useServerPrepStmts", "true");
1177:
1178: Connection bareConn = getConnectionWithProps(props);
1179:
1180: int currentOpenStatements = ((com.mysql.jdbc.Connection) bareConn)
1181: .getActiveStatementCount();
1182:
1183: try {
1184: bareConn.prepareStatement("Boo!");
1185: fail("Should not've been able to prepare that one!");
1186: } catch (SQLException sqlEx) {
1187: assertEquals(currentOpenStatements,
1188: ((com.mysql.jdbc.Connection) bareConn)
1189: .getActiveStatementCount());
1190: } finally {
1191: if (bareConn != null) {
1192: bareConn.close();
1193: }
1194: }
1195: }
1196: }
1197:
1198: /**
1199: * Tests fix for BUG#10496 - SQLException is thrown when using property
1200: * "characterSetResults"
1201: */
1202: public void testBug10496() throws Exception {
1203: if (versionMeetsMinimum(5, 0, 3)) {
1204: Properties props = new Properties();
1205: props.setProperty("useUnicode", "true");
1206: props.setProperty("characterEncoding", "WINDOWS-31J");
1207: props.setProperty("characterSetResults", "WINDOWS-31J");
1208: getConnectionWithProps(props).close();
1209:
1210: props = new Properties();
1211: props.setProperty("useUnicode", "true");
1212: props.setProperty("characterEncoding", "EUC_JP");
1213: props.setProperty("characterSetResults", "EUC_JP");
1214: getConnectionWithProps(props).close();
1215: }
1216: }
1217:
1218: /**
1219: * Tests fix for BUG#11259, autoReconnect ping causes exception on
1220: * connection startup.
1221: *
1222: * @throws Exception
1223: * if the test fails.
1224: */
1225: public void testBug11259() throws Exception {
1226: Connection dsConn = null;
1227: try {
1228: Properties props = new Properties();
1229: props.setProperty("autoReconnect", "true");
1230: dsConn = getConnectionWithProps(props);
1231: } finally {
1232: if (dsConn != null) {
1233: dsConn.close();
1234: }
1235: }
1236: }
1237:
1238: /**
1239: * Tests fix for BUG#11879 -- ReplicationConnection won't switch to slave,
1240: * throws "Catalog can't be null" exception.
1241: *
1242: * @throws Exception
1243: * if the test fails
1244: */
1245: public void testBug11879() throws Exception {
1246: if (runMultiHostTests()) {
1247: Connection replConn = null;
1248:
1249: try {
1250: replConn = getMasterSlaveReplicationConnection();
1251: replConn.setReadOnly(true);
1252: replConn.setReadOnly(false);
1253: } finally {
1254: if (replConn != null) {
1255: replConn.close();
1256: }
1257: }
1258: }
1259: }
1260:
1261: /**
1262: * Tests fix for BUG#11976 - maxPerformance.properties mis-spells
1263: * "elideSetAutoCommits".
1264: *
1265: * @throws Exception
1266: * if the test fails.
1267: */
1268: public void testBug11976() throws Exception {
1269: if (isRunningOnJdk131()) {
1270: return; // test not valid on JDK-1.3.1
1271: }
1272:
1273: Properties props = new Properties();
1274: props.setProperty("useConfigs", "maxPerformance");
1275:
1276: Connection maxPerfConn = getConnectionWithProps(props);
1277: assertEquals(true, ((com.mysql.jdbc.Connection) maxPerfConn)
1278: .getElideSetAutoCommits());
1279: }
1280:
1281: /**
1282: * Tests fix for BUG#12218, properties shared between master and slave with
1283: * replication connection.
1284: *
1285: * @throws Exception
1286: * if the test fails.
1287: */
1288: public void testBug12218() throws Exception {
1289: if (runMultiHostTests()) {
1290: Connection replConn = null;
1291:
1292: try {
1293: replConn = getMasterSlaveReplicationConnection();
1294: assertTrue(!((ConnectionImpl) ((ReplicationConnection) replConn)
1295: .getMasterConnection())
1296: .hasSameProperties(((ReplicationConnection) replConn)
1297: .getSlavesConnection()));
1298: } finally {
1299: if (replConn != null) {
1300: replConn.close();
1301: }
1302: }
1303: }
1304: }
1305:
1306: /**
1307: * Tests fix for BUG#12229 - explainSlowQueries hangs with server-side
1308: * prepared statements.
1309: *
1310: * @throws Exception
1311: * if the test fails.
1312: */
1313: public void testBug12229() throws Exception {
1314: createTable("testBug12229", "(`int_field` integer )");
1315: this .stmt
1316: .executeUpdate("insert into testBug12229 values (123456),(1)");
1317:
1318: Properties props = new Properties();
1319: props.put("profileSQL", "true");
1320: props.put("slowQueryThresholdMillis", "0");
1321: props.put("logSlowQueries", "true");
1322: props.put("explainSlowQueries", "true");
1323: props.put("useServerPrepStmts", "true");
1324:
1325: Connection explainConn = getConnectionWithProps(props);
1326:
1327: this .pstmt = explainConn
1328: .prepareStatement("SELECT `int_field` FROM `testBug12229` WHERE `int_field` = ?");
1329: this .pstmt.setInt(1, 1);
1330:
1331: this .rs = this .pstmt.executeQuery();
1332: assertTrue(this .rs.next());
1333:
1334: this .rs = this .pstmt.executeQuery();
1335: assertTrue(this .rs.next());
1336:
1337: this .rs = this .pstmt.executeQuery();
1338: assertTrue(this .rs.next());
1339: }
1340:
1341: /**
1342: * Tests fix for BUG#12752 - Cp1251 incorrectly mapped to win1251 for
1343: * servers newer than 4.0.x.
1344: *
1345: * @throws Exception
1346: * if the test fails.
1347: */
1348: public void testBug12752() throws Exception {
1349: Properties props = new Properties();
1350: props.setProperty("characterEncoding", "Cp1251");
1351: getConnectionWithProps(props).close();
1352: }
1353:
1354: /**
1355: * Tests fix for BUG#12753, sessionVariables=....=...., doesn't work as it's
1356: * tokenized incorrectly.
1357: *
1358: * @throws Exception
1359: * if the test fails.
1360: */
1361: public void testBug12753() throws Exception {
1362: if (versionMeetsMinimum(4, 1)) {
1363: Properties props = new Properties();
1364: props.setProperty("sessionVariables", "sql_mode=ansi");
1365:
1366: Connection sessionConn = null;
1367:
1368: try {
1369: sessionConn = getConnectionWithProps(props);
1370:
1371: String sqlMode = getMysqlVariable(sessionConn,
1372: "sql_mode");
1373: assertTrue(sqlMode.indexOf("ANSI") != -1);
1374: } finally {
1375: if (sessionConn != null) {
1376: sessionConn.close();
1377: sessionConn = null;
1378: }
1379: }
1380: }
1381: }
1382:
1383: /**
1384: * Tests fix for BUG#13048 - maxQuerySizeToLog is not respected.
1385: *
1386: * @throws Exception
1387: * if the test fails
1388: */
1389: public void testBug13048() throws Exception {
1390:
1391: Connection profileConn = null;
1392: PrintStream oldErr = System.err;
1393:
1394: try {
1395: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1396: System.setErr(new PrintStream(bOut));
1397:
1398: Properties props = new Properties();
1399: props.setProperty("profileSQL", "true");
1400: props.setProperty("maxQuerySizeToLog", "2");
1401: props.setProperty("logger",
1402: "com.mysql.jdbc.log.StandardLogger");
1403:
1404: profileConn = getConnectionWithProps(props);
1405:
1406: StringBuffer queryBuf = new StringBuffer("SELECT '");
1407:
1408: for (int i = 0; i < 500; i++) {
1409: queryBuf.append("a");
1410: }
1411:
1412: queryBuf.append("'");
1413:
1414: this .rs = profileConn.createStatement().executeQuery(
1415: queryBuf.toString());
1416: this .rs.close();
1417:
1418: String logString = new String(bOut.toString("ISO8859-1"));
1419: assertTrue(logString.indexOf("... (truncated)") != -1);
1420:
1421: bOut = new ByteArrayOutputStream();
1422: System.setErr(new PrintStream(bOut));
1423:
1424: this .rs = profileConn.prepareStatement(queryBuf.toString())
1425: .executeQuery();
1426: logString = new String(bOut.toString("ISO8859-1"));
1427:
1428: assertTrue(logString.indexOf("... (truncated)") != -1);
1429: } finally {
1430: System.setErr(oldErr);
1431:
1432: if (profileConn != null) {
1433: profileConn.close();
1434: }
1435:
1436: if (this .rs != null) {
1437: ResultSet toClose = this .rs;
1438: this .rs = null;
1439: toClose.close();
1440: }
1441: }
1442: }
1443:
1444: /**
1445: * Tests fix for BUG#13453 - can't use & or = in URL configuration values
1446: * (we now allow you to use www-form-encoding).
1447: *
1448: * @throws Exception
1449: * if the test fails
1450: */
1451: public void testBug13453() throws Exception {
1452: StringBuffer urlBuf = new StringBuffer(dbUrl);
1453:
1454: if (dbUrl.indexOf('?') == -1) {
1455: urlBuf.append('?');
1456: } else {
1457: urlBuf.append('&');
1458: }
1459:
1460: urlBuf.append("sessionVariables=@testBug13453='%25%26+%3D'");
1461:
1462: Connection encodedConn = null;
1463:
1464: try {
1465: encodedConn = DriverManager.getConnection(
1466: urlBuf.toString(), null);
1467:
1468: this .rs = encodedConn.createStatement().executeQuery(
1469: "SELECT @testBug13453");
1470: assertTrue(this .rs.next());
1471: assertEquals("%& =", this .rs.getString(1));
1472: } finally {
1473: if (this .rs != null) {
1474: this .rs.close();
1475: this .rs = null;
1476: }
1477:
1478: if (encodedConn != null) {
1479: encodedConn.close();
1480: }
1481: }
1482: }
1483:
1484: /**
1485: * Tests fix for BUG#15065 - Usage advisor complains about unreferenced
1486: * columns, even though they've been referenced.
1487: *
1488: * @throws Exception
1489: * if the test fails.
1490: */
1491: public void testBug15065() throws Exception {
1492: if (isRunningOnJdk131()) {
1493: return; // test not valid on JDK-1.3.1
1494: }
1495:
1496: createTable("testBug15065", "(field1 int)");
1497:
1498: this .stmt.executeUpdate("INSERT INTO testBug15065 VALUES (1)");
1499:
1500: Connection advisorConn = null;
1501: Statement advisorStmt = null;
1502:
1503: try {
1504: Properties props = new Properties();
1505: props.setProperty("useUsageAdvisor", "true");
1506: props.setProperty("logger",
1507: "com.mysql.jdbc.log.StandardLogger");
1508:
1509: advisorConn = getConnectionWithProps(props);
1510: advisorStmt = advisorConn.createStatement();
1511:
1512: Method[] getMethods = ResultSet.class.getMethods();
1513:
1514: PrintStream oldErr = System.err;
1515:
1516: try {
1517: ByteArrayOutputStream bOut = new ByteArrayOutputStream();
1518: System.setErr(new PrintStream(bOut));
1519:
1520: HashMap methodsToSkipMap = new HashMap();
1521:
1522: // Needs an actual URL
1523: methodsToSkipMap.put("getURL", null);
1524:
1525: // Java6 JDBC4.0 methods we don't implement
1526: methodsToSkipMap.put("getNCharacterStream", null);
1527: methodsToSkipMap.put("getNClob", null);
1528: methodsToSkipMap.put("getNString", null);
1529: methodsToSkipMap.put("getRowId", null);
1530: methodsToSkipMap.put("getSQLXML", null);
1531:
1532: for (int j = 0; j < 2; j++) {
1533: for (int i = 0; i < getMethods.length; i++) {
1534: String methodName = getMethods[i].getName();
1535:
1536: if (methodName.startsWith("get")
1537: && !methodsToSkipMap
1538: .containsKey(methodName)) {
1539: Class[] parameterTypes = getMethods[i]
1540: .getParameterTypes();
1541:
1542: if (parameterTypes.length == 1
1543: && parameterTypes[0] == Integer.TYPE) {
1544: if (j == 0) {
1545: this .rs = advisorStmt
1546: .executeQuery("SELECT COUNT(*) FROM testBug15065");
1547: } else {
1548: this .rs = advisorConn
1549: .prepareStatement(
1550: "SELECT COUNT(*) FROM testBug15065")
1551: .executeQuery();
1552: }
1553:
1554: this .rs.next();
1555:
1556: try {
1557:
1558: getMethods[i].invoke(this .rs,
1559: new Object[] { new Integer(
1560: 1) });
1561: } catch (InvocationTargetException invokeEx) {
1562: // we don't care about bad values, just that
1563: // the
1564: // column gets "touched"
1565: if (!invokeEx
1566: .getCause()
1567: .getClass()
1568: .isAssignableFrom(
1569: java.sql.SQLException.class)
1570: && !invokeEx
1571: .getCause()
1572: .getClass()
1573: .getName()
1574: .equals(
1575: "com.mysql.jdbc.NotImplemented")) {
1576: throw invokeEx;
1577: }
1578: }
1579:
1580: this .rs.close();
1581: this .rs = null;
1582: }
1583: }
1584: }
1585: }
1586:
1587: String logOut = bOut.toString("ISO8859-1");
1588:
1589: if (logOut.indexOf(".Level") != -1) {
1590: return; // we ignore for warnings
1591: }
1592:
1593: assertTrue(
1594: "Usage advisor complained about columns:\n\n"
1595: + logOut,
1596: logOut.indexOf("columns") == -1);
1597: } finally {
1598: System.setErr(oldErr);
1599: }
1600: } finally {
1601: if (advisorConn != null) {
1602: advisorConn.close();
1603: }
1604: }
1605: }
1606:
1607: /**
1608: * Tests fix for BUG#15544, no "dos" character set in MySQL > 4.1.0
1609: *
1610: * @throws Exception
1611: * if the test fails
1612: */
1613: public void testBug15544() throws Exception {
1614: Properties props = new Properties();
1615: props.setProperty("characterEncoding", "Cp437");
1616: Connection dosConn = null;
1617:
1618: try {
1619: dosConn = getConnectionWithProps(props);
1620: } finally {
1621: if (dosConn != null) {
1622: dosConn.close();
1623: }
1624: }
1625: }
1626:
1627: public void testCSC5765() throws Exception {
1628: if (isRunningOnJdk131()) {
1629: return; // test not valid on JDK-1.3.1
1630: }
1631:
1632: Properties props = new Properties();
1633: props.setProperty("useUnicode", "true");
1634: props.setProperty("characterEncoding", "utf8");
1635: props.setProperty("characterSetResults", "utf8");
1636: props.setProperty("connectionCollation", "utf8_bin");
1637:
1638: Connection utf8Conn = null;
1639:
1640: try {
1641: utf8Conn = getConnectionWithProps(props);
1642: this .rs = utf8Conn.createStatement().executeQuery(
1643: "SHOW VARIABLES LIKE 'character_%'");
1644: while (this .rs.next()) {
1645: System.out.println(this .rs.getString(1) + " = "
1646: + this .rs.getString(2));
1647: }
1648:
1649: this .rs = utf8Conn.createStatement().executeQuery(
1650: "SHOW VARIABLES LIKE 'collation_%'");
1651: while (this .rs.next()) {
1652: System.out.println(this .rs.getString(1) + " = "
1653: + this .rs.getString(2));
1654: }
1655: } finally {
1656: if (utf8Conn != null) {
1657: utf8Conn.close();
1658: }
1659: }
1660: }
1661:
1662: private Connection getMasterSlaveReplicationConnection()
1663: throws SQLException {
1664:
1665: Connection replConn = new ReplicationDriver().connect(
1666: getMasterSlaveUrl(), getMasterSlaveProps());
1667:
1668: return replConn;
1669: }
1670:
1671: protected String getMasterSlaveUrl() throws SQLException {
1672: StringBuffer urlBuf = new StringBuffer("jdbc:mysql://");
1673: Properties defaultProps = getPropertiesFromTestsuiteUrl();
1674: String hostname = defaultProps
1675: .getProperty(NonRegisteringDriver.HOST_PROPERTY_KEY);
1676:
1677: int colonIndex = hostname.indexOf(":");
1678:
1679: String portNumber = "3306";
1680:
1681: if (colonIndex != -1 && !hostname.startsWith(":")) {
1682: portNumber = hostname.substring(colonIndex + 1);
1683: hostname = hostname.substring(0, colonIndex);
1684: } else if (hostname.startsWith(":")) {
1685: portNumber = hostname.substring(1);
1686: hostname = "localhost";
1687: } else {
1688: portNumber = defaultProps
1689: .getProperty(NonRegisteringDriver.PORT_PROPERTY_KEY);
1690: }
1691:
1692: for (int i = 0; i < 2; i++) {
1693: urlBuf.append(hostname);
1694: urlBuf.append(":");
1695: urlBuf.append(portNumber);
1696:
1697: if (i == 0) {
1698: urlBuf.append(",");
1699: }
1700: }
1701: urlBuf.append("/");
1702:
1703: return urlBuf.toString();
1704: }
1705:
1706: protected Properties getMasterSlaveProps() throws SQLException {
1707: Properties props = getPropertiesFromTestsuiteUrl();
1708:
1709: props.remove(NonRegisteringDriver.HOST_PROPERTY_KEY);
1710: props.remove(NonRegisteringDriver.PORT_PROPERTY_KEY);
1711:
1712: return props;
1713: }
1714:
1715: /**
1716: * Tests fix for BUG#15570 - ReplicationConnection incorrectly copies state,
1717: * doesn't transfer connection context correctly when transitioning between
1718: * the same read-only states.
1719: *
1720: * (note, this test will fail if the test user doesn't have permission to
1721: * "USE 'mysql'".
1722: *
1723: * @throws Exception
1724: * if the test fails.
1725: */
1726: public void testBug15570() throws Exception {
1727: Connection replConn = null;
1728:
1729: try {
1730: replConn = getMasterSlaveReplicationConnection();
1731:
1732: int masterConnectionId = Integer
1733: .parseInt(getSingleIndexedValueWithQuery(replConn,
1734: 1, "SELECT CONNECTION_ID()").toString());
1735:
1736: replConn.setReadOnly(false);
1737:
1738: assertEquals(masterConnectionId, Integer
1739: .parseInt(getSingleIndexedValueWithQuery(replConn,
1740: 1, "SELECT CONNECTION_ID()").toString()));
1741:
1742: String currentCatalog = replConn.getCatalog();
1743:
1744: replConn.setCatalog(currentCatalog);
1745: assertEquals(currentCatalog, replConn.getCatalog());
1746:
1747: replConn.setReadOnly(true);
1748:
1749: int slaveConnectionId = Integer
1750: .parseInt(getSingleIndexedValueWithQuery(replConn,
1751: 1, "SELECT CONNECTION_ID()").toString());
1752:
1753: // The following test is okay for now, as the chance
1754: // of MySQL wrapping the connection id counter during our
1755: // testsuite is very small.
1756:
1757: assertTrue("Slave id " + slaveConnectionId
1758: + " is not newer than master id "
1759: + masterConnectionId,
1760: slaveConnectionId > masterConnectionId);
1761:
1762: assertEquals(currentCatalog, replConn.getCatalog());
1763:
1764: String newCatalog = "mysql";
1765:
1766: replConn.setCatalog(newCatalog);
1767: assertEquals(newCatalog, replConn.getCatalog());
1768:
1769: replConn.setReadOnly(true);
1770: assertEquals(newCatalog, replConn.getCatalog());
1771:
1772: replConn.setReadOnly(false);
1773: assertEquals(masterConnectionId, Integer
1774: .parseInt(getSingleIndexedValueWithQuery(replConn,
1775: 1, "SELECT CONNECTION_ID()").toString()));
1776: } finally {
1777: if (replConn != null) {
1778: replConn.close();
1779: }
1780: }
1781: }
1782:
1783: /**
1784: * Tests bug where downed slave caused round robin load balance not to
1785: * cycle back to first host in the list.
1786: *
1787: * @throws Exception
1788: * if the test fails...Note, test is timing-dependent, but
1789: * should work in most cases.
1790: */
1791: public void testBug23281() throws Exception {
1792: Properties props = new Driver().parseURL(BaseTestCase.dbUrl,
1793: null);
1794: props.setProperty("autoReconnect", "false");
1795: props.setProperty("roundRobinLoadBalance", "true");
1796: props.setProperty("failoverReadOnly", "false");
1797:
1798: if (!isRunningOnJdk131()) {
1799: props.setProperty("connectTimeout", "5000");
1800: }
1801:
1802: // Re-build the connection information
1803: int firstIndexOfHost = BaseTestCase.dbUrl.indexOf("//") + 2;
1804: int lastIndexOfHost = BaseTestCase.dbUrl.indexOf("/",
1805: firstIndexOfHost);
1806:
1807: String hostPortPair = BaseTestCase.dbUrl.substring(
1808: firstIndexOfHost, lastIndexOfHost);
1809:
1810: StringTokenizer st = new StringTokenizer(hostPortPair, ":");
1811:
1812: String host = null;
1813: String port = null;
1814:
1815: if (st.hasMoreTokens()) {
1816: String possibleHostOrPort = st.nextToken();
1817:
1818: if (Character.isDigit(possibleHostOrPort.charAt(0))
1819: && (possibleHostOrPort.indexOf(".") == -1 /* IPV4 */)
1820: && (possibleHostOrPort.indexOf("::") == -1 /* IPV6 */)) {
1821: port = possibleHostOrPort;
1822: host = "localhost";
1823: } else {
1824: host = possibleHostOrPort;
1825: }
1826: }
1827:
1828: if (st.hasMoreTokens()) {
1829: port = st.nextToken();
1830: }
1831:
1832: if (host == null) {
1833: host = "";
1834: }
1835:
1836: if (port == null) {
1837: port = "3306";
1838: }
1839:
1840: StringBuffer newHostBuf = new StringBuffer();
1841:
1842: newHostBuf.append(host);
1843: if (port != null) {
1844: newHostBuf.append(":");
1845: newHostBuf.append(port);
1846: }
1847:
1848: newHostBuf.append(",");
1849: //newHostBuf.append(host);
1850: newHostBuf.append("192.0.2.1"); // non-exsitent machine from RFC3330 test network
1851: newHostBuf.append(":65532"); // make sure the slave fails
1852:
1853: props.remove("PORT");
1854: props.remove("HOST");
1855:
1856: Connection failoverConnection = null;
1857:
1858: try {
1859: failoverConnection = getConnectionWithProps("jdbc:mysql://"
1860: + newHostBuf.toString() + "/", props);
1861:
1862: String originalConnectionId = getSingleIndexedValueWithQuery(
1863: failoverConnection, 1, "SELECT CONNECTION_ID()")
1864: .toString();
1865:
1866: System.out.println(originalConnectionId);
1867:
1868: Connection nextConnection = getConnectionWithProps(
1869: "jdbc:mysql://" + newHostBuf.toString() + "/",
1870: props);
1871:
1872: String nextId = getSingleIndexedValueWithQuery(
1873: nextConnection, 1, "SELECT CONNECTION_ID()")
1874: .toString();
1875:
1876: System.out.println(nextId);
1877:
1878: } finally {
1879: if (failoverConnection != null) {
1880: failoverConnection.close();
1881: }
1882: }
1883: }
1884:
1885: /**
1886: * Tests to insure proper behavior for BUG#24706.
1887: *
1888: * @throws Exception if the test fails.
1889: */
1890: public void testBug24706() throws Exception {
1891: if (!versionMeetsMinimum(5, 0)) {
1892: return; // server status isn't there to support this feature
1893: }
1894:
1895: Properties props = new Properties();
1896: props.setProperty("elideSetAutoCommits", "true");
1897: props.setProperty("logger", "StandardLogger");
1898: props.setProperty("profileSQL", "true");
1899: Connection c = null;
1900:
1901: StringBuffer logBuf = new StringBuffer();
1902:
1903: StandardLogger.bufferedLog = logBuf;
1904:
1905: try {
1906: c = getConnectionWithProps(props);
1907: c.setAutoCommit(true);
1908: c.createStatement().execute("SELECT 1");
1909: c.setAutoCommit(true);
1910: c.setAutoCommit(false);
1911: c.createStatement().execute("SELECT 1");
1912: c.setAutoCommit(false);
1913:
1914: // We should only see _one_ "set autocommit=" sent to the server
1915:
1916: String log = logBuf.toString();
1917: int searchFrom = 0;
1918: int count = 0;
1919: int found = 0;
1920:
1921: while ((found = log.indexOf("SET autocommit=", searchFrom)) != -1) {
1922: searchFrom = found + 1;
1923: count++;
1924: }
1925:
1926: // The SELECT doesn't actually start a transaction, so being pedantic the
1927: // driver issues SET autocommit=0 again in this case.
1928: assertEquals(2, count);
1929: } finally {
1930: StandardLogger.bufferedLog = null;
1931:
1932: if (c != null) {
1933: c.close();
1934: }
1935:
1936: }
1937: }
1938:
1939: /**
1940: * Tests fix for BUG#25514 - Timer instance used for Statement.setQueryTimeout()
1941: * created per-connection, rather than per-VM, causing memory leak.
1942: *
1943: * @throws Exception if the test fails.
1944: */
1945: public void testBug25514() throws Exception {
1946:
1947: for (int i = 0; i < 10; i++) {
1948: getConnectionWithProps((Properties) null).close();
1949: }
1950:
1951: ThreadGroup root = Thread.currentThread().getThreadGroup()
1952: .getParent();
1953:
1954: while (root.getParent() != null) {
1955: root = root.getParent();
1956: }
1957:
1958: int numThreadsNamedTimer = findNamedThreadCount(root, "Timer");
1959:
1960: if (numThreadsNamedTimer == 0) {
1961: numThreadsNamedTimer = findNamedThreadCount(root,
1962: "MySQL Statement Cancellation Timer");
1963: }
1964:
1965: // Notice that this seems impossible to test on JDKs prior to 1.5, as there is no
1966: // reliable way to find the TimerThread, so we have to rely on new JDKs for this
1967: // test.
1968: assertTrue("More than one timer for cancel was created",
1969: numThreadsNamedTimer <= 1);
1970: }
1971:
1972: private int findNamedThreadCount(ThreadGroup group, String nameStart) {
1973:
1974: int count = 0;
1975:
1976: int numThreads = group.activeCount();
1977: Thread[] threads = new Thread[numThreads * 2];
1978: numThreads = group.enumerate(threads, false);
1979:
1980: for (int i = 0; i < numThreads; i++) {
1981: if (threads[i].getName().startsWith(nameStart)) {
1982: count++;
1983: }
1984: }
1985:
1986: int numGroups = group.activeGroupCount();
1987: ThreadGroup[] groups = new ThreadGroup[numGroups * 2];
1988: numGroups = group.enumerate(groups, false);
1989:
1990: for (int i = 0; i < numGroups; i++) {
1991: count += findNamedThreadCount(groups[i], nameStart);
1992: }
1993:
1994: return count;
1995: }
1996:
1997: /**
1998: * Ensures that we don't miss getters/setters for driver properties in
1999: * ConnectionProperties so that names given in documentation work with
2000: * DataSources which will use JavaBean-style names and reflection to
2001: * set the values (and often fail silently! when the method isn't available).
2002: *
2003: * @throws Exception
2004: */
2005: public void testBug23626() throws Exception {
2006: Class clazz = this .conn.getClass();
2007:
2008: DriverPropertyInfo[] dpi = new NonRegisteringDriver()
2009: .getPropertyInfo(dbUrl, null);
2010: StringBuffer missingSettersBuf = new StringBuffer();
2011: StringBuffer missingGettersBuf = new StringBuffer();
2012:
2013: Class[][] argTypes = { new Class[] { String.class },
2014: new Class[] { Integer.TYPE },
2015: new Class[] { Long.TYPE }, new Class[] { Boolean.TYPE } };
2016:
2017: for (int i = 0; i < dpi.length; i++) {
2018:
2019: String propertyName = dpi[i].name;
2020:
2021: if (propertyName.equals("HOST")
2022: || propertyName.equals("PORT")
2023: || propertyName.equals("DBNAME")
2024: || propertyName.equals("user")
2025: || propertyName.equals("password")) {
2026: continue;
2027: }
2028:
2029: StringBuffer mutatorName = new StringBuffer("set");
2030: mutatorName.append(Character.toUpperCase(propertyName
2031: .charAt(0)));
2032: mutatorName.append(propertyName.substring(1));
2033:
2034: StringBuffer accessorName = new StringBuffer("get");
2035: accessorName.append(Character.toUpperCase(propertyName
2036: .charAt(0)));
2037: accessorName.append(propertyName.substring(1));
2038:
2039: try {
2040: clazz.getMethod(accessorName.toString(), null);
2041: } catch (NoSuchMethodException nsme) {
2042: missingGettersBuf.append(accessorName.toString());
2043: missingGettersBuf.append("\n");
2044: }
2045:
2046: boolean foundMethod = false;
2047:
2048: for (int j = 0; j < argTypes.length; j++) {
2049: try {
2050: clazz
2051: .getMethod(mutatorName.toString(),
2052: argTypes[j]);
2053: foundMethod = true;
2054: break;
2055: } catch (NoSuchMethodException nsme) {
2056:
2057: }
2058: }
2059:
2060: if (!foundMethod) {
2061: missingSettersBuf.append(mutatorName);
2062: missingSettersBuf.append("\n");
2063: }
2064: }
2065:
2066: assertEquals(
2067: "Missing setters for listed configuration properties.",
2068: "", missingSettersBuf.toString());
2069: assertEquals(
2070: "Missing getters for listed configuration properties.",
2071: "", missingSettersBuf.toString());
2072: }
2073:
2074: /**
2075: * Tests fix for BUG#25545 - Client flags not sent correctly during handshake
2076: * when using SSL.
2077: *
2078: * Requires test certificates from testsuite/ssl-test-certs to be installed
2079: * on the server being tested.
2080: *
2081: * @throws Exception if the test fails.
2082: */
2083: public void testBug25545() throws Exception {
2084: if (!versionMeetsMinimum(5, 0)) {
2085: return;
2086: }
2087:
2088: if (isRunningOnJdk131()) {
2089: return;
2090: }
2091:
2092: createProcedure("testBug25545", "() BEGIN SELECT 1; END");
2093:
2094: String trustStorePath = "src/testsuite/ssl-test-certs/test-cert-store";
2095:
2096: System.setProperty("javax.net.ssl.keyStore", trustStorePath);
2097: System
2098: .setProperty("javax.net.ssl.keyStorePassword",
2099: "password");
2100: System.setProperty("javax.net.ssl.trustStore", trustStorePath);
2101: System.setProperty("javax.net.ssl.trustStorePassword",
2102: "password");
2103:
2104: Connection sslConn = null;
2105:
2106: try {
2107: Properties props = new Properties();
2108: props.setProperty("useSSL", "true");
2109: props.setProperty("requireSSL", "true");
2110:
2111: sslConn = getConnectionWithProps(props);
2112: sslConn.prepareCall("{ call testBug25545()}").execute();
2113: } finally {
2114: if (sslConn != null) {
2115: sslConn.close();
2116: }
2117: }
2118: }
2119:
2120: /**
2121: * Tests fix for BUG#27655 - getTransactionIsolation() uses
2122: * "SHOW VARIABLES LIKE" which is very inefficient on MySQL-5.0+
2123: *
2124: * @throws Exception
2125: */
2126: public void testBug27655() throws Exception {
2127: StringBuffer logBuf = new StringBuffer();
2128: Properties props = new Properties();
2129: props.setProperty("profileSQL", "true");
2130: props.setProperty("logger", "StandardLogger");
2131: StandardLogger.bufferedLog = logBuf;
2132:
2133: Connection loggedConn = null;
2134:
2135: try {
2136: loggedConn = getConnectionWithProps(props);
2137: loggedConn.getTransactionIsolation();
2138:
2139: if (versionMeetsMinimum(4, 0, 3)) {
2140: assertEquals(-1, logBuf.toString().indexOf(
2141: "SHOW VARIABLES LIKE 'tx_isolation'"));
2142: }
2143: } finally {
2144: if (loggedConn != null) {
2145: loggedConn.close();
2146: }
2147: }
2148: }
2149:
2150: /**
2151: * Tests fix for issue where a failed-over connection would let
2152: * an application call setReadOnly(false), when that call
2153: * should be ignored until the connection is reconnected to a
2154: * writable master.
2155: *
2156: * @throws Exception if the test fails.
2157: */
2158: public void testFailoverReadOnly() throws Exception {
2159: Properties props = getMasterSlaveProps();
2160: props.setProperty("autoReconnect", "true");
2161:
2162: Connection failoverConn = null;
2163:
2164: Statement failoverStmt = null;
2165:
2166: try {
2167: failoverConn = getConnectionWithProps(getMasterSlaveUrl(),
2168: props);
2169:
2170: ((com.mysql.jdbc.Connection) failoverConn)
2171: .setPreferSlaveDuringFailover(true);
2172:
2173: failoverStmt = failoverConn.createStatement();
2174:
2175: String masterConnectionId = getSingleIndexedValueWithQuery(
2176: failoverConn, 1, "SELECT connection_id()")
2177: .toString();
2178:
2179: this .stmt.execute("KILL " + masterConnectionId);
2180:
2181: // die trying, so we get the next host
2182: for (int i = 0; i < 100; i++) {
2183: try {
2184: failoverStmt.executeQuery("SELECT 1");
2185: } catch (SQLException sqlEx) {
2186: break;
2187: }
2188: }
2189:
2190: String slaveConnectionId = getSingleIndexedValueWithQuery(
2191: failoverConn, 1, "SELECT connection_id()")
2192: .toString();
2193:
2194: assertTrue("Didn't get a new physical connection",
2195: !masterConnectionId.equals(slaveConnectionId));
2196:
2197: failoverConn.setReadOnly(false); // this should be ignored
2198:
2199: assertTrue(failoverConn.isReadOnly());
2200:
2201: ((com.mysql.jdbc.Connection) failoverConn)
2202: .setPreferSlaveDuringFailover(false);
2203:
2204: this .stmt.execute("KILL " + slaveConnectionId); // we can't issue this on our own connection :p
2205:
2206: // die trying, so we get the next host
2207: for (int i = 0; i < 100; i++) {
2208: try {
2209: failoverStmt.executeQuery("SELECT 1");
2210: } catch (SQLException sqlEx) {
2211: break;
2212: }
2213: }
2214:
2215: String newMasterId = getSingleIndexedValueWithQuery(
2216: failoverConn, 1, "SELECT connection_id()")
2217: .toString();
2218:
2219: assertTrue("Didn't get a new physical connection",
2220: !slaveConnectionId.equals(newMasterId));
2221:
2222: failoverConn.setReadOnly(false);
2223:
2224: assertTrue(!failoverConn.isReadOnly());
2225: } finally {
2226: if (failoverStmt != null) {
2227: failoverStmt.close();
2228: }
2229:
2230: if (failoverConn != null) {
2231: failoverConn.close();
2232: }
2233: }
2234: }
2235:
2236: public void testPropertiesDescriptionsKeys() throws Exception {
2237: DriverPropertyInfo[] dpi = new NonRegisteringDriver()
2238: .getPropertyInfo(dbUrl, null);
2239:
2240: for (int i = 0; i < dpi.length; i++) {
2241: String description = dpi[i].description;
2242: String propertyName = dpi[i].name;
2243:
2244: if (description.indexOf("Missing error message for key '") != -1
2245: || description.startsWith("!")) {
2246: fail("Missing message for configuration property "
2247: + propertyName);
2248: }
2249:
2250: if (description.length() < 10) {
2251: fail("Suspiciously short description for configuration property "
2252: + propertyName);
2253: }
2254: }
2255: }
2256:
2257: public void testBug29852() throws Exception {
2258: Connection lbConn = getLoadBalancedConnection();
2259: assertTrue(!lbConn.getClass().getName().startsWith(
2260: "com.mysql.jdbc"));
2261: lbConn.close();
2262: }
2263:
2264: private Connection getLoadBalancedConnection() throws SQLException {
2265: int indexOfHostStart = dbUrl.indexOf("://") + 3;
2266: int indexOfHostEnd = dbUrl.indexOf("/", indexOfHostStart);
2267:
2268: String backHalf = dbUrl.substring(indexOfHostStart,
2269: indexOfHostEnd);
2270:
2271: if (backHalf.length() == 0) {
2272: backHalf = "localhost:3306";
2273: }
2274:
2275: String dbAndConfigs = dbUrl.substring(indexOfHostEnd);
2276:
2277: Connection lbConn = DriverManager
2278: .getConnection("jdbc:mysql:loadbalance://" + backHalf
2279: + "," + backHalf + dbAndConfigs);
2280: return lbConn;
2281: }
2282:
2283: /**
2284: * Test of a new feature to fix BUG 22643, specifying a
2285: * "validation query" in your connection pool that starts
2286: * with "slash-star ping slash-star" _exactly_ will cause the driver to " +
2287: * instead send a ping to the server (much lighter weight), and when using
2288: * a ReplicationConnection or a LoadBalancedConnection, will send
2289: * the ping across all active connections.
2290: *
2291: * @throws Exception
2292: */
2293: public void testBug22643() throws Exception {
2294: checkPingQuery(this .conn);
2295:
2296: Connection replConnection = getMasterSlaveReplicationConnection();
2297:
2298: try {
2299: checkPingQuery(replConnection);
2300: } finally {
2301: if (replConnection != null) {
2302: replConnection.close();
2303: }
2304: }
2305:
2306: Connection lbConn = getLoadBalancedConnection();
2307:
2308: try {
2309: checkPingQuery(lbConn);
2310: } finally {
2311: if (lbConn != null) {
2312: lbConn.close();
2313: }
2314: }
2315: }
2316:
2317: private void checkPingQuery(Connection c) throws SQLException {
2318: // Yes, I know we're sending 2, and looking for 1
2319: // that's part of the test, since we don't _really_
2320: // send the query to the server!
2321: String aPingQuery = "/* ping */ SELECT 2";
2322: Statement pingStmt = c.createStatement();
2323: PreparedStatement pingPStmt = null;
2324:
2325: try {
2326: this .rs = pingStmt.executeQuery(aPingQuery);
2327: assertTrue(this .rs.next());
2328: assertEquals(this .rs.getInt(1), 1);
2329:
2330: assertTrue(pingStmt.execute(aPingQuery));
2331: this .rs = pingStmt.getResultSet();
2332: assertTrue(this .rs.next());
2333: assertEquals(this .rs.getInt(1), 1);
2334:
2335: pingPStmt = c.prepareStatement(aPingQuery);
2336:
2337: assertTrue(pingPStmt.execute());
2338: this .rs = pingPStmt.getResultSet();
2339: assertTrue(this .rs.next());
2340: assertEquals(this .rs.getInt(1), 1);
2341:
2342: this .rs = pingPStmt.executeQuery();
2343: assertTrue(this .rs.next());
2344: assertEquals(this .rs.getInt(1), 1);
2345: } finally {
2346: closeMemberJDBCResources();
2347: }
2348: }
2349: }
|