Search in sources :

Example 31 with SessionFactory

use of com.mysql.cj.xdevapi.SessionFactory in project aws-mysql-jdbc by awslabs.

the class SessionTest method invalidDefaultSchema.

@Test
public void invalidDefaultSchema() {
    try {
        // Create user with mysql_native_password authentication plugin as it can be used with any of the authentication mechanisms.
        this.session.sql("CREATE USER IF NOT EXISTS 'testUserN'@'%' IDENTIFIED WITH mysql_native_password BY 'testUserN'").execute();
        this.session.sql("GRANT SELECT ON *.* TO 'testUserN'@'%'").execute();
        final String testSchemaName = getRandomTestSchemaName();
        final SessionFactory testSessionFactory = new SessionFactory();
        final String testUriPattern = "mysqlx://testUserN:testUserN@%s:%s/%s?xdevapi.auth=%s";
        // Check if the default schema is correctly sent when using different authentication mechanisms.
        String[] authMechs = mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.4")) ? new String[] { "PLAIN", "MYSQL41", "SHA256_MEMORY" } : new String[] { "PLAIN", "MYSQL41" };
        for (String authMech : authMechs) {
            final String testCase = "Testing missing default schema provided in authentication mecanism '" + authMech + "'.";
            // Test using a connection String.
            final String testUri = String.format(testUriPattern, getTestHost(), getTestPort(), testSchemaName, authMech);
            assertThrows(testCase, XProtocolError.class, "ERROR \\d{4} \\(HY000\\) Unknown database '" + testSchemaName + "'", () -> {
                testSessionFactory.getSession(testUri);
                return null;
            });
            // Test using a properties map.
            final Properties testProps = new Properties();
            testProps.setProperty(PropertyKey.USER.getKeyName(), "testUserN");
            testProps.setProperty(PropertyKey.PASSWORD.getKeyName(), "testUserN");
            testProps.setProperty(PropertyKey.HOST.getKeyName(), getTestHost());
            testProps.setProperty(PropertyKey.PORT.getKeyName(), String.valueOf(getTestPort()));
            testProps.setProperty(PropertyKey.DBNAME.getKeyName(), testSchemaName);
            testProps.setProperty(PropertyKey.xdevapiAuth.getKeyName(), authMech);
            assertThrows(testCase, XProtocolError.class, "ERROR \\d{4} \\(HY000\\) Unknown database '" + testSchemaName + "'", () -> {
                testSessionFactory.getSession(testUri);
                return null;
            });
        }
    } finally {
        this.session.sql("DROP USER IF EXISTS testUserN").execute();
    }
}
Also used : SessionFactory(com.mysql.cj.xdevapi.SessionFactory) JsonString(com.mysql.cj.xdevapi.JsonString) Properties(java.util.Properties) Test(org.junit.jupiter.api.Test)

Example 32 with SessionFactory

use of com.mysql.cj.xdevapi.SessionFactory in project aws-mysql-jdbc by awslabs.

the class SessionTest method testBug21690043.

/**
 * Tests fix for Bug#21690043, CONNECT FAILS WHEN PASSWORD IS BLANK.
 */
@Test
public void testBug21690043() {
    try {
        this.session.sql("CREATE USER 'bug21690043user1'@'%' IDENTIFIED WITH mysql_native_password").execute();
        this.session.sql("GRANT SELECT ON *.* TO 'bug21690043user1'@'%'").execute();
        Properties props = new Properties();
        props.putAll(this.testProperties);
        props.setProperty("user", "bug21690043user1");
        props.setProperty("password", "");
        new SessionFactory().getSession(props);
    } catch (Throwable t) {
        throw t;
    } finally {
        this.session.sql("DROP USER 'bug21690043user1'@'%'").execute();
    }
}
Also used : SessionFactory(com.mysql.cj.xdevapi.SessionFactory) Properties(java.util.Properties) Test(org.junit.jupiter.api.Test)

Example 33 with SessionFactory

use of com.mysql.cj.xdevapi.SessionFactory in project aws-mysql-jdbc by awslabs.

the class TableDeleteTest method testPreparedStatements.

@Test
public void testPreparedStatements() {
    assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.14")), "MySQL 8.0.14+ is required to run this test.");
    try {
        // Prepare test data.
        testPreparedStatementsResetData();
        SessionFactory sf = new SessionFactory();
        /*
             * Test common usage.
             */
        Session testSession = sf.getSession(this.testProperties);
        int sessionThreadId = getThreadId(testSession);
        assertPreparedStatementsCount(sessionThreadId, 0, 1);
        assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
        Table testTbl1 = testSession.getDefaultSchema().getTable("testPrepareDelete_1");
        Table testTbl2 = testSession.getDefaultSchema().getTable("testPrepareDelete_2");
        Table testTbl3 = testSession.getDefaultSchema().getTable("testPrepareDelete_3");
        Table testTbl4 = testSession.getDefaultSchema().getTable("testPrepareDelete_4");
        // Initialize several DeleteStatement objects.
        // Delete all.
        DeleteStatement testDelete1 = testTbl1.delete().where("true");
        // Criteria with one placeholder.
        DeleteStatement testDelete2 = testTbl2.delete().where("ord >= :n");
        // Criteria with same placeholder repeated.
        DeleteStatement testDelete3 = testTbl3.delete().where("ord >= :n AND ord <= :n + 1");
        // Criteria with multiple placeholders.
        DeleteStatement testDelete4 = testTbl4.delete().where("ord >= :n AND ord <= :m");
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete1, 0, -1);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete2, 0, -1);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete3, 0, -1);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete4, 0, -1);
        // A. Set binds: 1st execute -> non-prepared.
        assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete1, 0, -1);
        assertTestPreparedStatementsResult(testDelete2.bind("n", 2).execute(), 3, testTbl2.getName(), 1);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete2, 0, -1);
        assertTestPreparedStatementsResult(testDelete3.bind("n", 2).execute(), 2, testTbl3.getName(), 1, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete3, 0, -1);
        assertTestPreparedStatementsResult(testDelete4.bind("n", 2).bind("m", 3).execute(), 2, testTbl4.getName(), 1, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete4, 0, -1);
        assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
        testPreparedStatementsResetData();
        // B. Set orderBy resets execution count: 1st execute -> non-prepared.
        assertTestPreparedStatementsResult(testDelete1.orderBy("id").execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete1, 0, -1);
        assertTestPreparedStatementsResult(testDelete2.orderBy("id").execute(), 3, testTbl2.getName(), 1);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete2, 0, -1);
        assertTestPreparedStatementsResult(testDelete3.orderBy("id").execute(), 2, testTbl3.getName(), 1, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete3, 0, -1);
        assertTestPreparedStatementsResult(testDelete4.orderBy("id").execute(), 2, testTbl4.getName(), 1, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete4, 0, -1);
        assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
        testPreparedStatementsResetData();
        // C. Set binds reuse statement: 2nd execute -> prepare + execute.
        assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 1, testDelete1, 1, 1);
        assertTestPreparedStatementsResult(testDelete2.bind("n", 3).execute(), 2, testTbl2.getName(), 1, 2);
        assertPreparedStatementsCountsAndId(testSession, 2, testDelete2, 2, 1);
        assertTestPreparedStatementsResult(testDelete3.bind("n", 3).execute(), 2, testTbl3.getName(), 1, 2);
        assertPreparedStatementsCountsAndId(testSession, 3, testDelete3, 3, 1);
        assertTestPreparedStatementsResult(testDelete4.bind("m", 4).execute(), 3, testTbl4.getName(), 1);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 1);
        assertPreparedStatementsStatusCounts(testSession, 4, 4, 0);
        testPreparedStatementsResetData();
        // D. Set binds reuse statement: 3rd execute -> execute.
        assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete1, 1, 2);
        assertTestPreparedStatementsResult(testDelete2.bind("n", 4).execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete2, 2, 2);
        assertTestPreparedStatementsResult(testDelete3.bind("n", 1).execute(), 2, testTbl3.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete3, 3, 2);
        assertTestPreparedStatementsResult(testDelete4.bind("m", 2).execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 2);
        assertPreparedStatementsStatusCounts(testSession, 4, 8, 0);
        testPreparedStatementsResetData();
        // E. Set orderBy deallocates and resets execution count: 1st execute -> deallocate + non-prepared.
        assertTestPreparedStatementsResult(testDelete1.orderBy("id").execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 3, testDelete1, 0, -1);
        assertTestPreparedStatementsResult(testDelete2.orderBy("id").execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 2, testDelete2, 0, -1);
        assertTestPreparedStatementsResult(testDelete3.orderBy("id").execute(), 2, testTbl3.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 1, testDelete3, 0, -1);
        assertTestPreparedStatementsResult(testDelete4.orderBy("id").execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete4, 0, -1);
        assertPreparedStatementsStatusCounts(testSession, 4, 8, 4);
        testPreparedStatementsResetData();
        // F. No Changes: 2nd execute -> prepare + execute.
        assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
        assertPreparedStatementsCountsAndId(testSession, 1, testDelete1, 1, 1);
        assertTestPreparedStatementsResult(testDelete2.execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 2, testDelete2, 2, 1);
        assertTestPreparedStatementsResult(testDelete3.execute(), 2, testTbl3.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 3, testDelete3, 3, 1);
        assertTestPreparedStatementsResult(testDelete4.execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 1);
        assertPreparedStatementsStatusCounts(testSession, 8, 12, 4);
        testPreparedStatementsResetData();
        // G. Set limit for the first time deallocates and re-prepares: 1st execute -> re-prepare + execute.
        assertTestPreparedStatementsResult(testDelete1.limit(1).execute(), 1, testTbl1.getName(), 2, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete1, 1, 1);
        assertTestPreparedStatementsResult(testDelete2.limit(1).execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete2, 2, 1);
        assertTestPreparedStatementsResult(testDelete3.limit(1).execute(), 1, testTbl3.getName(), 2, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete3, 3, 1);
        assertTestPreparedStatementsResult(testDelete4.limit(1).execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 1);
        assertPreparedStatementsStatusCounts(testSession, 12, 16, 8);
        testPreparedStatementsResetData();
        // H. Set limit reuse prepared statement: 2nd execute -> execute.
        assertTestPreparedStatementsResult(testDelete1.limit(2).execute(), 2, testTbl1.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete1, 1, 2);
        assertTestPreparedStatementsResult(testDelete2.limit(2).execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete2, 2, 2);
        assertTestPreparedStatementsResult(testDelete3.limit(2).execute(), 2, testTbl3.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete3, 3, 2);
        assertTestPreparedStatementsResult(testDelete4.limit(2).execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 2);
        assertPreparedStatementsStatusCounts(testSession, 12, 20, 8);
        testPreparedStatementsResetData();
        // I. Set sort deallocates and resets execution count, set limit has no effect: 1st execute -> deallocate + non-prepared.
        assertTestPreparedStatementsResult(testDelete1.orderBy("id").limit(1).execute(), 1, testTbl1.getName(), 2, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 3, testDelete1, 0, -1);
        assertTestPreparedStatementsResult(testDelete2.orderBy("id").limit(1).execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 2, testDelete2, 0, -1);
        assertTestPreparedStatementsResult(testDelete3.orderBy("id").limit(1).execute(), 1, testTbl3.getName(), 2, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 1, testDelete3, 0, -1);
        assertTestPreparedStatementsResult(testDelete4.orderBy("id").limit(1).execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 0, testDelete4, 0, -1);
        assertPreparedStatementsStatusCounts(testSession, 12, 20, 12);
        testPreparedStatementsResetData();
        // J. Set limit reuse statement: 2nd execute -> prepare + execute.
        assertTestPreparedStatementsResult(testDelete1.limit(2).execute(), 2, testTbl1.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 1, testDelete1, 1, 1);
        assertTestPreparedStatementsResult(testDelete2.limit(2).execute(), 1, testTbl2.getName(), 1, 2, 3);
        assertPreparedStatementsCountsAndId(testSession, 2, testDelete2, 2, 1);
        assertTestPreparedStatementsResult(testDelete3.limit(2).execute(), 2, testTbl3.getName(), 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 3, testDelete3, 3, 1);
        assertTestPreparedStatementsResult(testDelete4.limit(2).execute(), 1, testTbl4.getName(), 1, 3, 4);
        assertPreparedStatementsCountsAndId(testSession, 4, testDelete4, 4, 1);
        assertPreparedStatementsStatusCounts(testSession, 16, 24, 12);
        testPreparedStatementsResetData();
        testSession.close();
        // Prepared statements won't live past the closing of the session.
        assertPreparedStatementsCount(sessionThreadId, 0, 10);
        /*
             * Test falling back onto non-prepared statements.
             */
        testSession = sf.getSession(this.testProperties);
        int origMaxPrepStmtCount = this.session.sql("SELECT @@max_prepared_stmt_count").execute().fetchOne().getInt(0);
        try {
            // Allow preparing only one more statement.
            this.session.sql("SET GLOBAL max_prepared_stmt_count = ?").bind(getPreparedStatementsCount() + 1).execute();
            sessionThreadId = getThreadId(testSession);
            assertPreparedStatementsCount(sessionThreadId, 0, 1);
            assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
            testTbl1 = testSession.getDefaultSchema().getTable("testPrepareDelete_1");
            testTbl2 = testSession.getDefaultSchema().getTable("testPrepareDelete_2");
            testDelete1 = testTbl1.delete().where("true");
            testDelete2 = testTbl2.delete().where("true");
            // 1st execute -> don't prepare.
            assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
            assertPreparedStatementsCountsAndId(testSession, 0, testDelete1, 0, -1);
            assertTestPreparedStatementsResult(testDelete2.execute(), 4, testTbl2.getName());
            assertPreparedStatementsCountsAndId(testSession, 0, testDelete2, 0, -1);
            assertPreparedStatementsStatusCounts(testSession, 0, 0, 0);
            testPreparedStatementsResetData();
            // 2nd execute -> prepare + execute.
            assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
            assertPreparedStatementsCountsAndId(testSession, 1, testDelete1, 1, 1);
            // Fails preparing, execute as non-prepared.
            assertTestPreparedStatementsResult(testDelete2.execute(), 4, testTbl2.getName());
            assertPreparedStatementsCountsAndId(testSession, 1, testDelete2, 0, -1);
            // Failed prepare also counts.
            assertPreparedStatementsStatusCounts(testSession, 2, 1, 0);
            testPreparedStatementsResetData();
            // 3rd execute -> execute.
            assertTestPreparedStatementsResult(testDelete1.execute(), 4, testTbl1.getName());
            assertPreparedStatementsCountsAndId(testSession, 1, testDelete1, 1, 2);
            // Execute as non-prepared.
            assertTestPreparedStatementsResult(testDelete2.execute(), 4, testTbl2.getName());
            assertPreparedStatementsCountsAndId(testSession, 1, testDelete2, 0, -1);
            assertPreparedStatementsStatusCounts(testSession, 2, 2, 0);
            testPreparedStatementsResetData();
            testSession.close();
            // Prepared statements won't live past the closing of the session.
            assertPreparedStatementsCount(sessionThreadId, 0, 10);
        } finally {
            this.session.sql("SET GLOBAL max_prepared_stmt_count = ?").bind(origMaxPrepStmtCount).execute();
        }
    } finally {
        for (int i = 0; i < 4; i++) {
            sqlUpdate("DROP TABLE IF EXISTS testPrepareDelete_" + (i + 1));
        }
    }
}
Also used : SessionFactory(com.mysql.cj.xdevapi.SessionFactory) Table(com.mysql.cj.xdevapi.Table) DeleteStatement(com.mysql.cj.xdevapi.DeleteStatement) Session(com.mysql.cj.xdevapi.Session) Test(org.junit.jupiter.api.Test)

Example 34 with SessionFactory

use of com.mysql.cj.xdevapi.SessionFactory in project aws-mysql-jdbc by awslabs.

the class TableSelectTest method testTableRowLocks.

@Test
public void testTableRowLocks() throws Exception {
    assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.3")), "MySQL 8.0.3+ is required to run this test.");
    sqlUpdate("drop table if exists testTableRowLocks");
    sqlUpdate("create table testTableRowLocks (_id varchar(32), a varchar(20))");
    // index is required to enable row locking
    sqlUpdate("CREATE UNIQUE INDEX myIndex ON testTableRowLocks (_id)");
    sqlUpdate("insert into testTableRowLocks values ('1', '1')");
    sqlUpdate("insert into testTableRowLocks values ('2', '1')");
    sqlUpdate("insert into testTableRowLocks values ('3', '1')");
    Session session1 = null;
    Session session2 = null;
    try {
        session1 = new SessionFactory().getSession(this.testProperties);
        Table table1 = session1.getDefaultSchema().getTable("testTableRowLocks");
        session2 = new SessionFactory().getSession(this.testProperties);
        Table table2 = session2.getDefaultSchema().getTable("testTableRowLocks");
        // test1: Shared Lock
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        // should return immediately
        table2.select("_id").where("_id = '2'").lockShared().execute();
        // should return immediately
        CompletableFuture<RowResult> res1 = table2.select("_id").where("_id = '1'").lockShared().executeAsync();
        res1.get(5, TimeUnit.SECONDS);
        assertTrue(res1.isDone());
        session1.rollback();
        session2.rollback();
        // test2: Shared Lock after Exclusive
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        // should return immediately
        table2.select("_id").where("_id = '2'").lockShared().execute();
        // session2 blocks
        CompletableFuture<RowResult> res2 = table2.select("_id").where("_id = '1'").lockShared().executeAsync();
        assertThrows(TimeoutException.class, new Callable<Void>() {

            public Void call() throws Exception {
                res2.get(5, TimeUnit.SECONDS);
                return null;
            }
        });
        // session2 should unblock now
        session1.rollback();
        res2.get(5, TimeUnit.SECONDS);
        assertTrue(res2.isDone());
        session2.rollback();
        // test3: Exclusive after Shared
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        table1.select("_id").where("_id = '3'").lockShared().execute();
        session2.startTransaction();
        // should return immediately
        table2.select("_id").where("_id = '2'").lockExclusive().execute();
        // should return immediately
        table2.select("_id").where("_id = '3'").lockShared().execute();
        // session2 blocks
        CompletableFuture<RowResult> res3 = table2.select("_id").where("_id = '1'").lockExclusive().executeAsync();
        assertThrows(TimeoutException.class, new Callable<Void>() {

            public Void call() throws Exception {
                res3.get(5, TimeUnit.SECONDS);
                return null;
            }
        });
        // session2 should unblock now
        session1.rollback();
        res3.get(5, TimeUnit.SECONDS);
        assertTrue(res3.isDone());
        session2.rollback();
        // test4: Exclusive after Exclusive
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        // should return immediately
        table2.select("_id").where("_id = '2'").lockExclusive().execute();
        // session2 blocks
        CompletableFuture<RowResult> res4 = table2.select("_id").where("_id = '1'").lockExclusive().executeAsync();
        assertThrows(TimeoutException.class, new Callable<Void>() {

            public Void call() throws Exception {
                res4.get(5, TimeUnit.SECONDS);
                return null;
            }
        });
        // session2 should unblock now
        session1.rollback();
        res4.get(5, TimeUnit.SECONDS);
        assertTrue(res4.isDone());
        session2.rollback();
    } finally {
        if (session1 != null) {
            session1.close();
        }
        if (session2 != null) {
            session2.close();
        }
        sqlUpdate("drop table if exists testTableRowLocks");
    }
}
Also used : SessionFactory(com.mysql.cj.xdevapi.SessionFactory) RowResult(com.mysql.cj.xdevapi.RowResult) Table(com.mysql.cj.xdevapi.Table) TimeoutException(java.util.concurrent.TimeoutException) DataConversionException(com.mysql.cj.exceptions.DataConversionException) ExecutionException(java.util.concurrent.ExecutionException) CoreSession(com.mysql.cj.CoreSession) Session(com.mysql.cj.xdevapi.Session) Test(org.junit.jupiter.api.Test)

Example 35 with SessionFactory

use of com.mysql.cj.xdevapi.SessionFactory in project aws-mysql-jdbc by awslabs.

the class TableSelectTest method testTableRowLockOptions.

@Test
public void testTableRowLockOptions() throws Exception {
    assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.5")), "MySQL 8.0.5+ is required to run this test.");
    Function<RowResult, List<String>> asStringList = rr -> rr.fetchAll().stream().map(r -> r.getString(0)).collect(Collectors.toList());
    sqlUpdate("DROP TABLE IF EXISTS testTableRowLockOptions");
    sqlUpdate("CREATE TABLE testTableRowLockOptions (_id VARCHAR(32), a VARCHAR(20))");
    // index is required to enable row locking
    sqlUpdate("CREATE UNIQUE INDEX myIndex ON testTableRowLockOptions (_id)");
    sqlUpdate("INSERT INTO testTableRowLockOptions VALUES ('1', '1'), ('2', '1'), ('3', '1')");
    Session session1 = null;
    Session session2 = null;
    try {
        session1 = new SessionFactory().getSession(this.testProperties);
        Table table1 = session1.getDefaultSchema().getTable("testTableRowLockOptions");
        session2 = new SessionFactory().getSession(this.testProperties);
        Table table2 = session2.getDefaultSchema().getTable("testTableRowLockOptions");
        RowResult res;
        CompletableFuture<RowResult> futRes;
        /*
             * 1. Shared Lock in both sessions.
             */
        // session2.lockShared() returns data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockShared().execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared().executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session1.rollback();
        // session2.lockShared(NOWAIT) returns data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.NOWAIT).executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session1.rollback();
        // session2.lockShared(SKIP_LOCK) returns data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session1.rollback();
        /*
             * 2. Shared Lock in first session and exclusive lock in second.
             */
        // session2.lockExclusive() blocks until session1 ends.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        // session2.startTransaction();
        // res = table2.select("_id").where("_id < '3'").lockExclusive().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive().executeAsync();
        final CompletableFuture<RowResult> fr1 = futRes;
        assertThrows(TimeoutException.class, () -> fr1.get(3, TimeUnit.SECONDS));
        // Unlocks session2.
        session1.rollback();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        // session2.lockExclusive(NOWAIT) should return locking error.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<RowResult> fr2 = futRes;
        assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr2.get(3, TimeUnit.SECONDS));
        session2.rollback();
        session1.rollback();
        // session2.lockExclusive(SKIP_LOCK) should return (unlocked) data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session1.rollback();
        /*
             * 3. Exclusive Lock in first session and shared lock in second.
             */
        // session2.lockShared() blocks until session1 ends.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        // session2.startTransaction();
        // res = table2.select("_id").where("_id < '3'").lockShared().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared().executeAsync();
        final CompletableFuture<RowResult> fr3 = futRes;
        assertThrows(TimeoutException.class, () -> fr3.get(3, TimeUnit.SECONDS));
        // Unlocks session2.
        session1.rollback();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        // session2.lockShared(NOWAIT) should return locking error.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<RowResult> fr4 = futRes;
        assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr4.get(3, TimeUnit.SECONDS));
        session2.rollback();
        session1.rollback();
        // session2.lockShared(SKIP_LOCK) should return (unlocked) data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session1.rollback();
        /*
             * 4. Exclusive Lock in both sessions.
             */
        // session2.lockExclusive() blocks until session1 ends.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        // session2.startTransaction();
        // res = table2.select("_id").where("_id < '3'").lockExclusive().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive().executeAsync();
        final CompletableFuture<RowResult> fr5 = futRes;
        assertThrows(TimeoutException.class, () -> fr5.get(3, TimeUnit.SECONDS));
        // Unlocks session2.
        session1.rollback();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        // session2.lockExclusive(NOWAIT) should return locking error.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        assertThrows(XProtocolError.class, "ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<RowResult> fr6 = futRes;
        assertThrows(ExecutionException.class, ".*XProtocolError: ERROR 3572 \\(HY000\\) Statement aborted because lock\\(s\\) could not be acquired immediately and NOWAIT is set\\.", () -> fr6.get(3, TimeUnit.SECONDS));
        session2.rollback();
        session1.rollback();
        // session2.lockExclusive(SKIP_LOCK) should return (unlocked) data immediately.
        session1.startTransaction();
        table1.select("_id").where("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        res = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = table2.select("_id").where("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("2"));
        session2.rollback();
        session1.rollback();
    } finally {
        if (session1 != null) {
            session1.close();
        }
        if (session2 != null) {
            session2.close();
        }
        sqlUpdate("DROP TABLE IF EXISTS testTableRowLockOptions");
    }
}
Also used : RowResult(com.mysql.cj.xdevapi.RowResult) Type(com.mysql.cj.xdevapi.Type) TimeoutException(java.util.concurrent.TimeoutException) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) Function(java.util.function.Function) Statement(com.mysql.cj.xdevapi.Statement) BigDecimal(java.math.BigDecimal) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) Map(java.util.Map) Assumptions.assumeTrue(org.junit.jupiter.api.Assumptions.assumeTrue) CoreSession(com.mysql.cj.CoreSession) BigInteger(java.math.BigInteger) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) Column(com.mysql.cj.xdevapi.Column) SessionImpl(com.mysql.cj.xdevapi.SessionImpl) Table(com.mysql.cj.xdevapi.Table) ServerVersion(com.mysql.cj.ServerVersion) Session(com.mysql.cj.xdevapi.Session) CoreMatchers.hasItems(org.hamcrest.CoreMatchers.hasItems) Field(java.lang.reflect.Field) Collectors(java.util.stream.Collectors) DataConversionException(com.mysql.cj.exceptions.DataConversionException) XProtocolError(com.mysql.cj.protocol.x.XProtocolError) SessionFactory(com.mysql.cj.xdevapi.SessionFactory) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Test(org.junit.jupiter.api.Test) Row(com.mysql.cj.xdevapi.Row) SqlResult(com.mysql.cj.xdevapi.SqlResult) List(java.util.List) SelectStatement(com.mysql.cj.xdevapi.SelectStatement) XProtocol(com.mysql.cj.protocol.x.XProtocol) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) PropertyKey(com.mysql.cj.conf.PropertyKey) SessionFactory(com.mysql.cj.xdevapi.SessionFactory) RowResult(com.mysql.cj.xdevapi.RowResult) Table(com.mysql.cj.xdevapi.Table) List(java.util.List) CoreSession(com.mysql.cj.CoreSession) Session(com.mysql.cj.xdevapi.Session) Test(org.junit.jupiter.api.Test)

Aggregations

SessionFactory (com.mysql.cj.xdevapi.SessionFactory)37 Session (com.mysql.cj.xdevapi.Session)35 Test (org.junit.jupiter.api.Test)33 JsonString (com.mysql.cj.xdevapi.JsonString)23 Collection (com.mysql.cj.xdevapi.Collection)21 ExecutionException (java.util.concurrent.ExecutionException)20 WrongArgumentException (com.mysql.cj.exceptions.WrongArgumentException)17 Schema (com.mysql.cj.xdevapi.Schema)16 DocResult (com.mysql.cj.xdevapi.DocResult)8 CoreSession (com.mysql.cj.CoreSession)7 Table (com.mysql.cj.xdevapi.Table)7 DbDoc (com.mysql.cj.xdevapi.DbDoc)6 Row (com.mysql.cj.xdevapi.Row)6 SqlResult (com.mysql.cj.xdevapi.SqlResult)6 RowResult (com.mysql.cj.xdevapi.RowResult)4 SessionImpl (com.mysql.cj.xdevapi.SessionImpl)4 Properties (java.util.Properties)4 DbDocImpl (com.mysql.cj.xdevapi.DbDocImpl)3 FindStatement (com.mysql.cj.xdevapi.FindStatement)3 SelectStatement (com.mysql.cj.xdevapi.SelectStatement)3