You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sa...@apache.org on 2016/05/02 12:15:00 UTC

[1/3] cassandra git commit: Add support for filtering on counter columns

Repository: cassandra
Updated Branches:
  refs/heads/cassandra-3.0 620efdc8c -> c08eeafdc
  refs/heads/trunk a529e6ae6 -> 1800a5b62


Add support for filtering on counter columns

Patch by Alex Petrov; reviewed by Sam Tunnicliffe for CASSANDRA-11629


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c08eeafd
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c08eeafd
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c08eeafd

Branch: refs/heads/cassandra-3.0
Commit: c08eeafdcfe4b5d0fb1a8aa34ca5df27be7934ce
Parents: 620efdc
Author: Alex Petrov <ol...@gmail.com>
Authored: Tue Apr 26 18:10:38 2016 +0200
Committer: Sam Tunnicliffe <sa...@beobal.com>
Committed: Mon May 2 11:07:39 2016 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../apache/cassandra/db/filter/RowFilter.java   | 22 ++++++
 .../cql3/validation/entities/CountersTest.java  | 74 ++++++++++++++++++++
 3 files changed, 97 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 64bcbd8..95f450b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.6
+ * Fix queries with filtering on counter columns (CASSANDRA-11629)
  * Improve tombstone printing in sstabledump (CASSANDRA-11655)
  * Fix paging for range queries where all clustering columns are specified (CASSANDRA-11669)
  * Don't require HEAP_NEW_SIZE to be set when using G1 (CASSANDRA-11600)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/src/java/org/apache/cassandra/db/filter/RowFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java
index 4960452..8060f23 100644
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@ -27,6 +27,7 @@ import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.Operator;
 import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.context.*;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.db.partitions.*;
 import org.apache.cassandra.db.rows.*;
@@ -611,6 +612,27 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
                 case LTE:
                 case GTE:
                 case GT:
+                    {
+                        assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";
+
+                        // In order to support operators on Counter types, their value has to be extracted from internal
+                        // representation. See CASSANDRA-11629
+                        if (column.type.isCounter())
+                        {
+                            ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                            if (foundValue == null)
+                                return false;
+
+                            ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue));
+                            return operator.isSatisfiedBy(LongType.instance, counterValue, value);
+                        }
+                        else
+                        {
+                            // Note that CQL expression are always of the form 'x < 4', i.e. the tested value is on the left.
+                            ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                            return foundValue != null && operator.isSatisfiedBy(column.type, foundValue, value);
+                        }
+                    }
                 case NEQ:
                     {
                         assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
index e54d105..89fd767 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
@@ -112,4 +112,78 @@ public class CountersTest extends CQLTester
                    row(1L) // no change to the counter value
         );
     }
+
+    @Test
+    public void testCounterFiltering() throws Throwable
+    {
+        for (String compactStorageClause: new String[] {"", " WITH COMPACT STORAGE"})
+        {
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter)" + compactStorageClause);
+
+            for (int i = 0; i < 10; i++)
+                execute("UPDATE %s SET a = a + ? WHERE k = ?", (long) i, i);
+
+            execute("UPDATE %s SET a = a + ? WHERE k = ?", 6L, 10);
+
+            // GT
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 5L),
+                                    row(6, 6L),
+                                    row(7, 7L),
+                                    row(8, 8L),
+                                    row(9, 9L),
+                                    row(10, 6L));
+
+            // GTE
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a >= ? ALLOW FILTERING", 6L),
+                                    row(6, 6L),
+                                    row(7, 7L),
+                                    row(8, 8L),
+                                    row(9, 9L),
+                                    row(10, 6L));
+
+            // LT
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a < ? ALLOW FILTERING", 3L),
+                                    row(0, 0L),
+                                    row(1, 1L),
+                                    row(2, 2L));
+
+            // LTE
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a <= ? ALLOW FILTERING", 3L),
+                                    row(0, 0L),
+                                    row(1, 1L),
+                                    row(2, 2L),
+                                    row(3, 3L));
+
+            // EQ
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 6L),
+                                    row(6, 6L),
+                                    row(10, 6L));
+        }
+    }
+
+    @Test
+    public void testCounterFilteringWithNull() throws Throwable
+    {
+        for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
+        {
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter, b counter)" + compactStorageClause);
+            execute("UPDATE %s SET a = a + ? WHERE k = ?", 1L, 1);
+
+            assertRows(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 0L),
+                       row(1, 1L, null));
+            // GT
+            assertEmpty(execute("SELECT * FROM %s WHERE b > ? ALLOW FILTERING", 1L));
+            // GTE
+            assertEmpty(execute("SELECT * FROM %s WHERE b >= ? ALLOW FILTERING", 1L));
+            // LT
+            assertEmpty(execute("SELECT * FROM %s WHERE b < ? ALLOW FILTERING", 1L));
+            // LTE
+            assertEmpty(execute("SELECT * FROM %s WHERE b <= ? ALLOW FILTERING", 1L));
+            // EQ
+            assertEmpty(execute("SELECT * FROM %s WHERE b = ? ALLOW FILTERING", 1L));
+            // with null
+            assertInvalidMessage("Invalid null value for counter increment/decrement",
+                                 "SELECT * FROM %s WHERE b = null ALLOW FILTERING");
+        }
+    }
 }


[3/3] cassandra git commit: Merge branch 'cassandra-3.0' into trunk

Posted by sa...@apache.org.
Merge branch 'cassandra-3.0' into trunk


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1800a5b6
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1800a5b6
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1800a5b6

Branch: refs/heads/trunk
Commit: 1800a5b627ce8fa4186d4b52902d029920bd8e5a
Parents: a529e6a c08eeaf
Author: Sam Tunnicliffe <sa...@beobal.com>
Authored: Mon May 2 11:12:01 2016 +0100
Committer: Sam Tunnicliffe <sa...@beobal.com>
Committed: Mon May 2 11:14:21 2016 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../apache/cassandra/db/filter/RowFilter.java   | 22 ++++++
 .../cql3/validation/entities/CountersTest.java  | 76 +++++++++++++++++++-
 .../cql3/validation/operations/SelectTest.java  | 38 +++++++++-
 4 files changed, 135 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/1800a5b6/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index b1ca6dd,95f450b..d30b7a4
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,67 -1,5 +1,68 @@@
 -3.0.6
 +3.6
 + * Add units to stress ouput (CASSANDRA-11352)
 + * Fix PER PARTITION LIMIT for single and multi partitions queries (CASSANDRA-11603)
 + * Add uncompressed chunk cache for RandomAccessReader (CASSANDRA-5863)
 + * Clarify ClusteringPrefix hierarchy (CASSANDRA-11213)
 + * Always perform collision check before joining ring (CASSANDRA-10134)
 + * SSTableWriter output discrepancy (CASSANDRA-11646)
 + * Fix potential timeout in NativeTransportService.testConcurrentDestroys (CASSANDRA-10756)
 + * Support large partitions on the 3.0 sstable format (CASSANDRA-11206)
 + * Add support to rebuild from specific range (CASSANDRA-10406)
 + * Optimize the overlapping lookup by calculating all the
 +   bounds in advance (CASSANDRA-11571)
 + * Support json/yaml output in noetool tablestats (CASSANDRA-5977)
 + * (stress) Add datacenter option to -node options (CASSANDRA-11591)
 + * Fix handling of empty slices (CASSANDRA-11513)
 + * Make number of cores used by cqlsh COPY visible to testing code (CASSANDRA-11437)
 + * Allow filtering on clustering columns for queries without secondary indexes (CASSANDRA-11310)
 + * Refactor Restriction hierarchy (CASSANDRA-11354)
 + * Eliminate allocations in R/W path (CASSANDRA-11421)
 + * Update Netty to 4.0.36 (CASSANDRA-11567)
 + * Fix PER PARTITION LIMIT for queries requiring post-query ordering (CASSANDRA-11556)
 + * Allow instantiation of UDTs and tuples in UDFs (CASSANDRA-10818)
 + * Support UDT in CQLSSTableWriter (CASSANDRA-10624)
 + * Support for non-frozen user-defined types, updating
 +   individual fields of user-defined types (CASSANDRA-7423)
 + * Make LZ4 compression level configurable (CASSANDRA-11051)
 + * Allow per-partition LIMIT clause in CQL (CASSANDRA-7017)
 + * Make custom filtering more extensible with UserExpression (CASSANDRA-11295)
 + * Improve field-checking and error reporting in cassandra.yaml (CASSANDRA-10649)
 + * Print CAS stats in nodetool proxyhistograms (CASSANDRA-11507)
 + * More user friendly error when providing an invalid token to nodetool (CASSANDRA-9348)
 + * Add static column support to SASI index (CASSANDRA-11183)
 + * Support EQ/PREFIX queries in SASI CONTAINS mode without tokenization (CASSANDRA-11434)
 + * Support LIKE operator in prepared statements (CASSANDRA-11456)
 + * Add a command to see if a Materialized View has finished building (CASSANDRA-9967)
 + * Log endpoint and port associated with streaming operation (CASSANDRA-8777)
 + * Print sensible units for all log messages (CASSANDRA-9692)
 + * Upgrade Netty to version 4.0.34 (CASSANDRA-11096)
 + * Break the CQL grammar into separate Parser and Lexer (CASSANDRA-11372)
 + * Compress only inter-dc traffic by default (CASSANDRA-8888)
 + * Add metrics to track write amplification (CASSANDRA-11420)
 + * cassandra-stress: cannot handle "value-less" tables (CASSANDRA-7739)
 + * Add/drop multiple columns in one ALTER TABLE statement (CASSANDRA-10411)
 + * Add require_endpoint_verification opt for internode encryption (CASSANDRA-9220)
 + * Add auto import java.util for UDF code block (CASSANDRA-11392)
 + * Add --hex-format option to nodetool getsstables (CASSANDRA-11337)
 + * sstablemetadata should print sstable min/max token (CASSANDRA-7159)
 + * Do not wrap CassandraException in TriggerExecutor (CASSANDRA-9421)
 + * COPY TO should have higher double precision (CASSANDRA-11255)
 + * Stress should exit with non-zero status after failure (CASSANDRA-10340)
 + * Add client to cqlsh SHOW_SESSION (CASSANDRA-8958)
 + * Fix nodetool tablestats keyspace level metrics (CASSANDRA-11226)
 + * Store repair options in parent_repair_history (CASSANDRA-11244)
 + * Print current leveling in sstableofflinerelevel (CASSANDRA-9588)
 + * Change repair message for keyspaces with RF 1 (CASSANDRA-11203)
 + * Remove hard-coded SSL cipher suites and protocols (CASSANDRA-10508)
 + * Improve concurrency in CompactionStrategyManager (CASSANDRA-10099)
 + * (cqlsh) interpret CQL type for formatting blobs (CASSANDRA-11274)
 + * Refuse to start and print txn log information in case of disk
 +   corruption (CASSANDRA-10112)
 + * Resolve some eclipse-warnings (CASSANDRA-11086)
 + * (cqlsh) Show static columns in a different color (CASSANDRA-11059)
 + * Allow to remove TTLs on table with default_time_to_live (CASSANDRA-11207)
 +Merged from 3.0:
+  * Fix queries with filtering on counter columns (CASSANDRA-11629)
   * Improve tombstone printing in sstabledump (CASSANDRA-11655)
   * Fix paging for range queries where all clustering columns are specified (CASSANDRA-11669)
   * Don't require HEAP_NEW_SIZE to be set when using G1 (CASSANDRA-11600)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/1800a5b6/src/java/org/apache/cassandra/db/filter/RowFilter.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/filter/RowFilter.java
index 0ef29c2,8060f23..ea60669
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@@ -32,9 -27,9 +32,10 @@@ import org.apache.cassandra.config.CFMe
  import org.apache.cassandra.config.ColumnDefinition;
  import org.apache.cassandra.cql3.Operator;
  import org.apache.cassandra.db.*;
+ import org.apache.cassandra.db.context.*;
  import org.apache.cassandra.db.marshal.*;
 -import org.apache.cassandra.db.partitions.*;
 +import org.apache.cassandra.db.partitions.ImmutableBTreePartition;
 +import org.apache.cassandra.db.partitions.UnfilteredPartitionIterator;
  import org.apache.cassandra.db.rows.*;
  import org.apache.cassandra.db.transform.Transformation;
  import org.apache.cassandra.exceptions.InvalidRequestException;
@@@ -654,11 -612,28 +655,32 @@@ public abstract class RowFilter impleme
                  case LTE:
                  case GTE:
                  case GT:
+                     {
+                         assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";
+ 
+                         // In order to support operators on Counter types, their value has to be extracted from internal
+                         // representation. See CASSANDRA-11629
+                         if (column.type.isCounter())
+                         {
+                             ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                             if (foundValue == null)
+                                 return false;
+ 
+                             ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue));
+                             return operator.isSatisfiedBy(LongType.instance, counterValue, value);
+                         }
+                         else
+                         {
+                             // Note that CQL expression are always of the form 'x < 4', i.e. the tested value is on the left.
+                             ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                             return foundValue != null && operator.isSatisfiedBy(column.type, foundValue, value);
+                         }
+                     }
                  case NEQ:
 +                case LIKE_PREFIX:
 +                case LIKE_SUFFIX:
 +                case LIKE_CONTAINS:
 +                case LIKE_MATCHES:
                      {
                          assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";
                          ByteBuffer foundValue = getValue(metadata, partitionKey, row);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/1800a5b6/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
index e54d105,89fd767..7a096b3
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
@@@ -112,4 -112,78 +112,78 @@@ public class CountersTest extends CQLTe
                     row(1L) // no change to the counter value
          );
      }
- }
+ 
+     @Test
+     public void testCounterFiltering() throws Throwable
+     {
 -        for (String compactStorageClause: new String[] {"", " WITH COMPACT STORAGE"})
++        for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
+         {
+             createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter)" + compactStorageClause);
+ 
+             for (int i = 0; i < 10; i++)
+                 execute("UPDATE %s SET a = a + ? WHERE k = ?", (long) i, i);
+ 
+             execute("UPDATE %s SET a = a + ? WHERE k = ?", 6L, 10);
+ 
+             // GT
+             assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 5L),
+                                     row(6, 6L),
+                                     row(7, 7L),
+                                     row(8, 8L),
+                                     row(9, 9L),
+                                     row(10, 6L));
+ 
+             // GTE
+             assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a >= ? ALLOW FILTERING", 6L),
+                                     row(6, 6L),
+                                     row(7, 7L),
+                                     row(8, 8L),
+                                     row(9, 9L),
+                                     row(10, 6L));
+ 
+             // LT
+             assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a < ? ALLOW FILTERING", 3L),
+                                     row(0, 0L),
+                                     row(1, 1L),
+                                     row(2, 2L));
+ 
+             // LTE
+             assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a <= ? ALLOW FILTERING", 3L),
+                                     row(0, 0L),
+                                     row(1, 1L),
+                                     row(2, 2L),
+                                     row(3, 3L));
+ 
+             // EQ
+             assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 6L),
+                                     row(6, 6L),
+                                     row(10, 6L));
+         }
+     }
+ 
+     @Test
+     public void testCounterFilteringWithNull() throws Throwable
+     {
+         for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
+         {
+             createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter, b counter)" + compactStorageClause);
+             execute("UPDATE %s SET a = a + ? WHERE k = ?", 1L, 1);
+ 
+             assertRows(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 0L),
+                        row(1, 1L, null));
+             // GT
+             assertEmpty(execute("SELECT * FROM %s WHERE b > ? ALLOW FILTERING", 1L));
+             // GTE
+             assertEmpty(execute("SELECT * FROM %s WHERE b >= ? ALLOW FILTERING", 1L));
+             // LT
+             assertEmpty(execute("SELECT * FROM %s WHERE b < ? ALLOW FILTERING", 1L));
+             // LTE
+             assertEmpty(execute("SELECT * FROM %s WHERE b <= ? ALLOW FILTERING", 1L));
+             // EQ
+             assertEmpty(execute("SELECT * FROM %s WHERE b = ? ALLOW FILTERING", 1L));
+             // with null
+             assertInvalidMessage("Invalid null value for counter increment/decrement",
+                                  "SELECT * FROM %s WHERE b = null ALLOW FILTERING");
+         }
+     }
 -}
++}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/1800a5b6/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
index 6e3b6eb,b49bd87..f91ec5a
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
@@@ -2437,381 -2426,6 +2437,417 @@@ public class SelectTest extends CQLTest
                               unset());
      }
  
 +    @Test
 +    public void filteringOnClusteringColumns() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (11, 12, 13, 14)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (11, 15, 16, 17)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (21, 22, 23, 24)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (31, 32, 33, 34)");
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(execute("SELECT * FROM %s WHERE a = 11 AND b = 15"),
 +                       row(11, 15, 16, 17));
 +
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE a = 11 AND b > 12 AND c = 15");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE a = 11 AND b = 15 AND c > 15"),
 +                       row(11, 15, 16, 17));
 +
 +            assertRows(execute("SELECT * FROM %s WHERE a = 11 AND b > 12 AND c > 13 AND d = 17 ALLOW FILTERING"),
 +                       row(11, 15, 16, 17));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE a = 11 AND b > 12 AND c > 13 and d = 17");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b > 20 AND c > 30 ALLOW FILTERING"),
 +                       row(31, 32, 33, 34));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE b > 20 AND c > 30");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b > 20 AND c < 30 ALLOW FILTERING"),
 +                       row(21, 22, 23, 24));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE b > 20 AND c < 30");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b > 20 AND c = 33 ALLOW FILTERING"),
 +                       row(31, 32, 33, 34));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE b > 20 AND c = 33");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE c = 33 ALLOW FILTERING"),
 +                       row(31, 32, 33, 34));
 +            assertInvalidMessage("PRIMARY KEY column \"c\" cannot be restricted as preceding column \"b\" is not restricted",
 +                                 "SELECT * FROM %s WHERE c = 33");
 +        });
 +
 +        // --------------------------------------------------
 +        // Clustering column within and across partition keys
 +        // --------------------------------------------------
 +        createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (11, 12, 13, 14)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (11, 15, 16, 17)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (11, 18, 19, 20)");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (21, 22, 23, 24)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (21, 25, 26, 27)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (21, 28, 29, 30)");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (31, 32, 33, 34)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (31, 35, 36, 37)");
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (31, 38, 39, 40)");
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a = 21 AND c > 23"),
 +                       row(21, 25, 26, 27),
 +                       row(21, 28, 29, 30));
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a = 21 AND c > 23 ORDER BY b DESC"),
 +                       row(21, 28, 29, 30),
 +                       row(21, 25, 26, 27));
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 16 and c < 36"),
 +                       row(11, 18, 19, 20),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27),
 +                       row(21, 28, 29, 30),
 +                       row(31, 32, 33, 34));
 +        });
 +    }
 +
 +    @Test
 +    public void filteringWithMultiColumnSlices() throws Throwable
 +    {
 +        //----------------------------------------
 +        // Multi-column slices for clustering keys
 +        //----------------------------------------
 +        createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY (a, b, c, d))");
 +
 +        execute("INSERT INTO %s (a,b,c,d,e) VALUES (11, 12, 13, 14, 15)");
 +        execute("INSERT INTO %s (a,b,c,d,e) VALUES (21, 22, 23, 24, 25)");
 +        execute("INSERT INTO %s (a,b,c,d,e) VALUES (31, 32, 33, 34, 35)");
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b = 22 AND d = 24 ALLOW FILTERING"),
 +                       row(21, 22, 23, 24, 25));
 +            assertInvalidMessage("PRIMARY KEY column \"d\" cannot be restricted as preceding column \"c\" is not restricted",
 +                                 "SELECT * FROM %s WHERE b = 22 AND d = 24");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE (b, c) > (20, 30) AND d = 34 ALLOW FILTERING"),
 +                       row(31, 32, 33, 34, 35));
 +            assertInvalidMessage("Clustering column \"d\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE (b, c) > (20, 30) AND d = 34");
 +        });
 +    }
 +
 +    @Test
 +    public void containsFilteringForClusteringKeys() throws Throwable
 +    {
 +        //-------------------------------------------------
 +        // Frozen collections filtering for clustering keys
 +        //-------------------------------------------------
 +
 +        // first clustering column
 +        createTable("CREATE TABLE %s (a int, b frozen<list<int>>, c int, PRIMARY KEY (a, b, c))");
 +        execute("INSERT INTO %s (a,b,c) VALUES (?, ?, ?)", 11, list(1, 3), 14);
 +        execute("INSERT INTO %s (a,b,c) VALUES (?, ?, ?)", 21, list(2, 3), 24);
 +        execute("INSERT INTO %s (a,b,c) VALUES (?, ?, ?)", 21, list(3, 3), 34);
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(execute("SELECT * FROM %s WHERE a = 21 AND b CONTAINS 2 ALLOW FILTERING"),
 +                       row(21, list(2, 3), 24));
 +            assertInvalidMessage("Clustering columns can only be restricted with CONTAINS with a secondary index or filtering",
 +                                 "SELECT * FROM %s WHERE a = 21 AND b CONTAINS 2");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b CONTAINS 2 ALLOW FILTERING"),
 +                       row(21, list(2, 3), 24));
 +            assertInvalidMessage("Clustering columns can only be restricted with CONTAINS with a secondary index or filtering",
 +                                 "SELECT * FROM %s WHERE b CONTAINS 2");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b CONTAINS 3 ALLOW FILTERING"),
 +                       row(11, list(1, 3), 14),
 +                       row(21, list(2, 3), 24),
 +                       row(21, list(3, 3), 34));
 +        });
 +
 +        // non-first clustering column
 +        createTable("CREATE TABLE %s (a int, b int, c frozen<list<int>>, d int, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 11, 12, list(1, 3), 14);
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 21, 22, list(2, 3), 24);
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 21, 22, list(3, 3), 34);
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(execute("SELECT * FROM %s WHERE a = 21 AND c CONTAINS 2 ALLOW FILTERING"),
 +                       row(21, 22, list(2, 3), 24));
 +            assertInvalidMessage("Clustering columns can only be restricted with CONTAINS with a secondary index or filtering",
 +                                 "SELECT * FROM %s WHERE a = 21 AND c CONTAINS 2");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE b > 20 AND c CONTAINS 2 ALLOW FILTERING"),
 +                       row(21, 22, list(2, 3), 24));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE b > 20 AND c CONTAINS 2");
 +
 +            assertRows(execute("SELECT * FROM %s WHERE c CONTAINS 3 ALLOW FILTERING"),
 +                       row(11, 12, list(1, 3), 14),
 +                       row(21, 22, list(2, 3), 24),
 +                       row(21, 22, list(3, 3), 34));
 +        });
 +
 +        createTable("CREATE TABLE %s (a int, b int, c frozen<map<text, text>>, d int, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 11, 12, map("1", "3"), 14);
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 21, 22, map("2", "3"), 24);
 +        execute("INSERT INTO %s (a,b,c,d) VALUES (?, ?, ?, ?)", 21, 22, map("3", "3"), 34);
 +
 +        beforeAndAfterFlush(() -> {
 +            assertRows(execute("SELECT * FROM %s WHERE b > 20 AND c CONTAINS KEY '2' ALLOW FILTERING"),
 +                       row(21, 22, map("2", "3"), 24));
 +            assertInvalidMessage("Clustering column \"c\" cannot be restricted (preceding column \"b\" is restricted by a non-EQ relation)",
 +                                 "SELECT * FROM %s WHERE b > 20 AND c CONTAINS KEY '2'");
 +        });
 +    }
 +
 +    @Test
 +    public void filteringWithOrderClause() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, d list<int>, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, list(1,4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, list(2,4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 26, list(2,7));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 33, list(3,4));
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d FROM %s WHERE a = 21 AND c > 20 ORDER BY b DESC"),
 +                       row(21, 25, 26, list(2, 7)),
 +                       row(21, 22, 23, list(2, 4)));
 +
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d FROM %s WHERE a IN(21, 31) AND c > 20 ORDER BY b DESC"),
 +                       row(31, 32, 33, list(3, 4)),
 +                       row(21, 25, 26, list(2, 7)),
 +                       row(21, 22, 23, list(2, 4)));
 +        });
 +    }
 +
 +
 +    @Test
 +    public void filteringOnStaticColumnTest() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, d int, s int static, PRIMARY KEY (a, b))");
 +
 +        execute("INSERT INTO %s (a, b, c, d, s) VALUES (11, 12, 13, 14, 15)");
 +        execute("INSERT INTO %s (a, b, c, d, s) VALUES (21, 22, 23, 24, 25)");
 +        execute("INSERT INTO %s (a, b, c, d, s) VALUES (21, 26, 27, 28, 29)");
 +        execute("INSERT INTO %s (a, b, c, d, s) VALUES (31, 32, 33, 34, 35)");
 +        execute("INSERT INTO %s (a, b, c, d, s) VALUES (11, 42, 43, 44, 45)");
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE s = 29"),
 +                       row(21, 22, 23, 24, 29),
 +                       row(21, 26, 27, 28, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE b > 22 AND s = 29"),
 +                       row(21, 26, 27, 28, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE b > 10 and b < 26 AND s = 29"),
 +                       row(21, 22, 23, 24, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE c > 10 and c < 27 AND s = 29"),
 +                       row(21, 22, 23, 24, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE c > 10 and c < 43 AND s = 29"),
 +                       row(21, 22, 23, 24, 29),
 +                       row(21, 26, 27, 28, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE c > 10 AND s > 15 AND s < 45"),
 +                       row(21, 22, 23, 24, 29),
 +                       row(21, 26, 27, 28, 29),
 +                       row(31, 32, 33, 34, 35));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE a = 21 AND s > 15 AND s < 45 ORDER BY b DESC"),
 +                       row(21, 26, 27, 28, 29),
 +                       row(21, 22, 23, 24, 29));
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d, s FROM %s WHERE c > 13 and d < 44"),
 +                       row(21, 22, 23, 24, 29),
 +                       row(21, 26, 27, 28, 29),
 +                       row(31, 32, 33, 34, 35));
 +        });
 +    }
 +
 +    @Test
 +    public void containsFilteringOnNonClusteringColumn() throws Throwable {
 +        createTable("CREATE TABLE %s (a int, b int, c int, d list<int>, PRIMARY KEY (a, b, c))");
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, list(1,4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, list(2,4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 26, list(2,7));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 33, list(3,4));
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d FROM %s WHERE b > 20 AND d CONTAINS 2"),
 +                       row(21, 22, 23, list(2, 4)),
 +                       row(21, 25, 26, list(2, 7)));
 +
 +            assertRows(executeFilteringOnly("SELECT a, b, c, d FROM %s WHERE b > 20 AND d CONTAINS 2 AND d contains 4"),
 +                       row(21, 22, 23, list(2, 4)));
 +        });
 +    }
 +
 +    @Test
 +    public void filteringOnCompactTable() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE");
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, 14);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, 24);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 26, 27);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 33, 34);
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 13"),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27),
 +                       row(31, 32, 33, 34));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 13 AND c < 33"),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 13 AND b < 32"),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a = 21 AND c > 13 AND b < 32 ORDER BY b DESC"),
 +                       row(21, 25, 26, 27),
 +                       row(21, 22, 23, 24));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a IN (21, 31) AND c > 13 ORDER BY b DESC"),
 +                       row(31, 32, 33, 34),
 +                       row(21, 25, 26, 27),
 +                       row(21, 22, 23, 24));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 13 AND d < 34"),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c > 13"),
 +                       row(21, 22, 23, 24),
 +                       row(21, 25, 26, 27),
 +                       row(31, 32, 33, 34));
 +        });
 +
 +        // with frozen in clustering key
 +        createTable("CREATE TABLE %s (a int, b int, c frozen<list<int>>, d int, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE");
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, list(1, 3), 14);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, list(2, 3), 24);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, list(2, 6), 27);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, list(3, 3), 34);
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c CONTAINS 2"),
 +                       row(21, 22, list(2, 3), 24),
 +                       row(21, 25, list(2, 6), 27));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c CONTAINS 2 AND b < 25"),
 +                       row(21, 22, list(2, 3), 24));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE c CONTAINS 2 AND c CONTAINS 3"),
 +                       row(21, 22, list(2, 3), 24));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE b > 12 AND c CONTAINS 2 AND d < 27"),
 +                       row(21, 22, list(2, 3), 24));
 +        });
 +
 +        // with frozen in value
 +        createTable("CREATE TABLE %s (a int, b int, c int, d frozen<list<int>>, PRIMARY KEY (a, b, c)) WITH COMPACT STORAGE");
 +
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 11, 12, 13, list(1, 4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 22, 23, list(2, 4));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 21, 25, 25, list(2, 6));
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 31, 32, 34, list(3, 4));
 +
 +        beforeAndAfterFlush(() -> {
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE d CONTAINS 2"),
 +                       row(21, 22, 23, list(2, 4)),
 +                       row(21, 25, 25, list(2, 6)));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE d CONTAINS 2 AND b < 25"),
 +                       row(21, 22, 23, list(2, 4)));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE d CONTAINS 2 AND d CONTAINS 4"),
 +                       row(21, 22, 23, list(2, 4)));
 +
 +            assertRows(executeFilteringOnly("SELECT * FROM %s WHERE b > 12 AND c < 25 AND d CONTAINS 2"),
 +                       row(21, 22, 23, list(2, 4)));
 +        });
 +    }
 +
 +    @Test
-     public void testCustomIndexWithFiltering() throws Throwable {
++    public void testCustomIndexWithFiltering() throws Throwable
++    {
 +        // Test for CASSANDRA-11310 compatibility with 2i
 +        createTable("CREATE TABLE %s (a text, b int, c text, d int, PRIMARY KEY (a, b, c));");
 +        createIndex("CREATE INDEX ON %s(c)");
 +        
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", "a", 0, "b", 1);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", "a", 1, "b", 2);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", "a", 2, "b", 3);
 +        execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", "c", 3, "b", 4);
 +
 +        assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a='a' AND b > 0 AND c = 'b'"),
 +                   row("a", 1, "b", 2),
 +                   row("a", 2, "b", 3));
 +    }
 +
++    @Test
++    public void testFilteringWithCounters() throws Throwable
++    {
++        for (String compactStorageClause: new String[] {"", " WITH COMPACT STORAGE"})
++        {
++            createTable("CREATE TABLE %s (a int, b int, c int, cnt counter, PRIMARY KEY (a, b, c))" + compactStorageClause);
++
++            execute("UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 14L, 11, 12, 13);
++            execute("UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24L, 21, 22, 23);
++            execute("UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 27L, 21, 25, 26);
++            execute("UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 34L, 31, 32, 33);
++            execute("UPDATE %s SET cnt = cnt + ? WHERE a = ? AND b = ? AND c = ?", 24L, 41, 42, 43);
++
++            beforeAndAfterFlush(() -> {
++
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE cnt = 24"),
++                           row(21, 22, 23, 24L),
++                           row(41, 42, 43, 24L));
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE b > 22 AND cnt = 24"),
++                           row(41, 42, 43, 24L));
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE b > 10 AND b < 25 AND cnt = 24"),
++                           row(21, 22, 23, 24L));
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE b > 10 AND c < 25 AND cnt = 24"),
++                           row(21, 22, 23, 24L));
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE a = 21 AND b > 10 AND cnt > 23 ORDER BY b DESC"),
++                           row(21, 25, 26, 27L),
++                           row(21, 22, 23, 24L));
++                assertRows(executeFilteringOnly("SELECT * FROM %s WHERE cnt > 20 AND cnt < 30"),
++                           row(21, 22, 23, 24L),
++                           row(21, 25, 26, 27L),
++                           row(41, 42, 43, 24L));
++            });
++        }
++    }
++
 +    private UntypedResultSet executeFilteringOnly(String statement) throws Throwable
 +    {
 +        assertInvalid(statement);
 +        return execute(statement + " ALLOW FILTERING");
 +    }
 +
      /**
       * Check select with and without compact storage, with different column
       * order. See CASSANDRA-10988


[2/3] cassandra git commit: Add support for filtering on counter columns

Posted by sa...@apache.org.
Add support for filtering on counter columns

Patch by Alex Petrov; reviewed by Sam Tunnicliffe for CASSANDRA-11629


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/c08eeafd
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/c08eeafd
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/c08eeafd

Branch: refs/heads/trunk
Commit: c08eeafdcfe4b5d0fb1a8aa34ca5df27be7934ce
Parents: 620efdc
Author: Alex Petrov <ol...@gmail.com>
Authored: Tue Apr 26 18:10:38 2016 +0200
Committer: Sam Tunnicliffe <sa...@beobal.com>
Committed: Mon May 2 11:07:39 2016 +0100

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../apache/cassandra/db/filter/RowFilter.java   | 22 ++++++
 .../cql3/validation/entities/CountersTest.java  | 74 ++++++++++++++++++++
 3 files changed, 97 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 64bcbd8..95f450b 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.6
+ * Fix queries with filtering on counter columns (CASSANDRA-11629)
  * Improve tombstone printing in sstabledump (CASSANDRA-11655)
  * Fix paging for range queries where all clustering columns are specified (CASSANDRA-11669)
  * Don't require HEAP_NEW_SIZE to be set when using G1 (CASSANDRA-11600)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/src/java/org/apache/cassandra/db/filter/RowFilter.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java
index 4960452..8060f23 100644
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@ -27,6 +27,7 @@ import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.Operator;
 import org.apache.cassandra.db.*;
+import org.apache.cassandra.db.context.*;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.db.partitions.*;
 import org.apache.cassandra.db.rows.*;
@@ -611,6 +612,27 @@ public abstract class RowFilter implements Iterable<RowFilter.Expression>
                 case LTE:
                 case GTE:
                 case GT:
+                    {
+                        assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";
+
+                        // In order to support operators on Counter types, their value has to be extracted from internal
+                        // representation. See CASSANDRA-11629
+                        if (column.type.isCounter())
+                        {
+                            ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                            if (foundValue == null)
+                                return false;
+
+                            ByteBuffer counterValue = LongType.instance.decompose(CounterContext.instance().total(foundValue));
+                            return operator.isSatisfiedBy(LongType.instance, counterValue, value);
+                        }
+                        else
+                        {
+                            // Note that CQL expression are always of the form 'x < 4', i.e. the tested value is on the left.
+                            ByteBuffer foundValue = getValue(metadata, partitionKey, row);
+                            return foundValue != null && operator.isSatisfiedBy(column.type, foundValue, value);
+                        }
+                    }
                 case NEQ:
                     {
                         assert !column.isComplex() : "Only CONTAINS and CONTAINS_KEY are supported for 'complex' types";

http://git-wip-us.apache.org/repos/asf/cassandra/blob/c08eeafd/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
index e54d105..89fd767 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/CountersTest.java
@@ -112,4 +112,78 @@ public class CountersTest extends CQLTester
                    row(1L) // no change to the counter value
         );
     }
+
+    @Test
+    public void testCounterFiltering() throws Throwable
+    {
+        for (String compactStorageClause: new String[] {"", " WITH COMPACT STORAGE"})
+        {
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter)" + compactStorageClause);
+
+            for (int i = 0; i < 10; i++)
+                execute("UPDATE %s SET a = a + ? WHERE k = ?", (long) i, i);
+
+            execute("UPDATE %s SET a = a + ? WHERE k = ?", 6L, 10);
+
+            // GT
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 5L),
+                                    row(6, 6L),
+                                    row(7, 7L),
+                                    row(8, 8L),
+                                    row(9, 9L),
+                                    row(10, 6L));
+
+            // GTE
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a >= ? ALLOW FILTERING", 6L),
+                                    row(6, 6L),
+                                    row(7, 7L),
+                                    row(8, 8L),
+                                    row(9, 9L),
+                                    row(10, 6L));
+
+            // LT
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a < ? ALLOW FILTERING", 3L),
+                                    row(0, 0L),
+                                    row(1, 1L),
+                                    row(2, 2L));
+
+            // LTE
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a <= ? ALLOW FILTERING", 3L),
+                                    row(0, 0L),
+                                    row(1, 1L),
+                                    row(2, 2L),
+                                    row(3, 3L));
+
+            // EQ
+            assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE a = ? ALLOW FILTERING", 6L),
+                                    row(6, 6L),
+                                    row(10, 6L));
+        }
+    }
+
+    @Test
+    public void testCounterFilteringWithNull() throws Throwable
+    {
+        for (String compactStorageClause : new String[]{ "", " WITH COMPACT STORAGE" })
+        {
+            createTable("CREATE TABLE %s (k int PRIMARY KEY, a counter, b counter)" + compactStorageClause);
+            execute("UPDATE %s SET a = a + ? WHERE k = ?", 1L, 1);
+
+            assertRows(execute("SELECT * FROM %s WHERE a > ? ALLOW FILTERING", 0L),
+                       row(1, 1L, null));
+            // GT
+            assertEmpty(execute("SELECT * FROM %s WHERE b > ? ALLOW FILTERING", 1L));
+            // GTE
+            assertEmpty(execute("SELECT * FROM %s WHERE b >= ? ALLOW FILTERING", 1L));
+            // LT
+            assertEmpty(execute("SELECT * FROM %s WHERE b < ? ALLOW FILTERING", 1L));
+            // LTE
+            assertEmpty(execute("SELECT * FROM %s WHERE b <= ? ALLOW FILTERING", 1L));
+            // EQ
+            assertEmpty(execute("SELECT * FROM %s WHERE b = ? ALLOW FILTERING", 1L));
+            // with null
+            assertInvalidMessage("Invalid null value for counter increment/decrement",
+                                 "SELECT * FROM %s WHERE b = null ALLOW FILTERING");
+        }
+    }
 }