/* * 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.IntegrationTest; /** * * */ @Category(IntegrationTest.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); } }