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();
}
}
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();
}
}
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));
}
}
}
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");
}
}
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");
}
}
Aggregations