Search in sources :

Example 1 with Collection

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

the class DevApiSample method documentWalkthrough.

public static void documentWalkthrough(Schema schema) {
    // document walthrough
    Collection coll = schema.createCollection("myBooks", /* reuseExisting? */
    true);
    DbDoc newDoc = new DbDocImpl().add("isbn", new JsonString().setValue("12345"));
    newDoc.add("title", new JsonString().setValue("Effi Briest"));
    newDoc.add("author", new JsonString().setValue("Theodor Fontane"));
    newDoc.add("currentlyReadingPage", new JsonNumber().setValue(String.valueOf(42)));
    coll.add(newDoc).execute();
    // note: "$" prefix for document paths is optional. "$.title.somethingElse[0]" is the same as "title.somethingElse[0]" in document expressions
    DocResult docs = coll.find("$.title = 'Effi Briest' and $.currentlyReadingPage > 10").execute();
    DbDoc book = docs.next();
    System.err.println("Currently reading " + ((JsonString) book.get("title")).getString() + " on page " + ((JsonNumber) book.get("currentlyReadingPage")).getInteger());
    // increment the page number and fetch it again
    coll.modify("$.isbn = 12345").set("$.currentlyReadingPage", ((JsonNumber) book.get("currentlyReadingPage")).getInteger() + 1).execute();
    docs = coll.find("$.title = 'Effi Briest' and $.currentlyReadingPage > 10").execute();
    book = docs.next();
    System.err.println("Currently reading " + ((JsonString) book.get("title")).getString() + " on page " + ((JsonNumber) book.get("currentlyReadingPage")).getInteger());
    // remove the doc
    coll.remove("true").execute();
    System.err.println("Number of books in collection: " + coll.count());
    schema.dropCollection(coll.getName());
}
Also used : DbDoc(com.mysql.cj.xdevapi.DbDoc) DbDocImpl(com.mysql.cj.xdevapi.DbDocImpl) JsonNumber(com.mysql.cj.xdevapi.JsonNumber) Collection(com.mysql.cj.xdevapi.Collection) JsonString(com.mysql.cj.xdevapi.JsonString) DocResult(com.mysql.cj.xdevapi.DocResult)

Example 2 with Collection

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

the class SchemaTest method testCreateCollectionWithOptions.

@Test
public void testCreateCollectionWithOptions() {
    String collName1 = "testCreateCollection1";
    String collName2 = "testCreateCollection2";
    dropCollection(collName1);
    dropCollection(collName2);
    String sch1 = "{" + "\"id\":\"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"description\":\"A geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{\"type\":\"number\"}," + "\"longitude\":{\"type\":\"number\"}},\"required\":[\"latitude\",\"longitude\"]}";
    String sch2 = "{\"id\":\"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"description\":\"The geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{\"type\":\"number\"}," + "\"longitude\":{\"type\":\"number\"}},\"required\":[\"latitude\",\"longitude\"]}";
    String sch3 = "{\"id\":\"http://json-schema.org/idx\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + "\"type\":\"object\",\"properties\":{\"index\":{\"type\":\"number\"}},\"required\":[\"index\"]}";
    try {
        if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.19"))) {
            // TSFR2b.1: Call createCollection with both level and schema options are set. Ensure that given values are set on server.
            Collection coll = // 
            this.schema.createCollection(// 
            collName1, new CreateCollectionOptions().setReuseExisting(false).setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
            SqlResult res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            String def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            coll.add("{\"latitude\": 20, \"longitude\": 30}").execute();
            Collection coll1 = // 
            this.schema.createCollection(// 
            collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setLevel(ValidationLevel.OFF).setSchema(sch1)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            coll1 = // 
            this.schema.createCollection(// 
            collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setSchema(sch2)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertFalse(def.contains(sch2));
            assertTrue(def.contains(sch1));
            coll1 = // 
            this.schema.createCollection(// 
            collName1, new CreateCollectionOptions().setReuseExisting(true).setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertFalse(def.contains(sch2));
            assertTrue(def.contains(sch1));
            coll1.add("{\"latitude\": 30, \"longitude\": 40}").execute();
            // TSFR6d: Call createCollection(String collectionName) and createCollection(String collectionName, boolean reuseExisting) methods against server implementing WL#12965 and ensure they work as before.
            this.schema.createCollection(collName2);
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
            def = res.next().getString(1);
            assertTrue(def.contains("NOT ENFORCED"));
            dropCollection(collName2);
            this.schema.createCollection(collName2, new CreateCollectionOptions().setReuseExisting(false));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
            def = res.next().getString(1);
            assertTrue(def.contains("NOT ENFORCED"));
            dropCollection(collName2);
            assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.createCollection(collName1);
                    return null;
                }
            }).getErrorCode());
            assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.createCollection(collName1, false);
                    return null;
                }
            }).getErrorCode());
            assertEquals(MysqlErrorNumbers.ER_TABLE_EXISTS_ERROR, assertThrows(XProtocolError.class, new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.createCollection(collName1, new CreateCollectionOptions().setReuseExisting(false));
                    return null;
                }
            }).getErrorCode());
            Collection coll2 = this.schema.createCollection(collName1, true);
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            coll2 = this.schema.createCollection(collName1, new CreateCollectionOptions().setReuseExisting(true));
            assertEquals(coll, coll2);
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            // TSFR2b.2: Call createCollection with only schema option. Ensure the default level value is set on server.
            dropCollection(collName2);
            this.schema.createCollection(collName2, new CreateCollectionOptions().setValidation(new Validation().setSchema(sch1)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
            def = res.next().getString(1);
            if (mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.20"))) {
                // After the Bug#30830962 fix when schema is set and level is omitted xplugin sets it to "strict"
                assertFalse(def.contains("NOT ENFORCED"));
            } else {
                assertTrue(def.contains("NOT ENFORCED"));
            }
            assertTrue(def.contains(sch1));
            // TSFR2b.3: Call createCollection with only level option. Ensure the default schema and the given level are set on server.
            dropCollection(collName2);
            this.schema.createCollection(collName2, new CreateCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName2 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains("{\"type\":\"object\"}"));
            // TSFR5: Create collection with json schema and level `strict`. Try to insert document which doesn't match this schema, ensure that a server error being raised.
            assertThrows(XProtocolError.class, "ERROR 5180 \\(HY000\\) Document is not valid according to the schema assigned to collection.*", new Callable<Void>() {

                public Void call() throws Exception {
                    coll.add("{\"_id\": 1}").execute();
                    return null;
                }
            });
            // TSFR2a.1: Call modifyCollection with only level option. Ensure it's changed on server.
            this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertTrue(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertTrue(def.contains(sch1));
            // TSFR2a.2: Call modifyCollection with only schema option. Ensure it's changed on server.
            // sch2 is compatible with sch1
            this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setSchema(sch2)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertFalse(def.contains(sch1));
            assertTrue(def.contains(sch2));
            assertThrows(XProtocolError.class, "ERROR 5180 \\(HY000\\) Document is not valid according to the schema assigned to collection.*", new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.modifyCollection(collName1, // sch3 is incompatible with sch1
                    new ModifyCollectionOptions().setValidation(new Validation().setSchema(sch3)));
                    return null;
                }
            });
            // TSFR2a.3: Call modifyCollection with both level and schema options. Ensure they are changed on server.
            this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF).setSchema(sch3)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertTrue(def.contains("NOT ENFORCED"));
            assertFalse(def.contains(sch2));
            assertTrue(def.contains(sch3));
            this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema(sch1)));
            res = this.session.sql("SHOW CREATE TABLE `" + this.schema.getName() + "`.`" + collName1 + "`").execute();
            def = res.next().getString(1);
            assertFalse(def.contains("NOT ENFORCED"));
            assertFalse(def.contains(sch3));
            assertTrue(def.contains(sch1));
            // TSFR2a.4: Call modifyCollection with neither level nor schema options are set. Ensure Connector/J throws the XProtocolError
            assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.modifyCollection(collName1, null);
                    return null;
                }
            });
            assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions());
                    return null;
                }
            });
            assertThrows(XProtocolError.class, "ERROR 5020 \\(HY000\\) Arguments value used under \"validation\" must be an object with at least one field", new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation()));
                    return null;
                }
            });
            // TSFR4: Try to create collection with an invalid json schema. Ensure that a server error being raised.
            assertThrows(XProtocolError.class, "ERROR 5182 \\(HY000\\) JSON validation schema .*", new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.createCollection("wrongSchema", new CreateCollectionOptions().setValidation(new Validation().setSchema("{\"id\": \"http://json-schema.org/geo\",\"$schema\":\"http://json-schema.org/draft-06/schema#\"," + // 
                    "\"description\":\"The geographical coordinate\",\"type\":\"object\",\"properties\":{\"latitude\":{" + // wrong type
                    "\"type\":\"blablabla\"" + "}},\"required\":[\"latitude\",\"foo\"]}")));
                    return null;
                }
            });
        } else {
            // for old servers
            // TSFR6b: Call createCollection(collectionName, createCollectionOptions) method against server which doesn't support validation parameter for `create_collection` X Protocol command,
            // eg. MySQL 5.7. Ensure that server responds with error code 5015 and that Connector/J wraps it to WrongArgumentException with message
            // "The server doesn't support the requested operation. Please update the MySQL Server and or Client library".
            assertThrows(WrongArgumentException.class, Messages.getString("Schema.CreateCollection"), new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.createCollection(collName1, new CreateCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.STRICT).setSchema("{\"id\": \"http://json-schema.org/geo\",\"$schema\": \"http://json-schema.org/draft-06/schema#\"," + "\"description\": \"A geographical coordinate\",\"type\": \"object\",\"properties\":" + "{\"latitude\": {\"type\": \"number\"},\"longitude\": {\"type\": \"number\"}}," + "\"required\": [\"latitude\", \"longitude\"]}")));
                    return null;
                }
            });
            // TSFR6c: Call modifyCollection(String collectionName, ModifyCollectionOptions options) method against server which doesn't implement `modify_collection_options` X Protocol command,
            // eg. MySQL 5.7. Ensure that server responds with error code 5157 and that Connector/J wraps it to WrongArgumentException with message
            // "The server doesn't support the requested operation. Please update the MySQL Server and or Client library".
            assertThrows(WrongArgumentException.class, Messages.getString("Schema.CreateCollection"), new Callable<Void>() {

                public Void call() throws Exception {
                    SchemaTest.this.schema.modifyCollection(collName1, new ModifyCollectionOptions().setValidation(new Validation().setLevel(ValidationLevel.OFF)));
                    return null;
                }
            });
        // TSFR6a: Call createCollection(String collectionName) and createCollection(String collectionName, boolean reuseExisting) methods against servers not implementing WL#12965 and ensure they work as before.
        // It's covered by testCreateCollection() test case.
        }
    } finally {
        dropCollection(collName1);
        dropCollection(collName2);
    }
}
Also used : Validation(com.mysql.cj.xdevapi.Schema.Validation) ModifyCollectionOptions(com.mysql.cj.xdevapi.Schema.ModifyCollectionOptions) SqlResult(com.mysql.cj.xdevapi.SqlResult) Collection(com.mysql.cj.xdevapi.Collection) CreateCollectionOptions(com.mysql.cj.xdevapi.Schema.CreateCollectionOptions) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException) Test(org.junit.jupiter.api.Test)

Example 3 with Collection

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

the class SchemaTest method testDropCollection.

@Test
public void testDropCollection() {
    String collName = "testDropCollection";
    dropCollection(collName);
    Collection coll = this.schema.getCollection(collName);
    assertEquals(DbObjectStatus.NOT_EXISTS, coll.existsInDatabase());
    // dropping non-existing collection should not fail
    this.schema.dropCollection(collName);
    coll = this.schema.createCollection(collName);
    assertEquals(DbObjectStatus.EXISTS, coll.existsInDatabase());
    this.schema.dropCollection(collName);
    // ensure that collection is dropped
    coll = this.schema.getCollection(collName);
    assertEquals(DbObjectStatus.NOT_EXISTS, coll.existsInDatabase());
    assertThrows(XProtocolError.class, "Parameter 'collectionName' must not be null.", new Callable<Void>() {

        public Void call() throws Exception {
            SchemaTest.this.schema.dropCollection(null);
            return null;
        }
    });
}
Also used : Collection(com.mysql.cj.xdevapi.Collection) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException) Test(org.junit.jupiter.api.Test)

Example 4 with Collection

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

the class SessionTest method testBug97269.

/**
 * Test fix for Bug#97269 (30438500), POSSIBLE BUG IN COM.MYSQL.CJ.XDEVAPI.STREAMINGDOCRESULTBUILDER.
 *
 * @throws Exception
 */
@Test
public void testBug97269() throws Exception {
    Session sess = null;
    try {
        String message1 = "W1";
        String message2 = "W2";
        // create notice message buffers
        Frame.Builder notice1 = Frame.newBuilder().setScope(Frame.Scope.LOCAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message1).build().toByteString());
        Frame.Builder notice2 = Frame.newBuilder().setScope(Frame.Scope.GLOBAL).setType(Frame.Type.WARNING_VALUE).setPayload(com.mysql.cj.x.protobuf.MysqlxNotice.Warning.newBuilder().setCode(MysqlErrorNumbers.ER_BAD_DB_ERROR).setMsg(message2).build().toByteString());
        byte[] notice1Bytes = makeNoticeBytes(notice1.build());
        byte[] notice2Bytes = makeNoticeBytes(notice2.build());
        int size = notice1Bytes.length + notice2Bytes.length;
        byte[] noticesBytes = new byte[size];
        System.arraycopy(notice1Bytes, 0, noticesBytes, 0, notice1Bytes.length);
        System.arraycopy(notice2Bytes, 0, noticesBytes, notice1Bytes.length, notice2Bytes.length);
        InjectedSocketFactory.flushAllStaticData();
        String url = this.baseUrl + (this.baseUrl.contains("?") ? "" : "?") + makeParam(PropertyKey.socketFactory, InjectedSocketFactory.class.getName(), !this.baseUrl.contains("?") || this.baseUrl.endsWith("?")) + makeParam(PropertyKey.xdevapiSslMode, XdevapiSslMode.DISABLED.toString()) + makeParam(PropertyKey.xdevapiCompression, Compression.DISABLED.toString()) + // to allow injection between result rows
        makeParam(PropertyKey.useReadAheadInput, "false");
        sess = this.fact.getSession(url);
        SocketFactory sf = ((SessionImpl) sess).getSession().getProtocol().getSocketConnection().getSocketFactory();
        assertTrue(InjectedSocketFactory.class.isAssignableFrom(sf.getClass()));
        Collection collection = sess.getDefaultSchema().createCollection("testBug97269");
        collection.add("{\"_id\":\"the_id\",\"g\":1}").execute();
        // StreamingDocResultBuilder
        InjectedSocketFactory.injectedBuffer = noticesBytes;
        DocResult docs = collection.find().fields("$._id as _id, $.g as g, 1 + 1 as q").execute();
        DbDoc doc = docs.next();
        assertEquals("the_id", ((JsonString) doc.get("_id")).getString());
        assertEquals(new Integer(1), ((JsonNumber) doc.get("g")).getInteger());
        assertEquals(new Integer(2), ((JsonNumber) doc.get("q")).getInteger());
        int cnt = 0;
        for (Iterator<Warning> warn = docs.getWarnings(); warn.hasNext(); ) {
            Warning w = warn.next();
            if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
                cnt++;
            }
        }
        assertEquals(2, cnt);
        InjectedSocketFactory.flushAllStaticData();
        InjectedSocketFactory.injectedBuffer = noticesBytes;
        SqlResult rs1 = sess.sql("select 1").execute();
        assertEquals(1, rs1.fetchOne().getInt(0));
        cnt = 0;
        for (Iterator<Warning> warn = rs1.getWarnings(); warn.hasNext(); ) {
            Warning w = warn.next();
            if (w.getMessage().equals(message1) || w.getMessage().equals(message2)) {
                cnt++;
            }
        }
        assertEquals(2, cnt);
    } finally {
        InjectedSocketFactory.flushAllStaticData();
        dropCollection("testBug97269");
        if (sess != null) {
            sess.close();
        }
    }
}
Also used : Frame(com.mysql.cj.x.protobuf.MysqlxNotice.Frame) Warning(com.mysql.cj.xdevapi.Warning) SqlResult(com.mysql.cj.xdevapi.SqlResult) SocketFactory(com.mysql.cj.protocol.SocketFactory) InjectedSocketFactory(testsuite.InjectedSocketFactory) UnreliableSocketFactory(testsuite.UnreliableSocketFactory) JsonString(com.mysql.cj.xdevapi.JsonString) DbDoc(com.mysql.cj.xdevapi.DbDoc) InjectedSocketFactory(testsuite.InjectedSocketFactory) Collection(com.mysql.cj.xdevapi.Collection) DocResult(com.mysql.cj.xdevapi.DocResult) CoreSession(com.mysql.cj.CoreSession) Session(com.mysql.cj.xdevapi.Session) Test(org.junit.jupiter.api.Test)

Example 5 with Collection

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

the class CollectionFindTest method testCollectionRowLockOptions.

@Test
public void testCollectionRowLockOptions() throws Exception {
    assumeTrue(mysqlVersionMeetsMinimum(ServerVersion.parseVersion("8.0.5")), "MySQL 8.0.5+ is required to run this test.");
    Function<DocResult, List<String>> asStringList = rr -> rr.fetchAll().stream().map(d -> ((JsonString) d.get("_id")).getString()).collect(Collectors.toList());
    this.collection.add("{\"_id\":\"1\", \"a\":1}").add("{\"_id\":\"2\", \"a\":1}").add("{\"_id\":\"3\", \"a\":1}").execute();
    Session session1 = null;
    Session session2 = null;
    try {
        session1 = new SessionFactory().getSession(this.testProperties);
        Collection col1 = session1.getDefaultSchema().getCollection(this.collectionName);
        session2 = new SessionFactory().getSession(this.testProperties);
        Collection col2 = session2.getDefaultSchema().getCollection(this.collectionName);
        DocResult res;
        CompletableFuture<DocResult> futRes;
        /*
             * 1. Shared Lock in both sessions.
             */
        // session2.lockShared() returns data immediately.
        session1.startTransaction();
        col1.find("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockShared().execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockShared().executeAsync();
        res = futRes.get(3, TimeUnit.SECONDS);
        assertTrue(futRes.isDone());
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        session1.rollback();
        // session2.lockShared(NOWAIT) returns data immediately.
        session1.startTransaction();
        col1.find("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_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), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        session1.rollback();
        // session2.lockShared(SKIP_LOCK) returns data immediately.
        session1.startTransaction();
        col1.find("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(2, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_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), CoreMatchers.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();
        col1.find("_id = '1'").lockShared().execute();
        // session2.startTransaction();
        // res = col2.find("_id < '3'").lockExclusive().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockExclusive().executeAsync();
        final CompletableFuture<DocResult> 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), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        // session2.lockExclusive(NOWAIT) should return locking error.
        session1.startTransaction();
        col1.find("_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\\.", () -> col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<DocResult> 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();
        col1.find("_id = '1'").lockShared().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_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), CoreMatchers.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();
        col1.find("_id = '1'").lockExclusive().execute();
        // session2.startTransaction();
        // res = col2.find("_id < '3'").lockShared().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockShared().executeAsync();
        final CompletableFuture<DocResult> 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), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        // session2.lockShared(NOWAIT) should return locking error.
        session1.startTransaction();
        col1.find("_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\\.", () -> col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockShared(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<DocResult> 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();
        col1.find("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockShared(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_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), CoreMatchers.hasItems("2"));
        session2.rollback();
        session1.rollback();
        /*
             * 4. Exclusive Lock in both sessions.
             */
        // session2.lockExclusive() blocks until session1 ends.
        session1.startTransaction();
        col1.find("_id = '1'").lockExclusive().execute();
        // session2.startTransaction();
        // res = col2.find("_id < '3'").lockExclusive().execute(); (Can't test)
        // session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockExclusive().executeAsync();
        final CompletableFuture<DocResult> 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), CoreMatchers.hasItems("1", "2"));
        session2.rollback();
        // session2.lockExclusive(NOWAIT) should return locking error.
        session1.startTransaction();
        col1.find("_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\\.", () -> col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).execute());
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_id < '3'").lockExclusive(Statement.LockContention.NOWAIT).executeAsync();
        final CompletableFuture<DocResult> 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();
        col1.find("_id = '1'").lockExclusive().execute();
        session2.startTransaction();
        res = col2.find("_id < '3'").lockExclusive(Statement.LockContention.SKIP_LOCKED).execute();
        assertEquals(1, asStringList.apply(res).size());
        assertThat(asStringList.apply(res), CoreMatchers.hasItems("2"));
        session2.rollback();
        session2.startTransaction();
        futRes = col2.find("_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), CoreMatchers.hasItems("2"));
        session2.rollback();
        session1.rollback();
    } finally {
        if (session1 != null) {
            session1.close();
        }
        if (session2 != null) {
            session2.close();
        }
    }
}
Also used : CoreMatchers(org.hamcrest.CoreMatchers) RowResult(com.mysql.cj.xdevapi.RowResult) JsonNumber(com.mysql.cj.xdevapi.JsonNumber) Assertions.assertNotEquals(org.junit.jupiter.api.Assertions.assertNotEquals) TimeoutException(java.util.concurrent.TimeoutException) Collection(com.mysql.cj.xdevapi.Collection) Statement(com.mysql.cj.xdevapi.Statement) BigDecimal(java.math.BigDecimal) Expression.expr(com.mysql.cj.xdevapi.Expression.expr) Assertions.assertFalse(org.junit.jupiter.api.Assertions.assertFalse) FindStatementImpl(com.mysql.cj.xdevapi.FindStatementImpl) Map(java.util.Map) Table(com.mysql.cj.xdevapi.Table) ServerVersion(com.mysql.cj.ServerVersion) WrongArgumentException(com.mysql.cj.exceptions.WrongArgumentException) Warning(com.mysql.cj.xdevapi.Warning) Collectors(java.util.stream.Collectors) Test(org.junit.jupiter.api.Test) List(java.util.List) Assertions.assertTrue(org.junit.jupiter.api.Assertions.assertTrue) FindStatement(com.mysql.cj.xdevapi.FindStatement) Assertions.fail(org.junit.jupiter.api.Assertions.fail) MysqlErrorNumbers(com.mysql.cj.exceptions.MysqlErrorNumbers) Assertions.assertNotNull(org.junit.jupiter.api.Assertions.assertNotNull) Result(com.mysql.cj.xdevapi.Result) DbDocImpl(com.mysql.cj.xdevapi.DbDocImpl) JsonArray(com.mysql.cj.xdevapi.JsonArray) Assertions.assertNull(org.junit.jupiter.api.Assertions.assertNull) HashMap(java.util.HashMap) Callable(java.util.concurrent.Callable) CompletableFuture(java.util.concurrent.CompletableFuture) JsonString(com.mysql.cj.xdevapi.JsonString) Function(java.util.function.Function) ArrayList(java.util.ArrayList) AddResult(com.mysql.cj.xdevapi.AddResult) Assumptions.assumeTrue(org.junit.jupiter.api.Assumptions.assumeTrue) MatcherAssert.assertThat(org.hamcrest.MatcherAssert.assertThat) Assertions.assertEquals(org.junit.jupiter.api.Assertions.assertEquals) SessionImpl(com.mysql.cj.xdevapi.SessionImpl) Session(com.mysql.cj.xdevapi.Session) Iterator(java.util.Iterator) CoreMatchers.hasItems(org.hamcrest.CoreMatchers.hasItems) DbDoc(com.mysql.cj.xdevapi.DbDoc) DocResult(com.mysql.cj.xdevapi.DocResult) XProtocolError(com.mysql.cj.protocol.x.XProtocolError) SessionFactory(com.mysql.cj.xdevapi.SessionFactory) ExecutionException(java.util.concurrent.ExecutionException) TimeUnit(java.util.concurrent.TimeUnit) Row(com.mysql.cj.xdevapi.Row) SqlResult(com.mysql.cj.xdevapi.SqlResult) JsonLiteral(com.mysql.cj.xdevapi.JsonLiteral) SessionFactory(com.mysql.cj.xdevapi.SessionFactory) Collection(com.mysql.cj.xdevapi.Collection) List(java.util.List) ArrayList(java.util.ArrayList) JsonString(com.mysql.cj.xdevapi.JsonString) DocResult(com.mysql.cj.xdevapi.DocResult) Session(com.mysql.cj.xdevapi.Session) Test(org.junit.jupiter.api.Test)

Aggregations

Collection (com.mysql.cj.xdevapi.Collection)45 Test (org.junit.jupiter.api.Test)41 JsonString (com.mysql.cj.xdevapi.JsonString)31 Session (com.mysql.cj.xdevapi.Session)29 SessionFactory (com.mysql.cj.xdevapi.SessionFactory)21 WrongArgumentException (com.mysql.cj.exceptions.WrongArgumentException)19 ExecutionException (java.util.concurrent.ExecutionException)19 Schema (com.mysql.cj.xdevapi.Schema)15 DocResult (com.mysql.cj.xdevapi.DocResult)14 DbDoc (com.mysql.cj.xdevapi.DbDoc)11 AddResult (com.mysql.cj.xdevapi.AddResult)8 JsonNumber (com.mysql.cj.xdevapi.JsonNumber)4 ArrayList (java.util.ArrayList)4 XProtocolError (com.mysql.cj.protocol.x.XProtocolError)3 DbDocImpl (com.mysql.cj.xdevapi.DbDocImpl)3 SqlResult (com.mysql.cj.xdevapi.SqlResult)3 Table (com.mysql.cj.xdevapi.Table)3 Warning (com.mysql.cj.xdevapi.Warning)3 Compression (com.mysql.cj.conf.PropertyDefinitions.Compression)2 FindStatement (com.mysql.cj.xdevapi.FindStatement)2