You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by xe...@apache.org on 2011/09/07 19:16:47 UTC
svn commit: r1166273 - in /cassandra/trunk: CHANGES.txt doc/cql/CQL.textile
src/java/org/apache/cassandra/cql/QueryProcessor.java test/system/test_cql.py
Author: xedin
Date: Wed Sep 7 17:16:46 2011
New Revision: 1166273
URL: http://svn.apache.org/viewvc?rev=1166273&view=rev
Log:
fix of the CQL count() behavior
patch by Jonathan Ellis and Pavel Yaskevich; reviewed by Eric Evans and Pavel Yaskevich for CASSANDRA-3068
Modified:
cassandra/trunk/CHANGES.txt
cassandra/trunk/doc/cql/CQL.textile
cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
cassandra/trunk/test/system/test_cql.py
Modified: cassandra/trunk/CHANGES.txt
URL: http://svn.apache.org/viewvc/cassandra/trunk/CHANGES.txt?rev=1166273&r1=1166272&r2=1166273&view=diff
==============================================================================
--- cassandra/trunk/CHANGES.txt (original)
+++ cassandra/trunk/CHANGES.txt Wed Sep 7 17:16:46 2011
@@ -61,7 +61,7 @@
* add ability to use multiple threads during a single compaction
(CASSANDRA-2901)
* make AbstractBounds.normalize support overlapping ranges (CASSANDRA-2641)
-
+ * fix of the CQL count() behavior (CASSANDRA-3068)
0.8.5
* fix NPE when encryption_options is unspecified (CASSANDRA-3007)
Modified: cassandra/trunk/doc/cql/CQL.textile
URL: http://svn.apache.org/viewvc/cassandra/trunk/doc/cql/CQL.textile?rev=1166273&r1=1166272&r2=1166273&view=diff
==============================================================================
--- cassandra/trunk/doc/cql/CQL.textile (original)
+++ cassandra/trunk/doc/cql/CQL.textile Wed Sep 7 17:16:46 2011
@@ -1,4 +1,4 @@
-h1. Cassandra Query Language (CQL) v1.1.1
+h1. Cassandra Query Language (CQL) v2.0
h2. Table of Contents
@@ -44,6 +44,13 @@ SELECT ... FROM <COLUMN FAMILY> ...
The @FROM@ clause is used to specify the Cassandra column family applicable to a @SELECT@ query.
+bc.
+SELECT count(*) FROM <COLUMN FAMILY> ...
+
+The @count@ aggregate function returns a single row, with a single column "count" whose value is the number of rows from the pre-aggregation resultset.
+
+Currently, @count@ is the only function supported by CQL.
+
h3. Consistency Level
bc.
@@ -373,6 +380,9 @@ Versioning of the CQL language adheres t
h1. Changes
pre.
+Thu, 07 Sep 2011 09:01:00 -0500 - Jonathan Ellis
+ * Updated version to 2.0; Documented row-based count()
+
Wed, 10 Aug 2011 11:22:00 -0500 - Eric Evans
* Improved INSERT vs. UPDATE wording.
* Documented counter column incr/descr.
Modified: cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL: http://svn.apache.org/viewvc/cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1166273&r1=1166272&r2=1166273&view=diff
==============================================================================
--- cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java (original)
+++ cassandra/trunk/src/java/org/apache/cassandra/cql/QueryProcessor.java Wed Sep 7 17:16:46 2011
@@ -320,9 +320,6 @@ public class QueryProcessor
/* Test for SELECT-specific taboos */
private static void validateSelect(String keyspace, SelectStatement select) throws InvalidRequestException
{
- if (select.isCountOperation() && (select.isKeyRange() || select.getKeys().size() < 1))
- throw new InvalidRequestException("Counts can only be performed for a single record (Hint: KEY=term)");
-
// Finish key w/o start key (KEY < foo)
if (!select.isKeyRange() && (select.getKeyFinish() != null))
throw new InvalidRequestException("Key range clauses must include a start key (i.e. KEY > term)");
@@ -530,17 +527,6 @@ public class QueryProcessor
if (!select.isKeyRange() && (select.getKeys().size() > 0))
{
rows = getSlice(keyspace, select);
-
- // Only return the column count, (of the at-most 1 row).
- if (select.isCountOperation())
- {
- result.type = CqlResultType.INT;
- if (rows.size() > 0)
- result.setNum(rows.get(0).cf != null ? rows.get(0).cf.getSortedColumns().size() : 0);
- else
- result.setNum(0);
- return result;
- }
}
else
{
@@ -555,15 +541,29 @@ public class QueryProcessor
rows = getIndexedSlices(keyspace, select);
}
}
-
- List<CqlRow> cqlRows = new ArrayList<CqlRow>();
+
+ // count resultset is a single column named "count"
result.type = CqlResultType.ROWS;
+ if (select.isCountOperation())
+ {
+ validateCountOperation(select);
+
+ ByteBuffer countBytes = ByteBufferUtil.bytes("count");
+ result.schema = new CqlMetadata(Collections.<ByteBuffer, String>emptyMap(),
+ Collections.<ByteBuffer, String>emptyMap(),
+ "AsciiType",
+ "LongType");
+ List<Column> columns = Collections.singletonList(new Column(countBytes).setValue(ByteBufferUtil.bytes((long) rows.size())));
+ result.rows = Collections.singletonList(new CqlRow(countBytes, columns));
+ return result;
+ }
+
+ // otherwise create resultset from query results
result.schema = new CqlMetadata(new HashMap<ByteBuffer, String>(),
new HashMap<ByteBuffer, String>(),
metadata.comparator.toString(),
TypeParser.getShortName(metadata.getDefaultValidator()));
-
- // Create the result set
+ List<CqlRow> cqlRows = new ArrayList<CqlRow>();
for (org.apache.cassandra.db.Row row : rows)
{
/// No results for this row
@@ -635,7 +635,7 @@ public class QueryProcessor
Collections.reverse(cqlRow.columns);
cqlRows.add(cqlRow);
}
-
+
result.rows = cqlRows;
return result;
@@ -1005,6 +1005,23 @@ public class QueryProcessor
throw new SchemaDisagreementException();
}
+ private static void validateCountOperation(SelectStatement select) throws InvalidRequestException
+ {
+ if (select.isWildcard())
+ return; // valid count(*)
+
+ if (!select.isColumnRange())
+ {
+ List<Term> columnNames = select.getColumnNames();
+ String firstColumn = columnNames.get(0).getText();
+
+ if (columnNames.size() == 1 && (firstColumn.equals("*") || firstColumn.equals("1")))
+ return; // valid count(*) || count(1)
+ }
+
+ throw new InvalidRequestException("Only COUNT(*) and COUNT(1) operations are currently supported.");
+ }
+
private static String bufferToString(ByteBuffer string)
{
try
Modified: cassandra/trunk/test/system/test_cql.py
URL: http://svn.apache.org/viewvc/cassandra/trunk/test/system/test_cql.py?rev=1166273&r1=1166272&r2=1166273&view=diff
==============================================================================
--- cassandra/trunk/test/system/test_cql.py (original)
+++ cassandra/trunk/test/system/test_cql.py Wed Sep 7 17:16:46 2011
@@ -336,11 +336,23 @@ class TestCql(ThriftTester):
def test_column_count(self):
"getting a result count instead of results"
cursor = init()
- cursor.execute("""
- SELECT COUNT(1..4) FROM StandardLongA WHERE KEY = 'aa';
- """)
+ cursor.execute("SELECT COUNT(*) FROM StandardLongA")
+ r = cursor.fetchone()
+ assert r[0] == 7, "expected 7 results, got %d" % (r and r or 0)
+ cursor.execute("SELECT COUNT(1) FROM StandardLongA")
r = cursor.fetchone()
- assert r[0] == 4, "expected 4 results, got %d" % (r and r or 0)
+ assert r[0] == 7, "expected 7 results, got %d" % (r and r or 0)
+
+ # count(*) and count(1) are only supported operations
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "SELECT COUNT(name) FROM StandardLongA")
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "SELECT COUNT(1..2) FROM StandardLongA")
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "SELECT COUNT(1, 2, 3) FROM StandardLongA")
def test_truncate_columnfamily(self):
"truncating a column family"