You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jb...@apache.org on 2016/01/12 21:47:33 UTC

svn commit: r1724319 - in /lucene/dev/trunk/solr: CHANGES.txt core/src/java/org/apache/solr/handler/SQLHandler.java core/src/test/org/apache/solr/handler/TestSQLHandler.java

Author: jbernste
Date: Tue Jan 12 20:47:33 2016
New Revision: 1724319

URL: http://svn.apache.org/viewvc?rev=1724319&view=rev
Log:
SOLR-8002: Add column alias support to the Parallel SQL Interface

Modified:
    lucene/dev/trunk/solr/CHANGES.txt
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SQLHandler.java
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java

Modified: lucene/dev/trunk/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/CHANGES.txt?rev=1724319&r1=1724318&r2=1724319&view=diff
==============================================================================
--- lucene/dev/trunk/solr/CHANGES.txt (original)
+++ lucene/dev/trunk/solr/CHANGES.txt Tue Jan 12 20:47:33 2016
@@ -130,6 +130,9 @@ New Features
 * SOLR-8479: Add JDBCStream to Streaming API and Streaming Expressions for integration with external data sources
   (Dennis Gove)
 
+* SOLR-8002: Add column alias support to the Parallel SQL Interface (Joel Bernstein)
+
+
 Bug Fixes
 ----------------------
 * SOLR-8386: Add field option in the new admin UI schema page loads up even when no schemaFactory has been

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SQLHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SQLHandler.java?rev=1724319&r1=1724318&r2=1724319&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SQLHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/handler/SQLHandler.java Tue Jan 12 20:47:33 2016
@@ -149,6 +149,7 @@ public class SQLHandler extends RequestH
       SQLVisitor sqlVistor = new SQLVisitor(new StringBuilder());
 
       sqlVistor.process(statement, new Integer(0));
+      sqlVistor.reverseAliases();
 
       TupleStream sqlStream = null;
 
@@ -234,13 +235,13 @@ public class SQLHandler extends RequestH
     // Once we make this a Expressionable the problem will be solved.
 
     if(sqlVisitor.havingExpression != null) {
-      tupleStream = new HavingStream(tupleStream, sqlVisitor.havingExpression);
+      tupleStream = new HavingStream(tupleStream, sqlVisitor.havingExpression, sqlVisitor.reverseColumnAliases );
     }
 
     if(sqlVisitor.sorts != null && sqlVisitor.sorts.size() > 0) {
-      if(!sortsEqual(buckets, sortDirection, sqlVisitor.sorts)) {
+      if(!sortsEqual(buckets, sortDirection, sqlVisitor.sorts, sqlVisitor.reverseColumnAliases)) {
         int limit = sqlVisitor.limit == -1 ? 100 : sqlVisitor.limit;
-        StreamComparator comp = getComp(sqlVisitor.sorts);
+        StreamComparator comp = getComp(sqlVisitor.sorts, sqlVisitor.reverseColumnAliases);
         //Rank the Tuples
         //If parallel stream is used ALL the Rolled up tuples from the workers will be ranked
         //Providing a true Top or Bottom.
@@ -254,6 +255,10 @@ public class SQLHandler extends RequestH
       }
     }
 
+    if(sqlVisitor.hasColumnAliases) {
+      tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases);
+    }
+
     return tupleStream;
   }
 
@@ -277,7 +282,7 @@ public class SQLHandler extends RequestH
     StreamComparator comp = null;
 
     if(sqlVisitor.sorts != null && sqlVisitor.sorts.size() > 0) {
-      StreamComparator[] adjustedSorts = adjustSorts(sqlVisitor.sorts, buckets);
+      StreamComparator[] adjustedSorts = adjustSorts(sqlVisitor.sorts, buckets, sqlVisitor.reverseColumnAliases);
         // Because of the way adjustSorts works we know that each FieldComparator has a single
         // field name. For this reason we can just look at the leftFieldName
       FieldEqualitor[] fieldEqualitors = new FieldEqualitor[adjustedSorts.length];
@@ -364,18 +369,22 @@ public class SQLHandler extends RequestH
       tupleStream = new LimitStream(tupleStream, sqlVisitor.limit);
     }
 
+    if(sqlVisitor.hasColumnAliases) {
+      tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases);
+    }
+
     return tupleStream;
   }
 
-  private static StreamComparator[] adjustSorts(List<SortItem> sorts, Bucket[] buckets) throws IOException {
+  private static StreamComparator[] adjustSorts(List<SortItem> sorts, Bucket[] buckets, Map<String, String> reverseColumnAliases) throws IOException {
     List<FieldComparator> adjustedSorts = new ArrayList();
     Set<String> bucketFields = new HashSet();
     Set<String> sortFields = new HashSet();
 
     for(SortItem sortItem : sorts) {
 
-      sortFields.add(getSortField(sortItem));
-      adjustedSorts.add(new FieldComparator(getSortField(sortItem),
+      sortFields.add(getSortField(sortItem, reverseColumnAliases));
+      adjustedSorts.add(new FieldComparator(getSortField(sortItem, reverseColumnAliases),
                                             ascDescComp(sortItem.getOrdering().toString())));
     }
 
@@ -384,7 +393,7 @@ public class SQLHandler extends RequestH
     }
 
     for(SortItem sortItem : sorts) {
-      String sortField = getSortField(sortItem);
+      String sortField = getSortField(sortItem, reverseColumnAliases);
       if(!bucketFields.contains(sortField)) {
         throw new IOException("All sort fields must be in the field list.");
       }
@@ -431,7 +440,7 @@ public class SQLHandler extends RequestH
         sorts[i] = new FieldComparator("index", ComparatorOrder.ASCENDING);
       }
     } else {
-      StreamComparator[] comps = adjustSorts(sqlVisitor.sorts, buckets);
+      StreamComparator[] comps = adjustSorts(sqlVisitor.sorts, buckets, sqlVisitor.reverseColumnAliases);
       sorts = new FieldComparator[comps.length];
       for(int i=0; i<comps.length; i++) {
         sorts[i] = (FieldComparator)comps[i];
@@ -450,7 +459,7 @@ public class SQLHandler extends RequestH
       tupleStream = new LimitStream(tupleStream, sqlVisitor.limit);
     }
 
-    return new SelectStream(tupleStream, sqlVisitor.fields);
+    return new SelectStream(tupleStream, sqlVisitor.columnAliases);
   }
 
   private static TupleStream doGroupByWithAggregatesFacets(SQLVisitor sqlVisitor) throws IOException {
@@ -480,7 +489,7 @@ public class SQLHandler extends RequestH
         sorts[i] = new FieldComparator("index", ComparatorOrder.ASCENDING);
       }
     } else {
-      sorts = getComps(sqlVisitor.sorts);
+      sorts = getComps(sqlVisitor.sorts, sqlVisitor.reverseColumnAliases);
     }
 
     TupleStream tupleStream = new FacetStream(zkHost,
@@ -492,7 +501,7 @@ public class SQLHandler extends RequestH
                                               limit);
 
     if(sqlVisitor.havingExpression != null) {
-      tupleStream = new HavingStream(tupleStream, sqlVisitor.havingExpression);
+      tupleStream = new HavingStream(tupleStream, sqlVisitor.havingExpression, sqlVisitor.reverseColumnAliases);
     }
 
     if(sqlVisitor.limit > 0)
@@ -500,6 +509,10 @@ public class SQLHandler extends RequestH
       tupleStream = new LimitStream(tupleStream, sqlVisitor.limit);
     }
 
+    if(sqlVisitor.hasColumnAliases) {
+      tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases);
+    }
+
     return tupleStream;
   }
 
@@ -559,7 +572,7 @@ public class SQLHandler extends RequestH
         if (comma) {
           siBuf.append(",");
         }
-        siBuf.append(getSortField(sortItem) + " " + ascDesc(sortItem.getOrdering().toString()));
+        siBuf.append(getSortField(sortItem, sqlVisitor.reverseColumnAliases) + " " + ascDesc(sortItem.getOrdering().toString()));
       }
     } else {
       if(sqlVisitor.limit < 0) {
@@ -585,17 +598,25 @@ public class SQLHandler extends RequestH
       params.put("sort", siBuf.toString());
     }
 
+    TupleStream tupleStream = null;
+
     if(sqlVisitor.limit > -1) {
       params.put("rows", Integer.toString(sqlVisitor.limit));
-      return new LimitStream(new CloudSolrStream(zkHost, collection, params), sqlVisitor.limit);
+      tupleStream = new LimitStream(new CloudSolrStream(zkHost, collection, params), sqlVisitor.limit);
     } else {
       //Only use the export handler when no limit is specified.
       params.put(CommonParams.QT, "/export");
-      return new CloudSolrStream(zkHost, collection, params);
+      tupleStream = new CloudSolrStream(zkHost, collection, params);
+    }
+
+    if(sqlVisitor.hasColumnAliases) {
+      return new SelectStream(tupleStream, sqlVisitor.columnAliases);
+    } else {
+      return tupleStream;
     }
   }
 
-  private static boolean sortsEqual(Bucket[] buckets, String direction, List<SortItem> sortItems) {
+  private static boolean sortsEqual(Bucket[] buckets, String direction, List<SortItem> sortItems, Map<String, String> reverseColumnAliases) {
     if(buckets.length != sortItems.size()) {
       return false;
     }
@@ -603,7 +624,7 @@ public class SQLHandler extends RequestH
     for(int i=0; i< buckets.length; i++) {
       Bucket bucket = buckets[i];
       SortItem sortItem = sortItems.get(i);
-      if(!bucket.toString().equals(getSortField(sortItem))) {
+      if(!bucket.toString().equals(getSortField(sortItem, reverseColumnAliases))) {
         return false;
       }
 
@@ -635,6 +656,10 @@ public class SQLHandler extends RequestH
                                               params,
                                               metrics);
 
+    if(sqlVisitor.hasColumnAliases) {
+      tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases);
+    }
+
     return tupleStream;
   }
 
@@ -690,13 +715,13 @@ public class SQLHandler extends RequestH
     }
   }
 
-  private static StreamComparator getComp(List<SortItem> sortItems) {
+  private static StreamComparator getComp(List<SortItem> sortItems, Map<String, String> reverseColumnAliases) {
     FieldComparator[] comps = new FieldComparator[sortItems.size()];
     for(int i=0; i<sortItems.size(); i++) {
       SortItem sortItem = sortItems.get(i);
       String ordering = sortItem.getOrdering().toString();
       ComparatorOrder comparatorOrder = ascDescComp(ordering);
-      String sortKey = getSortField(sortItem);
+      String sortKey = getSortField(sortItem, reverseColumnAliases);
       comps[i] = new FieldComparator(sortKey, comparatorOrder);
     }
 
@@ -707,13 +732,13 @@ public class SQLHandler extends RequestH
     }
   }
 
-  private static FieldComparator[] getComps(List<SortItem> sortItems) {
+  private static FieldComparator[] getComps(List<SortItem> sortItems, Map<String, String> reverseColumnAliases) {
     FieldComparator[] comps = new FieldComparator[sortItems.size()];
     for(int i=0; i<sortItems.size(); i++) {
       SortItem sortItem = sortItems.get(i);
       String ordering = sortItem.getOrdering().toString();
       ComparatorOrder comparatorOrder = ascDescComp(ordering);
-      String sortKey = getSortField(sortItem);
+      String sortKey = getSortField(sortItem, reverseColumnAliases);
       comps[i] = new FieldComparator(sortKey, comparatorOrder);
     }
 
@@ -884,6 +909,9 @@ public class SQLHandler extends RequestH
     public boolean groupByQuery;
     public Expression havingExpression;
     public boolean isDistinct;
+    public boolean hasColumnAliases;
+    public Map<String, String> columnAliases = new HashMap();
+    public Map<String, String> reverseColumnAliases = new HashMap();
 
     public SQLVisitor(StringBuilder builder) {
       this.builder = builder;
@@ -893,6 +921,28 @@ public class SQLHandler extends RequestH
       throw new UnsupportedOperationException("not yet implemented: " + node);
     }
 
+    protected void reverseAliases() {
+      for(String key : columnAliases.keySet()) {
+        reverseColumnAliases.put(columnAliases.get(key), key);
+      }
+
+      //Handle the group by.
+      List<String> newGroups = new ArrayList();
+
+      for(String g : groupBy) {
+        if (reverseColumnAliases.containsKey(g)) {
+          newGroups.add(reverseColumnAliases.get(g));
+        } else {
+          newGroups.add(g);
+        }
+      }
+
+      groupBy = newGroups;
+    }
+
+
+
+
     protected Void visitUnnest(Unnest node, Integer indent) {
       return null;
     }
@@ -966,8 +1016,6 @@ public class SQLHandler extends RequestH
       return null;
     }
 
-
-
     protected Void visitComparisonExpression(ComparisonExpression node, Integer index) {
       String field = node.getLeft().toString();
       String value = node.getRight().toString();
@@ -1029,6 +1077,11 @@ public class SQLHandler extends RequestH
       fields.add(field);
 
       if(node.getAlias().isPresent()) {
+        String alias = node.getAlias().get();
+        columnAliases.put(field, alias);
+        hasColumnAliases = true;
+      } else {
+        columnAliases.put(field, field);
       }
 
       return null;
@@ -1078,7 +1131,7 @@ public class SQLHandler extends RequestH
     }
   }
 
-  private static String getSortField(SortItem sortItem)
+  private static String getSortField(SortItem sortItem, Map<String, String> reverseColumnAliases)
   {
     String field;
     Expression ex = sortItem.getSortKey();
@@ -1105,6 +1158,10 @@ public class SQLHandler extends RequestH
       field = stripSingleQuotes(stringLiteral.toString());
     }
 
+    if(reverseColumnAliases.containsKey(field)) {
+      field = reverseColumnAliases.get(field);
+    }
+
     return field;
   }
 
@@ -1238,9 +1295,9 @@ public class SQLHandler extends RequestH
     private HavingVisitor havingVisitor;
     private Expression havingExpression;
 
-    public HavingStream(TupleStream stream, Expression havingExpression) {
+    public HavingStream(TupleStream stream, Expression havingExpression, Map<String, String> reverseAliasMap) {
       this.stream = stream;
-      this.havingVisitor = new HavingVisitor();
+      this.havingVisitor = new HavingVisitor(reverseAliasMap);
       this.havingExpression = havingExpression;
     }
 
@@ -1282,6 +1339,12 @@ public class SQLHandler extends RequestH
 
   private static class HavingVisitor extends AstVisitor<Boolean, Tuple> {
 
+    private Map<String,String> reverseAliasMap;
+
+    public HavingVisitor(Map<String, String> reverseAliasMap) {
+      this.reverseAliasMap = reverseAliasMap;
+    }
+
     protected Boolean visitLogicalBinaryExpression(LogicalBinaryExpression node, Tuple tuple) {
 
       Boolean b = process(node.getLeft(), tuple);
@@ -1304,6 +1367,11 @@ public class SQLHandler extends RequestH
 
     protected Boolean visitComparisonExpression(ComparisonExpression node, Tuple tuple) {
       String field = getHavingField(node.getLeft());
+
+      if(reverseAliasMap.containsKey(field)) {
+        field = reverseAliasMap.get(field);
+      }
+
       double d = Double.parseDouble(node.getRight().toString());
       double td = tuple.getDouble(field);
       ComparisonExpression.Type t = node.getType();

Modified: lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java?rev=1724319&r1=1724318&r2=1724319&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java (original)
+++ lucene/dev/trunk/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java Tue Jan 12 20:47:33 2016
@@ -320,6 +320,56 @@ public class TestSQLHandler extends Abst
       assert(tuple.getLong("field_i") == 7);
       assert(tuple.get("str_s").equals("a"));
 
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select id as myId, field_i as myInt, str_s as myString from collection1 where text='XXXX' AND id='(1 2 3)' order by myInt desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      assert(tuples.size() == 3);
+
+      tuple = tuples.get(0);
+      assert(tuple.getLong("myId") == 3);
+      assert(tuple.getLong("myInt") == 20);
+      assert(tuple.get("myString").equals("a"));
+
+      tuple = tuples.get(1);
+      assert(tuple.getLong("myId") == 2);
+      assert(tuple.getLong("myInt") == 8);
+      assert(tuple.get("myString").equals("b"));
+
+      tuple = tuples.get(2);
+      assert(tuple.getLong("myId") == 1);
+      assert(tuple.getLong("myInt") == 7);
+      assert(tuple.get("myString").equals("a"));
+
+
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select id as myId, field_i as myInt, str_s as myString from collection1 where text='XXXX' AND id='(1 2 3)' order by field_i desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      assert(tuples.size() == 3);
+
+      tuple = tuples.get(0);
+      assert(tuple.getLong("myId") == 3);
+      assert(tuple.getLong("myInt") == 20);
+      assert(tuple.get("myString").equals("a"));
+
+      tuple = tuples.get(1);
+      assert(tuple.getLong("myId") == 2);
+      assert(tuple.getLong("myInt") == 8);
+      assert(tuple.get("myString").equals("b"));
+
+      tuple = tuples.get(2);
+      assert(tuple.getLong("myId") == 1);
+      assert(tuple.getLong("myInt") == 7);
+      assert(tuple.get("myString").equals("a"));
+
+
     } finally {
       delete();
     }
@@ -559,6 +609,33 @@ public class TestSQLHandler extends Abst
       assert(tuple.getDouble("max(field_i)") == 20);
       assert(tuple.getDouble("avg(field_i)") == 13.5D);
 
+
+      params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select str_s as myString, 'count(*)', sum('field_i') as sum, min(field_i), max(field_i), avg(field_i) from collection1 where text='XXXX' group by 'str_s' order by sum asc limit 2");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      //Only two results because of the limit.
+      assert(tuples.size() == 2);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 19);
+      assert(tuple.getDouble("min(field_i)") == 8);
+      assert(tuple.getDouble("max(field_i)") == 11);
+      assert(tuple.getDouble("avg(field_i)") == 9.5D);
+
+      tuple = tuples.get(1);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 27);
+      assert(tuple.getDouble("min(field_i)") == 7);
+      assert(tuple.getDouble("max(field_i)") == 20);
+      assert(tuple.getDouble("avg(field_i)") == 13.5D);
+
+
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
       params.put("stmt", "select str_s, count(*), sum(field_i), min(field_i), max(field_i), avg(field_i) from collection1 where (text='XXXX' AND NOT text='XXXX XXX') group by str_s order by str_s desc");
@@ -598,6 +675,44 @@ public class TestSQLHandler extends Abst
 
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select str_s as myString, count(*) as count, sum(field_i) as sum, min(field_i) as min, max(field_i) as max, avg(field_i) as avg from collection1 where (text='XXXX' AND NOT text='XXXX XXX') group by str_s order by str_s desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      //The sort by and order by match and no limit is applied. All the Tuples should be returned in
+      //this scenario.
+
+      assert(tuples.size() == 3);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getDouble("count") == 4);
+      assert(tuple.getDouble("sum") == 180);
+      assert(tuple.getDouble("min") == 30);
+      assert(tuple.getDouble("max") == 60);
+      assert(tuple.getDouble("avg") == 45);
+
+      tuple = tuples.get(1);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getDouble("count") == 2);
+      assert(tuple.getDouble("sum") == 19);
+      assert(tuple.getDouble("min") == 8);
+      assert(tuple.getDouble("max") == 11);
+      assert(tuple.getDouble("avg") == 9.5D);
+
+      tuple = tuples.get(2);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getDouble("count") == 2);
+      assert(tuple.getDouble("sum") == 27);
+      assert(tuple.getDouble("min") == 7);
+      assert(tuple.getDouble("max") == 20);
+      assert(tuple.getDouble("avg") == 13.5D);
+
+
+
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
       params.put("stmt", "select str_s, count(*), sum(field_i), min(field_i), max(field_i), avg(field_i) from collection1 where text='XXXX' group by str_s having sum(field_i) = 19");
 
       solrStream = new SolrStream(jetty.url, params);
@@ -633,6 +748,25 @@ public class TestSQLHandler extends Abst
 
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select str_s as myString, count(*), sum(field_i) as sum, min(field_i), max(field_i), avg(field_i) from collection1 where text='XXXX' group by myString having ((sum = 19) AND (min(field_i) = 8))");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      //Only two results because of the limit.
+      assert(tuples.size() == 1);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 19);
+      assert(tuple.getDouble("min(field_i)") == 8);
+      assert(tuple.getDouble("max(field_i)") == 11);
+      assert(tuple.getDouble("avg(field_i)") == 9.5D);
+
+
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
       params.put("stmt", "select str_s, count(*), sum(field_i), min(field_i), max(field_i), avg(field_i) from collection1 where text='XXXX' group by str_s having ((sum(field_i) = 19) AND (min(field_i) = 100))");
 
       solrStream = new SolrStream(jetty.url, params);
@@ -740,6 +874,43 @@ public class TestSQLHandler extends Abst
       assert(tuple.getLong("field_i") == 1);
 
 
+      //reverse the sort
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("aggregationMode", "facet");
+      params.put("stmt", "select distinct str_s as myString, field_i as myInt from collection1 order by str_s desc, myInt desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      assert(tuples.size() == 6);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("myInt") == 60);
+
+      tuple = tuples.get(1);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("myInt") == 50);
+
+
+      tuple = tuples.get(2);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("myInt") == 30);
+
+      tuple = tuples.get(3);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getLong("myInt") == 2);
+
+
+      tuple = tuples.get(4);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getLong("myInt") == 20);
+
+      tuple = tuples.get(5);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getLong("myInt") == 1);
+
       //test with limit
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
@@ -915,6 +1086,42 @@ public class TestSQLHandler extends Abst
       assert(tuple.getLong("field_i") == 1);
 
 
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("stmt", "select distinct str_s as myString, field_i from collection1 order by myString desc, field_i desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      assert(tuples.size() == 6);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("field_i") == 60);
+
+      tuple = tuples.get(1);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("field_i") == 50);
+
+
+      tuple = tuples.get(2);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getLong("field_i") == 30);
+
+      tuple = tuples.get(3);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getLong("field_i") == 2);
+
+
+      tuple = tuples.get(4);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getLong("field_i") == 20);
+
+      tuple = tuples.get(5);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getLong("field_i") == 1);
+
+
       //test with limit
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
@@ -1254,6 +1461,45 @@ public class TestSQLHandler extends Abst
       assert(tuple.getDouble("max(field_i)") == 20);
       assert(tuple.getDouble("avg(field_i)") == 13.5D);
 
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("aggregationMode", "facet");
+      params.put("stmt", "select str_s as myString, count(*), sum(field_i) as sum, min(field_i), max(field_i), avg(field_i) from collection1 where (text='XXXX' AND NOT text='XXXX XXX') group by myString order by myString desc");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      //The sort by and order by match and no limit is applied. All the Tuples should be returned in
+      //this scenario.
+
+      assert(tuples.size() == 3);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("c"));
+      assert(tuple.getDouble("count(*)") == 4);
+      assert(tuple.getDouble("sum") == 180);
+      assert(tuple.getDouble("min(field_i)") == 30);
+      assert(tuple.getDouble("max(field_i)") == 60);
+      assert(tuple.getDouble("avg(field_i)") == 45);
+
+      tuple = tuples.get(1);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 19);
+      assert(tuple.getDouble("min(field_i)") == 8);
+      assert(tuple.getDouble("max(field_i)") == 11);
+      assert(tuple.getDouble("avg(field_i)") == 9.5D);
+
+      tuple = tuples.get(2);
+      assert(tuple.get("myString").equals("a"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 27);
+      assert(tuple.getDouble("min(field_i)") == 7);
+      assert(tuple.getDouble("max(field_i)") == 20);
+      assert(tuple.getDouble("avg(field_i)") == 13.5D);
+
+
+
 
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
@@ -1292,6 +1538,26 @@ public class TestSQLHandler extends Abst
       assert(tuple.getDouble("max(field_i)") == 11);
       assert(tuple.getDouble("avg(field_i)") == 9.5D);
 
+
+      params = new HashMap();
+      params.put(CommonParams.QT, "/sql");
+      params.put("aggregationMode", "facet");
+      params.put("stmt", "select str_s myString, count(*), sum(field_i) as sum, min(field_i), max(field_i), avg(field_i) from collection1 where text='XXXX' group by myString having ((sum = 19) AND (min(field_i) = 8))");
+
+      solrStream = new SolrStream(jetty.url, params);
+      tuples = getTuples(solrStream);
+
+      //Only two results because of the limit.
+      assert(tuples.size() == 1);
+
+      tuple = tuples.get(0);
+      assert(tuple.get("myString").equals("b"));
+      assert(tuple.getDouble("count(*)") == 2);
+      assert(tuple.getDouble("sum") == 19);
+      assert(tuple.getDouble("min(field_i)") == 8);
+      assert(tuple.getDouble("max(field_i)") == 11);
+      assert(tuple.getDouble("avg(field_i)") == 9.5D);
+
       params = new HashMap();
       params.put(CommonParams.QT, "/sql");
       params.put("aggregationMode", "facet");
@@ -1516,6 +1782,45 @@ public class TestSQLHandler extends Abst
     assertTrue(count.doubleValue() == 10);
 
 
+
+    params = new HashMap();
+    params.put(CommonParams.QT, "/sql");
+    params.put("stmt", "select count(*) as count, sum(a_i) as sum, min(a_i) as min, max(a_i) as max, avg(a_i) as avg, sum(a_f), min(a_f), max(a_f), avg(a_f) from collection1");
+
+    solrStream = new SolrStream(jetty.url, params);
+
+
+    tuples = getTuples(solrStream);
+
+    assert(tuples.size() == 1);
+
+    //Test Long and Double Sums
+
+    tuple = tuples.get(0);
+
+    sumi = tuple.getDouble("sum");
+    sumf = tuple.getDouble("sum(a_f)");
+    mini = tuple.getDouble("min");
+    minf = tuple.getDouble("min(a_f)");
+    maxi = tuple.getDouble("max");
+    maxf = tuple.getDouble("max(a_f)");
+    avgi = tuple.getDouble("avg");
+    avgf = tuple.getDouble("avg(a_f)");
+    count = tuple.getDouble("count");
+
+    assertTrue(sumi.longValue() == 70);
+    assertTrue(sumf.doubleValue() == 55.0D);
+    assertTrue(mini.doubleValue() == 0.0D);
+    assertTrue(minf.doubleValue() == 1.0D);
+    assertTrue(maxi.doubleValue() == 14.0D);
+    assertTrue(maxf.doubleValue() == 10.0D);
+    assertTrue(avgi.doubleValue() == 7.0D);
+    assertTrue(avgf.doubleValue() == 5.5D);
+    assertTrue(count.doubleValue() == 10);
+
+
+
+
     // Test where clause hits
 
     params = new HashMap();