Search in sources :

Example 11 with ReplicationConnection

use of com.mysql.cj.jdbc.ha.ReplicationConnection in project aws-mysql-jdbc by awslabs.

the class StatementRegressionTest method testBug21876798.

/**
 * Tests fix for Bug#21876798 - CONNECTOR/J WITH MYSQL FABRIC AND SPRING PRODUCES PROXY ERROR.
 *
 * Although this is a Fabric related bug we are able reproduce it using a couple of multi-host connections.
 *
 * @throws Exception
 */
@Test
public void testBug21876798() throws Exception {
    createTable("testBug21876798", "(tst INT, val INT)");
    for (int tst = 0; tst < 4; tst++) {
        boolean useServerPrepStmts = (tst & 0x1) != 0;
        boolean rewriteBatchedStatements = (tst & 0x2) != 0;
        Properties props = new Properties();
        props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
        props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
        props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), Boolean.toString(useServerPrepStmts));
        props.setProperty(PropertyKey.rewriteBatchedStatements.getKeyName(), Boolean.toString(rewriteBatchedStatements));
        String testCase = String.format("Case: %d [ %s | %s ]", tst, useServerPrepStmts ? "useSPS" : "-", rewriteBatchedStatements ? "rwBatchedStmts" : "-");
        Connection highLevelConn = getLoadBalancedConnection(props);
        assertTrue(highLevelConn.getClass().getName().startsWith("com.sun.proxy") || highLevelConn.getClass().getName().startsWith("$Proxy"), testCase);
        Connection lowLevelConn = getSourceReplicaReplicationConnection(props);
        // This simulates the behavior from Fabric connections that are causing the problem.
        ((ReplicationConnection) lowLevelConn).setProxy((JdbcConnection) highLevelConn);
        // Insert data. We need at least 4 rows to force rewriting batch statements.
        this.pstmt = lowLevelConn.prepareStatement("INSERT INTO testBug21876798 VALUES (?, ?)");
        for (int i = 1; i <= 4; i++) {
            this.pstmt.setInt(1, tst);
            this.pstmt.setInt(2, i);
            this.pstmt.addBatch();
        }
        this.pstmt.executeBatch();
        // Check if data was inserted correctly.
        this.rs = this.stmt.executeQuery("SELECT val FROM testBug21876798 WHERE tst = " + tst);
        for (int i = 1; i <= 4; i++) {
            assertTrue(this.rs.next(), testCase + "/Row#" + i);
            assertEquals(i, this.rs.getInt(1), testCase + "/Row#" + i);
        }
        assertFalse(this.rs.next(), testCase);
        // Update data. We need at least 4 rows to force rewriting batch statements.
        this.pstmt = lowLevelConn.prepareStatement("UPDATE testBug21876798 SET val = ? WHERE tst = ? AND val = ?");
        for (int i = 1; i <= 4; i++) {
            this.pstmt.setInt(1, -i);
            this.pstmt.setInt(2, tst);
            this.pstmt.setInt(3, i);
            this.pstmt.addBatch();
        }
        this.pstmt.executeBatch();
        // Check if data was updated correctly.
        this.rs = this.stmt.executeQuery("SELECT val FROM testBug21876798 WHERE tst = " + tst);
        for (int i = 1; i <= 4; i++) {
            assertTrue(this.rs.next(), testCase + "/Row#" + i);
            assertEquals(-i, this.rs.getInt(1), testCase + "/Row#" + i);
        }
        assertFalse(this.rs.next(), testCase);
        lowLevelConn.close();
        highLevelConn.close();
    }
}
Also used : ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection) Connection(java.sql.Connection) XAConnection(javax.sql.XAConnection) JdbcConnection(com.mysql.cj.jdbc.JdbcConnection) MysqlConnection(com.mysql.cj.MysqlConnection) Properties(java.util.Properties) ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection) StatementsTest(testsuite.simple.StatementsTest) Test(org.junit.jupiter.api.Test)

Example 12 with ReplicationConnection

use of com.mysql.cj.jdbc.ha.ReplicationConnection in project aws-mysql-jdbc by awslabs.

the class ConnectionRegressionTest method testBug11879.

/**
 * Tests fix for BUG#11879 -- ReplicationConnection won't switch to replica, throws "Catalog can't be null" exception.
 *
 * @throws Exception
 */
@Test
public void testBug11879() throws Exception {
    Connection replConn = null;
    try {
        Properties props = new Properties();
        props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
        props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
        replConn = getSourceReplicaReplicationConnection(props);
        replConn.setReadOnly(true);
        replConn.setReadOnly(false);
    } finally {
        if (replConn != null) {
            replConn.close();
        }
    }
}
Also used : ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection) MysqlPooledConnection(com.mysql.cj.jdbc.MysqlPooledConnection) SuspendableXAConnection(com.mysql.cj.jdbc.SuspendableXAConnection) Connection(java.sql.Connection) XAConnection(javax.sql.XAConnection) PooledConnection(javax.sql.PooledConnection) MysqlXAConnection(com.mysql.cj.jdbc.MysqlXAConnection) JdbcConnection(com.mysql.cj.jdbc.JdbcConnection) MysqlConnection(com.mysql.cj.MysqlConnection) Properties(java.util.Properties) Test(org.junit.jupiter.api.Test)

Example 13 with ReplicationConnection

use of com.mysql.cj.jdbc.ha.ReplicationConnection in project aws-mysql-jdbc by awslabs.

the class ConnectionRegressionTest method testBug15570.

/**
 * Tests fix for BUG#15570 - ReplicationConnection incorrectly copies state, doesn't transfer connection context correctly when transitioning between the
 * same read-only states.
 *
 * (note, this test will fail if the test user doesn't have permission to "USE 'mysql'".
 *
 * @throws Exception
 */
@Test
public void testBug15570() throws Exception {
    Connection replConn = null;
    try {
        Properties props = new Properties();
        props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
        props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
        replConn = getSourceReplicaReplicationConnection(props);
        boolean dbMapsToSchema = ((JdbcConnection) replConn).getPropertySet().<DatabaseTerm>getEnumProperty(PropertyKey.databaseTerm).getValue() == DatabaseTerm.SCHEMA;
        int sourceConnectionId = Integer.parseInt(getSingleIndexedValueWithQuery(replConn, 1, "SELECT CONNECTION_ID()").toString());
        replConn.setReadOnly(false);
        assertEquals(sourceConnectionId, Integer.parseInt(getSingleIndexedValueWithQuery(replConn, 1, "SELECT CONNECTION_ID()").toString()));
        String currentDb = dbMapsToSchema ? replConn.getSchema() : replConn.getCatalog();
        if (dbMapsToSchema) {
            replConn.setSchema(currentDb);
            assertEquals(currentDb, replConn.getSchema());
        } else {
            replConn.setCatalog(currentDb);
            assertEquals(currentDb, replConn.getCatalog());
        }
        replConn.setReadOnly(true);
        int replicaConnectionId = Integer.parseInt(getSingleIndexedValueWithQuery(replConn, 1, "SELECT CONNECTION_ID()").toString());
        // The following test is okay for now, as the chance of MySQL wrapping the connection id counter during our testsuite is very small.
        // As per Bug#21286268 fix a Replication connection first initializes the Replicas sub-connection, then the Sources.
        assertTrue(sourceConnectionId > replicaConnectionId, "Source id " + sourceConnectionId + " is not newer than replica id " + replicaConnectionId);
        assertEquals(currentDb, dbMapsToSchema ? replConn.getSchema() : replConn.getCatalog());
        String newDb = "mysql";
        if (dbMapsToSchema) {
            replConn.setSchema(newDb);
            assertEquals(newDb, replConn.getSchema());
        } else {
            replConn.setCatalog(newDb);
            assertEquals(newDb, replConn.getCatalog());
        }
        replConn.setReadOnly(true);
        assertEquals(newDb, dbMapsToSchema ? replConn.getSchema() : replConn.getCatalog());
        replConn.setReadOnly(false);
        assertEquals(sourceConnectionId, Integer.parseInt(getSingleIndexedValueWithQuery(replConn, 1, "SELECT CONNECTION_ID()").toString()));
    } finally {
        if (replConn != null) {
            replConn.close();
        }
    }
}
Also used : DatabaseTerm(com.mysql.cj.conf.PropertyDefinitions.DatabaseTerm) ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection) MysqlPooledConnection(com.mysql.cj.jdbc.MysqlPooledConnection) SuspendableXAConnection(com.mysql.cj.jdbc.SuspendableXAConnection) Connection(java.sql.Connection) XAConnection(javax.sql.XAConnection) PooledConnection(javax.sql.PooledConnection) MysqlXAConnection(com.mysql.cj.jdbc.MysqlXAConnection) JdbcConnection(com.mysql.cj.jdbc.JdbcConnection) MysqlConnection(com.mysql.cj.MysqlConnection) Properties(java.util.Properties) Test(org.junit.jupiter.api.Test)

Example 14 with ReplicationConnection

use of com.mysql.cj.jdbc.ha.ReplicationConnection in project aws-mysql-jdbc by awslabs.

the class ConnectionRegressionTest method testReplicationConnectionGroupHostManagement.

@Test
public void testReplicationConnectionGroupHostManagement() throws Exception {
    String replicationGroup1 = "rg1";
    Properties props = new Properties();
    props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name());
    props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true");
    props.setProperty(PropertyKey.replicationConnectionGroup.getKeyName(), replicationGroup1);
    props.setProperty(PropertyKey.retriesAllDown.getKeyName(), "3");
    props.setProperty(PropertyKey.loadBalanceHostRemovalGracePeriod.getKeyName(), "1");
    ReplicationConnection conn2 = this.getUnreliableReplicationConnection(new String[] { "first", "second", "third" }, props);
    assertNotNull(this.conn, "Connection should not be null");
    conn2.setAutoCommit(false);
    String port = getPort(props);
    String firstHost = "first:" + port;
    String secondHost = "second:" + port;
    String thirdHost = "third:" + port;
    // "first" should be source, "second" and "third" should be replicas.
    assertEquals(1, ReplicationConnectionGroupManager.getConnectionCountWithHostAsSource(replicationGroup1, firstHost));
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsReplica(replicationGroup1, firstHost));
    // remove "third" from replica pool:
    conn2.removeReplica(thirdHost);
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsSource(replicationGroup1, thirdHost));
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsReplica(replicationGroup1, thirdHost));
    // add "third" back into replica pool:
    conn2.addReplicaHost(thirdHost);
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsSource(replicationGroup1, thirdHost));
    assertEquals(1, ReplicationConnectionGroupManager.getConnectionCountWithHostAsReplica(replicationGroup1, thirdHost));
    conn2.setReadOnly(false);
    assertEquals(0, ReplicationConnectionGroupManager.getNumberOfSourcePromotion(replicationGroup1));
    // failover to "second" as source
    ReplicationConnectionGroupManager.promoteReplicaToSource(replicationGroup1, secondHost);
    assertEquals(1, ReplicationConnectionGroupManager.getNumberOfSourcePromotion(replicationGroup1));
    // "first" is still a source:
    assertEquals(1, ReplicationConnectionGroupManager.getConnectionCountWithHostAsSource(replicationGroup1, firstHost));
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsReplica(replicationGroup1, firstHost));
    assertEquals(1, ReplicationConnectionGroupManager.getConnectionCountWithHostAsSource(replicationGroup1, secondHost));
    assertEquals(0, ReplicationConnectionGroupManager.getConnectionCountWithHostAsReplica(replicationGroup1, secondHost));
    ReplicationConnectionGroupManager.removeSourceHost(replicationGroup1, firstHost);
    conn2.createStatement().execute("SELECT 1");
    assertFalse(conn2.isClosed());
    conn2.commit();
    // validate that queries are successful:
    conn2.createStatement().execute("SELECT 1");
    assertTrue(conn2.isHostSource(secondHost));
    // source is now offline
    UnreliableSocketFactory.downHost("second");
    try {
        Statement lstmt = conn2.createStatement();
        lstmt.execute("SELECT 1");
        fail("Should fail here due to closed connection");
    } catch (SQLException sqlEx) {
        assertEquals("08S01", sqlEx.getSQLState());
    }
}
Also used : SQLException(java.sql.SQLException) PreparedStatement(java.sql.PreparedStatement) Statement(java.sql.Statement) ServerPreparedStatement(com.mysql.cj.jdbc.ServerPreparedStatement) ClientPreparedStatement(com.mysql.cj.jdbc.ClientPreparedStatement) Properties(java.util.Properties) ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection) Test(org.junit.jupiter.api.Test)

Example 15 with ReplicationConnection

use of com.mysql.cj.jdbc.ha.ReplicationConnection in project aws-mysql-jdbc by awslabs.

the class BaseTestCase method getUnreliableReplicationConnection.

protected ReplicationConnection getUnreliableReplicationConnection(Set<MockConnectionConfiguration> configs, Properties props) throws Exception {
    props = getHostFreePropertiesFromTestsuiteUrl(props);
    props.setProperty(PropertyKey.socketFactory.getKeyName(), "testsuite.UnreliableSocketFactory");
    HostInfo defaultHost = mainConnectionUrl.getMainHost();
    String db = defaultHost.getDatabase();
    String port = String.valueOf(defaultHost.getPort());
    String host = defaultHost.getHost();
    UnreliableSocketFactory.flushAllStaticData();
    StringBuilder hostString = new StringBuilder();
    String glue = "";
    for (MockConnectionConfiguration config : configs) {
        UnreliableSocketFactory.mapHost(config.hostName, host);
        hostString.append(glue);
        glue = ",";
        if (config.port == null) {
            config.port = (port == null ? "3306" : port);
        }
        hostString.append(config.getAddress());
        if (config.isDowned) {
            UnreliableSocketFactory.downHost(config.hostName);
        }
    }
    return (ReplicationConnection) getConnectionWithProps(ConnectionUrl.Type.REPLICATION_CONNECTION.getScheme() + "//" + hostString.toString() + "/" + db, props);
}
Also used : HostInfo(com.mysql.cj.conf.HostInfo) ReplicationConnection(com.mysql.cj.jdbc.ha.ReplicationConnection)

Aggregations

ReplicationConnection (com.mysql.cj.jdbc.ha.ReplicationConnection)23 Properties (java.util.Properties)21 Test (org.junit.jupiter.api.Test)20 Connection (java.sql.Connection)9 MysqlConnection (com.mysql.cj.MysqlConnection)8 JdbcConnection (com.mysql.cj.jdbc.JdbcConnection)8 SQLException (java.sql.SQLException)8 XAConnection (javax.sql.XAConnection)8 ClientPreparedStatement (com.mysql.cj.jdbc.ClientPreparedStatement)6 MysqlPooledConnection (com.mysql.cj.jdbc.MysqlPooledConnection)6 MysqlXAConnection (com.mysql.cj.jdbc.MysqlXAConnection)6 ServerPreparedStatement (com.mysql.cj.jdbc.ServerPreparedStatement)6 SuspendableXAConnection (com.mysql.cj.jdbc.SuspendableXAConnection)6 PreparedStatement (java.sql.PreparedStatement)6 Statement (java.sql.Statement)6 PooledConnection (javax.sql.PooledConnection)6 HostInfo (com.mysql.cj.conf.HostInfo)4 HashSet (java.util.HashSet)4 ClosedOnExpiredPasswordException (com.mysql.cj.exceptions.ClosedOnExpiredPasswordException)3 PasswordExpiredException (com.mysql.cj.exceptions.PasswordExpiredException)3