diff --git a/CHANGES.txt b/CHANGES.txt index 12de385765..0b8be6e1ae 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -57,6 +57,7 @@ Merged from 2.0: * Re-add parameter columns to tracing session (CASSANDRA-6942) * Fix writetime/ttl functions for static columns (CASSANDRA-7081) * Suggest CTRL-C or semicolon after three blank lines in cqlsh (CASSANDRA-7142) + * Fix 2ndary index queries with DESC clustering order (CASSANDRA-6950) Merged from 1.2: * Add Cloudstack snitch (CASSANDRA-7147) * Update system.peers correctly when relocating tokens (CASSANDRA-7126) diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 55ce6f971a..ca990a4438 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -928,7 +928,13 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache if (slice.hasBound(b)) { ByteBuffer value = validateIndexedValue(def, slice.bound(b, options)); - expressions.add(new IndexExpression(def.name.bytes, slice.getIndexOperator(b), value)); + IndexOperator op = slice.getIndexOperator(b); + // If the underlying comparator for name is reversed, we need to reverse the IndexOperator: user operation + // always refer to the "forward" sorting even if the clustering order is reversed, but the 2ndary code does + // use the underlying comparator as is. + if (name.type instanceof ReversedType) + op = reverse(op); + expressions.add(new IndexExpression(def.name.bytes, op, value)); } } } @@ -998,6 +1004,18 @@ public class SelectStatement implements CQLStatement, MeasurableForPreparedCache }; } + private static IndexOperator reverse(IndexOperator op) + { + switch (op) + { + case LT: return IndexOperator.GT; + case LTE: return IndexOperator.GTE; + case GT: return IndexOperator.LT; + case GTE: return IndexOperator.LTE; + default: return op; + } + } + private ResultSet process(List rows, QueryOptions options, int limit, long now) throws InvalidRequestException { Selection.ResultSetBuilder result = selection.resultSetBuilder(now);