You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by br...@apache.org on 2014/06/26 18:02:36 UTC

[03/13] git commit: Refuse range queries with strict bounds on compact tables

Refuse range queries with strict bounds on compact tables

patch by slebresne; reviewed by iamaleksey for CASSANDRA-7059


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

Branch: refs/heads/trunk
Commit: 79a4dd58cd060cc28f32e0fc17001fe1179552a2
Parents: 6e4dca0
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Thu May 8 17:51:29 2014 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Thu Jun 26 10:12:59 2014 +0200

----------------------------------------------------------------------
 CHANGES.txt                                     |  2 ++
 .../cassandra/cql3/SingleColumnRelation.java    | 10 ++++++
 .../cql3/statements/SelectStatement.java        | 34 ++++++++++++++++++++
 3 files changed, 46 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/79a4dd58/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index c3fe8d7..2b3ace3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -23,6 +23,8 @@
  * Accept subtypes for function results, type casts (CASSANDRA-6766)
  * Support DISTINCT for static columns and fix behaviour when DISTINC is
    not use (CASSANDRA-7305).
+ * Refuse range queries with strict bounds on compact tables since they
+   are broken (CASSANDRA-7059)
 Merged from 1.2:
  * Expose global ColumnFamily metrics (CASSANDRA-7273)
  * cqlsh: Fix CompositeType columns in DESCRIBE TABLE output (CASSANDRA-7399)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/79a4dd58/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
index 5464c23..642be66 100644
--- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
+++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java
@@ -84,6 +84,16 @@ public class SingleColumnRelation extends Relation
         return false;
     }
 
+    public SingleColumnRelation withNonStrictOperator()
+    {
+        switch (relationType)
+        {
+            case GT: return new SingleColumnRelation(entity, Type.GTE, value);
+            case LT:  return new SingleColumnRelation(entity, Type.LTE, value);
+            default: return this;
+        }
+    }
+
     @Override
     public String toString()
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/79a4dd58/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 f106402..98bd99a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -1977,6 +1977,40 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
                                                       "thus may have unpredictable performance. If you want to execute " +
                                                       "this query despite the performance unpredictability, use ALLOW FILTERING");
             }
+
+            // We don't internally support exclusive slice bounds on non-composite tables. To deal with it we do an
+            // inclusive slice and remove post-query the value that shouldn't be returned. One problem however is that
+            // if there is a user limit, that limit may make the query return before the end of the slice is reached,
+            // in which case, once we'll have removed bound post-query, we might end up with less results than
+            // requested which would be incorrect. For single-partition query, this is not a problem, we just ask for
+            // one more result (see updateLimitForQuery()) since that's enough to compensate for that problem. For key
+            // range however, each returned row may include one result that will have to be trimmed, so we would have
+            // to bump the query limit by N where N is the number of rows we will return, but we don't know that in
+            // advance. So, since we currently don't have a good way to handle such query, we refuse it (#7059) rather
+            // than answering with something that is wrong.
+            if (stmt.sliceRestriction != null && stmt.isKeyRange && limit != null)
+            {
+                SingleColumnRelation rel = findInclusiveClusteringRelationForCompact(stmt.cfDef);
+                throw new InvalidRequestException(String.format("The query requests a restriction of rows with a strict bound (%s) over a range of partitions. "
+                                                              + "This is not supported by the underlying storage engine for COMPACT tables if a LIMIT is provided. "
+                                                              + "Please either make the condition non strict (%s) or remove the user LIMIT", rel, rel.withNonStrictOperator()));
+            }
+        }
+
+        private SingleColumnRelation findInclusiveClusteringRelationForCompact(CFDefinition cfDef)
+        {
+            for (Relation r : whereClause)
+            {
+                // We only call this when sliceRestriction != null, i.e. for compact table with non composite comparator,
+                // so it can't be a MultiColumnRelation.
+                SingleColumnRelation rel = (SingleColumnRelation)r;
+                if (cfDef.get(rel.getEntity()).kind == CFDefinition.Name.Kind.COLUMN_ALIAS
+                    && (rel.operator() == Relation.Type.GT || rel.operator() == Relation.Type.LT))
+                    return rel;
+            }
+
+            // We're not supposed to call this method unless we know this can't happen
+            throw new AssertionError();
         }
 
         private boolean containsAlias(final ColumnIdentifier name)