blob: ebe7b5cacd338058214ac27877c4988afb280299 [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 org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.CacheUtils;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.IndexExistsException;
import org.apache.geode.cache.query.IndexInvalidException;
import org.apache.geode.cache.query.IndexNameConflictException;
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.RegionNotFoundException;
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.data.Position;
import org.apache.geode.cache.query.internal.QueryObserverHolder;
import org.apache.geode.cache.query.types.ObjectType;
import org.apache.geode.test.junit.categories.OQLQueryTest;
@Category({OQLQueryTest.class})
public class NonDistinctOrderByReplicatedJUnitTest extends NonDistinctOrderByTestImplementation {
@Override
public boolean assertIndexUsedOnQueryNode() {
return true;
}
@Override
public Region createRegion(String regionName, Class valueConstraint) {
Region r1 = CacheUtils.createRegion(regionName, valueConstraint);
return r1;
}
@Override
public Index createIndex(String indexName, IndexType indexType, String indexedExpression,
String fromClause) throws IndexInvalidException, IndexNameConflictException,
IndexExistsException, RegionNotFoundException, UnsupportedOperationException {
return CacheUtils.getQueryService().createIndex(indexName, indexType, indexedExpression,
fromClause);
}
@Override
public Index createIndex(String indexName, String indexedExpression, String regionPath)
throws IndexInvalidException, IndexNameConflictException, IndexExistsException,
RegionNotFoundException, UnsupportedOperationException {
return CacheUtils.getQueryService().createIndex(indexName, indexedExpression, regionPath);
}
@Test
public void testLimitAndOrderByApplicationOnPrimaryKeyIndexQuery() throws Exception {
String queries[] = {
// The PK index should be used but limit should not be applied as order
// by cannot be applied while data is fetched
// from index
"SELECT ID, description, createTime FROM /portfolio1 pf1 where pf1.ID != '10' order by ID desc limit 5 ",
"SELECT ID, description, createTime FROM /portfolio1 pf1 where pf1.ID != $1 order by ID "
};
Object r[][] = new Object[queries.length][2];
QueryService qs;
qs = CacheUtils.getQueryService();
Position.resetCounter();
// Create Regions
Region r1 = this.createRegion("portfolio1", Portfolio.class);
for (int i = 0; i < 50; i++) {
r1.put(i + "", new Portfolio(i));
}
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute(new Object[] {new Integer(10)});
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
// Create Indexes
qs.createIndex("PKIDIndexPf1", IndexType.PRIMARY_KEY, "ID", "/portfolio1");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
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(new Object[] {"10"});
int indexLimit = queries[i].indexOf("limit");
int limit = -1;
boolean limitQuery = indexLimit != -1;
if (limitQuery) {
limit = Integer.parseInt(queries[i].substring(indexLimit + 5).trim());
}
boolean orderByQuery = queries[i].indexOf("order by") != -1;
SelectResults rcw = (SelectResults) r[i][1];
if (orderByQuery) {
assertTrue(rcw.getCollectionType().isOrdered());
}
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
if (limitQuery) {
if (orderByQuery) {
assertFalse(observer.limitAppliedAtIndex);
} else {
assertTrue(observer.limitAppliedAtIndex);
}
} else {
assertFalse(observer.limitAppliedAtIndex);
}
Iterator itr = observer.indexesUsed.iterator();
while (itr.hasNext()) {
String indexUsed = itr.next().toString();
if (!(indexUsed).equals("PKIDIndexPf1")) {
fail("<PKIDIndexPf1> was expected but found " + indexUsed);
}
// assertIndexDetailsEquals("statusIndexPf1",itr.next().toString());
}
int indxs = observer.indexesUsed.size();
System.out.println("**************************************************Indexes Used :::::: "
+ indxs + " Index Name: " + observer.indexName);
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, true, queries);
}
@Test
public void testLimitApplicationOnPrimaryKeyIndex() throws Exception {
String queries[] = {
// The PK index should be used but limit should not be applied as order by
// cannot be applied while data is fetched
// from index
"SELECT ID, description, createTime FROM /portfolio1 pf1 where pf1.ID != $1 limit 10",};
Object r[][] = new Object[queries.length][2];
QueryService qs;
qs = CacheUtils.getQueryService();
Position.resetCounter();
// Create Regions
Region r1 = this.createRegion("portfolio1", Portfolio.class);
for (int i = 0; i < 50; i++) {
r1.put(i + "", new Portfolio(i));
}
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute(new Object[] {new Integer(10)});
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
// Create Indexes
qs.createIndex("PKIDIndexPf1", IndexType.PRIMARY_KEY, "ID", "/portfolio1");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
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(new Object[] {"10"});
int indexLimit = queries[i].indexOf("limit");
int limit = -1;
boolean limitQuery = indexLimit != -1;
if (limitQuery) {
limit = Integer.parseInt(queries[i].substring(indexLimit + 5).trim());
}
boolean orderByQuery = queries[i].indexOf("order by") != -1;
SelectResults rcw = (SelectResults) r[i][1];
if (orderByQuery) {
assertEquals("Ordered", rcw.getCollectionType().getSimpleClassName());
}
if (!observer.isIndexesUsed) {
fail("Index is NOT uesd");
}
int indexDistinct = queries[i].indexOf("distinct");
boolean distinctQuery = indexDistinct != -1;
if (limitQuery) {
if (orderByQuery) {
assertFalse(observer.limitAppliedAtIndex);
} else {
assertTrue(observer.limitAppliedAtIndex);
}
} else {
assertFalse(observer.limitAppliedAtIndex);
}
Iterator itr = observer.indexesUsed.iterator();
while (itr.hasNext()) {
String indexUsed = itr.next().toString();
if (!(indexUsed).equals("PKIDIndexPf1")) {
fail("<PKIDIndexPf1> was expected but found " + indexUsed);
}
// assertIndexDetailsEquals("statusIndexPf1",itr.next().toString());
}
int indxs = observer.indexesUsed.size();
System.out.println("**************************************************Indexes Used :::::: "
+ indxs + " Index Name: " + observer.indexName);
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
// Result set verification
Collection coll1 = null;
Collection coll2 = null;
Iterator itert1 = null;
Iterator itert2 = null;
ObjectType type1, type2;
type1 = ((SelectResults) r[0][0]).getCollectionType().getElementType();
type2 = ((SelectResults) r[0][1]).getCollectionType().getElementType();
if ((type1.getClass().getName()).equals(type2.getClass().getName())) {
CacheUtils.log("Both SelectResults are of the same Type i.e.--> "
+ ((SelectResults) r[0][0]).getCollectionType().getElementType());
} else {
CacheUtils
.log("Classes are : " + type1.getClass().getName() + " " + type2.getClass().getName());
fail("FAILED:Select result Type is different in both the cases." + "; failed query="
+ queries[0]);
}
if (((SelectResults) r[0][0]).size() == ((SelectResults) r[0][1]).size()) {
CacheUtils.log(
"Both SelectResults are of Same Size i.e. Size= " + ((SelectResults) r[0][1]).size());
} else {
fail("FAILED:SelectResults size is different in both the cases. Size1="
+ ((SelectResults) r[0][0]).size() + " Size2 = " + ((SelectResults) r[0][1]).size()
+ "; failed query=" + queries[0]);
}
coll2 = (((SelectResults) r[0][1]).asSet());
coll1 = (((SelectResults) r[0][0]).asSet());
itert1 = coll1.iterator();
itert2 = coll2.iterator();
while (itert1.hasNext()) {
Object[] values1 = ((Struct) itert1.next()).getFieldValues();
Object[] values2 = ((Struct) itert2.next()).getFieldValues();
assertEquals(values1.length, values2.length);
assertTrue((((Integer) values1[0]).intValue() != 10));
assertTrue((((Integer) values2[0]).intValue() != 10));
}
}
@Test
public void testNonDistinctOrderbyResultSetForReplicatedRegion() throws Exception {
final int numElements = 200;
CacheUtils.getCache();
Region region = this.createRegion("portfolios", Portfolio.class);
Short[] expectedArray = new Short[numElements - 1];
for (int i = 1; i < numElements; ++i) {
Portfolio pf = new Portfolio(i);
pf.shortID = (short) ((short) i / 5);
region.put("" + i, pf);
expectedArray[i - 1] = pf.shortID;
}
Arrays.sort(expectedArray, new Comparator<Short>() {
@Override
public int compare(Short o1, Short o2) {
return o1.shortValue() - o2.shortValue();
}
});
String query = "select pf.shortID from /portfolios pf order by pf.shortID";
QueryService qs = CacheUtils.getQueryService();
SelectResults sr = (SelectResults) qs.newQuery(query).execute();
Object[] results = sr.toArray();
assertTrue(Arrays.equals(expectedArray, results));
}
@Test
public void testOrderedResultsReplicatedRegion() throws Exception {
String queries[] = {
"select status as st from /portfolio1 where ID > 0 order by status",
"select p.status as st from /portfolio1 p where ID > 0 and status = 'inactive' order by p.status",
"select distinct p.position1.secId as st from /portfolio1 p where p.ID > 0 and p.position1.secId != 'IBM' order by p.position1.secId",
"select distinct key.status as st from /portfolio1 key where key.ID > 5 order by key.status",
"select distinct key.status as st from /portfolio1 key where key.status = 'inactive' order by key.status desc, key.ID"
};
Object r[][] = new Object[queries.length][2];
QueryService qs;
qs = CacheUtils.getQueryService();
Position.resetCounter();
// Create Regions
Region r1 = this.createRegion("portfolio1", Portfolio.class);
for (int i = 0; i < 200; i++) {
r1.put(i + "", new Portfolio(i));
}
// Execute Queries without Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
q = CacheUtils.getQueryService().newQuery(queries[i]);
CacheUtils.getLogger().info("Executing query: " + queries[i]);
r[i][0] = q.execute();
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
// Create Indexes
qs.createIndex("i1", IndexType.FUNCTIONAL, "p.status", "/portfolio1 p");
qs.createIndex("i2", IndexType.FUNCTIONAL, "p.ID", "/portfolio1 p");
qs.createIndex("i3", IndexType.FUNCTIONAL, "p.position1.secId", "/portfolio1 p");
// Execute Queries with Indexes
for (int i = 0; i < queries.length; i++) {
Query q = null;
try {
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();
} catch (Exception e) {
e.printStackTrace();
fail(q.getQueryString());
}
}
StructSetOrResultsSet ssOrrs = new StructSetOrResultsSet();
ssOrrs.CompareQueryResultsWithoutAndWithIndexes(r, queries.length, true, queries);
ssOrrs.compareExternallySortedQueriesWithOrderBy(queries, r);
}
}