blob: f8a45c4a77c5801ef04b3827c1e575f3d7bd0a04 [file] [log] [blame]
/*
* 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.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.configuration.Factory;
import javax.cache.expiry.Duration;
import javax.cache.expiry.TouchedExpiryPolicy;
import org.apache.ignite.Ignite;
import org.apache.ignite.IgniteBinary;
import org.apache.ignite.IgniteCache;
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.IgniteSystemProperties;
import org.apache.ignite.Ignition;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.cache.CacheAtomicityMode;
import org.apache.ignite.cache.CacheMode;
import org.apache.ignite.cache.CachePeekMode;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.QueryIndex;
import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
import org.apache.ignite.cache.query.QueryCursor;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.SqlQuery;
import org.apache.ignite.cache.query.TextQuery;
import org.apache.ignite.cache.query.annotations.QuerySqlField;
import org.apache.ignite.cache.query.annotations.QuerySqlFunction;
import org.apache.ignite.cache.query.annotations.QueryTextField;
import org.apache.ignite.cache.store.CacheStore;
import org.apache.ignite.cache.store.CacheStoreAdapter;
import org.apache.ignite.client.Config;
import org.apache.ignite.client.IgniteClient;
import org.apache.ignite.configuration.CacheConfiguration;
import org.apache.ignite.configuration.ClientConfiguration;
import org.apache.ignite.configuration.DataStorageConfiguration;
import org.apache.ignite.configuration.IgniteConfiguration;
import org.apache.ignite.configuration.NearCacheConfiguration;
import org.apache.ignite.events.CacheQueryExecutedEvent;
import org.apache.ignite.events.CacheQueryReadEvent;
import org.apache.ignite.events.Event;
import org.apache.ignite.events.EventType;
import org.apache.ignite.events.SqlQueryExecutionEvent;
import org.apache.ignite.internal.binary.BinaryMarshaller;
import org.apache.ignite.internal.processors.cache.query.QueryCursorEx;
import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata;
import org.apache.ignite.internal.util.lang.GridPlainCallable;
import org.apache.ignite.internal.util.tostring.GridToStringBuilder;
import org.apache.ignite.internal.util.tostring.GridToStringExclude;
import org.apache.ignite.internal.util.typedef.F;
import org.apache.ignite.internal.util.typedef.G;
import org.apache.ignite.internal.util.typedef.internal.S;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.lang.IgniteBiPredicate;
import org.apache.ignite.lang.IgnitePredicate;
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
import org.apache.ignite.testframework.GridTestUtils;
import org.apache.ignite.testframework.junits.WithSystemProperty;
import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
import org.junit.Test;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheMode.REPLICATED;
import static org.apache.ignite.cache.CacheRebalanceMode.SYNC;
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC;
import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_EXECUTED;
import static org.apache.ignite.events.EventType.EVT_CACHE_QUERY_OBJECT_READ;
import static org.apache.ignite.events.EventType.EVT_SQL_QUERY_EXECUTION;
import static org.apache.ignite.internal.processors.cache.query.CacheQueryType.FULL_TEXT;
import static org.apache.ignite.internal.processors.cache.query.CacheQueryType.SCAN;
import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause;
import static org.junit.Assert.assertArrayEquals;
/**
* Various tests for cache queries.
*/
public abstract class IgniteCacheAbstractQuerySelfTest extends GridCommonAbstractTest {
/** Key count. */
private static final int KEY_CNT = 5000;
/** Cache store. */
private static TestStore store = new TestStore();
/**
* @return Grid count.
*/
protected abstract int gridCount();
/**
* @return Cache mode.
*/
protected abstract CacheMode cacheMode();
/**
* @return Atomicity mode.
*/
protected CacheAtomicityMode atomicityMode() {
return TRANSACTIONAL;
}
/**
* @return Distribution.
*/
protected NearCacheConfiguration nearCacheConfiguration() {
return new NearCacheConfiguration();
}
/** {@inheritDoc} */
@SuppressWarnings("unchecked")
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
IgniteConfiguration c = super.getConfiguration(igniteInstanceName);
((TcpDiscoverySpi)c.getDiscoverySpi()).setForceServerMode(true);
if (igniteInstanceName.startsWith("client"))
c.setDataStorageConfiguration(new DataStorageConfiguration());
c.setIncludeEventTypes(EventType.EVTS_ALL);
return c;
}
/**
* @return cache configuration
*/
protected CacheConfiguration cacheConfiguration() {
CacheConfiguration cc = defaultCacheConfiguration();
cc.setCacheMode(cacheMode());
cc.setAtomicityMode(atomicityMode());
cc.setNearConfiguration(nearCacheConfiguration());
cc.setWriteSynchronizationMode(FULL_SYNC);
cc.setCacheStoreFactory(new StoreFactory());
cc.setReadThrough(true);
cc.setWriteThrough(true);
cc.setLoadPreviousValue(true);
cc.setRebalanceMode(SYNC);
cc.setSqlFunctionClasses(SqlFunctions.class);
List<QueryEntity> entityList = new ArrayList<>();
QueryEntity qryEntity = new QueryEntity();
qryEntity.setKeyType(Integer.class.getName());
qryEntity.setValueType(Type1.class.getName());
qryEntity.addQueryField("id", Integer.class.getName(), null);
qryEntity.addQueryField("name", String.class.getName(), null);
qryEntity.setTableName("Type2");
qryEntity.setIndexes(Arrays.asList(new QueryIndex("id")
.setName("index~!@#$%^&*()_=-+;[]{}|?,.*`:nameWithNonLetterSymbols")));
entityList.add(qryEntity);
qryEntity = new QueryEntity();
qryEntity.setKeyType(Integer.class.getName());
qryEntity.setValueType(Type2.class.getName());
qryEntity.addQueryField("id", Integer.class.getName(), null);
qryEntity.addQueryField("name", String.class.getName(), null);
qryEntity.setTableName("Type1");
qryEntity.setIndexes(Arrays.asList(new QueryIndex("id")));
entityList.add(qryEntity);
qryEntity = new QueryEntity();
qryEntity.setKeyType(Integer.class.getName());
qryEntity.setValueType(ObjectValue2.class.getName());
qryEntity.addQueryField("strVal", String.class.getName(), null);
final QueryIndex strIdx = new QueryIndex(); // Default index type
strIdx.setFieldNames(Collections.singletonList("strVal"), true);
qryEntity.setIndexes(Arrays.asList(strIdx));
entityList.add(qryEntity);
cc.setQueryEntities(entityList);
cc.setAffinity(new RendezvousAffinityFunction());
// Explicitly set number of backups equal to number of grids.
if (cacheMode() == CacheMode.PARTITIONED)
cc.setBackups(gridCount());
//cc.setSnapshotableIndex(snapshotableIndex());
return cc;
}
/**
* @param clsK Key class.
* @param clsV Value class.
*
* @return cache instance
*/
protected <K, V> IgniteCache<K, V> jcache(Class<K> clsK, Class<V> clsV) {
return jcache(ignite(), clsK, clsV);
}
/**
* @param ig Ignite.
* @param clsK Key class.
* @param clsV Value class.
*
* @return cache instance
*/
protected <K, V> IgniteCache<K, V> jcache(Ignite ig, Class<K> clsK, Class<V> clsV) {
IgniteCache<K, V> cache = jcache(ig, cacheConfiguration(), clsK, clsV);
return cache;
}
/**
* @return {@code True} if index snapshot is enabled.
*/
protected boolean snapshotableIndex() {
return false;
}
/**
* @return Ignite instance.
*/
protected Ignite ignite() {
return grid(0);
}
/** {@inheritDoc} */
@Override protected void afterTest() throws Exception {
super.afterTest();
for (String cacheName : ignite().cacheNames())
ignite().cache(cacheName).destroy();
}
/** {@inheritDoc} */
@Override protected void beforeTestsStarted() throws Exception {
super.beforeTestsStarted();
startGridsMultiThreaded(gridCount());
}
/** {@inheritDoc} */
@Override protected void afterTestsStopped() throws Exception {
store.reset();
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testDifferentKeyTypes() throws Exception {
final IgniteCache<Object, Object> cache = jcache(Object.class, Object.class);
cache.put(1, "value");
cache.put("key", "value");
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testDifferentValueTypes() throws Exception {
IgniteCache<Integer, Object> cache = jcache(Integer.class, Object.class);
cache.put(7, "value");
// Put value of different type but for the same key type.
// Operation should succeed but with warning log message.
cache.put(7, 1);
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testStringType() throws Exception {
IgniteCache<Integer, String> cache = jcache(Integer.class, String.class);
cache.put(666, "test");
QueryCursor<Cache.Entry<Integer, String>> qry =
cache.query(new SqlQuery<Integer, String>(String.class, "_val='test'"));
Cache.Entry<Integer, String> entry = F.first(qry.getAll());
assert entry != null;
assertEquals(666, entry.getKey().intValue());
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testIntegerType() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
int key = 898;
int val = 2;
cache.put(key, val);
QueryCursor<Cache.Entry<Integer, Integer>> qry =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_key = ? and _val > 1").setArgs(key));
Cache.Entry<Integer, Integer> entry = F.first(qry.getAll());
assert entry != null;
assertEquals(key, entry.getKey().intValue());
assertEquals(val, entry.getValue().intValue());
}
/**
* Test table alias in SqlQuery.
*
* @throws Exception In case of error.
*/
@Test
public void testTableAliasInSqlQuery() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
int key = 898;
int val = 2;
cache.put(key, val);
SqlQuery<Integer, Integer> sqlQry = new SqlQuery<>(Integer.class, "t1._key = ? and t1._val > 1");
QueryCursor<Cache.Entry<Integer, Integer>> qry = cache.query(sqlQry.setAlias("t1").setArgs(key));
Cache.Entry<Integer, Integer> entry = F.first(qry.getAll());
assert entry != null;
assertEquals(key, entry.getKey().intValue());
assertEquals(val, entry.getValue().intValue());
sqlQry = new SqlQuery<>(Integer.class, "FROM Integer as t1 WHERE t1._key = ? and t1._val > 1");
qry = cache.query(sqlQry.setAlias("t1").setArgs(key));
entry = F.first(qry.getAll());
assert entry != null;
assertEquals(key, entry.getKey().intValue());
assertEquals(val, entry.getValue().intValue());
}
/**
* Tests UDFs.
*
* @throws IgniteCheckedException If failed.
*/
@Test
public void testUserDefinedFunction() throws IgniteCheckedException {
// Without alias.
final IgniteCache<Object, Object> cache = jcache(Object.class, Object.class);
QueryCursor<List<?>> qry = cache.query(new SqlFieldsQuery("select square(1), square(2)"));
Collection<List<?>> res = qry.getAll();
assertEquals(1, res.size());
List<?> row = res.iterator().next();
assertEquals(1, row.get(0));
assertEquals(4, row.get(1));
// With alias.
qry = cache.query(new SqlFieldsQuery("select _cube_(1), _cube_(2)"));
res = qry.getAll();
assertEquals(1, res.size());
row = res.iterator().next();
assertEquals(1, row.get(0));
assertEquals(8, row.get(1));
// Not registered.
GridTestUtils.assertThrows(
log,
new Callable<Object>() {
@Override public Object call() throws Exception {
cache.query(new SqlFieldsQuery("select no()"));
return null;
}
},
CacheException.class,
null
);
}
/**
* Expired entries are not included to result.
*
* @throws Exception If failed.
*/
@Test
public void testExpiration() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
cache.withExpiryPolicy(new TouchedExpiryPolicy(new Duration(MILLISECONDS, 1000))).put(7, 1);
List<Cache.Entry<Integer, Integer>> qry =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "1=1")).getAll();
Cache.Entry<Integer, Integer> res = F.first(qry);
assertEquals(1, res.getValue().intValue());
U.sleep(300); // Less than minimal amount of time that must pass before a cache entry is considered expired.
qry = cache.query(new SqlQuery<Integer, Integer>(Integer.class, "1=1")).getAll();
res = F.first(qry);
assertEquals(1, res.getValue().intValue());
U.sleep(1800); // No expiry guarantee here. Test should be refactored in case of fails.
qry = cache.query(new SqlQuery<Integer, Integer>(Integer.class, "1=1")).getAll();
res = F.first(qry);
assertNull(res);
}
/**
* @throws Exception If failed.
*/
@Test
public void testIllegalBounds() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
cache.put(1, 1);
cache.put(2, 2);
QueryCursor<Cache.Entry<Integer, Integer>> qry =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_key between 2 and 1"));
assertTrue(qry.getAll().isEmpty());
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testComplexType() throws Exception {
IgniteCache<Key, GridCacheQueryTestValue> cache = jcache(Key.class, GridCacheQueryTestValue.class);
GridCacheQueryTestValue val1 = new GridCacheQueryTestValue();
val1.setField1("field1");
val1.setField2(1);
val1.setField3(1L);
GridCacheQueryTestValue val2 = new GridCacheQueryTestValue();
val2.setField1("field2");
val2.setField2(2);
val2.setField3(2L);
val2.setField6(null);
cache.put(new Key(100500), val1);
cache.put(new Key(100501), val2);
QueryCursor<Cache.Entry<Key, GridCacheQueryTestValue>> qry = cache
.query(new SqlQuery<Key, GridCacheQueryTestValue>(GridCacheQueryTestValue.class,
"fieldName='field1' and field2=1 and field3=1 and id=100500 and embeddedField2=11 and x=3"));
Cache.Entry<Key, GridCacheQueryTestValue> entry = F.first(qry.getAll());
assertNotNull(entry);
assertEquals(100500, entry.getKey().id);
assertEquals(val1, entry.getValue());
}
/**
* @throws Exception In case of error.
*/
@Test
public void testComplexTypeKeepBinary() throws Exception {
if (ignite().configuration().getMarshaller() == null || ignite().configuration().getMarshaller() instanceof BinaryMarshaller) {
IgniteCache<Key, GridCacheQueryTestValue> cache = jcache(Key.class, GridCacheQueryTestValue.class);
GridCacheQueryTestValue val1 = new GridCacheQueryTestValue();
val1.setField1("field1");
val1.setField2(1);
val1.setField3(1L);
GridCacheQueryTestValue val2 = new GridCacheQueryTestValue();
val2.setField1("field2");
val2.setField2(2);
val2.setField3(2L);
val2.setField6(null);
cache.put(new Key(100500), val1);
cache.put(new Key(100501), val2);
QueryCursor<Cache.Entry<BinaryObject, BinaryObject>> qry = cache.withKeepBinary()
.query(new SqlQuery<BinaryObject, BinaryObject>(GridCacheQueryTestValue.class,
"fieldName='field1' and field2=1 and field3=1 and id=100500 and embeddedField2=11 and x=3"));
Cache.Entry<BinaryObject, BinaryObject> entry = F.first(qry.getAll());
assertNotNull(entry);
assertEquals(Long.valueOf(100500L), entry.getKey().field("id"));
assertEquals(val1, entry.getValue().deserialize());
}
}
/**
* Complex key type.
*/
private static class Key {
/** */
@QuerySqlField
private final long id;
/**
* @param id Id.
*/
private Key(long id) {
this.id = id;
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Key key = (Key)o;
return id == key.id;
}
/** {@inheritDoc} */
@Override public int hashCode() {
return (int)(id ^ (id >>> 32));
}
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testSelectQuery() throws Exception {
IgniteCache<Integer, String> cache = jcache(Integer.class, String.class);
cache.put(10, "value");
QueryCursor<Cache.Entry<Integer, String>> qry =
cache.query(new SqlQuery<Integer, String>(String.class, "true"));
Iterator<Cache.Entry<Integer, String>> iter = qry.iterator();
assert iter != null;
assert iter.next() != null;
}
/**
* JUnit.
*/
@Test
public void testSimpleCustomTableName() {
CacheConfiguration<Integer, Object> cacheConf = new CacheConfiguration<Integer, Object>(cacheConfiguration())
.setName(DEFAULT_CACHE_NAME)
.setQueryEntities(Arrays.asList(
new QueryEntity(Integer.class, Type1.class),
new QueryEntity(Integer.class, Type2.class)
));
final IgniteCache<Integer, Object> cache = ignite().getOrCreateCache(cacheConf);
cache.put(10, new Type1(1, "Type1 record #1"));
cache.put(20, new Type1(2, "Type1 record #2"));
QueryCursor<Cache.Entry<Integer, Type1>> qry1 =
cache.query(new SqlQuery<Integer, Type1>(Type1.class, "FROM Type2"));
List<Cache.Entry<Integer, Type1>> all = qry1.getAll();
assertEquals(2, all.size());
QueryCursor<List<?>> qry = cache.query(new SqlFieldsQuery("SELECT name FROM Type2"));
assertEquals(2, qry.getAll().size());
GridTestUtils.assertThrows(log, new GridPlainCallable<Void>() {
@Override public Void call() throws Exception {
QueryCursor<Cache.Entry<Integer, Type1>> qry =
cache.query(new SqlQuery<Integer, Type1>(Type1.class, "FROM Type1"));
qry.getAll();
return null;
}
}, CacheException.class, null);
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testMixedCustomTableName() throws Exception {
final IgniteCache<Integer, Object> cache = jcache(Integer.class, Object.class);
cache.put(10, new Type1(1, "Type1 record #1"));
cache.put(20, new Type1(2, "Type1 record #2"));
cache.put(30, new Type2(1, "Type2 record #1"));
cache.put(40, new Type2(2, "Type2 record #2"));
cache.put(50, new Type2(3, "Type2 record #3"));
QueryCursor<Cache.Entry<Integer, Type1>> qry1 =
cache.query(new SqlQuery<Integer, Type1>(Type1.class, "FROM Type2"));
List<Cache.Entry<Integer, Type1>> all = qry1.getAll();
assertEquals(2, all.size());
QueryCursor<Cache.Entry<Integer, Type2>> qry2 =
cache.query(new SqlQuery<Integer, Type2>(Type2.class, "FROM Type1"));
assertEquals(3, qry2.getAll().size());
QueryCursor<List<?>> qry = cache.query(new SqlFieldsQuery("SELECT name FROM Type1"));
assertEquals(3, qry.getAll().size());
qry = cache.query(new SqlFieldsQuery("SELECT name FROM Type2"));
assertEquals(2, qry.getAll().size());
GridTestUtils.assertThrows(log, new GridPlainCallable<Void>() {
@Override public Void call() throws Exception {
QueryCursor<Cache.Entry<Integer, Type1>> qry1 =
cache.query(new SqlQuery<Integer, Type1>(Type1.class, "FROM Type1"));
qry1.getAll().size();
return null;
}
}, CacheException.class, null);
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testDistributedJoinCustomTableName() throws Exception {
IgniteCache<Integer, Object> cache = jcache(Integer.class, Object.class);
cache.put(10, new Type1(1, "Type1 record #1"));
cache.put(20, new Type1(2, "Type1 record #2"));
cache.put(30, new Type2(1, "Type2 record #1"));
cache.put(40, new Type2(2, "Type2 record #2"));
cache.put(50, new Type2(3, "Type2 record #3"));
QueryCursor<List<?>> query = cache.query(
new SqlFieldsQuery("SELECT t2.name, t1.name FROM Type2 as t2 LEFT JOIN Type1 as t1 ON t1.id = t2.id")
.setDistributedJoins(cacheMode() == PARTITIONED));
assertEquals(2, query.getAll().size());
query = cache.query(
new SqlFieldsQuery("SELECT t2.name, t1.name FROM Type2 as t2 RIGHT JOIN Type1 as t1 ON t1.id = t2.id")
.setDistributedJoins(cacheMode() == PARTITIONED));
assertEquals(3, query.getAll().size());
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testObjectQuery() throws Exception {
IgniteCache<Integer, ObjectValue> cache = jcache(Integer.class, ObjectValue.class);
ObjectValue val = new ObjectValue("test", 0);
cache.put(1, val);
QueryCursor<Cache.Entry<Integer, ObjectValue>> qry =
cache.query(new SqlQuery<Integer, ObjectValue>(ObjectValue.class, "_val=?").setArgs(val));
Iterator<Cache.Entry<Integer, ObjectValue>> iter = qry.iterator();
assert iter != null;
int expCnt = 1;
for (int i = 0; i < expCnt; i++)
assert iter.next() != null;
assert !iter.hasNext();
qry = cache.query(new TextQuery<Integer, ObjectValue>(ObjectValue.class, "test"));
iter = qry.iterator();
assert iter != null;
for (int i = 0; i < expCnt; i++)
assert iter.next() != null;
assert !iter.hasNext();
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testObjectWithString() throws Exception {
IgniteCache<Integer, ObjectValue2> cache = jcache(Integer.class, ObjectValue2.class);
cache.put(1, new ObjectValue2("value 1"));
cache.put(2, new ObjectValue2("value 2"));
cache.put(3, new ObjectValue2("value 3"));
QueryCursor<Cache.Entry<Integer, ObjectValue2>> qry
= cache.query(new SqlQuery<Integer, ObjectValue2>(ObjectValue2.class, "strVal like ?").setArgs("value%"));
int expCnt = 3;
List<Cache.Entry<Integer, ObjectValue2>> results = qry.getAll();
assertEquals(expCnt, results.size());
qry = cache.query(new SqlQuery<Integer, ObjectValue2>(ObjectValue2.class, "strVal > ?").setArgs("value 1"));
results = qry.getAll();
assertEquals(expCnt - 1, results.size());
qry = cache.query(new TextQuery<Integer, ObjectValue2>(ObjectValue2.class, "value"));
results = qry.getAll();
assertEquals(0, results.size()); //Should fail for FULL_TEXT index, but SORTED
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testEnumObjectQuery() throws Exception {
final IgniteCache<Long, EnumObject> cache = jcache(Long.class, EnumObject.class);
for (long i = 0; i < 50; i++)
cache.put(i, new EnumObject(i, i % 2 == 0 ? EnumType.TYPE_A : EnumType.TYPE_B));
assertEnumQry("type = ?", EnumType.TYPE_A, EnumType.TYPE_A, cache, 25);
assertEnumQry("type > ?", EnumType.TYPE_A, EnumType.TYPE_B, cache, 25);
assertEnumQry("type < ?", EnumType.TYPE_B, EnumType.TYPE_A, cache, 25);
assertEnumQry("type != ?", EnumType.TYPE_B, EnumType.TYPE_A, cache, 25);
assertEmptyEnumQry("type = ?", null, cache);
assertEmptyEnumQry("type > ?", EnumType.TYPE_B, cache);
assertEmptyEnumQry("type < ?", EnumType.TYPE_A, cache);
cache.put(50L, new EnumObject(50, null));
assertNoArgEnumQry("type is null", null, cache, 1);
assertAnyResTypeEnumQry("type is not null", cache, 50);
// Additional tests for binary enums.
IgniteBinary binary = ignite().binary();
if (binary != null) {
assertEnumQry("type = ?", binaryEnum(binary, EnumType.TYPE_A), EnumType.TYPE_A, cache, 25);
assertEnumQry("type > ?", binaryEnum(binary, EnumType.TYPE_A), EnumType.TYPE_B, cache, 25);
assertEnumQry("type < ?", binaryEnum(binary, EnumType.TYPE_B), EnumType.TYPE_A, cache, 25);
assertEnumQry("type != ?", binaryEnum(binary, EnumType.TYPE_B), EnumType.TYPE_A, cache, 25);
assertEmptyEnumQry("type > ?", binaryEnum(binary, EnumType.TYPE_B), cache);
assertEmptyEnumQry("type < ?", binaryEnum(binary, EnumType.TYPE_A), cache);
}
}
/**
* Create binary enum.
*
* @param binary Binary facade.
* @param val Enum value.
* @return Binary enum.
*/
private static BinaryObject binaryEnum(IgniteBinary binary, EnumType val) {
return binary.buildEnum(EnumType.class.getName(), val.ordinal());
}
/**
* Fails if result size not equals to resSize.
*
* @param qryStr to execute.
* @param cache cache.
* @param resSize size of the result.
*/
private void assertAnyResTypeEnumQry(String qryStr, IgniteCache<Long, EnumObject> cache, int resSize) {
final SqlQuery<Long, EnumObject> qry = new SqlQuery<>(EnumObject.class, qryStr);
final List<Cache.Entry<Long, EnumObject>> res = cache.query(qry).getAll();
assert resSize == res.size();
}
/**
* Fails if result size not equals to resSize or
* at least one entry has different of resType type.
*
* @param qryStr to execute.
* @param resType to compare with.
* @param cache cache.
* @param resSize size of the result.
*/
private void assertNoArgEnumQry(String qryStr, EnumType resType, IgniteCache<Long, EnumObject> cache, int resSize) {
final SqlQuery<Long, EnumObject> qry = new SqlQuery<>(EnumObject.class, qryStr);
final List<Cache.Entry<Long, EnumObject>> res = cache.query(qry).getAll();
assert resSize == res.size();
assertEnumType(res, resType);
}
/**
* Fails if result size not equals to resSize or
* at least one entry has different of resType type.
*
* @param qryStr to execute.
* @param arg to be passed to query.
* @param resType to compare with.
* @param cache cache.
* @param resSize size of the result.
*/
private void assertEnumQry(String qryStr, Object arg, EnumType resType, IgniteCache<Long, EnumObject> cache,
int resSize) {
final SqlQuery<Long, EnumObject> qry = new SqlQuery<>(EnumObject.class, qryStr);
qry.setArgs(arg);
final List<Cache.Entry<Long, EnumObject>> res = cache.query(qry).getAll();
assert resSize == res.size();
assertEnumType(res, resType);
}
/**
* Fails if result has entries.
*
* @param qryStr to execute.
* @param arg argument that will be passed to query.
* @param cache cache on which query will be executed.
*/
private void assertEmptyEnumQry(String qryStr, Object arg, IgniteCache<Long, EnumObject> cache) {
final SqlQuery<Long, EnumObject> qry = new SqlQuery<>(EnumObject.class, qryStr);
qry.setArgs(arg);
final List<Cache.Entry<Long, EnumObject>> res = cache.query(qry).getAll();
assert res.isEmpty();
}
/**
* Fails if at least one object in result has type field that doesn't
* equal to passed enumType.
*
* @param enumObjects query execution result.
* @param enumType compare to.
*/
private void assertEnumType(final List<Cache.Entry<Long, EnumObject>> enumObjects, final EnumType enumType) {
for (final Cache.Entry<Long, EnumObject> entry : enumObjects)
assert entry.getValue().type == enumType;
}
/**
* JUnit.
*/
@Test
public void testObjectQueryWithSwap() {
CacheConfiguration<Integer, ObjectValue> config = new CacheConfiguration<Integer, ObjectValue>(cacheConfiguration());
config.setOnheapCacheEnabled(true);
IgniteCache<Integer, ObjectValue> cache = jcache(ignite(), config, Integer.class, ObjectValue.class);
boolean partitioned = cache.getConfiguration(CacheConfiguration.class).getCacheMode() == PARTITIONED;
int cnt = 10;
for (int i = 0; i < cnt; i++)
cache.put(i, new ObjectValue("test" + i, i));
for (Ignite g : G.allGrids()) {
IgniteCache<Integer, ObjectValue> c = g.cache(cache.getName());
for (int i = 0; i < cnt; i++) {
assertNotNull(c.localPeek(i, CachePeekMode.ONHEAP));
c.localEvict(Collections.singleton(i)); // Swap.
if (!partitioned || g.affinity(cache.getName()).mapKeyToNode(i).isLocal()) {
ObjectValue peekVal = c.localPeek(i, CachePeekMode.ONHEAP);
assertNull("Non-null value for peek [key=" + i + ", val=" + peekVal + ']', peekVal);
}
}
}
QueryCursor<Cache.Entry<Integer, ObjectValue>> qry =
cache.query(new SqlQuery<Integer, ObjectValue>(ObjectValue.class, "intVal >= ? order by intVal").
setArgs(0));
Iterator<Cache.Entry<Integer, ObjectValue>> iter = qry.iterator();
assert iter != null;
Collection<Integer> set = new HashSet<>(cnt);
Cache.Entry<Integer, ObjectValue> next;
while (iter.hasNext()) {
next = iter.next();
ObjectValue v = next.getValue();
assert !set.contains(v.intValue());
set.add(v.intValue());
}
assert !iter.hasNext();
assertEquals(cnt, set.size());
for (int i = 0; i < cnt; i++)
assert set.contains(i);
qry = cache.query(new SqlQuery<Integer, ObjectValue>(ObjectValue.class, "MOD(intVal, 2) = ? order by intVal").
setArgs(0));
iter = qry.iterator();
assert iter != null;
set.clear();
while (iter.hasNext()) {
next = iter.next();
ObjectValue v = next.getValue();
assert !set.contains(v.intValue());
set.add(v.intValue());
}
assert !iter.hasNext();
assertEquals(cnt / 2, set.size());
for (int i = 0; i < cnt; i++)
if (i % 2 == 0)
assert set.contains(i);
else
assert !set.contains(i);
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testFullTextSearch() throws Exception {
IgniteCache<Integer, ObjectValue> cache = jcache(Integer.class, ObjectValue.class);
// Try to execute on empty cache first.
QueryCursor<Cache.Entry<Integer, ObjectValue>> qry =
cache.query(new TextQuery<Integer, ObjectValue>(ObjectValue.class, "full"));
assert qry.getAll().isEmpty();
qry = cache.query(new TextQuery<Integer, ObjectValue>(ObjectValue.class, "full"));
assert qry.getAll().isEmpty();
// Now put indexed values into cache.
int key1 = 1;
ObjectValue val1 = new ObjectValue("test full text", 0);
cache.put(key1, val1);
int key2 = 2;
ObjectValue val2 = new ObjectValue("test full text more", 0);
cache.put(key2, val2);
qry = cache.query(new TextQuery<Integer, ObjectValue>(ObjectValue.class, "full"));
Collection<Cache.Entry<Integer, ObjectValue>> res = qry.getAll();
assertNotNull(res);
assertEquals(2, res.size());
qry = cache.query(new TextQuery<Integer, ObjectValue>(ObjectValue.class, "full"));
res = qry.getAll();
assertNotNull(res);
assertEquals(2, res.size());
}
/**
* JUnit.
*
* @throws Exception In case of error.
*/
@Test
public void testScanQuery() throws Exception {
IgniteCache<Integer, String> c1 = jcache(Integer.class, String.class);
Map<Integer, String> map = new HashMap<>();
for (int i = 0; i < 5000; i++)
map.put(i, "str" + i);
for (Map.Entry<Integer, String> e : map.entrySet())
c1.put(e.getKey(), e.getValue());
// Scan query.
QueryCursor<Cache.Entry<Integer, String>> qry = c1.query(new ScanQuery<Integer, String>());
Iterator<Cache.Entry<Integer, String>> iter = qry.iterator();
assert iter != null;
int cnt = 0;
while (iter.hasNext()) {
Cache.Entry<Integer, String> e = iter.next();
String expVal = map.get(e.getKey());
assertNotNull(expVal);
assertEquals(expVal, e.getValue());
cnt++;
}
assertEquals(map.size(), cnt);
}
/**
* @throws Exception In case of error.
*/
@Test
public void testScanPartitionQuery() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
GridCacheContext cctx = ((IgniteCacheProxy)cache).context();
Map<Integer, Map<Integer, Integer>> entries = new HashMap<>();
for (int i = 0; i < KEY_CNT; i++) {
cache.put(i, i);
int part = cctx.affinity().partition(i);
Map<Integer, Integer> partEntries = entries.get(part);
if (partEntries == null)
entries.put(part, partEntries = new HashMap<>());
partEntries.put(i, i);
}
for (int i = 0; i < cctx.affinity().partitions(); i++) {
ScanQuery<Integer, Integer> scan = new ScanQuery<>(i);
Collection<Cache.Entry<Integer, Integer>> actual = cache.query(scan).getAll();
Map<Integer, Integer> exp = entries.get(i);
int size = exp == null ? 0 : exp.size();
assertEquals("Failed for partition: " + i, size, actual.size());
if (exp == null)
assertTrue(actual.isEmpty());
else
for (Cache.Entry<Integer, Integer> entry : actual)
assertTrue(entry.getValue().equals(exp.get(entry.getKey())));
}
}
/**
* JUnit.
*/
@Test
public void testTwoObjectsTextSearch() {
CacheConfiguration<Object, Object> conf = new CacheConfiguration<>(cacheConfiguration());
conf.setQueryEntities(Arrays.asList(
new QueryEntity(Integer.class, ObjectValue.class),
new QueryEntity(String.class, ObjectValueOther.class)
));
IgniteCache<Object, Object> c = jcache(ignite(), conf, Object.class, Object.class);
c.put(1, new ObjectValue("ObjectValue str", 1));
c.put("key", new ObjectValueOther("ObjectValueOther str"));
Collection<Cache.Entry<Object, Object>> res = c.query(new TextQuery<>(ObjectValue.class, "str")).getAll();
assert res != null;
int expCnt = 1;
assert res.size() == expCnt;
assert F.first(res).getValue().getClass() == ObjectValue.class;
res = c.query(new TextQuery<>(ObjectValueOther.class, "str")).getAll();
assert res != null;
assert res.size() == expCnt;
assert F.first(res).getValue().getClass() == ObjectValueOther.class;
}
/**
* @throws Exception If failed.
*/
@Test
public void testPrimitiveType() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
cache.put(1, 1);
cache.put(2, 2);
QueryCursor<Cache.Entry<Integer, Integer>> q =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_val > 1"));
Collection<Cache.Entry<Integer, Integer>> res = q.getAll();
assertEquals(1, res.size());
for (Cache.Entry<Integer, Integer> e : res) {
assertEquals(2, (int)e.getKey());
assertEquals(2, (int)e.getValue());
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testPaginationIteratorDefaultCache() throws Exception {
testPaginationIterator(jcache(ignite(), cacheConfiguration(), DEFAULT_CACHE_NAME, Integer.class, Integer.class));
}
/**
* @throws Exception If failed.
*/
@Test
public void testPaginationIteratorNamedCache() throws Exception {
testPaginationIterator(jcache(ignite(), cacheConfiguration(), Integer.class, Integer.class));
}
/**
* @param cache Ignite cache.
* @throws Exception If failed.
*/
private void testPaginationIterator(IgniteCache<Integer, Integer> cache) throws Exception {
for (int i = 0; i < 50; i++)
cache.put(i, i);
SqlQuery<Integer, Integer> qry = new SqlQuery<>(Integer.class, "_key >= 0");
qry.setPageSize(10);
QueryCursor<Cache.Entry<Integer, Integer>> q = cache.query(qry);
int cnt = 0;
for (Cache.Entry<Integer, Integer> e : q) {
assertTrue(e.getKey() >= 0 && e.getKey() < 50);
assertTrue(e.getValue() >= 0 && e.getValue() < 50);
cnt++;
}
assertEquals(50, cnt);
}
/**
* @throws Exception If failed.
*/
@Test
public void testPaginationGetDefaultCache() throws Exception {
testPaginationGet(jcache(ignite(), cacheConfiguration(), DEFAULT_CACHE_NAME, Integer.class, Integer.class));
}
/**
* @throws Exception If failed.
*/
@Test
public void testPaginationGetNamedCache() throws Exception {
testPaginationGet(jcache(ignite(), cacheConfiguration(), Integer.class, Integer.class));
}
/**
* @param cache Ignite cache.
* @throws Exception If failed.
*/
private void testPaginationGet(IgniteCache<Integer, Integer> cache) throws Exception {
for (int i = 0; i < 50; i++)
cache.put(i, i);
QueryCursor<Cache.Entry<Integer, Integer>> q =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_key >= 0"));
List<Cache.Entry<Integer, Integer>> list = new ArrayList<>(q.getAll());
Collections.sort(list, new Comparator<Cache.Entry<Integer, Integer>>() {
@Override public int compare(Cache.Entry<Integer, Integer> e1, Cache.Entry<Integer, Integer> e2) {
return e1.getKey().compareTo(e2.getKey());
}
});
for (int i = 0; i < 50; i++) {
Cache.Entry<Integer, Integer> e = list.get(i);
assertEquals(i, (int)e.getKey());
assertEquals(i, (int)e.getValue());
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testScanFilters() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
for (int i = 0; i < 50; i++)
cache.put(i, i);
QueryCursor<Cache.Entry<Integer, Integer>> q = cache.query(new ScanQuery<>(new IgniteBiPredicate<Integer, Integer>() {
@Override public boolean apply(Integer k, Integer v) {
assertNotNull(k);
assertNotNull(v);
return k >= 20 && v < 40;
}
}));
List<Cache.Entry<Integer, Integer>> list = new ArrayList<>(q.getAll());
Collections.sort(list, new Comparator<Cache.Entry<Integer, Integer>>() {
@Override public int compare(Cache.Entry<Integer, Integer> e1, Cache.Entry<Integer, Integer> e2) {
return e1.getKey().compareTo(e2.getKey());
}
});
assertEquals(20, list.size());
for (int i = 20; i < 40; i++) {
Cache.Entry<Integer, Integer> e = list.get(i - 20);
assertEquals(i, (int)e.getKey());
assertEquals(i, (int)e.getValue());
}
}
/**
* @throws IgniteCheckedException if failed.
*/
@Test
public void testBadHashObjectKey() throws IgniteCheckedException {
IgniteCache<BadHashKeyObject, Byte> cache = jcache(BadHashKeyObject.class, Byte.class);
cache.put(new BadHashKeyObject("test_key1"), (byte)1);
cache.put(new BadHashKeyObject("test_key0"), (byte)10);
cache.put(new BadHashKeyObject("test_key1"), (byte)7);
assertEquals(10, cache.query(new SqlQuery<BadHashKeyObject, Byte>(Byte.class, "_key = ?").
setArgs(new BadHashKeyObject("test_key0"))).getAll().get(0).getValue().intValue());
}
/**
* @throws IgniteCheckedException if failed.
*/
@Test
public void testTextIndexedKey() throws IgniteCheckedException {
IgniteCache<ObjectValue, Long> cache = jcache(ObjectValue.class, Long.class);
cache.put(new ObjectValue("test_key1", 10), 19L);
cache.put(new ObjectValue("test_key0", 11), 11005L);
cache.put(new ObjectValue("test_key1", 12), 17L);
assertEquals(11005L,
cache.query(new TextQuery<ObjectValue, Long>(Long.class, "test_key0"))
.getAll().get(0).getValue().intValue());
}
/**
* @throws Exception If failed.
*/
@Test
public void testOrderByOnly() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
for (int i = 0; i < 10; i++)
cache.put(i, i);
QueryCursor<Cache.Entry<Integer, Integer>> q =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_key >= 0"));
Collection<Cache.Entry<Integer, Integer>> res = q.getAll();
assertEquals(10, res.size());
if (cacheMode() != PARTITIONED) {
Iterator<Cache.Entry<Integer, Integer>> it = res.iterator();
for (Integer i = 0; i < 10; i++) {
assertTrue(it.hasNext());
Cache.Entry<Integer, Integer> e = it.next();
assertEquals(i, e.getKey());
assertEquals(i, e.getValue());
}
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testLimitOnly() throws Exception {
IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
for (int i = 0; i < 10; i++)
cache.put(i, i);
QueryCursor<Cache.Entry<Integer, Integer>> q =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "limit 5"));
Collection<Cache.Entry<Integer, Integer>> res = q.getAll();
assertEquals(5, res.size());
Set<Integer> checkDuplicate = new HashSet<>();
for (Cache.Entry<Integer, Integer> e : res) {
assert e.getKey() < 10 && e.getKey() >= 0;
assert e.getValue() < 10 && e.getValue() >= 0;
checkDuplicate.add(e.getValue());
}
assertEquals(5, checkDuplicate.size());
}
/**
* @throws Exception If failed.
*/
@Test
public void testArray() throws Exception {
IgniteCache<Integer, ArrayObject> cache = jcache(Integer.class, ArrayObject.class);
cache.put(1, new ArrayObject(new Long[] {1L, null, 3L}));
cache.put(2, new ArrayObject(new Long[] {4L, 5L, 6L}));
QueryCursor<Cache.Entry<Integer, ArrayObject>> q =
cache.query(new SqlQuery<Integer, ArrayObject>(ArrayObject.class, "array_contains(arr, cast(? as long))").
setArgs(4));
Collection<Cache.Entry<Integer, ArrayObject>> res = q.getAll();
assertEquals(1, res.size());
Cache.Entry<Integer, ArrayObject> e = F.first(res);
assertEquals(2, (int)e.getKey());
assertArrayEquals(new Long[]{4L, 5L, 6L}, e.getValue().arr);
}
/**
* @throws Exception If failed.
*/
@Test
public void testFieldsQueryMetadata() throws Exception {
IgniteCache<UUID, Person> cache = jcache(UUID.class, Person.class);
for (int i = 0; i < 100; i++)
cache.put(UUID.randomUUID(), new Person("name-" + i, (i + 1) * 100));
QueryCursor<List<?>> cur = cache.query(new SqlFieldsQuery("select name, salary from Person where name like ?")
.setArgs("name-"));
assertTrue(cur instanceof QueryCursorEx);
QueryCursorEx<List<?>> curEx = (QueryCursorEx<List<?>>)cur;
List<GridQueryFieldMetadata> meta = curEx.fieldsMeta();
assertNotNull(meta);
assertEquals(2, meta.size());
}
/**
* @throws Exception If failed.
*/
@Test
public void testSqlQueryEvents() throws Exception {
final IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
final boolean evtsDisabled = cache.getConfiguration(CacheConfiguration.class).isEventsDisabled();
final CountDownLatch execLatch = new CountDownLatch(evtsDisabled ? 0 :
cacheMode() == REPLICATED ? 1 : gridCount());
IgnitePredicate[] lsnrs = new IgnitePredicate[gridCount()];
for (int i = 0; i < gridCount(); i++) {
IgnitePredicate<Event> pred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryExecutedEvent;
System.out.println(">>> EVENT");
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryExecutedEvent qe = (CacheQueryExecutedEvent)evt;
assertEquals(cache.getName(), qe.cacheName());
assertNotNull(qe.clause());
assertNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertArrayEquals(new Integer[] {10}, qe.arguments());
execLatch.countDown();
return true;
}
};
grid(i).events().localListen(pred, EVT_CACHE_QUERY_EXECUTED);
lsnrs[i] = pred;
}
try {
for (int i = 0; i < 20; i++)
cache.put(i, i);
QueryCursor<Cache.Entry<Integer, Integer>> q =
cache.query(new SqlQuery<Integer, Integer>(Integer.class, "_key >= ?").setArgs(10));
q.getAll();
assert execLatch.await(1000, MILLISECONDS);
}
finally {
for (int i = 0; i < gridCount(); i++)
grid(i).events().stopLocalListen(lsnrs[i], EVT_CACHE_QUERY_EXECUTED);
}
}
/** @throws Exception If failed. */
@Test
@WithSystemProperty(key = IgniteSystemProperties.IGNITE_TO_STRING_INCLUDE_SENSITIVE, value = "false")
public void testClientQueryExecutedEvents() throws Exception {
((Map<?, ?>)GridTestUtils.getFieldValue(new GridToStringBuilder(), S.class, "classCache")).clear();
doTestClientQueryExecutedEvents(false);
}
/** @throws Exception If failed. */
@Test
@WithSystemProperty(key = IgniteSystemProperties.IGNITE_TO_STRING_INCLUDE_SENSITIVE, value = "true")
public void testClientQueryExecutedEventsIncludeSensitive() throws Exception {
((Map<?, ?>)GridTestUtils.getFieldValue(new GridToStringBuilder(), S.class, "classCache")).clear();
doTestClientQueryExecutedEvents(true);
}
/** */
public void doTestClientQueryExecutedEvents(boolean inclSens) throws Exception {
CountDownLatch execLatch = new CountDownLatch(9);
IgnitePredicate<SqlQueryExecutionEvent> lsnr = evt -> {
assertNotNull(evt.text());
if (inclSens)
assertTrue(evt.toString().contains("args="));
else
assertFalse(evt.toString().contains("args="));
execLatch.countDown();
return true;
};
ignite().events().localListen(lsnr, EVT_SQL_QUERY_EXECUTION);
ClientConfiguration cc = new ClientConfiguration().setAddresses(Config.SERVER);
try (IgniteClient client = Ignition.startClient(cc)) {
client.query(new SqlFieldsQuery("create table TEST_TABLE(key int primary key, val int)"))
.getAll();
client.query(new SqlFieldsQuery("insert into TEST_TABLE values (?, ?)").setArgs(1, 1))
.getAll();
client.query(new SqlFieldsQuery("update TEST_TABLE set val = ?2 where key = ?1").setArgs(1, 2))
.getAll();
client.query(new SqlFieldsQuery("select * from TEST_TABLE"))
.getAll();
client.query(new SqlFieldsQuery("create index idx_1 on TEST_TABLE(key)"))
.getAll();
client.query(new SqlFieldsQuery("drop index idx_1"))
.getAll();
client.query(new SqlFieldsQuery("alter table TEST_TABLE add column val2 int"))
.getAll();
client.query(new SqlFieldsQuery("alter table TEST_TABLE drop val2"))
.getAll();
client.query(new SqlFieldsQuery("drop table TEST_TABLE"))
.getAll();
assert execLatch.await(3_000, MILLISECONDS);
}
finally {
ignite().events().stopLocalListen(lsnr, EVT_SQL_QUERY_EXECUTION);
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testScanQueryEvents() throws Exception {
final Map<Integer, Integer> map = new ConcurrentHashMap<>();
final IgniteCache<Integer, Integer> cache = jcache(Integer.class, Integer.class);
final boolean evtsDisabled = cache.getConfiguration(CacheConfiguration.class).isEventsDisabled();
final CountDownLatch latch = new CountDownLatch(evtsDisabled ? 0 : 10);
final CountDownLatch execLatch = new CountDownLatch(evtsDisabled ? 0 :
cacheMode() == REPLICATED ? 1 : gridCount());
IgnitePredicate[] objReadLsnrs = new IgnitePredicate[gridCount()];
IgnitePredicate[] qryExecLsnrs = new IgnitePredicate[gridCount()];
for (int i = 0; i < gridCount(); i++) {
IgnitePredicate<Event> pred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryReadEvent;
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryReadEvent<Integer, Integer> qe = (CacheQueryReadEvent<Integer, Integer>)evt;
assertEquals(SCAN.name(), qe.queryType());
assertEquals(cache.getName(), qe.cacheName());
assertNull(qe.className());
assertNull(null, qe.clause());
assertNotNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertNull(qe.arguments());
map.put(qe.key(), qe.value());
latch.countDown();
return true;
}
};
grid(i).events().localListen(pred, EVT_CACHE_QUERY_OBJECT_READ);
objReadLsnrs[i] = pred;
IgnitePredicate<Event> execPred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryExecutedEvent;
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryExecutedEvent qe = (CacheQueryExecutedEvent)evt;
assertEquals(SCAN.name(), qe.queryType());
assertEquals(cache.getName(), qe.cacheName());
assertNull(qe.className());
assertNull(null, qe.clause());
assertNotNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertNull(qe.arguments());
execLatch.countDown();
return true;
}
};
grid(i).events().localListen(execPred, EVT_CACHE_QUERY_EXECUTED);
qryExecLsnrs[i] = execPred;
}
try {
for (int i = 0; i < 20; i++)
cache.put(i, i);
IgniteBiPredicate<Integer, Integer> filter = new IgniteBiPredicate<Integer, Integer>() {
@Override public boolean apply(Integer k, Integer v) {
return k >= 10;
}
};
QueryCursor<Cache.Entry<Integer, Integer>> q = cache.query(new ScanQuery<>(filter));
q.getAll();
assert latch.await(1000, MILLISECONDS);
assert execLatch.await(1000, MILLISECONDS);
if (!evtsDisabled) {
assertEquals(10, map.size());
for (int i = 10; i < 20; i++)
assertEquals(i, map.get(i).intValue());
}
}
finally {
for (int i = 0; i < gridCount(); i++) {
grid(i).events().stopLocalListen(objReadLsnrs[i]);
grid(i).events().stopLocalListen(qryExecLsnrs[i]);
}
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testTextQueryEvents() throws Exception {
final Map<UUID, Person> map = new ConcurrentHashMap<>();
final IgniteCache<UUID, Person> cache = jcache(UUID.class, Person.class);
final boolean evtsDisabled = cache.getConfiguration(CacheConfiguration.class).isEventsDisabled();
final CountDownLatch latch = new CountDownLatch(evtsDisabled ? 0 : 2);
final CountDownLatch execLatch = new CountDownLatch(evtsDisabled ? 0 :
cacheMode() == REPLICATED ? 1 : gridCount());
IgnitePredicate[] objReadLsnrs = new IgnitePredicate[gridCount()];
IgnitePredicate[] qryExecLsnrs = new IgnitePredicate[gridCount()];
for (int i = 0; i < gridCount(); i++) {
IgnitePredicate<Event> objReadPred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryReadEvent;
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryReadEvent<UUID, Person> qe = (CacheQueryReadEvent<UUID, Person>)evt;
assertEquals(FULL_TEXT.name(), qe.queryType());
assertEquals(cache.getName(), qe.cacheName());
assertEquals("Person", qe.className());
assertEquals("White", qe.clause());
assertNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertNull(qe.arguments());
map.put(qe.key(), qe.value());
latch.countDown();
return true;
}
};
grid(i).events().localListen(objReadPred, EVT_CACHE_QUERY_OBJECT_READ);
objReadLsnrs[i] = objReadPred;
IgnitePredicate<Event> qryExecPred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryExecutedEvent;
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryExecutedEvent qe = (CacheQueryExecutedEvent)evt;
assertEquals(FULL_TEXT.name(), qe.queryType());
assertEquals(cache.getName(), qe.cacheName());
assertEquals("Person", qe.className());
assertEquals("White", qe.clause());
assertNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertNull(qe.arguments());
execLatch.countDown();
return true;
}
};
grid(i).events().localListen(qryExecPred, EVT_CACHE_QUERY_EXECUTED);
qryExecLsnrs[i] = qryExecPred;
}
try {
UUID k1 = UUID.randomUUID();
UUID k2 = UUID.randomUUID();
UUID k3 = UUID.randomUUID();
cache.put(k1, new Person("Bob White", 1000));
cache.put(k2, new Person("Tom White", 1000));
cache.put(k3, new Person("Mike Green", 1000));
QueryCursor<Cache.Entry<UUID, Person>> q = cache.query(new TextQuery<UUID, Person>(Person.class, "White"));
q.getAll();
assert latch.await(1000, MILLISECONDS);
assert execLatch.await(1000, MILLISECONDS);
if (!evtsDisabled) {
assertEquals(2, map.size());
assertEquals("Bob White", map.get(k1).name());
assertEquals("Tom White", map.get(k2).name());
}
}
finally {
for (int i = 0; i < gridCount(); i++) {
grid(i).events().stopLocalListen(objReadLsnrs[i]);
grid(i).events().stopLocalListen(qryExecLsnrs[i]);
}
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testFieldsQueryEvents() throws Exception {
final IgniteCache<UUID, Person> cache = jcache(UUID.class, Person.class);
final boolean evtsDisabled = cache.getConfiguration(CacheConfiguration.class).isEventsDisabled();
final CountDownLatch execLatch = new CountDownLatch(evtsDisabled ? 0 :
cacheMode() == REPLICATED ? 1 : gridCount());
IgnitePredicate[] qryExecLsnrs = new IgnitePredicate[gridCount()];
for (int i = 0; i < gridCount(); i++) {
IgnitePredicate<Event> pred = new IgnitePredicate<Event>() {
@Override public boolean apply(Event evt) {
assert evt instanceof CacheQueryExecutedEvent;
if (evtsDisabled)
fail("Cache events are disabled");
CacheQueryExecutedEvent qe = (CacheQueryExecutedEvent)evt;
assertEquals(cache.getName(), qe.cacheName());
assertNotNull(qe.clause());
assertNull(qe.scanQueryFilter());
assertNull(qe.continuousQueryFilter());
assertArrayEquals(new Integer[] {10}, qe.arguments());
execLatch.countDown();
return true;
}
};
grid(i).events().localListen(pred, EVT_CACHE_QUERY_EXECUTED);
qryExecLsnrs[i] = pred;
}
try {
for (int i = 1; i <= 20; i++)
cache.put(UUID.randomUUID(), new Person("Person " + i, i));
QueryCursor<List<?>> q = cache.query(new SqlFieldsQuery("select _key, name from Person where salary > ?").
setArgs(10));
q.getAll();
assert execLatch.await(1000, MILLISECONDS);
}
finally {
for (int i = 0; i < gridCount(); i++)
grid(i).events().stopLocalListen(qryExecLsnrs[i]);
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testLocalSqlQueryFromClient() throws Exception {
try (Ignite g = startClientGrid("client")) {
IgniteCache<Integer, Integer> c = jcache(g, Integer.class, Integer.class);
for (int i = 0; i < 10; i++)
c.put(i, i);
SqlQuery<Integer, Integer> qry = new SqlQuery<>(Integer.class, "_key >= 5 order by _key");
qry.setLocal(true);
assertThrowsWithCause(() -> c.query(qry), CacheException.class);
}
}
/**
* @throws Exception If failed.
*/
@Test
public void testLocalSqlFieldsQueryFromClient() throws Exception {
try (Ignite g = startClientGrid("client")) {
IgniteCache<UUID, Person> c = jcache(g, UUID.class, Person.class);
Person p = new Person("Jon", 1500);
c.put(p.id(), p);
SqlFieldsQuery qry = new SqlFieldsQuery("select count(*) from Person");
qry.setLocal(true);
assertThrowsWithCause(() -> c.query(qry), CacheException.class);
}
}
/**
*
*/
private static class ArrayObject implements Serializable {
/** */
@QuerySqlField
private Long[] arr;
/**
* @param arr Array.
*/
private ArrayObject(Long[] arr) {
this.arr = arr;
}
}
/**
*
*/
public static class Person implements Externalizable {
/** */
@GridToStringExclude
@QuerySqlField
private UUID id = UUID.randomUUID();
/** */
@QuerySqlField
@QueryTextField
private String name;
/** */
@QuerySqlField
private int salary;
/** */
@QuerySqlField(index = true)
private int fake$Field;
/**
* Required by {@link Externalizable}.
*/
public Person() {
// No-op.
}
/**
* @param name Name.
* @param salary Salary.
*/
public Person(String name, int salary) {
assert name != null;
assert salary > 0;
this.name = name;
this.salary = salary;
}
/**
* @return Id.
*/
public UUID id() {
return id;
}
/**
* @return Name.
*/
public String name() {
return name;
}
/**
* @return Salary.
*/
public int salary() {
return salary;
}
/** {@inheritDoc} */
@Override public void writeExternal(ObjectOutput out) throws IOException {
U.writeUuid(out, id);
U.writeString(out, name);
out.writeInt(salary);
}
/** {@inheritDoc} */
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
id = U.readUuid(in);
name = U.readString(in);
salary = in.readInt();
}
/** {@inheritDoc} */
@Override public int hashCode() {
return id.hashCode() + 31 * name.hashCode() + 31 * 31 * salary;
}
/** {@inheritDoc} */
@Override public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Person))
return false;
Person that = (Person)obj;
return that.id.equals(id) && that.name.equals(name) && that.salary == salary;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(Person.class, this);
}
}
/**
*
*/
public static class Type1 implements Serializable {
/** */
private int id;
/** */
private String name;
/**
* @param id ID.
* @param name Name.
*/
Type1(int id, String name) {
assert name != null;
assert id > 0;
this.name = name;
this.id = id;
}
/**
* @return Name.
*/
public String name() {
return name;
}
/**
* @return ID.
*/
public int id() {
return id;
}
/** {@inheritDoc} */
@Override public int hashCode() {
return name.hashCode() + 31 * id;
}
/** {@inheritDoc} */
@Override public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Type1))
return false;
Type1 that = (Type1)obj;
return that.name.equals(name) && that.id == id;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(Type1.class, this);
}
}
/**
*
*/
public static class Type2 implements Serializable {
/** */
private int id;
/** */
private String name;
/**
* @param id ID.
* @param name Name.
*/
Type2(int id, String name) {
assert name != null;
assert id > 0;
this.name = name;
this.id = id;
}
/**
* @return Name.
*/
public String name() {
return name;
}
/**
* @return ID.
*/
public int id() {
return id;
}
/** {@inheritDoc} */
@Override public int hashCode() {
return name.hashCode() + 31 * id;
}
/** {@inheritDoc} */
@Override public boolean equals(Object obj) {
if (obj == this)
return true;
if (!(obj instanceof Type2))
return false;
Type2 that = (Type2)obj;
return that.name.equals(name) && that.id == id;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(Type2.class, this);
}
}
/**
* Test value object.
*/
@SuppressWarnings("PublicInnerClass")
public static class ObjectValue implements Serializable {
/** String value. */
@QueryTextField
private String strVal;
/** Integer value. */
@QuerySqlField
private int intVal;
/**
* Constructor.
*
* @param strVal String value.
* @param intVal Integer value.
*/
ObjectValue(String strVal, int intVal) {
this.strVal = strVal;
this.intVal = intVal;
}
/**
* Gets value.
*
* @return Value.
*/
public String getStringValue() {
return strVal;
}
/**
* @return Integer value.
*/
public int intValue() {
return intVal;
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ObjectValue other = (ObjectValue)o;
return strVal == null ? other.strVal == null : strVal.equals(other.strVal);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return strVal != null ? strVal.hashCode() : 0;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(ObjectValue.class, this);
}
}
/**
* Another test value object.
*/
private static class ObjectValueOther {
/** Value. */
@QueryTextField
private String val;
/**
* @param val String value.
*/
ObjectValueOther(String val) {
this.val = val;
}
/**
* Gets value.
*
* @return Value.
*/
public String value() {
return val;
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ObjectValueOther other = (ObjectValueOther)o;
return val == null ? other.val == null : val.equals(other.val);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return val != null ? val.hashCode() : 0;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(ObjectValueOther.class, this);
}
}
/**
* Another test value object.
*/
private static class ObjectValue2 {
/** Value. */
private String strVal;
/**
* @param strVal String value.
*/
ObjectValue2(String strVal) {
this.strVal = strVal;
}
/**
* Gets value.
*
* @return Value.
*/
public String value() {
return strVal;
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
ObjectValue2 other = (ObjectValue2)o;
return strVal == null ? other.strVal == null : strVal.equals(other.strVal);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return strVal != null ? strVal.hashCode() : 0;
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(ObjectValue2.class, this);
}
}
/**
*
*/
private static class BadHashKeyObject implements Serializable, Comparable<BadHashKeyObject> {
/** */
@QuerySqlField(index = false)
private final String str;
/**
* @param str String.
*/
private BadHashKeyObject(String str) {
this.str = str == null ? "" : str;
}
/** {@inheritDoc} */
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BadHashKeyObject keyObj = (BadHashKeyObject)o;
return str.equals(keyObj.str);
}
/** {@inheritDoc} */
@Override public int hashCode() {
return 10;
}
/** {@inheritDoc} */
@Override public int compareTo(BadHashKeyObject o) {
return str.compareTo(o.str);
}
/** {@inheritDoc} */
@Override public String toString() {
return S.toString(BadHashKeyObject.class, this);
}
}
/**
* Test store.
*/
private static class TestStore extends CacheStoreAdapter<Object, Object> {
/** */
private Map<Object, Object> map = new ConcurrentHashMap<>();
/** */
void reset() {
map.clear();
}
/** {@inheritDoc} */
@Override public Object load(Object key) {
return map.get(key);
}
/** {@inheritDoc} */
@Override public void write(javax.cache.Cache.Entry<? extends Object, ? extends Object> e) {
map.put(e.getKey(), e.getValue());
}
/** {@inheritDoc} */
@Override public void delete(Object key) {
map.remove(key);
}
}
/**
* Functions for test.
*/
@SuppressWarnings("PublicInnerClass")
public static class SqlFunctions {
/**
* @param x Argument.
* @return Square of given value.
*/
@QuerySqlFunction
public static int square(int x) {
return x * x;
}
/**
* @param x Argument.
* @return Cube of given value.
*/
@QuerySqlFunction(alias = "_cube_")
public static int cube(int x) {
return x * x * x;
}
/**
* Method which should not be registered.
* @return Nothing.
*/
public static int no() {
throw new IllegalStateException();
}
}
/**
*
*/
private static class StoreFactory implements Factory<CacheStore> {
/** {@inheritDoc} */
@Override public CacheStore create() {
return store;
}
}
/**
* Test enum class.
*/
private static class EnumObject {
/**
* Test id.
*/
@QuerySqlField(index = true)
private long id;
/**
* Test enum.
*/
@QuerySqlField
private EnumType type;
/**
* @param id id.
* @param type enum.
*/
public EnumObject(long id, EnumType type) {
this.id = id;
this.type = type;
}
/**
* @return string representation of object.
*/
@Override public String toString() {
return "EnumObject{" +
"id=" + id +
", type=" + type +
'}';
}
}
/**
* Test enum.
*/
private enum EnumType {
/** */
TYPE_A,
/** */
TYPE_B
}
}