diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/IgniteVsH2QueryTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/IgniteVsH2QueryTest.java index 537b8d175ab9a..afafa7b81d93e 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/IgniteVsH2QueryTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/h2/sql/IgniteVsH2QueryTest.java @@ -47,6 +47,12 @@ public class IgniteVsH2QueryTest extends GridCommonAbstractTest { /** */ private static Ignite ignite; + /** Partitioned cache. */ + private static IgniteCache pCache; + + /** Replicated cache. */ + private static IgniteCache rCache; + /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { @@ -60,35 +66,57 @@ public class IgniteVsH2QueryTest extends GridCommonAbstractTest { c.setMarshaller(new OptimizedMarshaller(true)); - CacheConfiguration cc = partitionedCacheConfig(); - - c.setCacheConfiguration(cc); + c.setCacheConfiguration(createCache("partitioned", CacheMode.PARTITIONED), + createCache("replicated", CacheMode.REPLICATED) + ); return c; } - private CacheConfiguration partitionedCacheConfig() { - CacheConfiguration cc = defaultCacheConfiguration(); - - cc.setName(PARTITIONED_CACHE); - cc.setCacheMode(CacheMode.PARTITIONED); - cc.setAtomicityMode(CacheAtomicityMode.ATOMIC); + /** + * Creates new cache configuration. + * + * @param name Cache name. + * @param mode Cache mode. + * @return Cache configuration. + */ + private static CacheConfiguration createCache(String name, CacheMode mode) { + CacheConfiguration cc = defaultCacheConfiguration(); + + cc.setName(name); + cc.setCacheMode(mode); + cc.setWriteSynchronizationMode(CacheWriteSynchronizationMode.FULL_SYNC); + cc.setEvictNearSynchronized(false); + cc.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); cc.setDistributionMode(PARTITIONED_ONLY); - cc.setBackups(1); - cc.setIndexedTypes( - UUID.class, Organization.class, - CacheAffinityKey.class, Person.class, - Integer.class, Long.class - ); + + if (mode == CacheMode.PARTITIONED) + cc.setIndexedTypes( + Integer.class, Organization.class, + CacheAffinityKey.class, Person.class, + CacheAffinityKey.class, Purchase.class + ); + else if (mode == CacheMode.REPLICATED) + cc.setIndexedTypes( + Integer.class, Product.class + ); + else + throw new IllegalStateException("mode: " + mode); + return cc; } + /** {@inheritDoc} */ @Override protected void beforeTestsStarted() throws Exception { super.beforeTestsStarted(); ignite = startGrids(4); + + pCache = ignite.jcache("partitioned"); + rCache = ignite.jcache("replicated"); + awaitPartitionMapExchange(); initialize(); @@ -101,15 +129,77 @@ private CacheConfiguration partitionedCacheConfig() { stopAllGrids(); } - - private void test0(String sql, Object... args){ - IgniteCache cache = ignite.jcache(PARTITIONED_CACHE); + /** + * Populate cache with test data. + */ + @SuppressWarnings("unchecked") + private void initialize() { + int idGen = 0; + + // Organizations. + List orgs = new ArrayList<>(); + + for (int i = 0; i < 3; i++) { + int id = idGen++; + + Organization org = new Organization(id, "Org" + id); + + orgs.add(org); + + pCache.put(org.id, org); + } + + // Persons. + List persons = new ArrayList<>(); + + for (int i = 0; i < 5; i++) { + int id = idGen++; + + Person person = new Person(id, orgs.get(i % orgs.size()), "name" + id, "lastname" + id, id * 100.0); + + persons.add(person); + + pCache.put(person.key(), person); + } + + // Products. + List products = new ArrayList<>(); + + for (int i = 0; i < 10; i++) { + int id = idGen++; + + Product product = new Product(id, "Product" + id, id*1000); + + products.add(product); + + rCache.put(product.id, product); + } + + // Purchases. + for (int i = 0; i < products.size() * 2; i++) { + int id = idGen++; + + Purchase purchase = new Purchase(id, products.get(i % products.size()), persons.get(i % persons.size())); + + pCache.put(purchase.key(), purchase); + } + } + + @SuppressWarnings("unchecked") + private void test0(IgniteCache cache, String sql, Object... args){ List> res1 = cache.queryFields(new SqlFieldsQuery(sql).setArgs(args)).getAll(); - print(res1); + log.info(">>> Results (count=" + res1.size() + "):"); + + for (List objects : res1) + log.info(objects.toString()); } + private void test0(String sql, Object... args) { + test0(pCache, sql, args); + } + /** * TODO */ @@ -135,77 +225,60 @@ public void testSqlFieldsQueryWithJoin() { } /** - * Populate cache with test data. + * @throws Exception If failed. */ - private void initialize() { - IgniteCache cache = ignite.jcache(PARTITIONED_CACHE); + public void testCrossCache() throws Exception { + log.info("-- Organizations --"); + test0("select id, name from Organization"); - // Organizations. - Organization org1 = new Organization("GridGain"); - Organization org2 = new Organization("Other"); - - // People. - Person p1 = new Person(org1, "John", "Doe", 2000, "John Doe has Master Degree."); - Person p2 = new Person(org1, "Jane", "Doe", 1000, "Jane Doe has Bachelor Degree."); - Person p3 = new Person(org2, "John", "Smith", 1000, "John Smith has Bachelor Degree."); - Person p4 = new Person(org2, "Jane", "Smith", 2000, "Jane Smith has Master Degree."); - - cache.put(org1.id, org1); - cache.put(org2.id, org2); - - cache.put(p1.key(), p1); - cache.put(p2.key(), p2); - cache.put(p3.key(), p3); - cache.put(p4.key(), p4); - } - - /** - * Prints collection of objects to standard out. - * - * @param msg Message to print before all objects are printed. - * @param col Query results. - */ - private static void print(String msg, Iterable col) { - if (msg != null) - System.out.println(">>> " + msg); - - print(col); - } - - /** - * Prints collection items. - * - * @param col Collection. - */ - private static void print(Iterable col) { - for (Object next : col) { - if (next instanceof Iterable) - print((Iterable)next); - else - System.out.println(">>> " + next); - } - } - - /** - * Prints out given object to standard out. - * - * @param o Object to print. - */ - private static void print(Object o) { - System.out.println(">>> " + o); + log.info("-- Persons --"); + test0("select id, firstName, lastName, orgId from Person"); + + log.info("-- Purchases --"); + test0("select id, personId, productId from Purchase"); + + log.info("-- Products --"); + test0(rCache, "select * from \"replicated\".Product"); + + log.info("-- Person.id=3 --"); + test0("select *" + + " from Person" + + " where Person.id = ?", 3); + + log.info("-- Person.id=3 with Purchase --"); //TODO Investigate + test0("select *" + + " from Person, Purchase" + + " where Person.id = ?", 3); + + log.info("-- Person.id = Purchase.personId --"); //TODO Investigate (should be 20 results instead of 8) + test0("select *" + + " from Person, Purchase" + + " where Person.id = Purchase.personId"); + + log.info("-- Cross query --"); //TODO Investigate + test0("select concat(firstName, ' ', lastName), Product.name " + + " from Person, Purchase, \"replicated\".Product " + + " where Person.id = Purchase.personId and Purchase.productId = Product.id" + + " group by Product.id"); + + log.info("-- Cross query with group by --"); //TODO Investigate + test0("select concat(firstName, ' ', lastName), count (Product.id) " + + " from Person, Purchase, \"replicated\".Product " + + " where Person.id = Purchase.personId and Purchase.productId = Product.id" + + " group by Product.id"); } - + /** * Person class. */ private static class Person implements Serializable { /** Person ID (indexed). */ @QuerySqlField(index = true) - private UUID id; + private int id; /** Organization ID (indexed). */ @QuerySqlField(index = true) - private UUID orgId; + private int orgId; /** First name (not-indexed). */ @QuerySqlField @@ -215,16 +288,12 @@ private static class Person implements Serializable { @QuerySqlField private String lastName; - /** Resume text (create LUCENE-based TEXT index for this field). */ - @QueryTextField - private String resume; - /** Salary (indexed). */ @QuerySqlField(index = true) private double salary; /** Custom cache key to guarantee that person is always collocated with its organization. */ - private transient CacheAffinityKey key; + private transient CacheAffinityKey key; /** * Constructs person record. @@ -233,18 +302,13 @@ private static class Person implements Serializable { * @param firstName First name. * @param lastName Last name. * @param salary Salary. - * @param resume Resume text. */ - Person(Organization org, String firstName, String lastName, double salary, String resume) { - // Generate unique ID for this person. - id = UUID.randomUUID(); - - orgId = org.id; - + Person(int id, Organization org, String firstName, String lastName, double salary) { + this.id = id; this.firstName = firstName; this.lastName = lastName; - this.resume = resume; this.salary = salary; + orgId = org.id; } /** @@ -253,7 +317,7 @@ private static class Person implements Serializable { * * @return Custom affinity key to guarantee that person is always collocated with organization. */ - public CacheAffinityKey key() { + public CacheAffinityKey key() { if (key == null) key = new CacheAffinityKey<>(id, orgId); @@ -266,7 +330,6 @@ public CacheAffinityKey key() { ", lastName=" + lastName + ", id=" + id + ", orgId=" + orgId + - ", resume=" + resume + ", salary=" + salary + ']'; } } @@ -277,20 +340,20 @@ public CacheAffinityKey key() { private static class Organization implements Serializable { /** Organization ID (indexed). */ @QuerySqlField(index = true) - private UUID id; + private int id; /** Organization name (indexed). */ @QuerySqlField(index = true) private String name; /** - * Create organization. + * Create Organization. * + * @param id Organization ID. * @param name Organization name. */ - Organization(String name) { - id = UUID.randomUUID(); - + Organization(int id, String name) { + this.id = id; this.name = name; } @@ -299,4 +362,85 @@ private static class Organization implements Serializable { return "Organization [id=" + id + ", name=" + name + ']'; } } + + /** + * Product class. + */ + private static class Product implements Serializable { + /** Primary key. */ + @QuerySqlField(index = true) + private int id; + + /** Product name. */ + @QuerySqlField + private String name; + + /** Product price */ + @QuerySqlField + private int price; + + /** + * Create Product. + * + * @param id Product ID. + * @param name Product name. + * @param price Product price. + */ + Product(int id, String name, int price) { + this.id = id; + this.name = name; + this.price = price; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return "Product [id=" + id + ", name=" + name + ", price=" + price + ']'; + } + } + + /** + * Purchase class. + */ + private static class Purchase implements Serializable { + /** Primary key. */ + @QuerySqlField(index = true) + private int id; + + /** Product ID. */ + @QuerySqlField + private int productId; + + /** Person ID. */ + @QuerySqlField + private int personId; + + /** Custom cache key to guarantee that purchase is always collocated with its person. */ + private transient CacheAffinityKey key; + + //TODO + Purchase(int id, Product product, Person person) { + this.id = id; + productId = product.id; + personId = person.id; + } + + /** + * Gets cache affinity key. Since in some examples purchase needs to be collocated with person, we create + * custom affinity key to guarantee this collocation. + * + * @return Custom affinity key to guarantee that purchase is always collocated with person. + */ + public CacheAffinityKey key() { + if (key == null) + key = new CacheAffinityKey<>(id, personId); + + return key; + } + + + /** {@inheritDoc} */ + @Override public String toString() { + return "Purchase [id=" + id + ", productId=" + productId + ", personId=" + personId + ']'; + } + } }