Merge branch 'cassandra-2.0' into cassandra-2.1 Conflicts: src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/143372bf Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/143372bf Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/143372bf Branch: refs/heads/trunk Commit: 143372bf7cba1ec25cfc08c5396ba0382b96b2c2 Parents: 3b4084b 4589656 Author: Sylvain Lebresne <sylv...@datastax.com> Authored: Fri Feb 21 14:09:26 2014 +0100 Committer: Sylvain Lebresne <sylv...@datastax.com> Committed: Fri Feb 21 14:09:26 2014 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cql3/statements/SelectStatement.java | 79 ++++---------------- 2 files changed, 15 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/143372bf/CHANGES.txt ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/143372bf/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 868d51c,9fbed03..dfeea84 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@@ -78,9 -80,8 +78,8 @@@ public class SelectStatement implement private boolean isKeyRange; private boolean keyIsInRelation; private boolean usesSecondaryIndexing; - private boolean needOrderOnLastClustering; - private Map<CFDefinition.Name, Integer> orderingIndexes; + private Map<ColumnIdentifier, Integer> orderingIndexes; private boolean selectsStaticColumns; private boolean selectsOnlyStaticColumns; @@@ -1114,82 -1108,92 +1124,32 @@@ /** * Orders results when multiple keys are selected (using IN) */ - private void orderResults(ResultSet cqlRows) + private void orderResults(ResultSet cqlRows, List<ByteBuffer> variables) throws InvalidRequestException { - if (cqlRows.size() == 0) - return; - - /* - * We need to do post-query ordering in 2 cases: - * 1) if the last clustering column is restricted by a IN and has no explicit ORDER BY on it. - * 2) if the partition key is restricted by a IN and there is some ORDER BY values - */ - boolean needOrderOnPartitionKey = keyIsInRelation && !parameters.orderings.isEmpty(); - if (!needOrderOnLastClustering && !needOrderOnPartitionKey) + if (cqlRows.size() == 0 || !needsPostQueryOrdering()) return; assert orderingIndexes != null; - // optimization when only *one* order condition was given - // because there is no point of using composite comparator if there is only one order condition - if (parameters.orderings.size() == 1) - { - CFDefinition.Name ordering = cfDef.get(parameters.orderings.keySet().iterator().next()); - Collections.sort(cqlRows.rows, new SingleColumnComparator(orderingIndexes.get(ordering), ordering.type)); - return; - } + List<Integer> idToSort = new ArrayList<Integer>(); + List<Comparator<ByteBuffer>> sorters = new ArrayList<Comparator<ByteBuffer>>(); - // Note that we add the ORDER BY sorters first as they should prevail over ordering - // on the last clustering restriction. - // builds a 'composite' type for multi-column comparison from the comparators of the ordering components - // and passes collected position information and built composite comparator to CompositeComparator to do - // an actual comparison of the CQL rows. - List<AbstractType<?>> types = new ArrayList<AbstractType<?>>(parameters.orderings.size()); - int[] positions = new int[parameters.orderings.size()]; - - int idx = 0; for (ColumnIdentifier identifier : parameters.orderings.keySet()) { - CFDefinition.Name orderingColumn = cfDef.get(identifier); - types.add(orderingColumn.type); - positions[idx++] = orderingIndexes.get(orderingColumn); - } - - Collections.sort(cqlRows.rows, new CompositeComparator(types, positions)); - } - - private void handleGroup(Selection selection, - Selection.ResultSetBuilder result, - ByteBuffer[] keyComponents, - ColumnGroupMap columns, - Map<CFDefinition.Name, ByteBuffer> staticValues) throws InvalidRequestException - { - // Respect requested order - result.newRow(); - for (CFDefinition.Name name : selection.getColumnsList()) - { - switch (name.kind) - { - case KEY_ALIAS: - result.add(keyComponents[name.position]); - break; - case COLUMN_ALIAS: - result.add(columns.getKeyComponent(name.position)); - break; - case VALUE_ALIAS: - // This should not happen for SPARSE - throw new AssertionError(); - case COLUMN_METADATA: - if (name.type.isCollection()) - { - result.add(getCollectionValue(name, columns)); - } - else - { - result.add(columns.getSimple(name.name.key)); - } - break; - case STATIC: - result.add(staticValues.get(name)); - break; - } + ColumnDefinition orderingColumn = cfm.getColumnDefinition(identifier); + idToSort.add(orderingIndexes.get(orderingColumn.name)); + sorters.add(orderingColumn.type); } - } - if (needOrderOnLastClustering) - { - List<ColumnDefinition> cc = cfm.clusteringColumns(); - idToSort.add(orderingIndexes.get(cc.get(cc.size() - 1).name)); - Restriction last = columnRestrictions[columnRestrictions.length - 1]; - sorters.add(makeComparatorFor(last.values(variables), isReversed)); - } - - private static ByteBuffer getCollectionValue(CFDefinition.Name name, ColumnGroupMap columns) - { - List<Pair<ByteBuffer, Column>> collection = columns.getCollection(name.name.key); - return collection == null ? null : ((CollectionType)name.type).serialize(collection); + Comparator<List<ByteBuffer>> comparator = idToSort.size() == 1 + ? new SingleColumnComparator(idToSort.get(0), sorters.get(0)) + : new CompositeComparator(sorters, idToSort); + Collections.sort(cqlRows.rows, comparator); } - // Comparator used when the last clustering key is an IN, to sort result - // rows in the order of the values provided for the IN. - private Comparator<ByteBuffer> makeComparatorFor(final List<ByteBuffer> vals, final boolean isReversed) - { - // This may not always be the most efficient, but it probably is if - // values is small, which is likely to be the most common case. - return new Comparator<ByteBuffer>() - { - private final List<ByteBuffer> values = isReversed ? com.google.common.collect.Lists.reverse(vals) : vals; - - public int compare(ByteBuffer b1, ByteBuffer b2) - { - int idx1 = -1; - int idx2 = -1; - for (int i = 0; i < values.size(); i++) - { - ByteBuffer bb = values.get(i); - if (bb.equals(b1)) - idx1 = i; - if (bb.equals(b2)) - idx2 = i; - - if (idx1 >= 0 && idx2 >= 0) - break; - } - assert idx1 >= 0 && idx2 >= 0 : "Got CQL3 row that was not queried in resultset"; - return idx1 - idx2; - } - }; - } - - private static ByteBuffer getSimpleValue(CFDefinition.Name name, ColumnGroupMap columns) + private static boolean isReversedType(ColumnDefinition def) { - Column c = columns.getSimple(name.name.key); - return c == null ? null : c.value(); - } - - private static boolean isReversedType(CFDefinition.Name name) - { - return name.type instanceof ReversedType; + return def.type instanceof ReversedType; } private boolean columnFilterIsIdentity() @@@ -1441,22 -1448,12 +1401,12 @@@ // We only support IN for the last name and for compact storage so far // TODO: #3885 allows us to extend to non compact as well, but that remains to be done if (i != stmt.columnRestrictions.length - 1) - throw new InvalidRequestException(String.format("PRIMARY KEY part %s cannot be restricted by IN relation", cname)); + throw new InvalidRequestException(String.format("PRIMARY KEY part %s cannot be restricted by IN relation", cdef.name)); else if (stmt.selectACollection()) - throw new InvalidRequestException(String.format("Cannot restrict PRIMARY KEY part %s by IN relation as a collection is selected by the query", cname)); + throw new InvalidRequestException(String.format("Cannot restrict PRIMARY KEY part %s by IN relation as a collection is selected by the query", cdef.name)); - // We will return rows in the order of the IN, unless that clustering column has a specific order set on. - if (parameters.orderings.get(cdef.name) == null) - { - stmt.needOrderOnLastClustering = true; - stmt.orderingIndexes = new HashMap<ColumnIdentifier, Integer>(); - int index = indexOf(cdef, stmt.selection); - if (index < 0) - index = stmt.selection.addColumnForOrdering(cdef); - stmt.orderingIndexes.put(cdef.name, index); - } } - previous = cname; + previous = cdef; } // Covers indexes on the first clustering column (among others). @@@ -1494,16 -1491,16 +1444,15 @@@ if (stmt.isKeyRange) throw new InvalidRequestException("ORDER BY is only supported when the partition key is restricted by an EQ or an IN."); - // If we order an IN query, we'll have to do a manual sort post-query. Currently, this sorting requires that we - // have queried the column on which we sort (TODO: we should update it to add the column on which we sort to the one - // queried automatically, and then removing it from the resultSet afterwards if needed) + // If we order post-query (see orderResults), the sorted column needs to be in the ResultSet for sorting, even if we don't + // ultimately ship them to the client (CASSANDRA-4911). - if (stmt.keyIsInRelation || stmt.needOrderOnLastClustering) + if (stmt.keyIsInRelation) { - if (stmt.orderingIndexes == null) - stmt.orderingIndexes = new HashMap<ColumnIdentifier, Integer>(); - stmt.orderingIndexes = new HashMap<CFDefinition.Name, Integer>(); ++ stmt.orderingIndexes = new HashMap<>(); for (ColumnIdentifier column : stmt.parameters.orderings.keySet()) { - final CFDefinition.Name name = cfDef.get(column); - if (name == null) + final ColumnDefinition def = cfm.getColumnDefinition(column); + if (def == null) { if (containsAlias(column)) throw new InvalidRequestException(String.format("Aliases are not allowed in order by clause ('%s')", column));