diff --git a/CHANGES.txt b/CHANGES.txt index 32d76b40c3..85ca01801e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -105,7 +105,7 @@ * fix re-created keyspace disappering after 1.1.5 upgrade (CASSANDRA-4698) * (CLI) display elapsed time in 2 fraction digits (CASSANDRA-3460) * add authentication support to sstableloader (CASSANDRA-4712) - * Fix CQL3 'is reversed' logic (CASSANDRA-4716) + * Fix CQL3 'is reversed' logic (CASSANDRA-4716, 4759) * (CQL3) Don't return ReversedType in result set metadata (CASSANDRA-4717) * Pluggable Thrift transport factories for CLI (CASSANDRA-4609) Merged from 1.0: diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 08b821128f..301c7c4ad9 100644 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@ -501,6 +501,11 @@ public class SelectStatement implements CQLStatement private ByteBuffer buildBound(Bound bound, Restriction[] restrictions, ColumnNameBuilder builder, List variables) throws InvalidRequestException { + // The end-of-component of composite doesn't depend on whether the + // component type is reversed or not (i.e. the ReversedType is applied + // to the component comparator but not to the end-of-component itself), + // it only depends on whether the slice is reversed + Bound eocBound = isReversed ? Bound.reverse(bound) : bound; for (CFDefinition.Name name : cfDef.columns.values()) { // In a restriction, we always have Bound.START < Bound.END for the "base" comparator. @@ -513,7 +518,7 @@ public class SelectStatement implements CQLStatement // There wasn't any non EQ relation on that key, we select all records having the preceding component as prefix. // For composites, if there was preceding component and we're computing the end, we must change the last component // End-Of-Component, otherwise we would be selecting only one record. - if (builder.componentCount() > 0 && b == Bound.END) + if (builder.componentCount() > 0 && eocBound == Bound.END) return builder.buildAsEndOfRange(); else return builder.build(); @@ -528,7 +533,7 @@ public class SelectStatement implements CQLStatement { Term t = r.bound(b); assert t != null; - return builder.add(t, r.getRelation(b), variables).build(); + return builder.add(t, r.getRelation(eocBound, b), variables).build(); } } // Means no relation at all or everything was an equal @@ -1339,14 +1344,14 @@ public class SelectStatement implements CQLStatement return bounds[b.idx] == null || boundInclusive[b.idx]; } - public Relation.Type getRelation(Bound b) + public Relation.Type getRelation(Bound eocBound, Bound inclusiveBound) { - switch (b) + switch (eocBound) { case START: - return boundInclusive[b.idx] ? Relation.Type.GTE : Relation.Type.GT; + return boundInclusive[inclusiveBound.idx] ? Relation.Type.GTE : Relation.Type.GT; case END: - return boundInclusive[b.idx] ? Relation.Type.LTE : Relation.Type.LT; + return boundInclusive[inclusiveBound.idx] ? Relation.Type.LTE : Relation.Type.LT; } throw new AssertionError(); }