| /* |
| * 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.internal.processors.cache; |
| |
| import java.io.Serializable; |
| import java.sql.PreparedStatement; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Random; |
| import java.util.Set; |
| import org.apache.ignite.Ignite; |
| import org.apache.ignite.IgniteCache; |
| import org.apache.ignite.cache.CacheMode; |
| import org.apache.ignite.cache.QueryEntity; |
| import org.apache.ignite.cache.QueryIndex; |
| import org.apache.ignite.cache.affinity.AffinityKey; |
| import org.apache.ignite.cache.query.Query; |
| import org.apache.ignite.cache.query.SqlFieldsQuery; |
| import org.apache.ignite.cache.query.SqlQuery; |
| import org.apache.ignite.cache.query.annotations.QuerySqlField; |
| import org.apache.ignite.configuration.CacheConfiguration; |
| import org.apache.ignite.configuration.IgniteConfiguration; |
| import org.apache.ignite.internal.processors.query.h2.sql.AbstractH2CompareQueryTest; |
| import org.apache.ignite.internal.util.tostring.GridToStringInclude; |
| import org.apache.ignite.internal.util.typedef.F; |
| import org.apache.ignite.internal.util.typedef.internal.S; |
| import org.apache.ignite.internal.util.typedef.internal.SB; |
| import org.junit.Test; |
| |
| import static org.apache.ignite.cache.CacheMode.PARTITIONED; |
| import static org.apache.ignite.cache.CacheMode.REPLICATED; |
| import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; |
| |
| /** |
| * |
| */ |
| @SuppressWarnings({"unchecked", "PackageVisibleField", "serial"}) |
| public class IgniteCrossCachesJoinsQueryTest extends AbstractH2CompareQueryTest { |
| /** */ |
| private static final String PERSON_CACHE_NAME = "person"; |
| |
| /** */ |
| private static final String ORG_CACHE_NAME = "org"; |
| |
| /** */ |
| private static final String ACC_CACHE_NAME = "acc"; |
| |
| /** */ |
| private static final int NODES = 5; |
| |
| /** */ |
| private boolean client; |
| |
| /** */ |
| private Data data; |
| |
| /** Tested qry. */ |
| private String qry; |
| |
| /** Tested cache. */ |
| private IgniteCache cache; |
| |
| /** */ |
| private boolean distributedJoins; |
| |
| /** */ |
| private static Random rnd; |
| |
| /** {@inheritDoc} */ |
| @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { |
| IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); |
| |
| cfg.setClientMode(client); |
| |
| return cfg; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void createCaches() { |
| // No-op. |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void beforeTestsStarted() throws Exception { |
| long seed = System.currentTimeMillis(); |
| |
| rnd = new Random(seed); |
| |
| log.info("Random seed: " + seed); |
| |
| startGridsMultiThreaded(NODES - 1); |
| |
| client = true; |
| |
| startGrid(NODES - 1); |
| |
| awaitPartitionMapExchange(); |
| |
| conn = openH2Connection(false); |
| |
| initializeH2Schema(); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void initCacheAndDbData() throws SQLException { |
| Statement st = conn.createStatement(); |
| |
| final String keyType = useCollocatedData() ? "other" : "int"; |
| |
| st.execute("create table \"" + ACC_CACHE_NAME + "\".Account" + |
| " (" + |
| " _key " + keyType + " not null," + |
| " _val other not null," + |
| " id int unique," + |
| " personId int," + |
| " personDateId TIMESTAMP," + |
| " personStrId varchar(255)" + |
| " )"); |
| |
| st.execute("create table \"" + PERSON_CACHE_NAME + "\".Person" + |
| " (" + |
| " _key " + keyType + " not null," + |
| " _val other not null," + |
| " id int unique," + |
| " strId varchar(255) ," + |
| " dateId TIMESTAMP ," + |
| " orgId int," + |
| " orgDateId TIMESTAMP," + |
| " orgStrId varchar(255), " + |
| " name varchar(255), " + |
| " salary int" + |
| " )"); |
| |
| st.execute("create table \"" + ORG_CACHE_NAME + "\".Organization" + |
| " (" + |
| " _key int not null," + |
| " _val other not null," + |
| " id int unique," + |
| " strId varchar(255) ," + |
| " dateId TIMESTAMP ," + |
| " name varchar(255) " + |
| " )"); |
| |
| conn.commit(); |
| |
| st.close(); |
| |
| for (Account account : data.accounts) |
| insertInDb(account); |
| |
| for (Person person : data.persons) |
| insertInDb(person); |
| |
| for (Organization org : data.orgs) |
| insertInDb(org); |
| } |
| |
| /** |
| * |
| */ |
| private void initCachesData() { |
| IgniteCache accCache = ignite(0).cache(ACC_CACHE_NAME); |
| |
| for (Account account : data.accounts) |
| accCache.put(account.key(useCollocatedData()), account); |
| |
| IgniteCache personCache = ignite(0).cache(PERSON_CACHE_NAME); |
| |
| for (Person person : data.persons) |
| personCache.put(person.key(useCollocatedData()), person); |
| |
| IgniteCache orgCache = ignite(0).cache(ORG_CACHE_NAME); |
| |
| for (Organization org : data.orgs) |
| orgCache.put(org.id, org); |
| } |
| |
| /** |
| * @param acc Account. |
| * @throws SQLException If failed. |
| */ |
| private void insertInDb(Account acc) throws SQLException { |
| try (PreparedStatement st = conn.prepareStatement( |
| "insert into \"" + ACC_CACHE_NAME + "\".Account (_key, _val, id, personId, personDateId, personStrId) " + |
| "values(?, ?, ?, ?, ?, ?)")) { |
| int i = 0; |
| |
| st.setObject(++i, acc.key(useCollocatedData())); |
| st.setObject(++i, acc); |
| st.setObject(++i, acc.id); |
| st.setObject(++i, acc.personId); |
| st.setObject(++i, acc.personDateId); |
| st.setObject(++i, acc.personStrId); |
| |
| st.executeUpdate(); |
| } |
| } |
| |
| /** |
| * @param p Person. |
| * @throws SQLException If failed. |
| */ |
| private void insertInDb(Person p) throws SQLException { |
| try (PreparedStatement st = conn.prepareStatement( |
| "insert into \"" + PERSON_CACHE_NAME + "\".Person (_key, _val, id, strId, dateId, name, orgId, orgDateId, " + |
| "orgStrId, salary) " + |
| "values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")) { |
| int i = 0; |
| |
| st.setObject(++i, p.key(useCollocatedData())); |
| st.setObject(++i, p); |
| st.setObject(++i, p.id); |
| st.setObject(++i, p.strId); |
| st.setObject(++i, p.dateId); |
| st.setObject(++i, p.name); |
| st.setObject(++i, p.orgId); |
| st.setObject(++i, p.orgDateId); |
| st.setObject(++i, p.orgStrId); |
| st.setObject(++i, p.salary); |
| |
| st.executeUpdate(); |
| } |
| } |
| |
| /** |
| * @param o Organization. |
| * @throws SQLException If failed. |
| */ |
| private void insertInDb(Organization o) throws SQLException { |
| try (PreparedStatement st = conn.prepareStatement( |
| "insert into \"" + ORG_CACHE_NAME + "\".Organization (_key, _val, id, strId, dateId, name) " + |
| "values(?, ?, ?, ?, ?, ?)")) { |
| int i = 0; |
| |
| st.setObject(++i, o.id); |
| st.setObject(++i, o); |
| st.setObject(++i, o.id); |
| st.setObject(++i, o.strId); |
| st.setObject(++i, o.dateId); |
| st.setObject(++i, o.name); |
| |
| st.executeUpdate(); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected void checkAllDataEquals() throws Exception { |
| compareQueryRes0(ignite(0).cache(ACC_CACHE_NAME), "select _key, _val, id, personId, personDateId, personStrId " + |
| "from \"" + ACC_CACHE_NAME + "\".Account"); |
| |
| compareQueryRes0(ignite(0).cache(PERSON_CACHE_NAME), "select _key, _val, id, strId, dateId, name, orgId, " + |
| "orgDateId, orgStrId, salary from \"" + PERSON_CACHE_NAME + "\".Person"); |
| |
| compareQueryRes0(ignite(0).cache(ORG_CACHE_NAME), "select _key, _val, id, strId, dateId, name " + |
| "from \"" + ORG_CACHE_NAME + "\".Organization"); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected Statement initializeH2Schema() throws SQLException { |
| Statement st = conn.createStatement(); |
| |
| for (String cacheName : new String[]{"person", "acc", "org"}) |
| st.execute("CREATE SCHEMA \"" + cacheName + "\""); |
| |
| return st; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override protected long getTestTimeout() { |
| return 30 * 60_000; |
| } |
| |
| /** |
| * @return Distributed joins flag. |
| */ |
| protected boolean distributedJoins() { |
| return distributedJoins; |
| } |
| |
| /** |
| * @return Use collocated data. |
| */ |
| private boolean useCollocatedData() { |
| return !distributedJoins(); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testDistributedJoins1() throws Exception { |
| distributedJoins = true; |
| |
| checkAllCacheCombinationsSet1(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testDistributedJoins2() throws Exception { |
| distributedJoins = true; |
| |
| checkAllCacheCombinationsSet2(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testDistributedJoins3() throws Exception { |
| distributedJoins = true; |
| |
| checkAllCacheCombinationsSet3(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testCollocatedJoins1() throws Exception { |
| distributedJoins = false; |
| |
| checkAllCacheCombinationsSet1(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testCollocatedJoins2() throws Exception { |
| distributedJoins = false; |
| |
| checkAllCacheCombinationsSet2(true); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| @Test |
| public void testCollocatedJoins3() throws Exception { |
| distributedJoins = false; |
| |
| checkAllCacheCombinationsSet3(true); |
| } |
| |
| /** |
| * @param idx Index flag. |
| * @throws Exception If failed. |
| */ |
| private void checkAllCacheCombinationsSet1(boolean idx) throws Exception { |
| List<List<TestCache>> types = cacheCombinations(TestCacheType.REPLICATED); |
| |
| checkAllCacheCombinations(idx, types); |
| } |
| |
| /** |
| * @param idx Index flag. |
| * @throws Exception If failed. |
| */ |
| private void checkAllCacheCombinationsSet2(boolean idx) throws Exception { |
| List<List<TestCache>> types = cacheCombinations(TestCacheType.PARTITIONED_b0); |
| |
| checkAllCacheCombinations(idx, types); |
| } |
| |
| /** |
| * @param idx Index flag. |
| * @throws Exception If failed. |
| */ |
| private void checkAllCacheCombinationsSet3(boolean idx) throws Exception { |
| List<List<TestCache>> types = cacheCombinations(TestCacheType.PARTITIONED_b1); |
| |
| checkAllCacheCombinations(idx, types); |
| } |
| |
| /** |
| * @param personType Person cache type. |
| * @return Cache combinations. |
| */ |
| private List<List<TestCache>> cacheCombinations(TestCacheType personType) { |
| List<List<TestCache>> res = new ArrayList<>(); |
| |
| for (TestCacheType accCacheType : TestCacheType.values()) { |
| for (TestCacheType orgCacheType : TestCacheType.values()) { |
| List<TestCache> cacheTypes = new ArrayList<>(3); |
| |
| cacheTypes.add(new TestCache("person", personType)); |
| cacheTypes.add(new TestCache("acc", accCacheType)); |
| cacheTypes.add(new TestCache("org", orgCacheType)); |
| |
| res.add(cacheTypes); |
| } |
| } |
| |
| return res; |
| } |
| |
| /** |
| * @param idx Index flag. |
| * @param cacheList Caches. |
| * @throws Exception If failed. |
| */ |
| private void checkAllCacheCombinations( |
| boolean idx, |
| List<List<TestCache>> cacheList) throws Exception { |
| data = prepareData(); |
| |
| initCacheAndDbData(); |
| |
| try { |
| Map<TestConfig, Throwable> errors = new LinkedHashMap<>(); |
| List<TestConfig> success = new ArrayList<>(); |
| |
| int cfgIdx = 0; |
| |
| for (List<TestCache> caches : cacheList) { |
| assert caches.size() == 3 : caches; |
| |
| TestCache personCache = caches.get(0); |
| TestCache accCache = caches.get(1); |
| TestCache orgCache = caches.get(2); |
| |
| try { |
| check(idx, personCache, accCache, orgCache); |
| |
| success.add(new TestConfig(cfgIdx, cache, personCache, accCache, orgCache, "")); |
| } |
| catch (Throwable e) { |
| error("", e); |
| |
| errors.put(new TestConfig(cfgIdx, cache, personCache, accCache, orgCache, qry), e); |
| } |
| |
| cfgIdx++; |
| } |
| |
| if (!errors.isEmpty()) { |
| int total = cacheList.size(); |
| |
| SB sb = new SB("Test failed for the following " + errors.size() + " combination(s) (" + total + " total):\n"); |
| |
| for (Map.Entry<TestConfig, Throwable> e : errors.entrySet()) |
| sb.a(e.getKey()).a(", error=").a(e.getValue()).a("\n"); |
| |
| sb.a("Successfully finished combinations:\n"); |
| |
| for (TestConfig t : success) |
| sb.a(t).a("\n"); |
| |
| sb.a("The following data has beed used for test:\n " + data); |
| |
| fail(sb.toString()); |
| } |
| } |
| finally { |
| for (String cacheName : new String[]{PERSON_CACHE_NAME, ACC_CACHE_NAME, ORG_CACHE_NAME}) |
| ignite(0).destroyCache(cacheName); |
| |
| Statement st = conn.createStatement(); |
| |
| st.execute("drop table \"" + ACC_CACHE_NAME + "\".Account"); |
| st.execute("drop table \"" + PERSON_CACHE_NAME + "\".Person"); |
| st.execute("drop table \"" + ORG_CACHE_NAME + "\".Organization"); |
| |
| conn.commit(); |
| |
| st.close(); |
| } |
| } |
| |
| /** |
| * @param idx Index flag. |
| * @param personCacheType Person cache personCacheType. |
| * @param accCacheType Account cache personCacheType. |
| * @param orgCacheType Organization cache personCacheType. |
| * @throws Exception If failed. |
| */ |
| private void check( |
| boolean idx, |
| final TestCache personCacheType, |
| final TestCache accCacheType, |
| final TestCache orgCacheType) throws Exception { |
| info("Checking cross cache joins [accCache=" + accCacheType + |
| ", personCache=" + personCacheType + |
| ", orgCache=" + orgCacheType + "]"); |
| |
| Collection<TestCache> cacheTypes = F.asList(personCacheType, accCacheType, orgCacheType); |
| |
| for (TestCache cache : cacheTypes) { |
| CacheConfiguration cc = cacheConfiguration(cache.cacheName, |
| cache.type.cacheMode, |
| cache.type.backups, |
| idx, |
| cache == accCacheType, |
| cache == personCacheType, |
| cache == orgCacheType |
| ); |
| |
| ignite(0).getOrCreateCache(cc); |
| |
| info("Created cache [name=" + cache.cacheName + ", mode=" + cache.type + "]"); |
| } |
| |
| initCachesData(); |
| |
| // checkAllDataEquals(); |
| |
| List<String> cacheNames = new ArrayList<>(); |
| |
| cacheNames.add(personCacheType.cacheName); |
| cacheNames.add(orgCacheType.cacheName); |
| cacheNames.add(accCacheType.cacheName); |
| |
| for (int i = 0; i < NODES; i++) { |
| Ignite testNode = ignite(i); |
| |
| log.info("Test node [idx=" + i + ", isClient=" + testNode.configuration().isClientMode() + "]"); |
| |
| for (String cacheName : cacheNames) { |
| cache = testNode.cache(cacheName); |
| |
| log.info("Use cache: " + cache.getName()); |
| |
| boolean distributeJoins0 = distributedJoins; |
| |
| if (replicated(cache)) { |
| // if (!testNode.configuration().isClientMode()) |
| // assertProperException(cache); |
| |
| boolean all3CachesAreReplicated = |
| replicated(ignite(0).cache(ACC_CACHE_NAME)) && |
| replicated(ignite(0).cache(PERSON_CACHE_NAME)) && |
| replicated(ignite(0).cache(ORG_CACHE_NAME)); |
| |
| // Queries running on replicated cache should not contain JOINs with partitioned tables. |
| if (distributeJoins0 && !all3CachesAreReplicated) |
| continue; |
| else |
| distributedJoins = false; |
| } |
| |
| if (!cache.getName().equals(orgCacheType.cacheName)) |
| checkPersonAccountsJoin(cache, data.accountsPerPerson); |
| |
| if (!cache.getName().equals(accCacheType.cacheName)) |
| checkOrganizationPersonsJoin(cache); |
| |
| checkOrganizationPersonAccountJoin(cache); |
| |
| checkUnion(); |
| checkUnionAll(); |
| |
| if (!cache.getName().equals(orgCacheType.cacheName)) |
| checkPersonAccountCrossJoin(cache); |
| |
| if (!cache.getName().equals(accCacheType.cacheName)) |
| checkPersonOrganizationGroupBy(cache); |
| |
| if (!cache.getName().equals(orgCacheType.cacheName)) |
| checkPersonAccountGroupBy(cache); |
| |
| checkGroupBy(); |
| |
| distributedJoins = distributeJoins0; |
| } |
| } |
| } |
| |
| /** |
| * @param cache Cache. |
| * @return {@code True} if cache is replicated. |
| */ |
| private boolean replicated(IgniteCache<?, ?> cache) { |
| return cache.getConfiguration(CacheConfiguration.class).getCacheMode() == REPLICATED; |
| } |
| |
| /** |
| * Organization ids: [0, 9]. Person ids: randoms at [10, 9999]. Accounts ids: randoms at [10000, 999_999] |
| * |
| * @return Data. |
| */ |
| private Data prepareData() { |
| Map<Integer, Integer> personsPerOrg = new HashMap<>(); |
| Map<Integer, Integer> accountsPerPerson = new HashMap<>(); |
| Map<Integer, Integer> accountsPerOrg = new HashMap<>(); |
| Map<Integer, Integer> maxSalaryPerOrg = new HashMap<>(); |
| |
| List<Organization> orgs = new ArrayList<>(); |
| List<Person> persons = new ArrayList<>(); |
| List<Account> accounts = new ArrayList<>(); |
| |
| final int ORG_CNT = 10; |
| final int MAX_PERSONS_PER_ORG = 20; |
| final int MAX_ACCOUNTS_PER_PERSON = 10; |
| |
| for (int id = 0; id < ORG_CNT; id++) |
| orgs.add(new Organization(id, "org-" + id)); |
| |
| Set<Integer> personIds = new HashSet<>(); |
| Set<Integer> accountIds = new HashSet<>(); |
| |
| for (int orgId = 0; orgId < ORG_CNT; orgId++) { |
| int personsCnt = rnd.nextInt(MAX_PERSONS_PER_ORG); |
| |
| int accsPerOrg = 0; |
| int maxSalary = -1; |
| |
| for (int p = 0; p < personsCnt; p++) { |
| int personId = rnd.nextInt(10_000) + 10; |
| |
| while (!personIds.add(personId)) |
| personId = rnd.nextInt(10_000) + 10; |
| |
| String name = "person-" + personId; |
| |
| int salary = (rnd.nextInt(10) + 1) * 1000; |
| |
| if (salary > maxSalary) |
| maxSalary = salary; |
| |
| persons.add(new Person(personId, orgId, name, salary)); |
| |
| int accountsCnt = rnd.nextInt(MAX_ACCOUNTS_PER_PERSON); |
| |
| for (int a = 0; a < accountsCnt; a++) { |
| int accountId = rnd.nextInt(100_000) + 10_000; |
| |
| while (!accountIds.add(accountId)) |
| accountId = rnd.nextInt(100_000) + 10_000; |
| |
| accounts.add(new Account(accountId, personId, orgId)); |
| } |
| |
| accountsPerPerson.put(personId, accountsCnt); |
| |
| accsPerOrg += accountsCnt; |
| } |
| |
| personsPerOrg.put(orgId, personsCnt); |
| accountsPerOrg.put(orgId, accsPerOrg); |
| maxSalaryPerOrg.put(orgId, maxSalary); |
| } |
| |
| return new Data(orgs, persons, accounts, personsPerOrg, accountsPerPerson, accountsPerOrg, maxSalaryPerOrg); |
| } |
| |
| /** |
| * @param cacheName Cache name. |
| * @param cacheMode Cache mode. |
| * @param backups Number of backups. |
| * @param idx Index flag. |
| * @param accountCache Account cache flag. |
| * @param personCache Person cache flag. |
| * @param orgCache Organization cache flag. |
| * @return Cache configuration. |
| */ |
| private CacheConfiguration cacheConfiguration(String cacheName, |
| CacheMode cacheMode, |
| int backups, |
| boolean idx, |
| boolean accountCache, |
| boolean personCache, |
| boolean orgCache) { |
| CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); |
| |
| ccfg.setName(cacheName); |
| ccfg.setCacheMode(cacheMode); |
| |
| if (cacheMode == PARTITIONED) |
| ccfg.setBackups(backups); |
| |
| ccfg.setWriteSynchronizationMode(FULL_SYNC); |
| |
| List<QueryEntity> entities = new ArrayList<>(); |
| |
| if (accountCache) { |
| QueryEntity account = new QueryEntity(); |
| account.setKeyType(useCollocatedData() ? AffinityKey.class.getName() : Integer.class.getName()); |
| account.setValueType(Account.class.getName()); |
| account.addQueryField("id", Integer.class.getName(), null); |
| account.addQueryField("personId", Integer.class.getName(), null); |
| account.addQueryField("personDateId", Date.class.getName(), null); |
| account.addQueryField("personStrId", String.class.getName(), null); |
| |
| if (idx) { |
| account.setIndexes(F.asList(new QueryIndex("id"), |
| new QueryIndex("personId"), |
| new QueryIndex("personDateId"), |
| new QueryIndex("personStrId"))); |
| } |
| |
| entities.add(account); |
| } |
| |
| if (personCache) { |
| QueryEntity person = new QueryEntity(); |
| person.setKeyType(useCollocatedData() ? AffinityKey.class.getName() : Integer.class.getName()); |
| person.setValueType(Person.class.getName()); |
| person.addQueryField("id", Integer.class.getName(), null); |
| person.addQueryField("dateId", Date.class.getName(), null); |
| person.addQueryField("strId", String.class.getName(), null); |
| person.addQueryField("orgId", Integer.class.getName(), null); |
| person.addQueryField("orgDateId", Date.class.getName(), null); |
| person.addQueryField("orgStrId", String.class.getName(), null); |
| person.addQueryField("name", String.class.getName(), null); |
| person.addQueryField("salary", Integer.class.getName(), null); |
| |
| if (idx) { |
| person.setIndexes(F.asList(new QueryIndex("id"), |
| new QueryIndex("dateId"), |
| new QueryIndex("strId"), |
| new QueryIndex("orgId"), |
| new QueryIndex("orgDateId"), |
| new QueryIndex("orgStrId"), |
| new QueryIndex("name"), |
| new QueryIndex("salary"))); |
| } |
| |
| entities.add(person); |
| } |
| |
| if (orgCache) { |
| QueryEntity org = new QueryEntity(); |
| org.setKeyType(Integer.class.getName()); |
| org.setValueType(Organization.class.getName()); |
| org.addQueryField("id", Integer.class.getName(), null); |
| org.addQueryField("dateId", Date.class.getName(), null); |
| org.addQueryField("strId", String.class.getName(), null); |
| org.addQueryField("name", String.class.getName(), null); |
| |
| if (idx) { |
| org.setIndexes(F.asList(new QueryIndex("id"), |
| new QueryIndex("dateId"), |
| new QueryIndex("strId"), |
| new QueryIndex("name"))); |
| } |
| |
| entities.add(org); |
| } |
| |
| ccfg.setQueryEntities(entities); |
| |
| return ccfg; |
| } |
| |
| /** |
| * @param cache Cache. |
| */ |
| private void checkOrganizationPersonsJoin(IgniteCache cache) { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ORG_CACHE_NAME)) |
| return; |
| |
| qry = "checkOrganizationPersonsJoin"; |
| |
| SqlFieldsQuery qry = new SqlFieldsQuery("select o.name, p.name " + |
| "from \"" + ORG_CACHE_NAME + "\".Organization o, \"" + PERSON_CACHE_NAME + "\".Person p " + |
| "where p.orgId = o._key and o._key=?"); |
| |
| qry.setDistributedJoins(distributedJoins()); |
| |
| SqlQuery qry2 = null; |
| |
| if (PERSON_CACHE_NAME.equals(cache.getName())) { |
| qry2 = new SqlQuery(Person.class, |
| "from \"" + ORG_CACHE_NAME + "\".Organization, \"" + PERSON_CACHE_NAME + "\".Person " + |
| "where Person.orgId = Organization._key and Organization._key=?" |
| ); |
| |
| qry2.setDistributedJoins(distributedJoins()); |
| } |
| |
| long total = 0; |
| |
| for (int i = 0; i < data.personsPerOrg.size(); i++) { |
| qry.setArgs(i); |
| |
| if (qry2 != null) |
| qry2.setArgs(i); |
| |
| List<List<Object>> res = cache.query(qry).getAll(); |
| |
| assertEquals((int)data.personsPerOrg.get(i), res.size()); |
| |
| if (qry2 != null) { |
| List<List<Object>> res2 = cache.query(qry2).getAll(); |
| |
| assertEquals((int)data.personsPerOrg.get(i), res2.size()); |
| } |
| |
| total += res.size(); |
| } |
| |
| SqlFieldsQuery qry3 = new SqlFieldsQuery("select count(*) " + |
| "from \"" + ORG_CACHE_NAME + "\".Organization o, \"" + PERSON_CACHE_NAME + "\".Person p where p.orgId = o._key"); |
| |
| qry3.setDistributedJoins(distributedJoins()); |
| |
| List<List<Object>> res = cache.query(qry3).getAll(); |
| |
| assertEquals(1, res.size()); |
| assertEquals(total, res.get(0).get(0)); |
| } |
| |
| /** |
| * @param cache Cache. |
| * @param cnts Accounts per person counts. |
| */ |
| private void checkPersonAccountsJoin(IgniteCache cache, Map<Integer, Integer> cnts) { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME)) |
| return; |
| |
| qry = "checkPersonAccountsJoin"; |
| |
| List<Query> qrys = new ArrayList<>(); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.id = a.personId and p.id=?") |
| ); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.dateId = a.personDateId and p.id=?") |
| ); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.strId = a.personStrId and p.id=?") |
| ); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.id = a.personId and p.id=?") |
| ); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.dateId = a.personDateId and p.id=?") |
| ); |
| |
| qrys.add(new SqlFieldsQuery("select p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.strId = a.personStrId and p.id=?") |
| ); |
| |
| if (PERSON_CACHE_NAME.equals(cache.getName())) { |
| qrys.add(new SqlQuery(Person.class, |
| "from \"" + PERSON_CACHE_NAME + "\".Person , \"" + ACC_CACHE_NAME + "\".Account " + |
| "where Person.id = Account.personId and Person.id=?") |
| ); |
| |
| qrys.add(new SqlQuery(Person.class, |
| "from \"" + PERSON_CACHE_NAME + "\".Person , \"" + ACC_CACHE_NAME + "\".Account " + |
| "where Person.id = Account.personId and Person.id=?") |
| ); |
| } |
| |
| List<Integer> keys = new ArrayList<>(cnts.keySet()); |
| |
| for (int i = 0; i < 10; i++) { |
| Integer key = keys.get(rnd.nextInt(keys.size())); |
| |
| List<List<Object>> res; |
| |
| for (Query q : qrys) { |
| if (q instanceof SqlFieldsQuery) { |
| ((SqlFieldsQuery)q).setDistributedJoins(distributedJoins()); |
| |
| ((SqlFieldsQuery)q).setArgs(key); |
| } |
| else { |
| ((SqlQuery)q).setDistributedJoins(distributedJoins()); |
| |
| ((SqlQuery)q).setArgs(key); |
| } |
| |
| res = cache.query(q).getAll(); |
| |
| assertEquals((int)cnts.get(key), res.size()); |
| } |
| } |
| |
| qrys.clear(); |
| |
| qrys.add(new SqlFieldsQuery("select count(*) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p, \"" + ACC_CACHE_NAME + "\".Account" + " a " + |
| "where p.id = a.personId")); |
| |
| qrys.add(new SqlFieldsQuery("select count(*) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p, \"" + ACC_CACHE_NAME + "\".Account" + " a " + |
| "where p.Dateid = a.personDateId")); |
| |
| qrys.add(new SqlFieldsQuery("select count(*) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p, \"" + ACC_CACHE_NAME + "\".Account" + " a " + |
| "where p.strId = a.personStrId")); |
| |
| qrys.add(new SqlFieldsQuery("select count(*) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p, \"" + ACC_CACHE_NAME + "\".Account" + " a " + |
| "where p.id = a.personId")); |
| |
| long total = 0; |
| |
| for (Integer cnt : data.accountsPerPerson.values()) |
| total += cnt; |
| |
| for (Query q : qrys) { |
| ((SqlFieldsQuery)q).setDistributedJoins(distributedJoins()); |
| |
| List<List<Object>> res = cache.query(q).getAll(); |
| |
| assertEquals(1, res.size()); |
| assertEquals(total, res.get(0).get(0)); |
| } |
| } |
| |
| /** |
| * @param cache Cache. |
| * @throws Exception If failed. |
| */ |
| private void checkOrganizationPersonAccountJoin(IgniteCache cache) throws Exception { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ORG_CACHE_NAME, ACC_CACHE_NAME)) |
| return; |
| |
| qry = "checkOrganizationPersonAccountJoin"; |
| |
| List<String> sqlFields = new ArrayList<>(); |
| |
| sqlFields.add("select o.name, p.name, a._key " + |
| "from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.orgId = o.id and p.id = a.personId and o.id = ?"); |
| |
| sqlFields.add("select o.name, p.name, a._key " + |
| "from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.orgDateId = o.dateId and p.strId = a.personStrId and o.id = ?"); |
| |
| sqlFields.add("select o.name, p.name, a._key " + |
| "from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.orgStrId = o.strId and p.id = a.personId and o.id = ?"); |
| |
| for (Organization org : data.orgs) { |
| for (String sql : sqlFields) |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[] {org.id}, Ordering.RANDOM); |
| } |
| |
| if (ACC_CACHE_NAME.equals(cache.getName())) { |
| for (int orgId = 0; orgId < data.accountsPerOrg.size(); orgId++) { |
| SqlQuery q = new SqlQuery(Account.class, "from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization , " + |
| "\"" + PERSON_CACHE_NAME + "\".Person , " + |
| "\"" + ACC_CACHE_NAME + "\".Account " + |
| "where Person.orgId = Organization.id and Person.id = Account.personId and Organization.id = ?"); |
| |
| q.setDistributedJoins(distributedJoins()); |
| |
| q.setArgs(orgId); |
| |
| List<List<Object>> res = cache.query(q).getAll(); |
| |
| assertEquals((int)data.accountsPerOrg.get(orgId), res.size()); |
| } |
| } |
| |
| String sql = "select count(*) " + |
| "from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.orgId = o.id and p.id = a.personId"; |
| |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[0], Ordering.RANDOM); |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| private void checkUnionAll() throws Exception { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME, ORG_CACHE_NAME)) |
| return; |
| |
| qry = "checkUnionAll"; |
| |
| String sql = "select a.id, p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.id = a.personId and p.id = ? " + |
| "union all " + |
| "select p.id, o.name from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p " + |
| "where p.orgStrId = o.strId and o.id = ?"; |
| |
| for (int i = 0; i < 10; i++) { |
| Person person = data.persons.get(rnd.nextInt(data.persons.size())); |
| |
| for (Organization org : data.orgs) |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[] {person.id, org.id}, Ordering.RANDOM); |
| } |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| private void checkUnion() throws Exception { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME, ORG_CACHE_NAME)) |
| return; |
| |
| qry = "checkUnion"; |
| |
| String sql = "select a.id, p.name from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.id = a.personId and p.id = ? " + |
| "union " + |
| "select p.id, o.name from " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p " + |
| "where p.orgStrId = o.strId and o.id = ?"; |
| |
| for (int i = 0; i < 10; i++) { |
| Person person = data.persons.get(rnd.nextInt(data.persons.size())); |
| |
| for (Organization org : data.orgs) |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[] {person.id, org.id}, Ordering.RANDOM); |
| } |
| } |
| |
| /** |
| * @param cache Cache. |
| * @throws Exception If failed. |
| */ |
| private void checkPersonAccountCrossJoin(IgniteCache cache) throws Exception { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME)) |
| return; |
| |
| qry = "checkPersonAccountCrossJoin"; |
| |
| String sql = "select p.name " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p " + |
| "cross join \"" + ACC_CACHE_NAME + "\".Account a"; |
| |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[0], Ordering.RANDOM); |
| } |
| |
| /** |
| * @param cache Cache. |
| */ |
| private void checkPersonOrganizationGroupBy(IgniteCache cache) { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ORG_CACHE_NAME)) |
| return; |
| |
| qry = "checkPersonOrganizationGroupBy"; |
| |
| // Max salary per organization. |
| SqlFieldsQuery q = new SqlFieldsQuery("select max(p.salary) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p join \"" + ORG_CACHE_NAME + "\".Organization o " + |
| "on p.orgId = o.id " + |
| "group by o.name " + |
| "having o.id = ?"); |
| |
| q.setDistributedJoins(distributedJoins()); |
| |
| for (Map.Entry<Integer, Integer> e : data.maxSalaryPerOrg.entrySet()) { |
| Integer orgId = e.getKey(); |
| Integer maxSalary = e.getValue(); |
| |
| q.setArgs(orgId); |
| |
| List<List<?>> res = cache.query(q).getAll(); |
| |
| String errMsg = "Expected data [orgId=" + orgId + ", maxSalary=" + maxSalary + ", data=" + data + "]"; |
| |
| // MaxSalary == -1 means that there are no persons at organization. |
| if (maxSalary > 0) { |
| assertEquals(errMsg, 1, res.size()); |
| assertEquals(errMsg, 1, res.get(0).size()); |
| assertEquals(errMsg, maxSalary, res.get(0).get(0)); |
| } |
| else |
| assertEquals(errMsg, 0, res.size()); |
| } |
| } |
| |
| /** |
| * @param cache Cache. |
| */ |
| private void checkPersonAccountGroupBy(IgniteCache cache) { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME)) |
| return; |
| |
| qry = "checkPersonAccountGroupBy"; |
| |
| // Count accounts per person. |
| SqlFieldsQuery q = new SqlFieldsQuery("select count(a.id) " + |
| "from \"" + PERSON_CACHE_NAME + "\".Person p join \"" + ACC_CACHE_NAME + "\".Account a " + |
| "on p.strId = a.personStrId " + |
| "group by p.name " + |
| "having p.id = ?"); |
| |
| q.setDistributedJoins(distributedJoins()); |
| |
| List<Integer> keys = new ArrayList<>(data.accountsPerPerson.keySet()); |
| |
| for (int i = 0; i < 10; i++) { |
| Integer personId = keys.get(rnd.nextInt(keys.size())); |
| Integer cnt = data.accountsPerPerson.get(personId); |
| |
| q.setArgs(personId); |
| |
| List<List<?>> res = cache.query(q).getAll(); |
| |
| String errMsg = "Expected data [personId=" + personId + ", cnt=" + cnt + ", data=" + data + "]"; |
| |
| // Cnt == 0 means that there are no accounts for the person. |
| if (cnt > 0) { |
| assertEquals(errMsg, 1, res.size()); |
| assertEquals(errMsg, 1, res.get(0).size()); |
| assertEquals(errMsg, (long)cnt, res.get(0).get(0)); |
| } |
| else |
| assertEquals(errMsg, 0, res.size()); |
| } |
| } |
| |
| /** |
| * @throws Exception If failed. |
| */ |
| private void checkGroupBy() throws Exception { |
| if (skipQuery(cache, PERSON_CACHE_NAME, ACC_CACHE_NAME, ORG_CACHE_NAME)) |
| return; |
| |
| qry = "checkGroupBy"; |
| |
| // Select persons with count of accounts of person at organization. |
| String sql = "select p.id, count(a.id) " + |
| "from " + |
| "\"" + PERSON_CACHE_NAME + "\".Person p, " + |
| "\"" + ORG_CACHE_NAME + "\".Organization o, " + |
| "\"" + ACC_CACHE_NAME + "\".Account a " + |
| "where p.id = a.personId and p.orgStrId = o.strId " + |
| "group by p.id " + |
| "having o.id = ?"; |
| |
| for (Organization org : data.orgs) |
| compareQueryRes0(cache, sql, distributedJoins(), new Object[] {org.id}, Ordering.RANDOM); |
| } |
| |
| /** |
| * @param cache Cache used to run query. |
| * @param caches Cache names. |
| * @return {@code True} if skip query execution. |
| */ |
| private boolean skipQuery(IgniteCache cache, String... caches) { |
| // Skip join replicated/partitioned caches executed on replicated cache. |
| Ignite node = (Ignite)cache.unwrap(Ignite.class); |
| |
| if (!distributedJoins() && replicated(cache)) { |
| for (String cacheName : caches) { |
| if (!replicated(node.cache(cacheName))) |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| private enum TestCacheType { |
| /** */ |
| REPLICATED(CacheMode.REPLICATED, 0), |
| |
| /** */ |
| PARTITIONED_b0(CacheMode.PARTITIONED, 0), |
| |
| /** */ |
| PARTITIONED_b1(CacheMode.PARTITIONED, 1); |
| |
| /** */ |
| final CacheMode cacheMode; |
| |
| /** */ |
| final int backups; |
| |
| /** |
| * @param mode Cache mode. |
| * @param backups Backups. |
| */ |
| TestCacheType(CacheMode mode, int backups) { |
| cacheMode = mode; |
| this.backups = backups; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class TestCache { |
| /** */ |
| @GridToStringInclude |
| final String cacheName; |
| |
| /** */ |
| @GridToStringInclude |
| final TestCacheType type; |
| |
| /** |
| * @param cacheName Cache name. |
| * @param type Cache type. |
| */ |
| public TestCache(String cacheName, TestCacheType type) { |
| this.cacheName = cacheName; |
| this.type = type; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return S.toString(TestCache.class, this); |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class Data { |
| /** */ |
| final List<Organization> orgs; |
| |
| /** */ |
| final List<Person> persons; |
| |
| /** */ |
| final List<Account> accounts; |
| |
| /** */ |
| final Map<Integer, Integer> personsPerOrg; |
| |
| /** PersonId to count of accounts that person has. */ |
| final Map<Integer, Integer> accountsPerPerson; |
| |
| /** */ |
| final Map<Integer, Integer> accountsPerOrg; |
| |
| /** */ |
| final Map<Integer, Integer> maxSalaryPerOrg; |
| |
| /** |
| * @param orgs Organizations. |
| * @param persons Persons. |
| * @param accounts Accounts. |
| * @param personsPerOrg Count of persons per organization. |
| * @param accountsPerPerson Count of accounts per person. |
| * @param accountsPerOrg Count of accounts per organization. |
| * @param maxSalaryPerOrg Maximum salary per organization. |
| */ |
| Data(List<Organization> orgs, |
| List<Person> persons, |
| List<Account> accounts, |
| Map<Integer, Integer> personsPerOrg, |
| Map<Integer, Integer> accountsPerPerson, |
| Map<Integer, Integer> accountsPerOrg, |
| Map<Integer, Integer> maxSalaryPerOrg) { |
| this.orgs = orgs; |
| this.persons = persons; |
| this.accounts = accounts; |
| this.personsPerOrg = personsPerOrg; |
| this.accountsPerPerson = accountsPerPerson; |
| this.accountsPerOrg = accountsPerOrg; |
| this.maxSalaryPerOrg = maxSalaryPerOrg; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return "Data [" + |
| "orgs=" + orgs + |
| ", persons=" + persons + |
| ", accounts=" + accounts + |
| ", personsPerOrg=" + personsPerOrg + |
| ", accountsPerPerson=" + accountsPerPerson + |
| ", accountsPerOrg=" + accountsPerOrg + |
| ", maxSalaryPerOrg=" + maxSalaryPerOrg + |
| ']'; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class Account implements Serializable { |
| /** */ |
| @QuerySqlField |
| private int id; |
| |
| /** */ |
| @QuerySqlField |
| private int personId; |
| |
| /** */ |
| @QuerySqlField |
| private Date personDateId; |
| |
| /** */ |
| @QuerySqlField |
| private String personStrId; |
| |
| /** */ |
| @QuerySqlField |
| private int orgId; |
| |
| /** |
| * @param id ID. |
| * @param personId Person ID. |
| * @param orgId Organization ID. |
| */ |
| Account(int id, int personId, int orgId) { |
| this.id = id; |
| this.personId = personId; |
| this.orgId = orgId; |
| personDateId = new Date(personId); |
| personStrId = "personId" + personId; |
| } |
| |
| /** |
| * @param useCollocatedData Use colocated data. |
| * @return Key. |
| */ |
| public Object key(boolean useCollocatedData) { |
| return useCollocatedData ? new AffinityKey<>(id, orgId) : id; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return "Account [" + |
| "id=" + id + |
| ", personId=" + personId + |
| ']'; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class Person implements Serializable { |
| /** */ |
| @QuerySqlField |
| int id; |
| |
| /** Date as ID. */ |
| @QuerySqlField |
| Date dateId; |
| |
| /** String as ID */ |
| @QuerySqlField |
| String strId; |
| |
| /** */ |
| @QuerySqlField |
| int orgId; |
| |
| /** */ |
| @QuerySqlField |
| Date orgDateId; |
| |
| /** */ |
| @QuerySqlField |
| String orgStrId; |
| |
| /** */ |
| @QuerySqlField |
| String name; |
| |
| /** */ |
| @QuerySqlField |
| int salary; |
| |
| /** |
| * @param id ID. |
| * @param orgId Organization ID. |
| * @param name Name. |
| * @param salary Salary. |
| */ |
| Person(int id, int orgId, String name, int salary) { |
| this.id = id; |
| dateId = new Date(id); |
| strId = "personId" + id; |
| this.orgId = orgId; |
| orgDateId = new Date(orgId); |
| orgStrId = "orgId" + orgId; |
| this.name = name; |
| this.salary = salary; |
| } |
| |
| /** |
| * @param useCollocatedData Use collocated data. |
| * @return Key. |
| */ |
| public Object key(boolean useCollocatedData) { |
| return useCollocatedData ? new AffinityKey<>(id, orgId) : id; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return "Person [" + |
| "id=" + id + |
| ", orgId=" + orgId + |
| ", name='" + name + '\'' + |
| ", salary=" + salary + |
| ']'; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class Organization implements Serializable { |
| /** */ |
| @QuerySqlField |
| int id; |
| |
| /** */ |
| @QuerySqlField |
| Date dateId; |
| |
| /** */ |
| @QuerySqlField |
| String strId; |
| |
| /** */ |
| @QuerySqlField |
| String name; |
| |
| /** |
| * @param id ID. |
| * @param name Name. |
| */ |
| Organization(int id, String name) { |
| this.id = id; |
| dateId = new Date(id); |
| strId = "orgId" + id; |
| this.name = name; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return "Organization [" + |
| "name='" + name + '\'' + |
| ", id=" + id + |
| ']'; |
| } |
| } |
| |
| /** |
| * |
| */ |
| private static class TestConfig { |
| /** */ |
| private final int idx; |
| |
| /** */ |
| private final IgniteCache testedCache; |
| |
| /** */ |
| private final TestCache personCache; |
| |
| /** */ |
| private final TestCache accCache; |
| |
| /** */ |
| private final TestCache orgCache; |
| |
| /** */ |
| private final String qry; |
| |
| /** |
| * @param cfgIdx Tested configuration index. |
| * @param testedCache Tested testedCache. |
| * @param personCacheType Person testedCache personCacheType. |
| * @param accCacheType Account testedCache personCacheType. |
| * @param orgCacheType Organization testedCache personCacheType. |
| * @param testedQry Query. |
| */ |
| TestConfig(int cfgIdx, |
| IgniteCache testedCache, |
| TestCache personCacheType, |
| TestCache accCacheType, |
| TestCache orgCacheType, |
| String testedQry) { |
| idx = cfgIdx; |
| this.testedCache = testedCache; |
| this.personCache = personCacheType; |
| this.accCache = accCacheType; |
| this.orgCache = orgCacheType; |
| qry = testedQry; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override public String toString() { |
| return "TestConfig [" + |
| "idx=" + idx + |
| ", testedCache=" + testedCache.getName() + |
| ", personCache=" + personCache + |
| ", accCache=" + accCache + |
| ", orgCache=" + orgCache + |
| ", qry=" + qry + |
| ']'; |
| } |
| } |
| } |