geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dschnei...@apache.org
Subject [40/57] [partial] incubator-geode git commit: Initial import of geode-1.0.0.0-SNAPSHOT-2. All the new sub-project directories (like jvsd) were not imported. A diff was done to confirm that this commit is exactly the same as the open directory the snapsho
Date Thu, 09 Jul 2015 17:02:58 GMT
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneIndex.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneIndex.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneIndex.java
new file mode 100644
index 0000000..9b08b05
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneIndex.java
@@ -0,0 +1,50 @@
+/*=========================================================================
+ * Copyright (c) 2002-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+
+
+/**
+ * An lucene index is built over the data stored in a GemFire Region.
+ * <p>
+ * An index is specified using a index name, field names, region name.
+ * <p>
+ * The index name and region name together uniquely identifies the lucene index.
+ * <p>
+ * 
+ * @author Xiaojian Zhou
+ * @since 8.5
+ */
+public interface LuceneIndex {
+
+  /**
+   * @return the index name of this index
+   */
+  public String getName();
+
+  /**
+   * @return the region name for this index
+   */
+  public String getRegionName();
+      
+  /**
+   * @return the indexed field names in a Set
+   */
+  public String[] getFieldNames();
+  
+  /**
+   * @return the field to analyzer map
+   */
+  public Map<String, Analyzer> getFieldAnalyzerMap();
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java
new file mode 100644
index 0000000..0579eef
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java
@@ -0,0 +1,37 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.Set;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory.ResultType;
+
+/**
+ * Provides wrapper object of Lucene's Query object and execute the search. 
+ * <p>Instances of this interface are created using
+ * {@link LuceneQueryFactory#create}.
+ * 
+ */
+public interface LuceneQuery {
+  /**
+   * Execute the search and get results. 
+   */
+  public LuceneQueryResults<?> search();
+  
+  /**
+   * Get page size setting of current query. 
+   */
+  public int getPageSize();
+  
+  /**
+   * Get limit size setting of current query. 
+   */
+  public int getLimit();
+
+  /**
+   * Get result types setting of current query. 
+   */
+  public ResultType[] getResultTypes();
+  
+  /**
+   * Get projected fields setting of current query. 
+   */
+  public String[] getProjectedFieldNames();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java
new file mode 100644
index 0000000..5636ea4
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java
@@ -0,0 +1,121 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.search.Query;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.DiskStore;
+
+/**
+ * Factory for creating instances of {@link LuceneQuery}.
+ * To get an instance of this factory call {@link LuceneService#createLuceneQueryFactory}.
+ * <P>
+ * To use this factory configure it with the <code>set</code> methods and then
+ * call {@link #create} to produce a {@link LuceneQuery} instance.
+ * 
+ * @author Xiaojian Zhou
+ * @since 8.5
+ */
+public interface LuceneQueryFactory {
+  
+  /**
+   * Default query result limit is 100
+   */
+  public static final int DEFAULT_LIMIT = 100;
+  
+  /**
+   *  Default page size of result is 0, which means no pagination
+   */
+  public static final int DEFAULT_PAGESIZE = 0;
+  
+  public enum ResultType {
+    /**
+     *  Query results only contain value, which is the default setting.
+     *  If field projection is specified, use projected fields' values instead of whole domain object
+     */
+    VALUE,
+    
+    /**
+     * Query results contain score
+     */
+    SCORE,
+    
+    /**
+     * Query results contain key
+     */
+    KEY
+  };
+
+  /**
+   * Set page size for a query result. The default page size is 0 which means no pagination.
+   * If specified negative value, throw IllegalArgumentException
+   * @param pageSize
+   * @return itself
+   */
+  LuceneQueryFactory setPageSize(int pageSize);
+  
+  /**
+   * Set max limit of result for a query
+   * If specified limit is less or equal to zero, throw IllegalArgumentException
+   * @param limit
+   * @return itself
+   */
+  LuceneQueryFactory setResultLimit(int limit);
+  
+  /**
+   * set weather to include SCORE, KEY in result
+   * 
+   * @param resultTypes
+   * @return itself
+   */
+  LuceneQueryFactory setResultTypes(ResultType... resultTypes);
+  
+  /**
+   * Set a list of fields for result projection.
+   * 
+   * @param fieldNames
+   * @return itself
+   */
+  LuceneQueryFactory setProjectionFields(String... fieldNames);
+  
+  /**
+   * Create wrapper object for lucene's QueryParser object.
+   * The queryString is using lucene QueryParser's syntax. QueryParser is for easy-to-use 
+   * with human understandable syntax. 
+   *  
+   * @param regionName region name
+   * @param indexName index name
+   * @param queryString query string in lucene QueryParser's syntax
+   * @param analyzer lucene Analyzer to parse the queryString
+   * @return LuceneQuery object
+   * @throws ParseException
+   */
+  public LuceneQuery create(String indexName, String regionName, String queryString, 
+      Analyzer analyzer) throws ParseException;
+  
+  /**
+   * Create wrapper object for lucene's QueryParser object using default standard analyzer.
+   * The queryString is using lucene QueryParser's syntax. QueryParser is for easy-to-use 
+   * with human understandable syntax. 
+   *  
+   * @param regionName region name
+   * @param indexName index name
+   * @param queryString query string in lucene QueryParser's syntax
+   * @return LuceneQuery object
+   * @throws ParseException
+   */
+  public LuceneQuery create(String indexName, String regionName, String queryString) 
+      throws ParseException;
+  
+  /**
+   * Create wrapper object for lucene's Query object.
+   * Advanced lucene users can customized their own Query object and directly use in this API.  
+   * 
+   * @param regionName region name
+   * @param indexName index name
+   * @param query lucene Query object
+   * @return LuceneQuery object
+   */
+  public LuceneQuery create(String indexName, String regionName, Query query);
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
new file mode 100644
index 0000000..d660a4b
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
@@ -0,0 +1,29 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.gemstone.gemfire.cache.execute.ResultSender;
+import com.gemstone.gemfire.distributed.DistributedMember;
+
+/**
+ * <p>
+ * Defines the interface for a container of lucene query result collected from function
+ * execution.<br>
+ * 
+ * @author Xiaojian Zhou
+ * @since 8.5
+ */
+
+public interface LuceneQueryResults<E> {
+
+  /* get next page of result if pagesize is specified in query, otherwise, return null */
+  public List<E> getNextPage();
+  
+  /* Is next page of result available */
+  public boolean hasNextPage();
+  
+  /* total number of items */
+  public int size();
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
new file mode 100644
index 0000000..a5b16b7
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
@@ -0,0 +1,59 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.LinkedList;
+
+/**
+ * <p>
+ * Abstract data structure for one item in query result.
+ * 
+ * @author Xiaojian Zhou
+ * @since 8.5
+ */
+public interface LuceneResultStruct {
+  /**
+   * Return the value associated with the given field name
+   *
+   * @param fieldName the String name of the field
+   * @return the value associated with the specified field
+   * @throws IllegalArgumentException If this struct does not have a field named fieldName
+   */
+  public Object getProjectedField(String fieldName);
+  
+  /**
+   * Return key of the entry
+   *
+   * @return key
+   * @throws IllegalArgumentException If this struct does not contain key
+   */
+  public Object getKey();
+  
+  /**
+   * Return value of the entry
+   *
+   * @return value the whole domain object
+   * @throws IllegalArgumentException If this struct does not contain value
+   */
+  public Object getValue();
+  
+  /**
+   * Return score of the query 
+   *
+   * @return score
+   * @throws IllegalArgumentException If this struct does not contain score
+   */
+  public Double getScore();
+  
+  /**
+   * Get the types of values ordered list
+   * Item in the list could be either ResultType, or field name
+   * @return the array of result types
+   */
+  public Object[] getNames();
+  
+  /**
+   * Get the values in same order as result types
+   * @return the array of values
+   */
+  public Object[] getResultValues();
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneService.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneService.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneService.java
new file mode 100644
index 0000000..dde54bf
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneService.java
@@ -0,0 +1,103 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.lucene.analysis.Analyzer;
+import com.gemstone.gemfire.cache.GemFireCache;
+
+/**
+ * LuceneService instance is a singleton for each cache. It will be created in cache 
+ * constructor and get its reference via {@link GemFireCache#getLuceneService()}.
+ * 
+ * It provides handle for managing the {@link LuceneIndex} and create the {@link LuceneQuery}
+ * via {@link LuceneQueryFactory}
+ * 
+ * </p>
+ * Example: <br>
+ * 
+ * <pre>
+ * At client and server JVM, initializing cache will create the LuceneServiceImpl object, 
+ * which is a singleton at each JVM. 
+ * 
+ * At each server JVM, for data region to create index, create the index on fields with default analyzer:
+ * LuceneIndex index = luceneService.createIndex(indexName, regionName, "field1", "field2", "field3"); 
+ * or create index on fields with specified analyzer:
+ * LuceneIndex index = luceneService.createIndex(indexName, regionName, analyzerPerField);
+ * 
+ * We can also create index via cache.xml or gfsh.
+ * 
+ * At client side, create query and run the search:
+ * 
+ * LuceneQuery query = luceneService.createLuceneQueryFactory().setLimit(200).setPageSize(20)
+ * .setResultTypes(SCORE, VALUE, KEY).setFieldProjection("field1", "field2")
+ * .create(indexName, regionName, querystring, analyzer);
+ * 
+ * The querystring is using lucene's queryparser syntax, such as "field1:zhou* AND field2:gzhou@pivotal.io"
+ *  
+ * LuceneQueryResults results = query.search();
+ * 
+ * If pagination is not specified:
+ * List list = results.getNextPage(); // return all results in one getNextPage() call
+ * or if paging is specified:
+ * if (results.hasNextPage()) {
+ *   List page = results.nextPage(); // return resules page by page
+ * }
+ * 
+ * The item of the list is either the domain object or instance of {@link LuceneResultStruct}
+ * </pre>
+ * 
+ * @author Xiaojian Zhou
+ *
+ */
+public interface LuceneService {
+
+  /**
+   * Create a lucene index using default analyzer.
+   * 
+   * @param indexName
+   * @param regionName
+   * @param fields
+   * @return LuceneIndex object
+   */
+  public LuceneIndex createIndex(String indexName, String regionName, String... fields);
+  
+  /**
+   * Create a lucene index using specified analyzer per field
+   * 
+   * @param indexName index name
+   * @param regionName region name
+   * @param analyzerPerField analyzer per field map
+   * @return LuceneIndex object
+   *
+   */
+  public LuceneIndex createIndex(String indexName, String regionName,  
+      Map<String, Analyzer> analyzerPerField);
+
+  /**
+   * Destroy the lucene index
+   * 
+   * @param index index object
+   */
+  public void destroyIndex(LuceneIndex index);
+  
+  /**
+   * Get the lucene index object specified by region name and index name
+   * @param indexName index name
+   * @param regionName region name
+   * @return LuceneIndex object
+   */
+  public LuceneIndex getIndex(String indexName, String regionName);
+  
+  /**
+   * get all the lucene indexes.
+   * @return all index objects in a Collection
+   */
+  public Collection<LuceneIndex> getAllIndexes();
+
+  /**
+   * create LuceneQueryFactory
+   * @return LuceneQueryFactory object
+   */
+  public LuceneQueryFactory createLuceneQueryFactory();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceFactory.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceFactory.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceFactory.java
new file mode 100644
index 0000000..637f1c0
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceFactory.java
@@ -0,0 +1,14 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.lucene.LuceneService;
+
+public interface LuceneServiceFactory {
+  
+  public void initialize();
+  
+  /**
+   * Create a new LuceneService for the given cache
+   */
+  public LuceneService create(Cache cache);
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceProvider.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceProvider.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceProvider.java
new file mode 100644
index 0000000..27395ab
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneServiceProvider.java
@@ -0,0 +1,36 @@
+package com.gemstone.gemfire.cache.lucene;
+
+import java.util.Iterator;
+import java.util.ServiceLoader;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.lucene.LuceneServiceFactory;
+
+public class LuceneServiceProvider {
+  
+  private static final LuceneServiceFactory factory;
+
+  static {
+    ServiceLoader<LuceneServiceFactory> loader = ServiceLoader.load(LuceneServiceFactory.class);
+    Iterator<LuceneServiceFactory> itr = loader.iterator();
+    if(!itr.hasNext()) {
+      factory = null;
+    } else {
+      factory = itr.next();
+      factory.initialize();
+    }
+  }
+  
+  public static LuceneService create(Cache cache) {
+    
+    if(factory == null) {
+      return null;
+    }
+    
+    return factory.create(cache);
+  }
+  
+  private LuceneServiceProvider() {
+    
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneIndexImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneIndexImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneIndexImpl.java
new file mode 100644
index 0000000..a7bdd99
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneIndexImpl.java
@@ -0,0 +1,54 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+
+import com.gemstone.gemfire.cache.lucene.LuceneIndex;
+
+/* wrapper of IndexWriter */
+public class LuceneIndexImpl implements LuceneIndex {
+
+  /* searchable fields should belong to a specific index
+   */
+  HashSet<String> searchableFieldNames;
+  
+  HashSet<String> searchablePDXFieldNames;
+  
+  @Override
+  public String getName() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String getRegionName() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public String[] getFieldNames() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  public void initialize() {
+    // TODO Auto-generated method stub
+    
+  }
+
+  public void close() {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public Map<String, Analyzer> getFieldAnalyzerMap() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java
new file mode 100644
index 0000000..3bd5b0c
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java
@@ -0,0 +1,88 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.lucene.analysis.Analyzer;
+import org.apache.lucene.analysis.standard.StandardAnalyzer;
+import org.apache.lucene.queryparser.classic.ParseException;
+import org.apache.lucene.queryparser.classic.QueryParser;
+import org.apache.lucene.search.Query;
+
+import com.gemstone.gemfire.cache.lucene.LuceneIndex;
+import com.gemstone.gemfire.cache.lucene.LuceneQuery;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory;
+
+public class LuceneQueryFactoryImpl implements LuceneQueryFactory {
+  private int limit_attr = DEFAULT_LIMIT;
+  private int pageSize_attr = DEFAULT_PAGESIZE;
+  private Set<ResultType> resultType_attr = new HashSet<ResultType>();
+  private Set<String> projection_fields_attr = new HashSet<String>();
+  
+  /* reference to the index. One index could have multiple Queries, but one Query must belong
+   * to one index
+   */
+  private LuceneIndex relatedIndex;
+
+  @Override
+  public LuceneQueryFactory setPageSize(int pageSize) {
+    this.pageSize_attr = pageSize;
+    return this;
+  }
+
+  @Override
+  public LuceneQueryFactory setResultLimit(int limit) {
+    this.limit_attr = limit;
+    return this;
+  }
+
+  @Override
+  public LuceneQueryFactory setResultTypes(ResultType... resultTypes) {
+    if (resultTypes != null) {
+      for (ResultType resultType:resultTypes) {
+        this.resultType_attr.add(resultType);
+      }
+    }
+    return this;
+  }
+
+  @Override
+  public LuceneQuery create(String indexName, String regionName,
+      String queryString, Analyzer analyzer) throws ParseException {
+    QueryParser parser = new QueryParser(null, analyzer);
+    Query query = parser.parse(queryString);
+    LuceneQueryImpl luceneQuery = new LuceneQueryImpl(indexName, regionName, limit_attr, pageSize_attr, 
+        resultType_attr, projection_fields_attr, query);
+    return luceneQuery;
+  }
+
+  @Override
+  public LuceneQuery create(String indexName, String regionName,
+      String queryString) throws ParseException {
+    StandardAnalyzer analyzer = new StandardAnalyzer();
+    return create(indexName, regionName, queryString, analyzer);
+  }
+  
+  @Override
+  public LuceneQuery create(String indexName, String regionName,
+      Query query) {
+    LuceneQueryImpl luceneQuery = new LuceneQueryImpl(indexName, regionName, limit_attr, pageSize_attr, 
+        resultType_attr, projection_fields_attr, query);
+    return luceneQuery;
+  }
+
+  public LuceneIndex getRelatedIndex() {
+    return this.relatedIndex;
+  }
+
+  @Override
+  public LuceneQueryFactory setProjectionFields(String... fieldNames) {
+    if (fieldNames != null) {
+      for (String fieldName:fieldNames) {
+        this.projection_fields_attr.add(fieldName);
+      }
+    }
+    return this;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java
new file mode 100644
index 0000000..04025d3
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java
@@ -0,0 +1,62 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.Set;
+
+import org.apache.lucene.search.Query;
+
+import com.gemstone.gemfire.cache.lucene.LuceneQuery;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory.ResultType;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryResults;
+
+public class LuceneQueryImpl implements LuceneQuery {
+  private int limit = LuceneQueryFactory.DEFAULT_LIMIT;
+  private int pageSize = LuceneQueryFactory.DEFAULT_PAGESIZE;
+  private String indexName;
+  private String regionName;
+  private Set<ResultType> resultTypes;
+  
+  // The projected fields are local to a specific index per Query object. 
+  private Set<String> projectedFieldNames;
+  
+  /* the lucene Query object to be wrapped here */
+  private Query query;
+  
+  LuceneQueryImpl(String indexName, String regionName, int limit, int pageSize, Set<ResultType> resultTypes, 
+      Set<String> projectionFieldNames, Query query) {
+    this.indexName = indexName;
+    this.regionName = regionName;
+    this.limit = limit;
+    this.pageSize = pageSize;
+    this.resultTypes = resultTypes;
+    this.projectedFieldNames = projectionFieldNames;
+    this.query = query;
+  }
+
+  @Override
+  public LuceneQueryResults<?> search() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public int getPageSize() {
+    return this.pageSize;
+  }
+
+  @Override
+  public int getLimit() {
+    return this.limit;
+  }
+
+  @Override
+  public ResultType[] getResultTypes() {
+    return (ResultType[])this.resultTypes.toArray();
+  }
+
+  @Override
+  public String[] getProjectedFieldNames() {
+    return (String[])this.projectedFieldNames.toArray();
+  }
+  
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
new file mode 100644
index 0000000..ecb6370
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
@@ -0,0 +1,66 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import com.gemstone.gemfire.cache.execute.FunctionException;
+import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryResults;
+import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
+import com.gemstone.gemfire.distributed.DistributedMember;
+
+public class LuceneQueryResultsImpl<E> implements LuceneQueryResults<E>, ResultCollector {
+
+  @Override
+  public Object getResult() throws FunctionException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Object getResult(long timeout, TimeUnit unit)
+      throws FunctionException, InterruptedException {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void addResult(DistributedMember memberID,
+      Object resultOfSingleExecution) {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public void endResults() {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public void clearResults() {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public List getNextPage() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public boolean hasNextPage() {
+    // TODO Auto-generated method stub
+    return false;
+  }
+
+  @Override
+  public int size() {
+    // TODO Auto-generated method stub
+    return 0;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
new file mode 100644
index 0000000..0db8f97
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
@@ -0,0 +1,45 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.LinkedList;
+
+import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
+
+public class LuceneResultStructImpl implements LuceneResultStruct {
+
+  @Override
+  public Object getProjectedField(String fieldName) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Object getKey() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Object getValue() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Double getScore() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Object[] getNames() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public Object[] getResultValues() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceFactoryImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceFactoryImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceFactoryImpl.java
new file mode 100644
index 0000000..d506f7a
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceFactoryImpl.java
@@ -0,0 +1,16 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.lucene.LuceneService;
+import com.gemstone.gemfire.cache.lucene.LuceneServiceFactory;
+
+public class LuceneServiceFactoryImpl implements LuceneServiceFactory {
+  
+  public void initialize() {
+  }
+
+  @Override
+  public LuceneService create(Cache cache) {
+    return LuceneServiceImpl.getInstance(cache);
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java
new file mode 100644
index 0000000..ed90f89
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java
@@ -0,0 +1,90 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.lucene.analysis.Analyzer;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.lucene.LuceneIndex;
+import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory;
+import com.gemstone.gemfire.cache.lucene.LuceneService;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+/**
+ * Implementation of LuceneService to create lucene index and query. 
+ * 
+ * @author Xiaojian Zhou
+ * 
+ * @since 8.5
+ */
+public class LuceneServiceImpl implements LuceneService {
+  private final Cache cache;
+  private static LuceneServiceImpl instance;
+
+  private final HashMap<String, LuceneIndex>  indexMap;
+
+  private LuceneServiceImpl(final Cache cache) {
+    if (cache == null) {
+      throw new IllegalStateException(LocalizedStrings.CqService_CACHE_IS_NULL.toLocalizedString());
+    }
+    GemFireCacheImpl gfc = (GemFireCacheImpl) cache;
+    gfc.getCancelCriterion().checkCancelInProgress(null);
+
+    this.cache = gfc;
+
+    
+    // Initialize the Map which maintains indexes
+    this.indexMap = new HashMap<String, LuceneIndex>();
+  }
+  
+  public static synchronized LuceneServiceImpl getInstance(final Cache cache) {
+    if (instance == null) {
+      instance = new LuceneServiceImpl(cache);
+    }
+    return instance;
+  }
+  
+  public String getUniqueIndexName(String indexName, String regionName) {
+    String name = indexName+"#"+regionName.replace('/', '_');
+    return name;
+  }
+  
+  @Override
+  public LuceneIndex createIndex(String indexName, String regionName, String... fields) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public LuceneIndex getIndex(String indexName, String regionName) {
+    return indexMap.get(getUniqueIndexName(indexName, regionName));
+  }
+
+  @Override
+  public Collection<LuceneIndex> getAllIndexes() {
+    return indexMap.values();
+  }
+
+  @Override
+  public LuceneIndex createIndex(String indexName, String regionName, 
+      Map<String, Analyzer> analyzerPerField) {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void destroyIndex(LuceneIndex index) {
+    LuceneIndexImpl indexImpl = (LuceneIndexImpl)index;
+    indexMap.remove(getUniqueIndexName(index.getName(), index.getRegionName()));
+    indexImpl.close();
+  }
+
+  @Override
+  public LuceneQueryFactory createLuceneQueryFactory() {
+    return new LuceneQueryFactoryImpl();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/operations/internal/GetOperationContextImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/operations/internal/GetOperationContextImpl.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/operations/internal/GetOperationContextImpl.java
new file mode 100644
index 0000000..b8e13c6
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/operations/internal/GetOperationContextImpl.java
@@ -0,0 +1,96 @@
+package com.gemstone.gemfire.cache.operations.internal;
+
+import com.gemstone.gemfire.cache.operations.GetOperationContext;
+import com.gemstone.gemfire.internal.offheap.Releasable;
+import com.gemstone.gemfire.internal.offheap.SimpleMemoryAllocatorImpl.Chunk;
+import com.gemstone.gemfire.internal.offheap.StoredObject;
+import com.gemstone.gemfire.internal.offheap.annotations.Unretained;
+
+/**
+ * This subclass's job is to keep customers from getting a reference to a value
+ * that is off-heap. Any access to an off-heap value should appear to the customer
+ * as a serialized value.
+ * 
+ * @author dschneider
+ *
+ */
+public class GetOperationContextImpl extends GetOperationContext implements Releasable {
+
+  private boolean released;
+  
+  public GetOperationContextImpl(Object key, boolean postOperation) {
+    super(key, postOperation);
+  }
+
+  /**
+   * This method is for internal use and should not be on the public apis.
+   */
+  public @Unretained Object getRawValue() {
+    return super.getValue();
+  }
+  
+  @Override
+  public Object getObject() {
+    Object result = super.getObject();
+    if (result instanceof StoredObject) {
+      // For off-heap object act as if they are serialized forcing them to call getSerializedValue or getValue
+      result = null;
+    }
+    return result;
+  }
+
+  @Override
+  public void setObject(Object value, boolean isObject) {
+    this.released = false;
+    super.setObject(value, isObject);
+  }
+
+  @Override
+  public void setValue(Object value, boolean isObject) {
+    this.released = false;
+    super.setValue(value, isObject);
+  }
+
+  private void checkForReleasedOffHeapValue(Object v) {
+    // Note that we only care about Chunk (instead of all StoredObject) because it is the only one using a refcount
+    if (this.released && v instanceof Chunk) {
+      throw new IllegalStateException("Attempt to access off-heap value after the OperationContext callback returned.");
+    }
+  }
+  
+  @Override
+  public byte[] getSerializedValue() {
+    byte[] result = super.getSerializedValue();
+    if (result == null) {
+      Object v = this.value;
+      if (v instanceof StoredObject) {
+        checkForReleasedOffHeapValue(v);
+        result = ((StoredObject) v).getValueAsHeapByteArray();
+      }
+    }
+    return result;
+  }
+
+  @Override
+  public Object getValue() {
+    Object result = super.getValue();
+    if (result instanceof StoredObject) {
+      checkForReleasedOffHeapValue(result);
+      result = ((StoredObject) result).getValueAsHeapByteArray();
+    }
+    return result;
+  }
+
+  @Override
+  public void release() {
+    // Note that if the context's value is stored off-heap
+    // and release has been called then we do not release
+    // our value (since this context did not retain it)
+    // but we do make sure that any future attempt to access
+    // the off-heap value fails.
+    if (this.value instanceof Chunk) {
+      this.released = true;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/Aggregator.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/Aggregator.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/Aggregator.java
new file mode 100644
index 0000000..9f54eba
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/Aggregator.java
@@ -0,0 +1,30 @@
+package com.gemstone.gemfire.cache.query;
+
+/**
+ * Behavior of a user-defined aggregator. Aggregates values and returns a
+ * result. In addition to the methods in the interface, implementing classes
+ * must have a 0-arg public constructor.
+ * 
+ * @author ashahid
+ *
+ */
+public interface Aggregator {
+
+  /**
+   * Accumulate the next scalar value
+   * 
+   * @param value
+   */
+  public void accumulate(Object value);
+
+  /**
+   * Initialize the Aggregator
+   */
+  public void init();
+
+  /**
+   * 
+   * @return Return the result scalar value
+   */
+  public Object terminate();
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractCompiledValue.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractCompiledValue.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractCompiledValue.java
index db504b6..2d64a01 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractCompiledValue.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractCompiledValue.java
@@ -229,8 +229,10 @@ public abstract class AbstractCompiledValue implements CompiledValue, Filter,
       List iterators = context.getCurrentIterators();
       int len = iterators.size();
       if (len == 1) {
-        emptySet = new ResultsBag(((RuntimeIterator) iterators.get(0))
-            .getElementType(), 0,  context.getCachePerfStats());
+        ObjectType elementType = ((RuntimeIterator) iterators.get(0))
+            .getElementType();
+        emptySet = context.isDistinct() ? new ResultsSet(elementType) :
+          new ResultsBag(elementType, 0,  context.getCachePerfStats());
       }
       else {
         String fieldNames[] = new String[len];
@@ -240,9 +242,8 @@ public abstract class AbstractCompiledValue implements CompiledValue, Filter,
           fieldNames[i] = iter.getInternalId();
           fieldTypes[i] = iter.getElementType();
         }
-        emptySet = new StructBag(0,
-                                 new StructTypeImpl(fieldNames, fieldTypes), 
-                                 context.getCachePerfStats());
+        emptySet = context.isDistinct() ? new StructSet(new StructTypeImpl(fieldNames, fieldTypes))
+        :new StructBag(0, new StructTypeImpl(fieldNames, fieldTypes), context.getCachePerfStats());
       }
       return emptySet;
     }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractGroupOrRangeJunction.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractGroupOrRangeJunction.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractGroupOrRangeJunction.java
index c3e7c89..f7d9289 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractGroupOrRangeJunction.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AbstractGroupOrRangeJunction.java
@@ -11,7 +11,12 @@
  */
 package com.gemstone.gemfire.cache.query.internal;
 
-import com.gemstone.gemfire.cache.query.AmbiguousNameException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
 import com.gemstone.gemfire.cache.query.FunctionDomainException;
 import com.gemstone.gemfire.cache.query.NameResolutionException;
 import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
@@ -25,14 +30,6 @@ import com.gemstone.gemfire.cache.query.types.ObjectType;
 import com.gemstone.gemfire.internal.Assert;
 import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
 /**
  * @author asif
  * 
@@ -388,11 +385,12 @@ public abstract class AbstractGroupOrRangeJunction extends
     currentIters.toArray(rIters);
     ObjectType elementType = intermediateResults.getCollectionType()
         .getElementType();
-    resultSet = (elementType.isStructType()) ?
-                ((SelectResults)new StructBag((StructTypeImpl)elementType,
-                                              context.getCachePerfStats())) :
-                ((SelectResults)new ResultsBag(elementType,
-                                               context.getCachePerfStats()));
+    if(elementType.isStructType()) {
+      resultSet = QueryUtils.createStructCollection(context, (StructTypeImpl)elementType) ;
+    }else {
+      resultSet = QueryUtils.createResultCollection(context, elementType) ;
+    }
+   
     QueryObserver observer = QueryObserverHolder.getInstance();
     try {
       observer.startIteration(intermediateResults, operand);

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AllGroupJunction.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AllGroupJunction.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AllGroupJunction.java
index 32f6ed5..9e6540d 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AllGroupJunction.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/AllGroupJunction.java
@@ -125,18 +125,16 @@ public class AllGroupJunction extends AbstractCompiledValue implements Filter,
         if (finalList.size() > 1) {
           StructType type = QueryUtils
               .createStructTypeForRuntimeIterators(finalList);
-          return new StructBag((StructTypeImpl)type,
-                               context.getCachePerfStats());
+          return QueryUtils.createStructCollection(context, type);
         }
         else {
           ObjectType type = ((RuntimeIterator) finalList.iterator().next())
               .getElementType();
           if (type instanceof StructType) {
-            return new StructBag((StructTypeImpl)type,
-                                 context.getCachePerfStats());
+            return QueryUtils.createStructCollection(context, (StructTypeImpl)type);
           }
           else {
-            return new ResultsBag(type, context.getCachePerfStats());
+            return QueryUtils.createResultCollection(context, type);
           }
         }
       }

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/Bag.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/Bag.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/Bag.java
new file mode 100644
index 0000000..2f4dd87
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/Bag.java
@@ -0,0 +1,717 @@
+/*=========================================================================
+ * Copyright (c) 2005-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * more patents listed at http://www.pivotal.io/patents.
+ *========================================================================
+ */
+
+package com.gemstone.gemfire.cache.query.internal;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.AbstractCollection;
+import java.util.AbstractSet;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.cache.query.CqResults;
+import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.cache.query.internal.ObjectIntHashMap.Entry;
+import com.gemstone.gemfire.cache.query.internal.types.CollectionTypeImpl;
+import com.gemstone.gemfire.cache.query.types.CollectionType;
+import com.gemstone.gemfire.cache.query.types.ObjectType;
+import com.gemstone.gemfire.cache.query.types.StructType;
+import com.gemstone.gemfire.internal.DataSerializableFixedID;
+import com.gemstone.gemfire.internal.Version;
+import com.gemstone.gemfire.internal.cache.CachePerfStats;
+import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
+
+// @todo probably should assert element type when elements added
+// @todo support generics when no longer support Java 1.4
+/**
+ * Implementation of SelectResults that allows duplicates . The keys store the
+ * elements of the collection and the the values store the number of occurrences
+ * as an int.
+ * 
+ * @see ResultsBag
+ * @see StructBag
+ * @see SortedResultsBag
+ *
+ * @author Eric Zoerner
+ * @author ashahid
+ * @since 8.1
+ */
+public abstract class Bag<E> extends AbstractCollection<E> implements
+    CqResults<E> {
+  protected ObjectType elementType;
+  // protected ObjectIntHashMap map;
+  protected int size = 0;
+
+  /** adds support for null elements */
+
+  protected int numNulls = 0;
+  // Asif: These fields are used for limiting the results based on the limit
+  // clause in the query
+  private int limit = -1;
+  boolean hasLimitIterator = false;
+  final Object limitLock = new Object();
+
+  public Bag() {
+
+  }
+
+  /**
+   * This constructor should only be used by the DataSerializer. Creates a
+   * ResultsBag with no fields.
+   */
+  public Bag(boolean ignored) {
+  }
+
+  /**
+   * @param stats
+   *          the CachePerfStats to track hash collisions. Should be null unless
+   *          this is used as a query execution-time result set.
+   */
+  public Bag(CachePerfStats stats) {
+
+  }
+
+  /**
+   * @param stats
+   *          the CachePerfStats to track hash collisions. Should be null unless
+   *          this is used as a query execution-time result set.
+   */
+  Bag(Collection c, CachePerfStats stats) {
+    this(stats);
+    for (Iterator itr = c.iterator(); itr.hasNext();) {
+      this.add(itr.next());
+    }
+  }
+
+  /**
+   * @param stats
+   *          the CachePerfStats to track hash collisions. Should be null unless
+   *          this is used as a query execution-time result set.
+   */
+  Bag(SelectResults sr, CachePerfStats stats) {
+    this((Collection) sr, stats);
+    // grab type info
+    setElementType(sr.getCollectionType().getElementType());
+  }
+
+  /**
+   * @param stats
+   *          the CachePerfStats to track hash collisions. Should be null unless
+   *          this is used as a query execution-time result set.
+   */
+  Bag(ObjectType elementType, CachePerfStats stats) {
+    this(stats);
+    setElementType(elementType);
+  }
+
+  public void setElementType(ObjectType elementType) {
+    if (elementType instanceof StructType)
+      throw new IllegalArgumentException(
+          LocalizedStrings.ResultsBag_THIS_COLLECTION_DOES_NOT_SUPPORT_STRUCT_ELEMENTS
+              .toLocalizedString());
+    this.elementType = elementType;
+  }
+
+  // @todo Currently does an iteration, could make this more efficient
+  // by providing a ListView
+  /**
+   * Returns this bag as a list.
+   */
+  public List asList() {
+    return new ArrayList(this);
+  }
+
+  /**
+   * Return an unmodifiable Set view of this bag. Does not require an iteration
+   * by using a lightweight wrapper.
+   */
+  public Set asSet() {
+    return new SetView();
+  }
+
+  public CollectionType getCollectionType() {
+    return new CollectionTypeImpl(Collection.class, this.elementType);
+  }
+
+  public abstract boolean isModifiable();
+
+  public int occurrences(Object element) {
+    if (this.hasLimitIterator) {
+      // Asif: If limit iterator then occurrence should be calculated
+      // via the limit iterator
+      int count = 0;
+      boolean encounteredObject = false;
+      for (Iterator itr = this.iterator(); itr.hasNext();) {
+        Object v = itr.next();
+        if (element == null ? v == null : element.equals(v)) {
+          count++;
+          encounteredObject = true;
+        } else if (encounteredObject) {
+          // Asif: No possibility of its occurrence again
+          break;
+        }
+      }
+      return count;
+    } else {
+      if (element == null) {
+        return this.numNulls;
+      }
+      return this.mapGet(element); // returns 0 if not
+                                   // found
+    }
+  }
+
+  protected abstract int mapGet(Object element);
+
+  /**
+   * Return an iterator over the elements in this collection. Duplicates will
+   * show up the number of times it has occurrences.
+   */
+  @Override
+  public Iterator iterator() {
+    if (this.hasLimitIterator) {
+      // Asif: Return a new LimitIterator in the block so that
+      // the current Limit does not get changed by a remove
+      // operation of another thread. The current limit is
+      // set in the limit iterator. So the setting of the current limit
+      // & creation of iterator should be atomic .If any subsequent
+      // modifcation in limit occurs, the iterator will itself fail.
+      // Similarly a remove called by a iterator should decrease the
+      // current limit and underlying itr.remove atomically
+      synchronized (this.limitLock) {
+        return new LimitBagIterator();
+      }
+    } else {
+      return new BagIterator();
+    }
+  }
+
+  @Override
+  public boolean contains(Object element) {
+    if (this.hasLimitIterator) {
+      return super.contains(element);
+    } else {
+      if (element == null) {
+        return this.numNulls > 0;
+      }
+      return mapContainsKey(element);
+    }
+  }
+
+  protected abstract boolean mapContainsKey(Object element);
+
+  // not thread safe!
+  @Override
+  public boolean add(Object element) {
+    if (this.limit > -1) {
+      throw new UnsupportedOperationException(
+          "Addition to the SelectResults not allowed as the query result is constrained by LIMIT");
+    }
+    if (element == null) {
+      numNulls++;
+    } else {
+      int count = this.mapGet(element); // 0 if not
+                                        // found
+      this.mapPut(element, count + 1);
+    }
+    this.size++;
+    assert this.size >= 0 : this.size;
+    return true;
+  }
+
+  protected abstract void mapPut(Object element, int count);
+
+  // Internal usage method
+  // Asif :In case of StructBag , we will ensure that it
+  // gets an Object [] indicating field values as parameter
+  // from the CompiledSelect
+  public int addAndGetOccurence(Object element) {
+    int occurence;
+    if (element == null) {
+      numNulls++;
+      occurence = numNulls;
+    } else {
+      occurence = this.mapGet(element); // 0 if not
+                                        // found
+      this.mapPut(element, ++occurence);
+    }
+    this.size++;
+    assert this.size >= 0 : this.size;
+    return occurence;
+  }
+
+  @Override
+  public int size() {
+    if (this.hasLimitIterator) {
+      synchronized (this.limitLock) {
+        return this.limit;
+      }
+    } else {
+      return this.size;
+    }
+  }
+
+  protected abstract int mapSize();
+
+  // not thread safe!
+  @Override
+  public boolean remove(Object element) {
+    if (this.hasLimitIterator) {
+      return super.remove(element);
+    } else {
+      if (element == null) {
+        if (this.numNulls > 0) {
+          this.numNulls--;
+          this.size--;
+          assert this.size >= 0 : this.size;
+          return true;
+        } else {
+          return false;
+        }
+      }
+      int count = this.mapGet(element); // 0 if not
+                                        // found
+      if (count == 0) {
+        return false;
+      }
+      if (count == 1) {
+        this.mapRemove(element);
+      } else {
+        this.mapPut(element, --count);
+      }
+      this.size--;
+      assert this.size >= 0 : this.size;
+      return true;
+    }
+  }
+
+  protected abstract int mapRemove(Object element);
+
+  // not thread safe!
+  @Override
+  public void clear() {
+    this.mapClear();// this.map.clear();
+    this.numNulls = 0;
+    this.size = 0;
+    if (this.hasLimitIterator) {
+      synchronized (this.limitLock) {
+        this.limit = 0;
+      }
+    }
+  }
+
+  protected abstract void mapClear();
+
+  // not thread safe!
+  @Override
+  public boolean equals(Object o) {
+    if (!(o instanceof Bag)) {
+      return false;
+    }
+    Bag otherBag = (Bag) o;
+    return this.size == otherBag.size
+        && this.elementType.equals(otherBag.elementType)
+
+        && this.getMap().equals(otherBag.getMap())
+        && this.numNulls == otherBag.numNulls;
+  }
+
+  protected abstract Object getMap();
+
+  @Override
+  // GemStoneAddition
+  public int hashCode() {
+    return this.mapHashCode();
+  }
+
+  protected abstract int mapHashCode();
+
+  public boolean addAll(Collection coll) {
+    if (this.limit > -1) {
+      throw new UnsupportedOperationException(
+          "Addition to the SelectResults not allowed as the query result is constrained by LIMIT");
+    } else {
+      return super.addAll(coll);
+    }
+  }
+
+  /**
+   * 
+   * @param out
+   * @throws IOException
+   */
+  void writeNumNulls(DataOutput out) throws IOException {
+    out.writeInt(this.numNulls);
+  }
+
+  /**
+   * 
+   * @param in
+   * @throws IOException
+   */
+  void readNumNulls(DataInput in) throws IOException {
+    this.numNulls = in.readInt();
+  }
+
+  void applyLimit(int limit) {
+    this.limit = limit;
+    // Asif : From the code of IntHashMap, it appears that if no data is
+    // going to be added , then the rehash does not occur & default code
+    // of rehash does not appear to change the order of data . So we can assume
+    // that this iterator will be returning data in order.
+    // Limit Iterator is needed if the limit happens to be less than the size
+    if (this.limit > -1 && this.size > this.limit) {
+      this.hasLimitIterator = true;
+    }
+  }
+
+  protected boolean nullOutputAtBegining() {
+    return true;
+  }
+
+  protected abstract boolean mapEmpty();
+
+  protected abstract Iterator mapEntryIterator();
+
+  protected abstract Iterator mapKeyIterator();
+
+  protected abstract Object keyFromEntry(Object entry);
+
+  protected abstract Integer valueFromEntry(Object entry);
+
+  private void checkModifiablity() {
+    if (!Bag.this.isModifiable()) {
+      throw new UnsupportedOperationException("Collection unmodifiable");
+    }
+  }
+
+  protected class BagIterator implements Iterator {
+    private final Iterator iter;
+
+    protected BagIterator() {
+      if (nullOutputAtBegining()) {
+        this.iter = new NullFirstBagIterator();
+      } else {
+        this.iter = new NullLastBagIterator();
+      }
+    }
+
+    @Override
+    public boolean hasNext() {
+      return this.iter.hasNext();
+    }
+
+    @Override
+    public Object next() {
+      return this.iter.next();
+    }
+
+    @Override
+    public void remove() {
+      this.iter.remove();
+    }
+
+    private class NullLastBagIterator implements Iterator {
+      final Iterator mapIterator = Bag.this.mapEntryIterator();
+
+      Object currentEntry = null;
+
+      /**
+       * duplicates are numbered from 1 to n; 0 = no current, otherwise goes
+       * from 1 to dupLimit, indicating the last dup that was emitted by next()
+       */
+      int currentDup = 0;
+      int dupLimit = 0;
+
+      int nullDup = 0;
+      int nullDupLimit = Bag.this.numNulls;
+
+      public boolean hasNext() {
+        return this.mapIterator.hasNext() || this.currentDup < this.dupLimit
+            || this.nullDup < this.nullDupLimit;
+      }
+
+      public Object next() {
+        // see if there is another duplicate to emit
+        if (this.currentDup < this.dupLimit) {
+          this.currentDup++;
+          return Bag.this.keyFromEntry(currentEntry);
+        } else if (this.mapIterator.hasNext()) {
+          // otherwise, go to next object
+          currentEntry = this.mapIterator.next();
+          this.dupLimit = Bag.this.valueFromEntry(currentEntry);
+          this.currentDup = 1;
+          return Bag.this.keyFromEntry(currentEntry);
+        } else if (this.nullDup < this.nullDupLimit) {
+          ++this.nullDup;
+          return null;
+        } else {
+          throw new NoSuchElementException();
+        }
+
+      }
+
+      public void remove() {
+        throw new UnsupportedOperationException("remove not supported");
+      }
+    }
+
+    private class NullFirstBagIterator implements Iterator {
+      final Iterator mapIterator = Bag.this.mapEntryIterator();
+      Object currentEntry = null;
+
+      /**
+       * duplicates are numbered from 1 to n; 0 = no current, otherwise goes
+       * from 1 to dupLimit, indicating the last dup that was emitted by next()
+       */
+      int currentDup = 0;
+      /**
+       * dupLimit is the total number of occurrences; start by emitting the
+       * nulls
+       */
+      int dupLimit = Bag.this.numNulls;
+
+      public boolean hasNext() {
+        return this.mapIterator.hasNext() || this.currentDup < this.dupLimit;
+      }
+
+      public Object next() {
+        // see if there is another duplicate to emit
+        if (this.currentDup < this.dupLimit) {
+          this.currentDup++;
+          return (this.currentEntry == null) ? null : Bag.this
+              .keyFromEntry(currentEntry);
+        }
+        // otherwise, go to next object
+        currentEntry = this.mapIterator.next();
+        this.dupLimit = Bag.this.valueFromEntry(currentEntry); // (Integer)
+
+        this.currentDup = 1;
+        return Bag.this.keyFromEntry(currentEntry);
+      }
+
+      public void remove() {
+        checkModifiablity();
+        if (this.currentDup == 0) {
+          // next has not yet been called
+          throw new IllegalStateException(
+              LocalizedStrings.ResultsBag_NEXT_MUST_BE_CALLED_BEFORE_REMOVE
+                  .toLocalizedString());
+        }
+
+        this.dupLimit--;
+        assert this.dupLimit >= 0 : this.dupLimit;
+        if (this.currentEntry == null) {
+          Bag.this.numNulls = this.dupLimit;
+          assert Bag.this.numNulls >= 0 : Bag.this.numNulls;
+        } else {
+          if (this.dupLimit > 0) {
+            Bag.this.mapPut(Bag.this.keyFromEntry(currentEntry), this.dupLimit);
+          } else {
+            this.mapIterator.remove();
+          }
+        }
+        Bag.this.size--;
+        this.currentDup--;
+        assert Bag.this.size >= 0 : Bag.this.size;
+        assert this.currentDup >= 0 : this.currentDup;
+      }
+    }
+  }
+
+  /**
+   * package visibility so ResultsCollectionWrapper can reference it. This
+   * SetView is serialized as a special case by a ResultsCollectionWrapper.
+   * Keith: Refactored to add consideration for LIMIT, April 1, 2009
+   * 
+   * @see ResultsCollectionWrapper#toData
+   */
+  class SetView extends AbstractSet {
+
+    private int localLimit;
+
+    SetView() {
+      localLimit = Bag.this.limit;
+    }
+
+    public Iterator iterator() {
+      if (localLimit > -1) {
+        return new LimitSetViewIterator();
+      } else {
+        return new SetViewIterator();
+      }
+    }
+
+    @Override
+    public boolean add(Object o) {
+      if (contains(o)) {
+        return false;
+      }
+      return Bag.this.add(o);
+    }
+
+    @Override
+    public void clear() {
+      Bag.this.clear();
+    }
+
+    @Override
+    public int size() {
+      int calculatedSize = Bag.this.mapSize() + (Bag.this.numNulls > 0 ? 1 : 0);
+      if (localLimit > -1) {
+        return Math.min(localLimit, calculatedSize);
+      }
+      return calculatedSize;
+    }
+
+    @Override
+    public boolean contains(Object o) {
+      if (o == null) {
+        return Bag.this.numNulls > 0;
+      }
+      return Bag.this.mapContainsKey(o);
+    }
+
+    @Override
+    public boolean isEmpty() {
+      if (localLimit == 0) {
+        return true;
+      }
+      if (Bag.this.numNulls > 0) {
+        return false;
+      }
+      return Bag.this.mapEmpty();
+    }
+
+    public class SetViewIterator implements Iterator {
+      /** need to emit a null value if true */
+      boolean emitNull = Bag.this.numNulls > 0;
+      final Iterator it = Bag.this.mapKeyIterator();
+      boolean currentIsNull = false;
+
+      public Object next() {
+        if (this.emitNull) {
+          this.emitNull = false;
+          currentIsNull = true;
+          return null;
+        }
+        Object key = it.next();
+        currentIsNull = false;
+        return key;
+      }
+
+      public boolean hasNext() {
+        if (this.emitNull) {
+          return true;
+        }
+        return it.hasNext();
+      }
+
+      public void remove() {
+        if (currentIsNull) {
+          Bag.this.numNulls = 0;
+        } else {
+          it.remove();
+        }
+      }
+    };
+
+    class LimitSetViewIterator extends SetViewIterator {
+      private int currPos = 0;
+      private Object currentKey;
+
+      @Override
+      public Object next() {
+        if (this.currPos == Bag.SetView.this.localLimit) {
+          throw new NoSuchElementException();
+        } else {
+          currentKey = super.next();
+          ++currPos;
+          return currentKey;
+        }
+      }
+
+      @Override
+      public boolean hasNext() {
+        return (this.currPos < Bag.SetView.this.localLimit) && super.hasNext();
+      }
+
+      @Override
+      public void remove() {
+        if (this.currPos == 0) {
+          // next has not yet been called
+          throw new IllegalStateException(
+              "next() must be called before remove()");
+        }
+        synchronized (Bag.this.limitLock) {
+          if (currentIsNull) {
+            Bag.this.limit -= Bag.this.numNulls;
+            Bag.this.numNulls = 0;
+            Bag.SetView.this.localLimit--;
+          } else {
+            int count = Bag.this.mapRemove(currentKey);
+            assert count != 0 : "Attempted to remove an element that was not in the map.";
+            Bag.this.limit -= count;
+            ResultsBag.SetView.this.localLimit--;
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * @author Asif
+   *
+   */
+  protected class LimitBagIterator extends Bag.BagIterator {
+    final private int localLimit;
+
+    private int currPos = 0;
+
+    /**
+     * guarded by ResultsBag.this.limitLock object
+     */
+    public LimitBagIterator() {
+      localLimit = Bag.this.limit;
+    }
+
+    public boolean hasNext() {
+      return this.currPos < this.localLimit;
+    }
+
+    public Object next() {
+      if (this.currPos == this.localLimit) {
+        throw new NoSuchElementException();
+      } else {
+        Object next = super.next();
+        ++currPos;
+        return next;
+      }
+
+    }
+
+    public void remove() {
+      if (this.currPos == 0) {
+        // next has not yet been called
+        throw new IllegalStateException("next() must be called before remove()");
+      }
+      synchronized (Bag.this.limitLock) {
+        super.remove();
+        --Bag.this.limit;
+      }
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledAggregateFunction.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledAggregateFunction.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledAggregateFunction.java
new file mode 100644
index 0000000..ba77310
--- /dev/null
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledAggregateFunction.java
@@ -0,0 +1,169 @@
+package com.gemstone.gemfire.cache.query.internal;
+
+import com.gemstone.gemfire.cache.query.AmbiguousNameException;
+import com.gemstone.gemfire.cache.query.FunctionDomainException;
+import com.gemstone.gemfire.cache.query.NameResolutionException;
+import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
+import com.gemstone.gemfire.cache.query.TypeMismatchException;
+import com.gemstone.gemfire.cache.query.internal.aggregate.AvgBucketNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.AvgDistinct;
+import com.gemstone.gemfire.cache.query.internal.aggregate.AvgDistinctPRQueryNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.AvgPRQueryNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.Count;
+import com.gemstone.gemfire.cache.query.internal.aggregate.CountDistinct;
+import com.gemstone.gemfire.cache.query.internal.aggregate.CountDistinctPRQueryNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.SumDistinctPRQueryNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.CountPRQueryNode;
+import com.gemstone.gemfire.cache.query.internal.aggregate.DistinctAggregator;
+import com.gemstone.gemfire.cache.query.internal.aggregate.MaxMin;
+import com.gemstone.gemfire.cache.query.internal.aggregate.Avg;
+import com.gemstone.gemfire.cache.query.internal.aggregate.Sum;
+import com.gemstone.gemfire.cache.query.internal.aggregate.SumDistinct;
+import com.gemstone.gemfire.cache.query.internal.parse.OQLLexerTokenTypes;
+import com.gemstone.gemfire.cache.query.internal.types.ObjectTypeImpl;
+import com.gemstone.gemfire.cache.query.types.ObjectType;
+
+/**
+ * 
+ * @author ashahid
+ *
+ */
+public class CompiledAggregateFunction extends AbstractCompiledValue {
+
+  private final CompiledValue expr;
+  private final int aggFuncType;
+  private final boolean distinctOnly;
+
+  public CompiledAggregateFunction(CompiledValue expr, int aggFunc) {
+    this(expr, aggFunc, false);
+  }
+
+  public CompiledAggregateFunction(CompiledValue expr, int aggFunc,
+      boolean distinctOnly) {
+    this.expr = expr;
+    this.aggFuncType = aggFunc;
+    this.distinctOnly = distinctOnly;
+  }
+
+  @Override
+  public int getType() {
+
+    return AGG_FUNC;
+  }
+
+  @Override
+  public Object evaluate(ExecutionContext context)
+      throws FunctionDomainException, TypeMismatchException,
+      NameResolutionException, QueryInvocationTargetException {
+    boolean isPRQueryNode = context.getIsPRQueryNode();
+    boolean isBucketNode = context.getBucketList() != null;
+    switch (this.aggFuncType) {
+
+    case OQLLexerTokenTypes.SUM:
+      if (isPRQueryNode) {
+        return this.distinctOnly ? new SumDistinctPRQueryNode() : new Sum();
+      } else {
+        return this.distinctOnly ? (isBucketNode ? new DistinctAggregator()
+            : new SumDistinct()) : new Sum();
+      }
+
+    case OQLLexerTokenTypes.MAX:
+      return new MaxMin(true);
+
+    case OQLLexerTokenTypes.MIN:
+      return new MaxMin(false);
+
+    case OQLLexerTokenTypes.AVG:
+      if (isPRQueryNode) {
+        return this.distinctOnly ? new AvgDistinctPRQueryNode()
+            : new AvgPRQueryNode();
+      } else {
+        return this.distinctOnly ? (isBucketNode ? new DistinctAggregator()
+            : new AvgDistinct()) : (isBucketNode ? new AvgBucketNode()
+            : new Avg());
+      }
+
+    case OQLLexerTokenTypes.COUNT:
+      if (isPRQueryNode) {
+        return this.distinctOnly ? new CountDistinctPRQueryNode()
+            : new CountPRQueryNode();
+      } else {
+        return this.distinctOnly ? (isBucketNode ? new DistinctAggregator()
+            : new CountDistinct()) : new Count();
+      }
+
+    default:
+      throw new UnsupportedOperationException(
+          "Aggregate function not implemented");
+
+    }
+
+  }
+
+  private String getStringRep() {
+    switch (this.aggFuncType) {
+
+    case OQLLexerTokenTypes.SUM:
+      return "sum";
+
+    case OQLLexerTokenTypes.MAX:
+      return "max";
+
+    case OQLLexerTokenTypes.MIN:
+      return "min";
+
+    case OQLLexerTokenTypes.AVG:
+      return "avg";
+    case OQLLexerTokenTypes.COUNT:
+      return "count";
+    default:
+      throw new UnsupportedOperationException(
+          "Aggregate function not implemented");
+
+    }
+  }
+
+  public int getFunctionType() {
+    return this.aggFuncType;
+  }
+
+  public CompiledValue getParameter() {
+    return this.expr;
+  }
+
+  public ObjectType getObjectType() {
+    switch (this.aggFuncType) {
+
+    case OQLLexerTokenTypes.SUM:
+    case OQLLexerTokenTypes.MAX:
+    case OQLLexerTokenTypes.MIN:
+    case OQLLexerTokenTypes.AVG:
+      return new ObjectTypeImpl(Number.class);
+
+    case OQLLexerTokenTypes.COUNT:
+      return new ObjectTypeImpl(Integer.class);
+
+    default:
+      throw new UnsupportedOperationException(
+          "Aggregate function not implemented");
+
+    }
+  }
+
+  @Override
+  public void generateCanonicalizedExpression(StringBuffer clauseBuffer,
+      ExecutionContext context) throws AmbiguousNameException,
+      TypeMismatchException, NameResolutionException {
+    clauseBuffer.insert(0, ')');
+    if (this.expr != null) {
+      this.expr.generateCanonicalizedExpression(clauseBuffer, context);
+    } else {
+      clauseBuffer.insert(0, '*');
+    }
+    if (this.distinctOnly) {
+      clauseBuffer.insert(0, "distinct ");
+    }
+    clauseBuffer.insert(0, '(');
+    clauseBuffer.insert(0, getStringRep());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledBindArgument.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledBindArgument.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledBindArgument.java
index 4cd1989..46123bc 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledBindArgument.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledBindArgument.java
@@ -41,16 +41,19 @@ public class CompiledBindArgument extends AbstractCompiledValue {
   public void generateCanonicalizedExpression(StringBuffer clauseBuffer,
       ExecutionContext context) throws AmbiguousNameException,
       TypeMismatchException, NameResolutionException {
-    Object rgn;
-    if ((rgn = context.getBindArgument(this.index)) instanceof Region) {
-      clauseBuffer.insert(0, ((Region)rgn).getFullPath());
-    }
-    else {
-      super.generateCanonicalizedExpression(clauseBuffer, context);
+
+    Object bindArg;
+    if (context.isBindArgsSet() && (bindArg = context.getBindArgument(this.index)) instanceof Region ) {
+      clauseBuffer.insert(0, ((Region) bindArg).getFullPath());
+    }else {
+      clauseBuffer.insert(0, "$" + this.index);      
     }
   }
     
     public Object evaluate(ExecutionContext context) {
+      if(!context.isBindArgsSet()) {
+        return null;
+      }
       Object obj = context.getBindArgument(this.index);
       // check for BucketRegion substitution
       if (obj instanceof Region) {

http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/31d1b20e/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledComparison.java
----------------------------------------------------------------------
diff --git a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledComparison.java b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledComparison.java
index f309a9b..d7d382d 100644
--- a/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledComparison.java
+++ b/gemfire-core/src/main/java/com/gemstone/gemfire/cache/query/internal/CompiledComparison.java
@@ -8,7 +8,9 @@
  */
 package com.gemstone.gemfire.cache.query.internal;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
 
 import com.gemstone.gemfire.cache.Region;
 import com.gemstone.gemfire.cache.query.AmbiguousNameException;
@@ -18,6 +20,7 @@ import com.gemstone.gemfire.cache.query.NameResolutionException;
 import com.gemstone.gemfire.cache.query.QueryInvocationTargetException;
 import com.gemstone.gemfire.cache.query.QueryService;
 import com.gemstone.gemfire.cache.query.SelectResults;
+import com.gemstone.gemfire.cache.query.Struct;
 import com.gemstone.gemfire.cache.query.TypeMismatchException;
 import com.gemstone.gemfire.cache.query.internal.index.IndexData;
 import com.gemstone.gemfire.cache.query.internal.index.IndexProtocol;
@@ -27,6 +30,7 @@ import com.gemstone.gemfire.cache.query.internal.types.StructTypeImpl;
 import com.gemstone.gemfire.cache.query.internal.types.TypeUtils;
 import com.gemstone.gemfire.cache.query.types.ObjectType;
 import com.gemstone.gemfire.cache.query.types.StructType;
+import com.gemstone.gemfire.internal.offheap.annotations.Retained;
 import com.gemstone.gemfire.pdx.PdxInstance;
 import com.gemstone.gemfire.pdx.internal.PdxString;
 
@@ -143,7 +147,7 @@ public class CompiledComparison extends AbstractCompiledValue implements
   @Override
   public SelectResults filterEvaluate(ExecutionContext context,
       SelectResults intermediateResults, boolean completeExpansionNeeded,
-      CompiledValue iterOperands, RuntimeIterator[] indpndntItrs, boolean isIntersection, boolean conditioningNeeded, boolean evaluateProjection)
+      @Retained CompiledValue iterOperands, RuntimeIterator[] indpndntItrs, boolean isIntersection, boolean conditioningNeeded, boolean evaluateProjection)
       throws FunctionDomainException, TypeMismatchException,
       NameResolutionException, QueryInvocationTargetException {
     // see if we're dependent on the current iterator
@@ -324,7 +328,7 @@ public class CompiledComparison extends AbstractCompiledValue implements
   // Invariant: the receiver is dependent on the current iterator.
   private SelectResults singleBaseCollectionFilterEvaluate(
       ExecutionContext context,  SelectResults intermediateResults,
-      final boolean completeExpansionNeeded, CompiledValue iterOperands,
+      final boolean completeExpansionNeeded, @Retained CompiledValue iterOperands,
       IndexInfo indexInfo, RuntimeIterator[] indpndntItr, boolean isIntersection, boolean conditioningNeeded, boolean evaluateProj)
       throws TypeMismatchException, AmbiguousNameException,
       FunctionDomainException, NameResolutionException,
@@ -374,11 +378,13 @@ public class CompiledComparison extends AbstractCompiledValue implements
       // we get the right idea. Also right now we will assume that only single
       // iterator cases will be candidates for this oprtmization.
       // dependent iterators will come later.
-      boolean useLinkedSet = false;      
+      boolean useLinkedDataStructure = false;  
+      boolean nullValuesAtStart = true;
       Boolean orderByClause = (Boolean)context.cacheGet(CompiledValue.CAN_APPLY_ORDER_BY_AT_INDEX);
       if(orderByClause != null && orderByClause.booleanValue()) {
         List orderByAttrs = (List)context.cacheGet(CompiledValue.ORDERBY_ATTRIB);        
-        useLinkedSet =orderByAttrs.size()==1; 
+        useLinkedDataStructure =orderByAttrs.size()==1;
+        nullValuesAtStart = !((CompiledSortCriterion)orderByAttrs.get(0)).getCriterion();
       }
       // ////////////////////////////////////////////////////////////////
       if (!conditioningNeeded) {
@@ -395,11 +401,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
             context.getCache().getLogger().fine(
                 "StructType resultType.class="
                     + resultType.getClass().getName());
-            if(useLinkedSet) {
-              set = new LinkedStructSet((StructTypeImpl)resultType);
+            if(useLinkedDataStructure) {
+              set = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType) 
+              : new SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
             }else {
-            set = new StructBag((StructTypeImpl)resultType,
-                context.getCachePerfStats());
+              set = QueryUtils.createStructCollection(context, (StructTypeImpl)resultType) ;
             }
             indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
           }
@@ -407,10 +413,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
             context.getCache().getLogger().fine(
                 "non-StructType resultType.class="
                     + resultType.getClass().getName());
-            if (useLinkedSet) {
-              set = new LinkedResultSet(resultType);
+            if (useLinkedDataStructure) {
+              set = context.isDistinct() ? new LinkedResultSet(resultType) :
+                new SortedResultsBag(resultType, nullValuesAtStart) ;
             } else {
-              set = new ResultsBag(resultType, context.getCachePerfStats());
+              set = QueryUtils.createResultCollection(context, resultType) ;
             }
             indexFieldsSize = 1;
           }
@@ -427,11 +434,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
               context.getCache().getLogger().fine(
                   "StructType resultType.class="
                       + resultType.getClass().getName());
-              if(useLinkedSet) {
-                set = new LinkedStructSet((StructTypeImpl)resultType);
+              if(useLinkedDataStructure) {
+                set = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType) 
+                : new  SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
               }else {
-                set = new StructBag((StructTypeImpl)resultType,
-                  context.getCachePerfStats());
+                set = QueryUtils.createStructCollection(context,(StructTypeImpl)resultType) ;
               }
               indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
             }
@@ -439,10 +446,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
               context.getCache().getLogger().fine(
                   "non-StructType resultType.class="
                       + resultType.getClass().getName());
-              if (useLinkedSet) {
-                set = new LinkedResultSet(resultType); 
+              if (useLinkedDataStructure) {
+                set = context.isDistinct() ? new LinkedResultSet(resultType) : 
+                  new SortedResultsBag(resultType, nullValuesAtStart ); 
               } else {
-                set = new ResultsBag(resultType, context.getCachePerfStats());
+                set = QueryUtils.createResultCollection(context, resultType) ;
               }
               indexFieldsSize = 1;
             }
@@ -458,11 +466,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
         if (resultType instanceof StructType) {
           context.getCache().getLogger().fine(
               "StructType resultType.class=" + resultType.getClass().getName());
-          if (useLinkedSet) {
-            set = new LinkedStructSet((StructTypeImpl)resultType);
+          if (useLinkedDataStructure) {
+            set = context.isDistinct() ? new LinkedStructSet((StructTypeImpl)resultType) 
+            : new SortedResultsBag<Struct>((StructTypeImpl)resultType, nullValuesAtStart);
           } else {
-            set = (SelectResults)new StructBag((StructTypeImpl)resultType,
-                context.getCachePerfStats());
+            set = QueryUtils.createStructCollection(context, (StructTypeImpl)resultType) ;
           }
           
           indexFieldsSize = ((StructTypeImpl)resultType).getFieldNames().length;
@@ -471,10 +479,11 @@ public class CompiledComparison extends AbstractCompiledValue implements
           context.getCache().getLogger().fine(
               "non-StructType resultType.class="
                   + resultType.getClass().getName());
-          if (useLinkedSet) {
-            set = new LinkedResultSet(resultType);
+          if (useLinkedDataStructure) {
+            set = context.isDistinct() ? new LinkedResultSet(resultType) :
+              new SortedResultsBag(resultType, nullValuesAtStart);
           } else {
-            set = new ResultsBag(resultType, context.getCachePerfStats());
+            set = QueryUtils.createResultCollection(context, resultType) ;
           }     
           indexFieldsSize = 1;
         }


Mime
View raw message