blob: e9c8704f41ccf135f76b709fd78210543a33ab47 [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.geode.cache.query.functional;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
import static org.assertj.core.api.Assertions.assertThat;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.AttributesFactory;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.query.CacheUtils;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.test.junit.categories.OQLQueryTest;
@Category({OQLQueryTest.class})
public class INOperatorJUnitTest {
@Before
public void setUp() throws Exception {
CacheUtils.startCache();
}
@After
public void tearDown() throws Exception {
CacheUtils.closeCache();
}
// For decomposition of IN expressions, need to unit-test the following:
// 1) IN expr gets decomposed on indexed expression with func index (done)
// 2) index gets used on IN clause (done)
// 3) IN expr does not get decomposed on unindexed expression (not done)
// 4) Decomposed IN expr works with bind parameters (not done)
// 5) IN expr does get decomposed on indexed expression with pk index (not done)
// 6) pk index gets used with IN expression (not done)
// 7) decomposition (or not) of nested IN expressions (not done)
// 8) test IN clauses with:
// a) zero elements (should shortcircuit to return false ideally) (not done)
// b) one element (not done)
// c) more than one element (done)
/**
* Test the decomposition of IN SET(..) that gets decomposed into ORs so an index can be used
*/
@Ignore
@Test
public void testInDecompositionWithFunctionalIndex() throws Exception {
// TODO: this test was never implemented?
}
@Test
public void testRegionBulkGet() throws Exception {
Cache cache = CacheUtils.getCache();
AttributesFactory attributesFactory = new AttributesFactory();
RegionAttributes regionAttributes = attributesFactory.create();
Region region = cache.createRegion("pos", regionAttributes);
region.put("6", new Integer(6));
region.put("10", new Integer(10));
region.put("12", new Integer(10));
QueryService qs = cache.getQueryService();
Query q;
SelectResults results;
Object[] keys;
Set expectedResults;
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
expectedResults.add(new Integer(6));
expectedResults.add(new Integer(10));
assertThat(results.asSet()).isEqualTo(expectedResults);
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"42"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
assertThat(results.asSet()).isEqualTo(expectedResults);
for (int i = 0; i < 1000; i++) {
region.put(String.valueOf(i), new Integer(i));
}
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
expectedResults.add(new Integer(5));
expectedResults.add(new Integer(6));
expectedResults.add(new Integer(10));
expectedResults.add(new Integer(45));
assertThat(results.asSet()).isEqualTo(expectedResults);
q = qs.newQuery("SELECT e.key, e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
assertThat(results).hasSize(4);
region.destroyRegion();
}
@Test
public void testIntSet() throws Exception {
Query q = CacheUtils.getQueryService().newQuery("2 IN SET(1,2,3)");
Object result = q.execute();
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testStringSet() throws Exception {
Query q = CacheUtils.getQueryService().newQuery("'a' IN SET('x','y','z')");
Object result = q.execute();
assertThat(result).isEqualTo(FALSE);
}
@Test
public void testShortNumSet() throws Exception {
Short num = Short.valueOf("1");
Object params[] = new Object[1];
params[0] = num;
Query q = CacheUtils.getQueryService().newQuery("$1 IN SET(1,2,3)");
Object result = q.execute(params);
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testCollection() throws Exception {
Object e1 = new Object();
Object e2 = new Object();
Object e3 = new Object();
HashSet C1 = new HashSet();
C1.add(e1);
C1.add(e2);
C1.add(e3);
Object params[] = new Object[3];
params[0] = e1;
params[1] = C1;
params[2] = e2;
Query q = CacheUtils.getQueryService().newQuery("$3 IN $2");
Object result = q.execute(params);
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testWithSet() throws Exception {
String s1 = "Hello";
String s2 = "World";
HashSet H1 = new HashSet();
H1.add(s1);
H1.add(s2);
Object params[] = new Object[2];
params[0] = s1;
params[1] = H1;
Query q = CacheUtils.getQueryService().newQuery("$1 IN $2");
Object result = q.execute(params);
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testArrayList() throws Exception {
String s1 = "sss";
String s2 = "ddd";
ArrayList AL1 = new ArrayList();
AL1.add(s1);
AL1.add(s2);
Object params[] = new Object[3];
params[0] = s1;
params[1] = s2;
params[2] = AL1;
Query q = CacheUtils.getQueryService().newQuery("$1 IN $3");
Object result = q.execute(params);
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testNULL() throws Exception {
Query q = CacheUtils.getQueryService().newQuery(" null IN SET('x','y','z')");
Object result = q.execute();
assertThat(result).isEqualTo(FALSE);
q = CacheUtils.getQueryService().newQuery(" null IN SET(null)");
result = q.execute();
assertThat(result).isEqualTo(TRUE);
}
@Test
public void testUNDEFINED() throws Exception {
Query q = CacheUtils.getQueryService().newQuery(" UNDEFINED IN SET(1,2,3)");
Object result = q.execute();
assertThat(result).isEqualTo(FALSE);
q = CacheUtils.getQueryService().newQuery(" UNDEFINED IN SET(UNDEFINED)");
result = q.execute();
assertThat(result).isEqualTo(QueryService.UNDEFINED);
q = CacheUtils.getQueryService().newQuery(" UNDEFINED IN SET(UNDEFINED,UNDEFINED)");
result = q.execute();
assertThat(result).isEqualTo(QueryService.UNDEFINED);
}
@Test
public void testMiscSet() throws Exception {
Query q = CacheUtils.getQueryService().newQuery(" $1 IN SET(1, 'a', $2, $3, $4, $5)");
Object params[] = {null, new Integer(0), "str", null, new Object()};
for (int i = 1; i < params.length; i++) {
params[0] = params[i];
Object result = q.execute(params);
assertThat(result).isEqualTo(TRUE);
}
}
@Test
public void testIndexUsageWithIn() throws Exception {
Cache cache = CacheUtils.getCache();
AttributesFactory attributesFactory = new AttributesFactory();
RegionAttributes regionAttributes = attributesFactory.create();
Region region = cache.createRegion("pos", regionAttributes);
region.put("6", new Integer(6));
region.put("10", new Integer(10));
region.put("12", new Integer(10));
QueryService qs = cache.getQueryService();
qs.createIndex("In Index", IndexType.FUNCTIONAL, "e.key", "/pos.entrySet e");
Query q;
SelectResults results;
Object[] keys;
Set expectedResults;
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
expectedResults.add(new Integer(6));
expectedResults.add(new Integer(10));
assertThat(results.asSet()).isEqualTo(expectedResults);
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"42"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
assertThat(results.asSet()).isEqualTo(expectedResults);
for (int i = 0; i < 1000; i++) {
region.put(String.valueOf(i), new Integer(i));
}
q = qs.newQuery("SELECT e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
expectedResults = new HashSet();
expectedResults.add(new Integer(5));
expectedResults.add(new Integer(6));
expectedResults.add(new Integer(10));
expectedResults.add(new Integer(45));
assertThat(results.asSet()).isEqualTo(expectedResults);
q = qs.newQuery("SELECT e.key, e.value FROM /pos.entrySet e WHERE e.key IN $1");
keys = new Object[] {"5", "6", "10", "45"};
results = (SelectResults) q.execute(new Object[] {keys});
assertThat(results).hasSize(4);
}
/**
* Tests optimization of compiled in where we no longer evaluate on every iteration The set is
* saved off into the query context and reused Each query should have it's own query context
*/
@Test
public void testCacheEvalCollnWithIn() throws Exception {
Cache cache = CacheUtils.getCache();
AttributesFactory attributesFactory = new AttributesFactory();
RegionAttributes regionAttributes = attributesFactory.create();
QueryService qs = cache.getQueryService();
Region customersRegion = cache.createRegionFactory(regionAttributes).create("customers");
Region receiptsRegion = cache.createRegionFactory(regionAttributes).create("receipts");
qs.createIndex("receiptsByProduct", "i.productId", "/receipts r, r.items i");
qs.createIndex("receiptsByCustomer", "r.productId", "/receipts r");
qs.createIndex("customersByProfile", "c.profile", "/customers c");
int numReceiptsPerCustomer = 10;
for (int i = 0; i < 1000; i++) {
customersRegion.put(i, new Customer(i, i % 2 == 0 ? "PremiumIndividual" : "AverageJoe"));
for (int j = 0; j < numReceiptsPerCustomer; j++) {
int receiptId = i * numReceiptsPerCustomer + j;
receiptsRegion.put(receiptId, new Receipt(receiptId, i));
}
}
Query q = qs.newQuery(
"<trace>select r from /receipts r, r.items i where i.productId = 8 and r.customerId in (select c.id from /customers c where c.profile = 'PremiumIndividual')");
SelectResults results = (SelectResults) q.execute();
assertThat(results).hasSize(500);
for (int i = 1000; i < 1100; i++) {
customersRegion.put(i, new Customer(i, i % 2 == 0 ? "PremiumIndividual" : "AverageJoe"));
for (int j = 0; j < numReceiptsPerCustomer; j++) {
int receiptId = i * numReceiptsPerCustomer + j;
receiptsRegion.put(receiptId, new Receipt(receiptId, i));
}
}
results = (SelectResults) q.execute();
assertThat(results).hasSize(550);
}
/**
* Tests optimization of compiled in where we no longer evaluate on every iteration The set is
* saved off into the query context and reused Each query should have it's own query context
*/
@Test
public void testCacheEvalCollnWithInWithMultipleNestedIn() throws Exception {
Cache cache = CacheUtils.getCache();
AttributesFactory attributesFactory = new AttributesFactory();
RegionAttributes regionAttributes = attributesFactory.create();
QueryService qs = cache.getQueryService();
Region customersRegion = cache.createRegionFactory(regionAttributes).create("customers");
Region receiptsRegion = cache.createRegionFactory(regionAttributes).create("receipts");
qs.createIndex("receiptsByProduct", "i.productId", "/receipts r, r.items i");
qs.createIndex("receiptsByCustomer", "r.productId", "/receipts r");
qs.createIndex("customersByProfile", "c.profile", "/customers c");
int numReceiptsPerCustomer = 10;
for (int i = 0; i < 1000; i++) {
customersRegion.put(i, new Customer(i, i % 2 == 0 ? "PremiumIndividual" : "AverageJoe"));
for (int j = 0; j < numReceiptsPerCustomer; j++) {
int receiptId = i * numReceiptsPerCustomer + j;
receiptsRegion.put(receiptId, new Receipt(receiptId, i));
}
}
Query q = qs.newQuery(
"<trace>select r from /receipts r, r.items i where i.productId = 8 and r.customerId in (select c.id from /customers c where c.id in (select d.id from /customers d where d.profile='PremiumIndividual'))");
SelectResults results = (SelectResults) q.execute();
assertThat(results).hasSize(500);
for (int i = 1000; i < 1100; i++) {
customersRegion.put(i, new Customer(i, i % 2 == 0 ? "PremiumIndividual" : "AverageJoe"));
for (int j = 0; j < numReceiptsPerCustomer; j++) {
int receiptId = i * numReceiptsPerCustomer + j;
receiptsRegion.put(receiptId, new Receipt(receiptId, i));
}
}
results = (SelectResults) q.execute();
assertThat(results).hasSize(550);
}
public static class Customer implements Serializable {
public int id;
public String profile;
public Customer(int id, String profile) {
this.id = id;
this.profile = profile;
}
public int getId() {
return id;
}
public String getProfile() {
return profile;
}
}
public static class Receipt implements Serializable {
public int customerId;
public Item[] items;
public Receipt(int receiptId, int customerId) {
this.customerId = customerId;
items = new Item[] {new Item(receiptId % 10)};
}
public int getCustomerId() {
return customerId;
}
public Item[] getItems() {
return items;
}
}
public static class Item implements Serializable {
public int productId;
public Item(int productId) {
this.productId = productId;
}
public int getProductId() {
return productId;
}
}
}