ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [04/13] ignite git commit: IGNITE-5462: JDBC thin driver: additional test for DDL/DML commands. This closes #2122.
Date Mon, 04 Sep 2017 08:14:10 GMT
IGNITE-5462: JDBC thin driver: additional test for DDL/DML commands. This closes #2122.


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/5738d7e7
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/5738d7e7
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/5738d7e7

Branch: refs/heads/ignite-3478
Commit: 5738d7e7d3b1e59df155bcaa3803430a9d897cd1
Parents: fd9ab95
Author: tledkov-gridgain <tledkov@gridgain.com>
Authored: Thu Aug 31 17:23:31 2017 +0300
Committer: devozerov <vozerov@gridgain.com>
Committed: Thu Aug 31 17:23:31 2017 +0300

----------------------------------------------------------------------
 .../jdbc/suite/IgniteJdbcDriverTestSuite.java   |   4 +
 .../thin/JdbcThinComplexDmlDdlSelfTest.java     | 486 +++++++++++++++++++
 .../internal/jdbc/thin/JdbcThinStatement.java   |   2 +-
 3 files changed, 491 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/5738d7e7/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
index 691ddbf..d08528d 100644
--- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java
@@ -53,6 +53,7 @@ import org.apache.ignite.jdbc.thin.JdbcThinPreparedStatementSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinResultSetSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinStatementSelfTest;
 import org.apache.ignite.jdbc.thin.JdbcThinUpdateStatementSelfTest;
+import org.apache.ignite.jdbc.thin.JdbcThinComplexDmlDdlSelfTest;
 
 /**
  * JDBC driver test suite.
@@ -137,6 +138,9 @@ public class IgniteJdbcDriverTestSuite extends TestSuite {
         suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedSelfTest.class));
         suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalReplicatedSelfTest.class));
 
+        // New thin JDBC driver, full SQL tests
+        suite.addTest(new TestSuite(JdbcThinComplexDmlDdlSelfTest.class));
+
         return suite;
     }
 }

http://git-wip-us.apache.org/repos/asf/ignite/blob/5738d7e7/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexDmlDdlSelfTest.java
----------------------------------------------------------------------
diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexDmlDdlSelfTest.java
b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexDmlDdlSelfTest.java
new file mode 100644
index 0000000..0760107
--- /dev/null
+++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinComplexDmlDdlSelfTest.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.jdbc.thin;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.ignite.cache.CacheAtomicityMode;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.internal.binary.BinaryMarshaller;
+import org.apache.ignite.internal.processors.cache.DynamicCacheDescriptor;
+import org.apache.ignite.lang.IgniteCallable;
+import org.apache.ignite.lang.IgnitePredicate;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Base class for complex SQL tests based on JDBC driver.
+ */
+public class JdbcThinComplexDmlDdlSelfTest extends GridCommonAbstractTest {
+    /** IP finder. */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** Cache mode to test with. */
+    private final CacheMode cacheMode = CacheMode.PARTITIONED;
+
+    /** Cache atomicity mode to test with. */
+    private final CacheAtomicityMode atomicityMode = CacheAtomicityMode.ATOMIC;
+
+    /** Names of companies to use. */
+    private static final List<String> COMPANIES = Arrays.asList("ASF", "GNU", "BSD");
+
+    /** Cities to use. */
+    private static final List<String> CITIES = Arrays.asList("St. Petersburg", "Boston",
"Berkeley", "London");
+
+    /** JDBC connection. */
+    private Connection conn;
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws
Exception {
+        IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+        cfg.setCacheConfiguration(cacheConfiguration(DEFAULT_CACHE_NAME));
+
+        TcpDiscoverySpi disco = new TcpDiscoverySpi();
+
+        disco.setIpFinder(IP_FINDER);
+
+        cfg.setDiscoverySpi(disco);
+
+        return cfg;
+    }
+
+    /**
+     * @param name Cache name.
+     * @return Cache configuration.
+     * @throws Exception In case of error.
+     */
+    private CacheConfiguration cacheConfiguration(@NotNull String name) throws Exception
{
+        CacheConfiguration cfg = defaultCacheConfiguration();
+
+        cfg.setName(name);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTestsStarted() throws Exception {
+        super.beforeTestsStarted();
+
+        startGridsMultiThreaded(2);
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTestsStopped() throws Exception {
+        stopAllGrids();
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void beforeTest() throws Exception {
+        super.beforeTest();
+
+        conn = DriverManager.getConnection("jdbc:ignite:thin://127.0.0.1");
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        conn.close();
+
+        // Destroy all SQL caches after test.
+        for (String cacheName : grid(0).cacheNames()) {
+            DynamicCacheDescriptor cacheDesc = grid(0).context().cache().cacheDescriptor(cacheName);
+
+            if (cacheDesc != null && cacheDesc.sql())
+                grid(0).destroyCache0(cacheName, true);
+        }
+
+        super.afterTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
+    public void testCreateSelect() throws Exception {
+        GridTestUtils.assertThrows(null, new IgniteCallable<Object>() {
+            @Override public Object call() throws Exception {
+                sql(new ResultChecker(new Object[][] {}), "SELECT * from Person");
+
+                return null;
+            }
+        }, SQLException.class, "Failed to parse query: SELECT * from Person");
+
+        sql(new UpdateChecker(0),
+            "CREATE TABLE person (id int, name varchar, age int, company varchar, city varchar,
" +
+                "primary key (id, name, city)) WITH \"template=" + cacheMode.name() + ",atomicity="
+ atomicityMode.name()
+                + ",affinitykey=city\"");
+
+        sql(new UpdateChecker(0), "CREATE INDEX idx on person (city asc, name asc)");
+
+        sql(new UpdateChecker(0), "CREATE TABLE city (name varchar, population int, primary
key (name)) WITH " +
+            "\"template=" + cacheMode.name() + ",atomicity=" + atomicityMode.name() + ",affinitykey=name\"");
+
+        sql(new UpdateChecker(3),
+            "INSERT INTO city (name, population) values(?, ?), (?, ?), (?, ?)",
+            "St. Petersburg", 6000000,
+            "Boston", 2000000,
+            "London", 8000000
+        );
+
+        sql(new ResultColumnChecker("id", "name", "age", "comp"),
+            "SELECT id, name, age, company as comp FROM person where id < 50");
+
+        for (int i = 0; i < 100; i++) {
+            sql(new UpdateChecker(1),
+                "INSERT INTO person (id, name, age, company, city) values (?, ?, ?, ?, ?)",
+                i,
+                "Person " + i,
+                20 + (i % 10),
+                COMPANIES.get(i % COMPANIES.size()),
+                CITIES.get(i % CITIES.size()));
+        }
+
+        final int[] cnt = {0};
+
+        sql(new ResultPredicateChecker(new IgnitePredicate<Object[]>() {
+            @Override public boolean apply(Object[] objs) {
+                int id = ((Integer)objs[0]);
+
+                if (id >= 50)
+                    return false;
+
+                if (20 + (id % 10) != ((Integer)objs[2]))
+                    return false;
+
+                if (!("Person " + id).equals(objs[1]))
+                    return false;
+
+                ++cnt[0];
+
+                return true;
+            }
+        }), "SELECT id, name, age FROM person where id < 50");
+
+        assert cnt[0] == 50 : "Invalid rows count";
+
+        // Berkeley is not present in City table, although 25 people have it specified as
their city.
+        sql(new ResultChecker(new Object[][] {{75L}}),
+            "SELECT COUNT(*) from Person p inner join City c on p.city = c.name");
+
+        sql(new UpdateChecker(34),
+            "UPDATE Person SET company = 'New Company', age = CASE WHEN MOD(id, 2) <>
0 THEN age + 5 ELSE "
+                + "age + 1 END WHERE company = 'ASF'");
+
+        cnt[0] = 0;
+
+        sql(new ResultPredicateChecker(new IgnitePredicate<Object[]>() {
+            @Override public boolean apply(Object[] objs) {
+                int id = ((Integer)objs[0]);
+                int age = ((Integer)objs[2]);
+
+                if (id % 2 == 0) {
+                    if (age != 20 + (id % 10) + 1)
+                        return false;
+                }
+                else {
+                    if (age != 20 + (id % 10) + 5)
+                        return false;
+                }
+
+                ++cnt[0];
+
+                return true;
+            }
+        }), "SELECT * FROM person where company = 'New Company'");
+
+        assert cnt[0] == 34 : "Invalid rows count";
+
+        sql(new UpdateChecker(0), "DROP INDEX idx");
+    }
+
+    /**
+     * Run sql statement with arguments and check results.
+     *
+     * @param checker Query result's checker.
+     * @param sql SQL statement to execute.
+     * @param args Arguments.
+     *
+     * @throws SQLException On failed.
+     */
+    protected void sql(SingleStatementChecker checker, String sql, Object... args) throws
SQLException {
+        Statement stmt;
+
+        if (args.length > 0) {
+            stmt = conn.prepareStatement(sql);
+
+            PreparedStatement pstmt = (PreparedStatement)stmt;
+
+            for (int i = 0; i < args.length; ++i)
+                pstmt.setObject(i + 1, args[i]);
+
+            pstmt.execute();
+        }
+        else {
+            stmt = conn.createStatement();
+
+            stmt.execute(sql);
+        }
+
+        checkResults(stmt, checker);
+    }
+
+    /**
+     * Check query results wwith provided checker.
+     *
+     * @param stmt Statement.
+     * @param checker Checker.
+     * @throws SQLException If failed.
+     */
+    private void checkResults(Statement stmt, SingleStatementChecker checker) throws SQLException
{
+        ResultSet rs = stmt.getResultSet();
+
+        if (rs != null)
+            checker.check(rs);
+        else {
+            int updCnt = stmt.getUpdateCount();
+
+            assert updCnt != -1 : "Invalid results. Result set is null and update count is
-1";
+
+            checker.check(updCnt);
+        }
+    }
+
+    /**
+     *
+     */
+    interface SingleStatementChecker {
+        /**
+         * Called when query produces results.
+         *
+         * @param rs Result set.
+         * @throws SQLException On error.
+         */
+        void check(ResultSet rs) throws SQLException;
+
+        /**
+         * Called when query produces any update.
+         *
+         * @param updateCount Update count.
+         */
+        void check(int updateCount);
+    }
+
+    /**
+     *
+     */
+    static class UpdateChecker implements SingleStatementChecker {
+        /** Expected update count. */
+        private final int expUpdCnt;
+
+        /**
+         * @param expUpdCnt Expected Update count.
+         */
+        UpdateChecker(int expUpdCnt) {
+            this.expUpdCnt = expUpdCnt;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(ResultSet rs) {
+            fail("Update results are expected. [rs=" + rs + ']');
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(int updateCount) {
+            assertEquals(expUpdCnt, updateCount);
+        }
+    }
+
+    /**
+     *
+     */
+    static class ResultChecker implements SingleStatementChecker {
+        /** Expected update count. */
+        private final Set<Row> expRs = new HashSet<>();
+
+        /**
+         * @param expRs Expected result set.
+         */
+        ResultChecker(Object[][] expRs) {
+            for (Object[] row : expRs)
+                this.expRs.add(new Row(row));
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(ResultSet rs) throws SQLException {
+            int cols = rs.getMetaData().getColumnCount();
+
+            while (rs.next()) {
+                Object [] rowObjs = new Object[cols];
+
+                for (int i = 0; i < cols; ++i)
+                    rowObjs[i] = rs.getObject(i + 1);
+
+                Row row = new Row(rowObjs);
+
+                assert expRs.remove(row) : "Invalid row. [row=" + row + ", remainedRows="
+                    + printRemainedExpectedResult() + ']';
+            }
+
+            assert expRs.isEmpty() : "Expected results has rows that aren't contained at
the result set. [remainedRows="
+                + printRemainedExpectedResult() + ']';
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(int updateCount) {
+            fail("Results set is expected. [updateCount=" + updateCount + ']');
+        }
+
+        /**
+         * @return Print remaining expected rows.
+         */
+        private String printRemainedExpectedResult() {
+            StringBuilder sb = new StringBuilder();
+
+            for (Row r : expRs)
+                sb.append('\n').append(r.toString());
+
+            return sb.toString();
+        }
+    }
+
+    /**
+     *
+     */
+    static class ResultColumnChecker extends ResultChecker {
+        /** Expected column names. */
+        private final String[] expColLabels;
+
+        /**
+         * Checker column names for rmpty results.
+         *
+         * @param expColLabels Expected column names.
+         */
+        ResultColumnChecker(String... expColLabels) {
+            super(new Object[][]{});
+
+            this.expColLabels = expColLabels;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(ResultSet rs) throws SQLException {
+            ResultSetMetaData meta = rs.getMetaData();
+
+            int cols = meta.getColumnCount();
+
+            assert cols == expColLabels.length : "Invalid columns count: [expected=" + expColLabels.length
+                + ", actual=" + cols + ']';
+
+            for (int i = 0; i < cols; ++i)
+                assert expColLabels[i].equalsIgnoreCase(meta.getColumnName(i + 1));
+
+            super.check(rs);
+        }
+    }
+
+    /**
+     *
+     */
+    static class ResultPredicateChecker implements SingleStatementChecker {
+        /** Row predicate. */
+        private IgnitePredicate<Object[]> rowPredicate;
+
+        /**
+         * @param rowPredicate Row predicate to check result set.
+         */
+        ResultPredicateChecker(IgnitePredicate<Object[]> rowPredicate) {
+            this.rowPredicate = rowPredicate;
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(ResultSet rs) throws SQLException {
+            int cols = rs.getMetaData().getColumnCount();
+
+            while (rs.next()) {
+                Object [] rowObjs = new Object[cols];
+
+                for (int i = 0; i < cols; ++i)
+                    rowObjs[i] = rs.getObject(i + 1);
+
+                assert rowPredicate.apply(rowObjs) : "Invalid row. [row=" + Arrays.toString(rowObjs)
+ ']';
+            }
+        }
+
+        /** {@inheritDoc} */
+        @Override public void check(int updateCount) {
+            fail("Results set is expected. [updateCount=" + updateCount + ']');
+        }
+    }
+
+    /**
+     *
+     */
+    private static class Row {
+        /** Row. */
+        private final Object[] row;
+
+        /**
+         * @param row Data row.
+         */
+        private Row(Object[] row) {
+            this.row = row;
+        }
+
+        /** {@inheritDoc} */
+        @Override public boolean equals(Object o) {
+            if (this == o)
+                return true;
+
+            if (o == null || getClass() != o.getClass())
+                return false;
+
+            Row row1 = (Row)o;
+
+            return Arrays.equals(row, row1.row);
+        }
+
+        /** {@inheritDoc} */
+        @Override public int hashCode() {
+            return Arrays.hashCode(row);
+        }
+
+        /** {@inheritDoc} */
+        @Override public String toString() {
+            return Arrays.toString(row);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ignite/blob/5738d7e7/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
index 3772b83..59a9db0 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java
@@ -128,7 +128,7 @@ public class JdbcThinStatement implements Statement {
             throw new SQLException("Failed to query Ignite.", e);
         }
         catch (IgniteCheckedException e) {
-            throw new SQLException("Failed to query Ignite.", e);
+            throw new SQLException("Failed to query Ignite [err=\"" + e.getMessage() + "\"]",
e);
         }
     }
 


Mime
View raw message