blob: 69c58110d1e654d3465022d2caaa0e30f95a803c [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.internal.index;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
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.PartitionAttributesFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.query.CacheUtils;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.IndexType;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.cache.query.Struct;
import org.apache.geode.cache.query.data.Portfolio;
import org.apache.geode.cache.query.functional.StructSetOrResultsSet;
import org.apache.geode.cache.query.internal.QueryObserverAdapter;
import org.apache.geode.cache.query.internal.QueryObserverHolder;
import org.apache.geode.cache.query.internal.index.IndexManager.TestHook;
import org.apache.geode.internal.cache.LocalRegion;
import org.apache.geode.test.junit.categories.OQLIndexTest;
@Category({OQLIndexTest.class})
public class IndexUseJUnitTest {
private Region region;
private QueryService qs;
@Before
public void setUp() throws Exception {
CacheUtils.startCache();
region = CacheUtils.createRegion("pos", Portfolio.class);
region.put("0", new Portfolio(0));
region.put("1", new Portfolio(1));
region.put("2", new Portfolio(2));
region.put("3", new Portfolio(3));
qs = CacheUtils.getQueryService();
qs.createIndex("statusIndex", IndexType.FUNCTIONAL, "status", "/pos");
qs.createIndex("idIndex", IndexType.FUNCTIONAL, "ID", "/pos");
qs.createIndex("secIdIndex", IndexType.FUNCTIONAL, "P1.secId", "/pos");
qs.createIndex("secIdIndex2", IndexType.FUNCTIONAL, "P2.secId", "/pos");
qs.createIndex("p1secindex", "p.position1.secId", " /pos p ");
}
@After
public void tearDown() throws Exception {
CacheUtils.closeCache();
IndexManager indexManager = ((LocalRegion) region).getIndexManager();
if (indexManager != null) {
indexManager.destroy();
}
IndexManager.TEST_RANGEINDEX_ONLY = false;
RangeIndex.setTestHook(null);
CompactRangeIndex.setTestHook(null);
}
@Test
public void testIndexUseSingleCondition() throws Exception {
String testData[][] = {{"status", "'active'"}, {"ID", "2"}, {"P1.secId", "'IBM'"},};
String operators[] = {"=", "<>", "!=", "<", "<=", ">", ">="};
for (int i = 0; i < operators.length; i++) {
String operator = operators[i];
for (int j = 0; j < testData.length; j++) {
Query q = qs.newQuery("SELECT DISTINCT * FROM /pos where " + testData[j][0] + " " + operator
+ " " + testData[j][1]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
q.execute();
if (!observer.isIndexesUsed) {
fail("Index not used for operator '" + operator + "'");
}
}
}
}
@Test
public void testIndexUseMultipleConditions() throws Exception {
String testData[][] = {{"P1.secType = 'a'", "0"}, {"status = 'active' AND ID = 2", "1"},
{"status = 'active' AND ID = 2 AND P1.secId = 'IBM'", "1"},
{"status = 'active' OR ID = 2", "2"},
{"status = 'active' OR ID = 2 OR P1.secId = 'IBM'", "3"},
{"status = 'active' AND ID = 2 OR P1.secId = 'IBM'", "2"},
{"status = 'active' AND ( ID = 2 OR P1.secId = 'IBM')", "1"},
{"status = 'active' OR ID = 2 AND P1.secId = 'IBM'", "2"},
{"(status = 'active' OR ID = 2) AND P1.secId = 'IBM'", "1"},
{"NOT (status = 'active') AND ID = 2", "1"}, {"status = 'active' AND NOT( ID = 2 )", "1"},
{"NOT (status = 'active') OR ID = 2", "2"}, {"status = 'active' OR NOT( ID = 2 )", "2"},
{"status = 'active' AND P1.secType = 'a'", "1"},
{"status = 'active' OR P1.secType = 'a'", "0"},
{"status = 'active' AND ID =1 AND P1.secType = 'a'", "1"},
{"status = 'active' AND ID = 1 OR P1.secType = 'a'", "0"},
{"status = 'active' OR ID = 1 AND P1.secType = 'a'", "2"}, {"P2.secId = null", "1"},
{"IS_UNDEFINED(P2.secId)", "1"}, {"IS_DEFINED(P2.secId)", "1"},
{"P2.secId = UNDEFINED", "0"},};
for (int j = 0; j < testData.length; j++) {
Query q = qs.newQuery("SELECT DISTINCT * FROM /pos where " + testData[j][0]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
q.execute();
if (observer.indexesUsed.size() != Integer.parseInt(testData[j][1])) {
fail("Wrong Index use for " + testData[j][0] + "\n Indexes used " + observer.indexesUsed);
}
}
}
/**
* Test to check if Region object is passed as bind argument, the index utilization occurs or not
*/
@Test
public void testBug36421_part1() throws Exception {
String testData[][] = {{"status", "'active'"},};
String operators[] = {"="};
for (int i = 0; i < operators.length; i++) {
String operator = operators[i];
for (int j = 0; j < testData.length; j++) {
Query q = qs.newQuery("SELECT DISTINCT * FROM $1 where " + testData[j][0] + " " + operator
+ " " + testData[j][1]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
q.execute(new Object[] {CacheUtils.getRegion("/pos")});
if (!observer.isIndexesUsed) {
fail("Index not used for operator '" + operator + "'");
}
}
}
}
/**
* Test to check if Region short cut method is used for querying, the index utilization occurs or
* not
*/
@Test
public void testBug36421_part2() throws Exception {
String testData[][] = {{"status", "'active'"},};
String operators[] = {"="};
for (int i = 0; i < operators.length; i++) {
String operator = operators[i];
for (int j = 0; j < testData.length; j++) {
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
CacheUtils.getRegion("/pos").query(testData[j][0] + " " + operator + " " + testData[j][1]);
if (!observer.isIndexesUsed) {
fail("Index not used for operator '" + operator + "'");
}
}
}
}
/**
* Test to check if a parametrized query when using different bind arguments of Region uses the
* index correctly
*/
@Test
public void testBug36421_part3() throws Exception {
Query q = qs.newQuery("SELECT DISTINCT * FROM $1 z where z.status = 'active'");
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
q.execute(new Object[] {CacheUtils.getRegion("/pos")});
if (!observer.isIndexesUsed) {
fail("Index not uesd for operator '='");
}
assertTrue(observer.indexesUsed.get(0).equals("statusIndex"));
region = CacheUtils.createRegion("pos1", Portfolio.class);
region.put("0", new Portfolio(0));
region.put("1", new Portfolio(1));
region.put("2", new Portfolio(2));
region.put("3", new Portfolio(3));
qs.createIndex("statusIndex1", IndexType.FUNCTIONAL, "pf1.status", "/pos1 pf1");
region.put("4", new Portfolio(4));
observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
q.execute(new Object[] {CacheUtils.getRegion("/pos1")});
if (!observer.isIndexesUsed) {
fail("Index not used for operator'='");
}
assertTrue(observer.indexesUsed.get(0).equals("statusIndex1"));
}
/**
* Test to check if Region short cut method is used for querying, the Primary key index
* utilization occurs or not
*/
@Test
public void testBug36421_part4() throws Exception {
qs.createIndex("pkIndex", IndexType.PRIMARY_KEY, "pk", "/pos");
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults rs = CacheUtils.getRegion("/pos").query("pk = '2'");
if (!observer.isIndexesUsed) {
fail("Index not uesd for operator '='");
}
assertTrue(rs.size() == 1);
assertTrue(((Portfolio) rs.iterator().next()).pkid.equals("2"));
assertTrue(observer.indexesUsed.get(0).equals("pkIndex"));
CacheUtils.getRegion("/pos").put("7", new Portfolio(7));
observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
rs = CacheUtils.getRegion("/pos").query("pk = '7'");
if (!observer.isIndexesUsed) {
fail("Index not used for operator '='");
}
assertTrue(rs.size() == 1);
assertTrue(((Portfolio) rs.iterator().next()).pkid.equals("7"));
assertTrue(observer.indexesUsed.get(0).equals("pkIndex"));
}
@Test
public void testMapIndexUsageAllKeys() throws Exception {
IndexManager.TEST_RANGEINDEX_ONLY = true;
evaluateMapTypeIndexUsageAllKeys();
}
private void evaluateMapTypeIndexUsageAllKeys() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.maap.put("key1", j * 1);
mkid.maap.put("key2", j * 2);
mkid.maap.put("key3", j * 3);
}
testRgn.put(ID, mkid);
}
String queries[] = {"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 16"
/* "SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap.get('key2') >= 16" , */
};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap.get('key2') >= 16"};
Object r[][] = new Object[queries.length][2];
qs = CacheUtils.getQueryService();
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "objs.maap[*]", "/testRgn objs");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT used");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
// Test queries index not used
for (int i = 0; i < queriesIndexNotUsed.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queriesIndexNotUsed[i]);
CacheUtils.getLogger().info("Executing query: " + queriesIndexNotUsed[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
CacheUtils.log("Executing query: " + queriesIndexNotUsed[i] + " with index created");
q.execute();
assertFalse(observer.isIndexesUsed);
Iterator itr = observer.indexesUsed.iterator();
assertFalse(itr.hasNext());
}
}
@Test
public void testCompactMapIndexUsageWithIndexOnSingleKey() throws Exception {
String queries[] = {"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap.get('key2') >= 3"};
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.addKeyValue("key1", j * 1);
mkid.addKeyValue("key2", j * 2);
mkid.addKeyValue("key3", j * 3);
}
testRgn.put(ID, mkid);
}
evaluateMapTypeIndexUsage("objs.maap['key2']", "/testRgn objs", queries, queriesIndexNotUsed,
CompactRangeIndex.class);
String query = "SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.liist[0] >= 2";
SelectResults withoutIndex, withIndex;
Query q = CacheUtils.getQueryService().newQuery(query);
CacheUtils.getLogger().info("Executing query: " + query);
withoutIndex = (SelectResults) q.execute();
CacheUtils.log("Executed query: " + query);
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "objs.liist[0]", "/testRgn objs");
assertTrue(i2 instanceof CompactRangeIndex);
CacheUtils.getLogger().info("Executing query: " + query);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
withIndex = (SelectResults) q.execute();
CacheUtils.log("Executing query: " + query + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT used");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index2");
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(new Object[][] {{withoutIndex, withIndex}}, 1,
queries);
}
@Test
public void testCompactMapIndexUsageWithIndexOnMultipleKeys() throws Exception {
String queries[] = {"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key3'] >= 3"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap.get('key2') >= 16",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key4'] >= 16",};
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.addKeyValue("key1", j * 1);
mkid.addKeyValue("key2", j * 2);
mkid.addKeyValue("key3", j * 3);
}
testRgn.put(ID, mkid);
}
evaluateMapTypeIndexUsage("objs.maap['key2','key3']", "/testRgn objs", queries,
queriesIndexNotUsed, CompactMapRangeIndex.class);
}
@Test
public void testMapIndexUsageWithIndexOnMultipleKeys() throws Exception {
IndexManager.TEST_RANGEINDEX_ONLY = true;
String queries[] = {"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key3'] >= 3"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap.get('key2') >= 16",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key4'] >= 16",};
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.addKeyValue("key1", j * 1);
mkid.addKeyValue("key2", j * 2);
mkid.addKeyValue("key3", j * 3);
}
testRgn.put(ID, mkid);
}
evaluateMapTypeIndexUsage("objs.maap['key2','key3']", "/testRgn objs", queries,
queriesIndexNotUsed, MapRangeIndex.class);
}
private void evaluateMapTypeIndexUsage(String indexExpression, String fromClause,
String[] queries, String[] queriesIndexNotUsed, Class expectedIndexClass) throws Exception {
QueryService qs = CacheUtils.getQueryService();
Object r[][] = new Object[queries.length][2];
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, indexExpression, fromClause);
assertTrue(i1.getClass().equals(expectedIndexClass));
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT used");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
// Test queries index not used
for (int i = 0; i < queriesIndexNotUsed.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queriesIndexNotUsed[i]);
CacheUtils.getLogger().info("Executing query: " + queriesIndexNotUsed[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
CacheUtils.log("Executing query: " + queriesIndexNotUsed[i] + " with index created");
q.execute();
assertFalse(observer.isIndexesUsed);
Iterator itr = observer.indexesUsed.iterator();
assertFalse(itr.hasNext());
}
}
@Test
public void testIndexUsageWithOrderBy() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int numObjects = 30;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (int i = 0; i < numObjects; i++) {
Portfolio p = new Portfolio(i);
p.pkid = ("" + (numObjects - i));
testRgn.put("" + i, p);
}
qs = CacheUtils.getQueryService();
String queries[] =
{"SELECT DISTINCT * FROM /testRgn p WHERE p.ID <= 10 order by p.pkid asc limit 1",
"SELECT DISTINCT * FROM /testRgn p WHERE p.ID <= 10 order by p.pkid desc limit 1",};
Object r[][] = new Object[queries.length][2];
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
// verify individual result
SelectResults sr = (SelectResults) q.execute();
List results = sr.asList();
for (int rows = 0; rows < results.size(); rows++) {
Portfolio p = (Portfolio) results.get(0);
CacheUtils.getLogger().info("p: " + p);
if (i == 0) {
assertEquals(p.getID(), 10);
assertEquals(p.pkid, "" + (numObjects - 10));
} else if (i == 1) {
assertEquals(p.getID(), 0);
assertEquals(p.pkid, "" + numObjects);
}
}
r[i][0] = sr;
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.ID", "/testRgn p");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults sr = (SelectResults) q.execute();
List results = sr.asList();
for (int rows = 0; rows < results.size(); rows++) {
Portfolio p = (Portfolio) results.get(0);
CacheUtils.getLogger().info("index p: " + p);
if (i == 0) {
assertEquals(p.getID(), 10);
assertEquals(p.pkid, "" + (numObjects - 10));
} else if (i == 1) {
assertEquals(p.getID(), 0);
assertEquals(p.pkid, "" + numObjects);
}
}
r[i][1] = sr;
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
}
@Test
public void testIndexUsageWithOrderBy3() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int numObjects = 30;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (int i = 0; i < numObjects; i++) {
Portfolio p = new Portfolio(i);
p.pkid = ("" + (numObjects - i));
testRgn.put("" + i, p);
}
qs = CacheUtils.getQueryService();
String queries[] =
{"SELECT DISTINCT * FROM /testRgn p WHERE p.ID <= 10 order by ID asc limit 1",
"SELECT DISTINCT * FROM /testRgn p WHERE p.ID <= 10 order by p.ID desc limit 1",};
Object r[][] = new Object[queries.length][2];
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.ID", "/testRgn p");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults sr = (SelectResults) q.execute();
List results = sr.asList();
for (int rows = 0; rows < results.size(); rows++) {
Portfolio p = (Portfolio) results.get(0);
CacheUtils.getLogger().info("index p: " + p);
if (i == 0) {
assertEquals(p.getID(), 0);
} else if (i == 1) {
assertEquals(p.getID(), 10);
}
}
r[i][1] = sr;
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
}
@Test
public void testIndexUsageWithOrderBy2() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int numObjects = 30;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (int i = 0; i < numObjects; i++) {
Portfolio p = new Portfolio(i % 2);
p.createTime = (numObjects - i);
testRgn.put("" + i, p);
}
qs = CacheUtils.getQueryService();
String queries[] = {
"SELECT DISTINCT p.key, p.value FROM /testRgn.entrySet p WHERE p.value.ID <= 10 order by p.value.createTime asc limit 1",
"SELECT DISTINCT p.key, p.value FROM /testRgn.entrySet p WHERE p.value.ID <= 10 order by p.value.createTime desc limit 1",};
Object r[][] = new Object[queries.length][2];
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
// verify individual result
SelectResults sr = (SelectResults) q.execute();
List results = sr.asList();
for (int rows = 0; rows < results.size(); rows++) {
Struct s = (Struct) results.get(0);
Portfolio p = (Portfolio) s.get("value");
CacheUtils.getLogger().info("p: " + p);
if (i == 0) {
assertEquals(p.createTime, 1);
} else if (i == 1) {
assertEquals(p.createTime, numObjects);
}
}
r[i][0] = sr;
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.value.ID", "/testRgn.entrySet p");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults sr = (SelectResults) q.execute();
List results = sr.asList();
for (int rows = 0; rows < results.size(); rows++) {
Struct s = (Struct) results.get(0);
Portfolio p = (Portfolio) s.get("value");
CacheUtils.getLogger().info("index p: " + p);
if (i == 0) {
assertEquals(p.createTime, 1);
} else if (i == 1) {
assertEquals(p.createTime, numObjects);
}
}
r[i][1] = sr;
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
}
@Test
public void testIncorrectIndexOperatorSyntax() {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.maap.put("key1", j * 1);
mkid.maap.put("key2", j * 2);
mkid.maap.put("key3", j * 3);
}
testRgn.put(ID, mkid);
}
qs = CacheUtils.getQueryService();
try {
Query q = CacheUtils.getQueryService()
.newQuery("SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap[*] >= 3");
fail("Should have thrown exception");
} catch (QueryInvalidException expected) {
// ok
}
try {
Query q = CacheUtils.getQueryService()
.newQuery("SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key1','key2'] >= 3");
fail("Should have thrown exception");
} catch (QueryInvalidException expected) {
// ok
}
}
@Test
public void testRangeGroupingBehaviourOfCompactMapIndex() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.addKeyValue("key1", j * 1);
mkid.addKeyValue("key2", j * 2);
mkid.addKeyValue("key3", j * 3);
}
testRgn.put(ID, mkid);
}
String queries[] = {
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key2'] <=18",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key3'] >= 3 and itr1.maap['key3'] >= 13 ",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key3'] >= 13 ",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key3'] < 18 "};
Object r[][] = new Object[queries.length][2];
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 =
qs.createIndex("Index1", IndexType.FUNCTIONAL, "objs.maap['key2','key3']", "/testRgn objs");
assertTrue(i1 instanceof CompactMapRangeIndex);
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
}
@Test
public void testRangeGroupingBehaviourOfMapIndex() throws Exception {
IndexManager.TEST_RANGEINDEX_ONLY = true;
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
// Add some test data now
// Add 5 main objects. 1 will contain key1, 2 will contain key1 & key2
// and so on
for (; ID <= 30; ++ID) {
MapKeyIndexData mkid = new MapKeyIndexData(ID);
for (int j = 1; j <= ID; ++j) {
mkid.addKeyValue("key1", j * 1);
mkid.addKeyValue("key2", j * 2);
mkid.addKeyValue("key3", j * 3);
}
testRgn.put(ID, mkid);
}
qs = CacheUtils.getQueryService();
String queries[] = {
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key2'] <=18",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key3'] >= 3 and itr1.maap['key3'] >= 13 ",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key3'] >= 13 ",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 and itr1.maap['key3'] < 18 "};
Object r[][] = new Object[queries.length][2];
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 =
qs.createIndex("Index1", IndexType.FUNCTIONAL, "objs.maap['key2','key3']", "/testRgn objs");
assertTrue(i1 instanceof MapRangeIndex);
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index1");
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
}
@Test
public void testMapIndexUsableQueryOnEmptyRegion() throws Exception {
IndexManager.TEST_RANGEINDEX_ONLY = true;
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
Index i1 =
qs.createIndex("Index1", IndexType.FUNCTIONAL, "objs.maap['key2','key3']", "/testRgn objs");
qs = CacheUtils.getQueryService();
// Execute Queries without Indexes
Query q = CacheUtils.getQueryService()
.newQuery("SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.maap['key2'] >= 3 ");
SelectResults sr = (SelectResults) q.execute();
assertTrue(sr.isEmpty());
}
@Test
public void testSizeEstimateLTInRangeIndexForNullMap() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
// Create indexes
Index i1 =
qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.status", "/testRgn p, p.positions");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "p.ID", "/testRgn p, p.positions");
// put values
testRgn.put(0, new Portfolio(0));
testRgn.put(1, new Portfolio(1));
// Set TestHook in RangeIndex
TestHook hook = new RangeIndexTestHook();
RangeIndex.setTestHook(hook);
// Execute Queries without Indexes
Query q = CacheUtils.getQueryService().newQuery(
"<trace> SELECT * FROM /testRgn p, p.positions where p.status = 'active' AND p.ID > 0 ");
// Following should throw NullPointerException.
SelectResults sr = (SelectResults) q.execute();
assertTrue("RangeIndexTestHook was not hooked for spot 2",
((RangeIndexTestHook) hook).isHooked(2));
RangeIndex.setTestHook(null);
}
@Test
public void testSizeEstimateGTInRangeIndexForNullMap() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
// Create indexes
Index i1 =
qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.status", "/testRgn p, p.positions");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "p.ID", "/testRgn p, p.positions");
// put values
testRgn.put(0, new Portfolio(0));
testRgn.put(1, new Portfolio(1));
// Set TestHook in RangeIndex
TestHook hook = new RangeIndexTestHook();
RangeIndex.setTestHook(hook);
// Execute Queries without Indexes
Query q = CacheUtils.getQueryService().newQuery(
"<trace> SELECT * FROM /testRgn p, p.positions where p.status = 'active' AND p.ID < 0 ");
// Following should throw NullPointerException.
SelectResults sr = (SelectResults) q.execute();
assertTrue("RangeIndexTestHook was not hooked for spot 1",
((RangeIndexTestHook) hook).isHooked(1));
RangeIndex.setTestHook(null);
}
@Test
public void testSizeEstimateLTInCompactRangeIndexForNullMap() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
// Create indexes
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.status", "/testRgn p");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "p.ID", "/testRgn p");
// put values
testRgn.put(0, new Portfolio(0));
testRgn.put(1, new Portfolio(1));
// Set TestHook in RangeIndex
TestHook hook = new RangeIndexTestHook();
CompactRangeIndex.setTestHook(hook);
// Execute Queries without Indexes
Query q = CacheUtils.getQueryService()
.newQuery("<trace> SELECT * FROM /testRgn p where p.status = 'active' AND p.ID > 0 ");
// Following should throw NullPointerException.
SelectResults sr = (SelectResults) q.execute();
assertTrue("RangeIndexTestHook was not hooked for spot 2",
((RangeIndexTestHook) hook).isHooked(2));
CompactRangeIndex.setTestHook(null);
}
@Test
public void testSizeEstimateGTInCompactRangeIndexForNullMap() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
// Create indexes
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "p.status", "/testRgn p");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "p.ID", "/testRgn p");
// put values
testRgn.put(0, new Portfolio(0));
testRgn.put(1, new Portfolio(1));
// Set TestHook in RangeIndex
TestHook hook = new RangeIndexTestHook();
CompactRangeIndex.setTestHook(hook);
// Execute Queries without Indexes
Query q = CacheUtils.getQueryService()
.newQuery("<trace> SELECT * FROM /testRgn p where p.status = 'active' AND p.ID < 0 ");
// Following should throw NullPointerException.
SelectResults sr = (SelectResults) q.execute();
assertTrue("RangeIndexTestHook was not hooked for spot 1",
((RangeIndexTestHook) hook).isHooked(1));
CompactRangeIndex.setTestHook(null);
}
@Test
public void testCompactMapIndexUsageAllKeysWithVariousValueTypes() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
for (; ID <= 30; ++ID) {
TestObject object = new TestObject(ID);
testRgn.put(ID, object);
}
String queries[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['string'] = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['double'] > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['integer'] > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['long'] > 1L"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('string') = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('double') > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('integer') > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('long') > 1L"};
evaluateMapTypeIndexUsage("itr1.testFields[*]", "/testRgn itr1", queries, queriesIndexNotUsed,
CompactMapRangeIndex.class);
}
@Test
public void testCompactMapIndexUsageAllKeysOneIndex() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
for (; ID <= 30; ++ID) {
TestObject object = new TestObject(ID);
testRgn.put(ID, object);
}
String queries[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['string'] = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['double'] > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['integer'] > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['long'] > 1L"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('string') = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('double') > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('integer') > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('long') > 1L"};
evaluateMapTypeIndexUsage("itr1.testFields['string','double','integer','long']",
"/testRgn itr1", queries, queriesIndexNotUsed, CompactMapRangeIndex.class);
}
@Test
public void testCompactMapIndexUsageManyGetKeysWithVariousValueTypes() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
for (; ID <= 30; ++ID) {
TestObject object = new TestObject(ID);
testRgn.put(ID, object);
}
String queries[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('string') = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('double') > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('integer') > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('long') > 1L"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['string'] = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['double'] > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['integer'] > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['long'] > 1L"};
Object r[][] = new Object[queries.length][2];
qs = CacheUtils.getQueryService();
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "itr1.testFields.get('string')",
"/testRgn itr1");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "itr1.testFields.get('double')",
"/testRgn itr1");
Index i3 = qs.createIndex("Index3", IndexType.FUNCTIONAL, "itr1.testFields.get('integer')",
"/testRgn itr1");
Index i4 = qs.createIndex("Index4", IndexType.FUNCTIONAL, "itr1.testFields.get('long')",
"/testRgn itr1");
Index i5 = qs.createIndex("Index5", IndexType.FUNCTIONAL, "itr1.testFields.get('complex')",
"/testRgn itr1");
assertTrue(i1 instanceof CompactRangeIndex);
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index" + (i + 1));
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
// Test queries index not used
for (int i = 0; i < queriesIndexNotUsed.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queriesIndexNotUsed[i]);
CacheUtils.getLogger().info("Executing query: " + queriesIndexNotUsed[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
CacheUtils.log("Executing query: " + queriesIndexNotUsed[i] + " with index created");
q.execute();
assertFalse(observer.isIndexesUsed);
Iterator itr = observer.indexesUsed.iterator();
assertFalse(itr.hasNext());
}
}
@Test
public void testCompactMapIndexUsageManyKeysWithVariousValueTypes() throws Exception {
QueryService qs = CacheUtils.getQueryService();
LocalRegion testRgn = (LocalRegion) CacheUtils.createRegion("testRgn", null);
int ID = 1;
for (; ID <= 30; ++ID) {
TestObject object = new TestObject(ID);
testRgn.put(ID, object);
}
String queries[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['string'] = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['double'] > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['integer'] > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields['long'] > 1L"};
String queriesIndexNotUsed[] =
{"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('string') = '1'",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('double') > 1D",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('integer') > 1",
"SELECT DISTINCT * FROM /testRgn itr1 WHERE itr1.testFields.get('long') > 1L"};
Object r[][] = new Object[queries.length][2];
qs = CacheUtils.getQueryService();
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
CacheUtils.log("Executed query: " + queries[i]);
}
Index i1 = qs.createIndex("Index1", IndexType.FUNCTIONAL, "itr1.testFields['string']",
"/testRgn itr1");
Index i2 = qs.createIndex("Index2", IndexType.FUNCTIONAL, "itr1.testFields['double']",
"/testRgn itr1");
Index i3 = qs.createIndex("Index3", IndexType.FUNCTIONAL, "itr1.testFields['integer']",
"/testRgn itr1");
Index i4 =
qs.createIndex("Index4", IndexType.FUNCTIONAL, "itr1.testFields['long']", "/testRgn itr1");
Index i5 = qs.createIndex("Index5", IndexType.FUNCTIONAL, "itr1.testFields['complex']",
"/testRgn itr1");
assertTrue(i1 instanceof CompactRangeIndex);
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
r[i][1] = q.execute();
CacheUtils.log("Executing query: " + queries[i] + " with index created");
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
Iterator itr = observer.indexesUsed.iterator();
assertTrue(itr.hasNext());
String temp = itr.next().toString();
assertEquals(temp, "Index" + (i + 1));
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, queries);
// Test queries index not used
for (int i = 0; i < queriesIndexNotUsed.length; i++) {
Query q = CacheUtils.getQueryService().newQuery(queriesIndexNotUsed[i]);
CacheUtils.getLogger().info("Executing query: " + queriesIndexNotUsed[i]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
CacheUtils.log("Executing query: " + queriesIndexNotUsed[i] + " with index created");
q.execute();
assertFalse(observer.isIndexesUsed);
Iterator itr = observer.indexesUsed.iterator();
assertFalse(itr.hasNext());
}
}
@Test
public void queryWithOrClauseShouldReturnCorrectResultSet() throws Exception {
String query =
"SELECT DISTINCT p1.ID FROM /pos p1 where p1.ID IN SET (0,1) OR p1.status = 'active'";
Query q = qs.newQuery(query);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults sr = (SelectResults) q.execute();
if (!observer.isIndexesUsed) {
fail("Index should have been used for query '" + q.getQueryString() + "'");
}
assertEquals(sr.size(), 3);
qs.removeIndexes();
}
@Test
public void testIndexUseSelfJoin() throws Exception {
String[] queries = {"SELECT DISTINCT * FROM /pos p1, /pos p2 where p1.status = p2.status",
"SELECT DISTINCT * FROM /pos p1, /pos p2 where p1.ID = p2.ID",
"SELECT DISTINCT * FROM /pos p1, /pos p2 where p1.P1.secId = p2.P1.secId",
"SELECT DISTINCT * FROM /pos p1, /pos p2 where p1.status = p2.status and p1.status = 'active'",
"SELECT DISTINCT * FROM /pos p1, /pos p2 where p1.ID = p2.ID and p1.ID < 2",
"SELECT * FROM /pos p1, /pos p2 where p1.ID = p2.ID",
"SELECT * FROM /pos p1, /pos p2 where p1.P1.secId = p2.P1.secId",
"SELECT * FROM /pos p1, /pos p2 where p1.status = p2.status and p1.status = 'active'",
"SELECT * FROM /pos p1, /pos p2 where p1.ID = p2.ID and p1.ID < 2"};
SelectResults[][] sr = new SelectResults[queries.length][2];
for (int j = 0; j < queries.length; j++) {
Query q = qs.newQuery(queries[j]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
sr[j][0] = (SelectResults) q.execute();
if (sr[j][0].size() == 0) {
fail("Query " + q.getQueryString() + " should have returned results");
}
if (!observer.isIndexesUsed) {
fail("Index should have been used for query '" + q.getQueryString() + "'");
}
}
qs.removeIndexes();
for (int j = 0; j < queries.length; j++) {
Query q = qs.newQuery(queries[j]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
sr[j][1] = (SelectResults) q.execute();
if (sr[j][1].size() == 0) {
fail("Query " + q.getQueryString() + " should have returned results");
}
if (observer.isIndexesUsed) {
fail("Index should not be used for query '" + q.getQueryString() + "'");
}
}
CacheUtils.compareResultsOfWithAndWithoutIndex(sr);
}
@Test
public void testIndexUseSelfJoinUsingOneRegion() throws Exception {
String[] queries = {"SELECT DISTINCT * FROM /pos p1 where p1.status = p1.status",
"SELECT DISTINCT * FROM /pos p1 where p1.ID = p1.ID",
"SELECT DISTINCT * FROM /pos p1 where p1.P1.secId = p1.P1.secId",
"SELECT DISTINCT * FROM /pos p1 where p1.status = p1.status and p1.status = 'active'",
"SELECT DISTINCT * FROM /pos p1 where p1.ID = p1.ID and p1.ID < 2",
"SELECT * FROM /pos p1 where p1.ID = p1.ID",
"SELECT * FROM /pos p1 where p1.P1.secId = p1.P1.secId",
"SELECT * FROM /pos p1 where p1.status = p1.status and p1.status = 'active'",
"SELECT * FROM /pos p1 where p1.ID = p1.ID and p1.ID < 2",
"SELECT DISTINCT * FROM /pos p1 WHERE p1.ID IN (SELECT DISTINCT p1.ID FROM /pos p1)",
"SELECT * FROM /pos p1 WHERE p1.ID IN (SELECT DISTINCT p1.ID FROM /pos p1)",
"SELECT DISTINCT * FROM /pos p1 WHERE p1.ID IN (SELECT DISTINCT p2.ID FROM /pos p2)",
"SELECT * FROM /pos p1 WHERE p1.ID IN (SELECT DISTINCT p2.ID FROM /pos p2)"};
SelectResults[][] sr = new SelectResults[queries.length][2];
for (int j = 0; j < queries.length; j++) {
Query q = qs.newQuery(queries[j]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
sr[j][0] = (SelectResults) q.execute();
if (sr[j][0].size() == 0) {
fail("Query " + q.getQueryString() + " should have returned results");
}
if (!observer.isIndexesUsed) {
fail("Index should have been used for query '" + q.getQueryString() + "'");
}
}
qs.removeIndexes();
for (int j = 0; j < queries.length; j++) {
Query q = qs.newQuery(queries[j]);
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
sr[j][1] = (SelectResults) q.execute();
if (sr[j][1].size() == 0) {
fail("Query " + q.getQueryString() + " should have returned results");
}
if (observer.isIndexesUsed) {
fail("Index should not be used for query '" + q.getQueryString() + "'");
}
}
CacheUtils.compareResultsOfWithAndWithoutIndex(sr);
}
@Test
public void testUndefinedResultsAreReturnedWhenANotEqualsQueryIsExecuted() throws Exception {
Portfolio p1 = new Portfolio(0);
p1.position1 = null;
region.put("0", p1);
Portfolio p2 = new Portfolio(2);
p2.position1 = null;
region.put("2", p2);
String query = "SELECT p.position1.secId FROM /pos p where p.position1.secId != 'MSFT' ";
SelectResults[][] sr = new SelectResults[1][2];
sr[0][0] = (SelectResults) qs.newQuery(query).execute();
qs.removeIndexes();
sr[0][1] = (SelectResults) qs.newQuery(query).execute();
if (!CacheUtils.compareResultsOfWithAndWithoutIndex(sr)) {
fail("Query results not same with and without index");
}
}
@Test
public void testIndexesRemainInUseAfterARebalance() throws Exception {
// Create partitioned region
PartitionAttributesFactory paf = new PartitionAttributesFactory();
AttributesFactory af = new AttributesFactory();
af.setPartitionAttributes(paf.create());
Region region =
CacheUtils.createRegion("testIndexesRemainInUseAfterARebalance", af.create(), false);
// Add index
PartitionedIndex index =
(PartitionedIndex) qs.createIndex("statusIndex", "status", region.getFullPath());
// Do puts
for (int i = 0; i < 200; i++) {
region.put(i, new Portfolio(i));
}
// Initialize query observer
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
// Create and run query
Query query = qs.newQuery("SELECT * FROM " + region.getFullPath() + " where status = 'active'");
query.execute();
// Verify index was used
assertTrue(observer.isIndexesUsed);
// Get the first index entry in the PartitionedIndex bucketIndexes and delete the index from it
// (to simulate what happens when a bucket is moved)
Map.Entry<Region, List<Index>> firstIndexEntry = index.getFirstBucketIndex();
assertTrue(!firstIndexEntry.getValue().isEmpty());
index.removeFromBucketIndexes(firstIndexEntry.getKey(),
firstIndexEntry.getValue().iterator().next());
// Verify the index was removed from the entry and the entry was removed from the bucket indexes
assertTrue(firstIndexEntry.getValue().isEmpty());
Map.Entry<Region, List<Index>> nextFirstIndexEntry = index.getFirstBucketIndex();
assertTrue(!nextFirstIndexEntry.getValue().isEmpty());
// Run query again
observer.reset();
query.execute();
// Verify index was still used
assertTrue(observer.isIndexesUsed);
}
@Test
public void testPKIndexUseWithPR() throws Exception {
evaluatePKIndexUsetest(RegionShortcut.PARTITION, "pkTest");
}
@Test
public void testPKIndexUseWithReplicate() throws Exception {
evaluatePKIndexUsetest(RegionShortcut.REPLICATE, "pkTest");
}
private void evaluatePKIndexUsetest(RegionShortcut regionShortcut, String regionName)
throws Exception {
Cache cache = CacheUtils.getCache();
Region r = cache.createRegionFactory(regionShortcut).create(regionName);
Map map0 = new HashMap();
Map map1 = new HashMap();
Map map2 = new HashMap();
r.put("A0", map0);
r.put("A1", map1);
r.put("A2", map2);
qs.createIndex("pkIndex", IndexType.PRIMARY_KEY, "p.pk", "/" + regionName + " p");
QueryObserverImpl observer = new QueryObserverImpl();
QueryObserverHolder.setInstance(observer);
SelectResults sr = (SelectResults) qs
.newQuery("select * from /" + regionName + " p where p.pk = 'A1'").execute();
assertEquals(1, sr.size());
if (!observer.isIndexesUsed) {
fail("Index not used for operator '='");
}
}
private static class QueryObserverImpl extends QueryObserverAdapter {
boolean isIndexesUsed = false;
ArrayList indexesUsed = new ArrayList();
@Override
public void beforeIndexLookup(Index index, int oper, Object key) {
indexesUsed.add(index.getName());
}
@Override
public void afterIndexLookup(Collection results) {
if (results != null) {
isIndexesUsed = true;
}
}
public void reset() {
isIndexesUsed = false;
indexesUsed.clear();
}
}
private static class RangeIndexTestHook implements TestHook {
int lastHook = -1;
@Override
public void hook(int spot) throws RuntimeException {
lastHook = spot;
if (spot == 1) { // LT size estimate
CacheUtils.getCache().getRegion("testRgn").clear();
} else if (spot == 2) { // GT size estimate
CacheUtils.getCache().getRegion("testRgn").clear();
}
}
public boolean isHooked(int spot) {
return spot == lastHook;
}
}
private static class MapKeyIndexData implements Serializable {
int id;
public Map maap = new HashMap();
public List liist = new ArrayList();
public MapKeyIndexData(int id) {
this.id = id;
}
public void addKeyValue(Object key, Object value) {
maap.put(key, value);
liist.add(value);
}
}
private static class TestObject implements Serializable {
public Map testFields = new HashMap();
TestObject(int i) {
testFields.put("string", "String Value" + i);
testFields.put("double", (double) i);
testFields.put("integer", i);
testFields.put("long", (long) i);
testFields.put("complex", new CompObject(i));
}
public Map getTestFields() {
return testFields;
}
}
private static class CompObject implements Comparable, Serializable {
int value;
CompObject(int i) {
value = i;
}
@Override
public int compareTo(Object o) {
if (o instanceof CompObject) {
CompObject other = (CompObject) o;
if (value > other.value) {
return 1;
} else if (value == other.value) {
return 0;
} else {
return -1;
}
}
throw new ClassCastException("Could not cast " + o.getClass().getName() + " to compObject");
}
}
}