diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index ba459f24647..49544ca3a04 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -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 diff --git a/solr/core/src/java/org/apache/solr/handler/SQLHandler.java b/solr/core/src/java/org/apache/solr/handler/SQLHandler.java index 9078de421bc..a27206f8206 100644 --- a/solr/core/src/java/org/apache/solr/handler/SQLHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SQLHandler.java @@ -149,6 +149,7 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { // 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 RequestHandlerBase implements SolrCoreAware { } } + if(sqlVisitor.hasColumnAliases) { + tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases); + } + return tupleStream; } @@ -277,7 +282,7 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { tupleStream = new LimitStream(tupleStream, sqlVisitor.limit); } + if(sqlVisitor.hasColumnAliases) { + tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases); + } + return tupleStream; } - private static StreamComparator[] adjustSorts(List sorts, Bucket[] buckets) throws IOException { + private static StreamComparator[] adjustSorts(List sorts, Bucket[] buckets, Map reverseColumnAliases) throws IOException { List adjustedSorts = new ArrayList(); Set bucketFields = new HashSet(); Set 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 RequestHandlerBase implements SolrCoreAware { } 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 RequestHandlerBase implements SolrCoreAware { 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 0) @@ -500,6 +509,10 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { 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 sortItems) { + private static boolean sortsEqual(Bucket[] buckets, String direction, List sortItems, Map reverseColumnAliases) { if(buckets.length != sortItems.size()) { return false; } @@ -603,7 +624,7 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { params, metrics); + if(sqlVisitor.hasColumnAliases) { + tupleStream = new SelectStream(tupleStream, sqlVisitor.columnAliases); + } + return tupleStream; } @@ -690,13 +715,13 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { } } - private static StreamComparator getComp(List sortItems) { + private static StreamComparator getComp(List sortItems, Map reverseColumnAliases) { FieldComparator[] comps = new FieldComparator[sortItems.size()]; for(int i=0; i sortItems) { + private static FieldComparator[] getComps(List sortItems, Map reverseColumnAliases) { FieldComparator[] comps = new FieldComparator[sortItems.size()]; for(int i=0; i columnAliases = new HashMap(); + public Map reverseColumnAliases = new HashMap(); public SQLVisitor(StringBuilder builder) { this.builder = builder; @@ -893,6 +921,28 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { 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 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 RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { 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 RequestHandlerBase implements SolrCoreAware { } } - private static String getSortField(SortItem sortItem) + private static String getSortField(SortItem sortItem, Map reverseColumnAliases) { String field; Expression ex = sortItem.getSortKey(); @@ -1105,6 +1158,10 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { field = stripSingleQuotes(stringLiteral.toString()); } + if(reverseColumnAliases.containsKey(field)) { + field = reverseColumnAliases.get(field); + } + return field; } @@ -1238,9 +1295,9 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { private HavingVisitor havingVisitor; private Expression havingExpression; - public HavingStream(TupleStream stream, Expression havingExpression) { + public HavingStream(TupleStream stream, Expression havingExpression, Map reverseAliasMap) { this.stream = stream; - this.havingVisitor = new HavingVisitor(); + this.havingVisitor = new HavingVisitor(reverseAliasMap); this.havingExpression = havingExpression; } @@ -1282,6 +1339,12 @@ public class SQLHandler extends RequestHandlerBase implements SolrCoreAware { private static class HavingVisitor extends AstVisitor { + private Map reverseAliasMap; + + public HavingVisitor(Map 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 RequestHandlerBase implements SolrCoreAware { 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(); diff --git a/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java b/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java index d5c50f225c9..3811cc9428f 100644 --- a/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java +++ b/solr/core/src/test/org/apache/solr/handler/TestSQLHandler.java @@ -320,6 +320,56 @@ public class TestSQLHandler extends AbstractFullDistribZkTestBase { 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 AbstractFullDistribZkTestBase { 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"); @@ -596,6 +673,44 @@ public class TestSQLHandler extends AbstractFullDistribZkTestBase { assert(tuple.getDouble("avg(field_i)") == 13.5D); + 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"); @@ -631,6 +746,25 @@ public class TestSQLHandler extends AbstractFullDistribZkTestBase { 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 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))"); @@ -740,6 +874,43 @@ public class TestSQLHandler extends AbstractFullDistribZkTestBase { 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 AbstractFullDistribZkTestBase { 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 AbstractFullDistribZkTestBase { 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 AbstractFullDistribZkTestBase { 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 AbstractFullDistribZkTestBase { 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();