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/cassandra-2.0 Commit: 79a4dd58cd060cc28f32e0fc17001fe1179552a2 Parents: 6e4dca0 Author: Sylvain Lebresne <sylv...@datastax.com> Authored: Thu May 8 17:51:29 2014 +0200 Committer: Sylvain Lebresne <sylv...@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)