Allow only DISTINCT queries with partition keys or static columns restrictions

patch by Alex Petrov; reviewed by Benjamin Lerer for CASSANDRA-11339


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

Branch: refs/heads/trunk
Commit: 6ad874509d6c7edd53bb3a4b897477d6a2753c19
Parents: 0818e1b
Author: Alex Petrov <oleksandr.pet...@gmail.com>
Authored: Thu Apr 14 12:35:07 2016 +0200
Committer: Benjamin Lerer <b.le...@gmail.com>
Committed: Thu Apr 14 12:35:07 2016 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |  1 +
 .../restrictions/StatementRestrictions.java     |  9 +++
 .../cql3/statements/SelectStatement.java        |  4 ++
 .../cql3/validation/operations/SelectTest.java  | 72 ++++++++++++++++++++
 4 files changed, 86 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/6ad87450/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index ed4c412..3b4d473 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 3.0.6
+ * Allow only DISTINCT queries with partition keys or static columns 
restrictions (CASSANDRA-11339)
  * LogAwareFileLister should only use OLD sstable files in current folder to 
determine disk consistency (CASSANDRA-11470)
  * Notify indexers of expired rows during compaction (CASSANDRA-11329)
  * Properly respond with ProtocolError when a v1/v2 native protocol

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6ad87450/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java 
b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
index 797b8e4..763a7be 100644
--- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
+++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java
@@ -396,6 +396,15 @@ public final class StatementRestrictions
     }
 
     /**
+     * Checks if the restrictions contain any non-primary key restrictions
+     * @return <code>true</code> if the restrictions contain any non-primary 
key restrictions, <code>false</code> otherwise.
+     */
+    public boolean hasNonPrimaryKeyRestrictions()
+    {
+        return !nonPrimaryKeyRestrictions.isEmpty();
+    }
+
+    /**
      * Returns the partition key components that are not restricted.
      * @return the partition key components that are not restricted.
      */

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6ad87450/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java 
b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 51d675b..b4215ac 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -896,6 +896,10 @@ public class SelectStatement implements CQLStatement
                                                       StatementRestrictions 
restrictions)
                                                       throws 
InvalidRequestException
         {
+            checkFalse(restrictions.hasClusteringColumnsRestriction() ||
+                       (restrictions.hasNonPrimaryKeyRestrictions() && 
!restrictions.nonPKRestrictedColumns(true).stream().allMatch(ColumnDefinition::isStatic)),
+                       "SELECT DISTINCT with WHERE clause only supports 
restriction by partition key and/or static columns.");
+
             Collection<ColumnDefinition> requestedColumns = 
selection.getColumns();
             for (ColumnDefinition def : requestedColumns)
                 checkFalse(!def.isPartitionKey() && !def.isStatic(),

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6ad87450/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
index a7eeeb8..5c19e1b 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
@@ -1253,6 +1253,78 @@ public class SelectTest extends CQLTester
         Assert.assertEquals(9, rows.length);
     }
 
+    @Test
+    public void testSelectDistinctWithWhereClause() throws Throwable {
+        createTable("CREATE TABLE %s (k int, a int, b int, PRIMARY KEY (k, 
a))");
+        createIndex("CREATE INDEX ON %s (b)");
+
+        for (int i = 0; i < 10; i++)
+        {
+            execute("INSERT INTO %s (k, a, b) VALUES (?, ?, ?)", i, i, i);
+            execute("INSERT INTO %s (k, a, b) VALUES (?, ?, ?)", i, i * 10, i 
* 10);
+        }
+
+        String distinctQueryErrorMsg = "SELECT DISTINCT with WHERE clause only 
supports restriction by partition key and/or static columns.";
+        assertInvalidMessage(distinctQueryErrorMsg,
+                             "SELECT DISTINCT k FROM %s WHERE a >= 80 ALLOW 
FILTERING");
+
+        assertInvalidMessage(distinctQueryErrorMsg,
+                             "SELECT DISTINCT k FROM %s WHERE k IN (1, 2, 3) 
AND a = 10");
+
+        assertInvalidMessage(distinctQueryErrorMsg,
+                            "SELECT DISTINCT k FROM %s WHERE b = 5");
+
+        assertRows(execute("SELECT DISTINCT k FROM %s WHERE k = 1"),
+                   row(1));
+        assertRows(execute("SELECT DISTINCT k FROM %s WHERE k IN (5, 6, 7)"),
+                   row(5),
+                   row(6),
+                   row(7));
+
+        // With static columns
+        createTable("CREATE TABLE %s (k int, a int, s int static, b int, 
PRIMARY KEY (k, a))");
+        createIndex("CREATE INDEX ON %s (b)");
+        for (int i = 0; i < 10; i++)
+        {
+            execute("INSERT INTO %s (k, a, b, s) VALUES (?, ?, ?, ?)", i, i, 
i, i);
+            execute("INSERT INTO %s (k, a, b, s) VALUES (?, ?, ?, ?)", i, i * 
10, i * 10, i * 10);
+        }
+
+        assertRows(execute("SELECT DISTINCT s FROM %s WHERE k = 5"),
+                   row(50));
+        assertRows(execute("SELECT DISTINCT s FROM %s WHERE k IN (5, 6, 7)"),
+                   row(50),
+                   row(60),
+                   row(70));
+    }
+
+    @Test
+    public void testSelectDistinctWithWhereClauseOnStaticColumn() throws 
Throwable
+    {
+        createTable("CREATE TABLE %s (k int, a int, s int static, s1 int 
static, b int, PRIMARY KEY (k, a))");
+
+        for (int i = 0; i < 10; i++)
+        {
+            execute("INSERT INTO %s (k, a, b, s, s1) VALUES (?, ?, ?, ?, ?)", 
i, i, i, i, i);
+            execute("INSERT INTO %s (k, a, b, s, s1) VALUES (?, ?, ?, ?, ?)", 
i, i * 10, i * 10, i * 10, i * 10);
+        }
+
+        execute("INSERT INTO %s (k, a, b, s, s1) VALUES (?, ?, ?, ?, ?)", 2, 
10, 10, 10, 10);
+
+        assertRows(execute("SELECT DISTINCT k, s, s1 FROM %s WHERE s = 90 AND 
s1 = 90 ALLOW FILTERING"),
+                   row(9, 90, 90));
+
+        assertRows(execute("SELECT DISTINCT k, s, s1 FROM %s WHERE s = 90 AND 
s1 = 90 ALLOW FILTERING"),
+                   row(9, 90, 90));
+
+        assertRows(execute("SELECT DISTINCT k, s, s1 FROM %s WHERE s = 10 AND 
s1 = 10 ALLOW FILTERING"),
+                   row(1, 10, 10),
+                   row(2, 10, 10));
+
+        assertRows(execute("SELECT DISTINCT k, s, s1 FROM %s WHERE k = 1 AND s 
= 10 AND s1 = 10 ALLOW FILTERING"),
+                   row(1, 10, 10));
+    }
+
     /**
      * Migrated from cql_tests.py:TestCQL.bug_6327_test()
      */

Reply via email to