cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From slebre...@apache.org
Subject [5/5] git commit: Add support for ReversedType in CQL3
Date Thu, 03 May 2012 07:30:04 GMT
Add support for ReversedType in CQL3

patch by slebresne; reviewed by jbellis for CASSANDRA-4004


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

Branch: refs/heads/trunk
Commit: 5b024bd256fa4ca9a19dab0dc4dd77f6e47a5019
Parents: 5c3db0d
Author: Sylvain Lebresne <sylvain@datastax.com>
Authored: Mon Apr 16 15:41:17 2012 +0200
Committer: Sylvain Lebresne <sylvain@datastax.com>
Committed: Thu May 3 09:11:31 2012 +0200

----------------------------------------------------------------------
 CHANGES.txt                                        |    1 +
 .../org/apache/cassandra/cql/SelectStatement.java  |    2 -
 src/java/org/apache/cassandra/cql3/Cql.g           |   30 ++++--
 .../statements/CreateColumnFamilyStatement.java    |   16 +++-
 .../cassandra/cql3/statements/SelectStatement.java |   75 +++++++++++----
 5 files changed, 90 insertions(+), 34 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/5b024bd2/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index a1eef54..3c452ca 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -24,6 +24,7 @@
  * Add way to force the cassandra-cli to refresh it's schema (CASSANDRA-4052)
  * Avoids having replicate on write tasks stacking up at CL.ONE (CASSANDRA-2889)
  * (cql) Fix order by for reversed queries (CASSANDRA-4160)
+ * (cql) Add ReversedType support (CASSANDRA-4004)
 Merged from 1.0:
  * Fix super columns bug where cache is not updated (CASSANDRA-4190)
  * fix maxTimestamp to include row tombstones (CASSANDRA-4116)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5b024bd2/src/java/org/apache/cassandra/cql/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql/SelectStatement.java b/src/java/org/apache/cassandra/cql/SelectStatement.java
index 23595f7..8f0abe7 100644
--- a/src/java/org/apache/cassandra/cql/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql/SelectStatement.java
@@ -196,6 +196,4 @@ public class SelectStatement
                              clause,
                              numRecords);
     }
-
-
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5b024bd2/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index 9051d61..f72aeda 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -26,11 +26,12 @@ options {
 @header {
     package org.apache.cassandra.cql3;
 
-    import java.util.Map;
-    import java.util.HashMap;
+    import java.util.ArrayList;
     import java.util.Collections;
+    import java.util.HashMap;
+    import java.util.LinkedHashMap;
     import java.util.List;
-    import java.util.ArrayList;
+    import java.util.Map;
 
     import org.apache.cassandra.cql3.statements.*;
     import org.apache.cassandra.utils.Pair;
@@ -156,20 +157,18 @@ selectStatement returns [SelectStatement.RawStatement expr]
         boolean isCount = false;
         ConsistencyLevel cLevel = ConsistencyLevel.ONE;
         int limit = 10000;
-        boolean reversed = false;
-        ColumnIdentifier orderBy = null;
+        Map<ColumnIdentifier, Boolean> orderings = new LinkedHashMap<ColumnIdentifier,
Boolean>();
     }
     : K_SELECT ( sclause=selectClause | (K_COUNT '(' sclause=selectClause ')' { isCount =
true; }) )
       K_FROM cf=columnFamilyName
       ( K_USING K_CONSISTENCY K_LEVEL { cLevel = ConsistencyLevel.valueOf($K_LEVEL.text.toUpperCase());
} )?
       ( K_WHERE wclause=whereClause )?
-      ( K_ORDER K_BY c=cident { orderBy = c; } (K_ASC | K_DESC { reversed = true; })? )?
+      ( K_ORDER K_BY orderByClause[orderings] ( ',' orderByClause[orderings] )* )?
       ( K_LIMIT rows=INTEGER { limit = Integer.parseInt($rows.text); } )?
       {
           SelectStatement.Parameters params = new SelectStatement.Parameters(cLevel,
                                                                              limit,
-                                                                             orderBy,
-                                                                             reversed,
+                                                                             orderings,
                                                                              isCount);
           $expr = new SelectStatement.RawStatement(cf, params, sclause, wclause);
       }
@@ -185,6 +184,14 @@ whereClause returns [List<Relation> clause]
     : first=relation { $clause.add(first); } (K_AND next=relation { $clause.add(next); })*
     ;
 
+orderByClause[Map<ColumnIdentifier, Boolean> orderings]
+    @init{
+        ColumnIdentifier orderBy = null;
+        boolean reversed = false;
+    }
+    : c=cident { orderBy = c; } (K_ASC | K_DESC { reversed = true; })? { orderings.put(c,
reversed); }
+    ;
+
 /**
  * INSERT INTO <CF> (<column>, <column>, <column>, ...)
  * VALUES (<value>, <value>, <value>, ...)
@@ -343,6 +350,12 @@ cfamColumns[CreateColumnFamilyStatement.RawStatement expr]
 cfamProperty[CreateColumnFamilyStatement.RawStatement expr]
     : k=property '=' v=propertyValue { $expr.addProperty(k, v); }
     | K_COMPACT K_STORAGE { $expr.setCompactStorage(); }
+    | K_CLUSTERING K_ORDER K_BY '(' cfamOrdering[expr] (',' cfamOrdering[expr])* ')'
+    ;
+
+cfamOrdering[CreateColumnFamilyStatement.RawStatement expr]
+    @init{ boolean reversed=false; }
+    : k=cident (K_ASC | K_DESC { reversed=true;} ) { $expr.setOrdering(k, reversed); }
     ;
 
 /**
@@ -538,6 +551,7 @@ K_ORDER:       O R D E R;
 K_BY:          B Y;
 K_ASC:         A S C;
 K_DESC:        D E S C;
+K_CLUSTERING:  C L U S T E R I N G;
 
 // Case-insensitive alpha characters
 fragment A: ('a'|'A');

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5b024bd2/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
index 1d993b1..eb0aeb4 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
@@ -35,11 +35,13 @@ import org.apache.cassandra.config.ConfigurationException;
 import org.apache.cassandra.db.ColumnFamilyType;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.CompositeType;
+import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.MigrationManager;
 import org.apache.cassandra.thrift.CqlResult;
 import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.io.compress.CompressionParameters;
+import org.apache.cassandra.utils.Pair;
 
 /** A <code>CREATE COLUMNFAMILY</code> parsed from a CQL query statement. */
 public class CreateColumnFamilyStatement extends SchemaAlteringStatement
@@ -131,7 +133,8 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
         private final CFPropDefs properties = new CFPropDefs();
 
         private final List<ColumnIdentifier> keyAliases = new ArrayList<ColumnIdentifier>();
-        private List<ColumnIdentifier> columnAliases = new ArrayList<ColumnIdentifier>();
+        private final List<ColumnIdentifier> columnAliases = new ArrayList<ColumnIdentifier>();
+        private final Map<ColumnIdentifier, Boolean> definedOrdering = new HashMap<ColumnIdentifier,
Boolean>();
 
         private boolean useCompactStorage;
         private Multiset<ColumnIdentifier> definedNames = HashMultiset.create(1);
@@ -236,13 +239,15 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
             }
         }
 
-        private static AbstractType<?> getTypeAndRemove(Map<ColumnIdentifier, String>
columns, ColumnIdentifier t) throws InvalidRequestException, ConfigurationException
+        private AbstractType<?> getTypeAndRemove(Map<ColumnIdentifier, String>
columns, ColumnIdentifier t) throws InvalidRequestException, ConfigurationException
         {
             String typeStr = columns.get(t);
             if (typeStr == null)
                 throw new InvalidRequestException(String.format("Unkown definition %s referenced
in PRIMARY KEY", t));
             columns.remove(t);
-            return CFPropDefs.parseType(typeStr);
+            AbstractType<?> type = CFPropDefs.parseType(typeStr);
+            Boolean isReversed = definedOrdering.get(t);
+            return isReversed != null && isReversed ? ReversedType.getInstance(type)
: type;
         }
 
         public void addDefinition(ColumnIdentifier def, String type)
@@ -266,6 +271,11 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
             properties.addProperty(name, value);
         }
 
+        public void setOrdering(ColumnIdentifier alias, boolean reversed)
+        {
+            definedOrdering.put(alias, reversed);
+        }
+
         public void setCompactStorage()
         {
             useCompactStorage = true;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/5b024bd2/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 03c2a16..00c3b24 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -44,6 +44,7 @@ import org.apache.cassandra.db.context.CounterContext;
 import org.apache.cassandra.db.filter.QueryPath;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.CompositeType;
+import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.db.marshal.TypeParser;
 import org.apache.cassandra.dht.AbstractBounds;
 import org.apache.cassandra.dht.Bounds;
@@ -93,6 +94,8 @@ public class SelectStatement implements CQLStatement
     private final Map<CFDefinition.Name, Restriction> metadataRestrictions = new HashMap<CFDefinition.Name,
Restriction>();
     private Restriction sliceRestriction;
 
+    private boolean isReversed;
+
     private static enum Bound
     {
         START(0), END(1);
@@ -194,8 +197,8 @@ public class SelectStatement implements CQLStatement
         // ...a range (slice) of column names
         if (isColumnRange())
         {
-            ByteBuffer start = getRequestedBound(parameters.isColumnsReversed ? Bound.END
: Bound.START, variables);
-            ByteBuffer finish = getRequestedBound(parameters.isColumnsReversed ? Bound.START
: Bound.END, variables);
+            ByteBuffer start = getRequestedBound(isReversed ? Bound.END : Bound.START, variables);
+            ByteBuffer finish = getRequestedBound(isReversed ? Bound.START : Bound.END, variables);
 
             // Note that we use the total limit for every key. This is
             // potentially inefficient, but then again, IN + LIMIT is not a
@@ -203,13 +206,13 @@ public class SelectStatement implements CQLStatement
             for (ByteBuffer key : getKeys(variables))
             {
                 QueryProcessor.validateKey(key);
-                QueryProcessor.validateSliceRange(cfDef.cfm, start, finish, parameters.isColumnsReversed);
+                QueryProcessor.validateSliceRange(cfDef.cfm, start, finish, isReversed);
                 commands.add(new SliceFromReadCommand(keyspace(),
                                                       key,
                                                       queryPath,
                                                       start,
                                                       finish,
-                                                      parameters.isColumnsReversed,
+                                                      isReversed,
                                                       getLimit()));
             }
         }
@@ -309,9 +312,9 @@ public class SelectStatement implements CQLStatement
         if (isColumnRange())
         {
             SliceRange sliceRange = new SliceRange();
-            sliceRange.start = getRequestedBound(parameters.isColumnsReversed ? Bound.END
: Bound.START, variables);
-            sliceRange.finish = getRequestedBound(parameters.isColumnsReversed ? Bound.START
: Bound.END, variables);
-            sliceRange.reversed = parameters.isColumnsReversed;
+            sliceRange.start = getRequestedBound(isReversed ? Bound.END : Bound.START, variables);
+            sliceRange.finish = getRequestedBound(isReversed ? Bound.START : Bound.END, variables);
+            sliceRange.reversed = isReversed;
             sliceRange.count = -1; // We use this for range slices, where the count is ignored
in favor of the global column count
             thriftSlicePredicate.slice_range = sliceRange;
         }
@@ -724,7 +727,7 @@ public class SelectStatement implements CQLStatement
             }
         }
         // We don't allow reversed on range scan, but we do on multiget (IN (...)), so let's
reverse the rows there too.
-        if (parameters.isColumnsReversed)
+        if (isReversed)
             Collections.reverse(cqlRows);
 
         // Trim result if needed to respect the limit
@@ -954,20 +957,47 @@ public class SelectStatement implements CQLStatement
                 }
             }
 
-            // We only support order by on the the second PK column
-            if (stmt.parameters.orderBy != null)
+            if (!stmt.parameters.orderings.isEmpty())
             {
-                CFDefinition.Name name = cfDef.get(stmt.parameters.orderBy);
-                if (name == null)
-                    throw new InvalidRequestException(String.format("Order by on unknown
column %s", stmt.parameters.orderBy));
+                boolean[] reversedMap = new boolean[cfDef.columns.size()];
+                int i = 0;
+                for (Map.Entry<ColumnIdentifier, Boolean> entry : stmt.parameters.orderings.entrySet())
+                {
+                    ColumnIdentifier column = entry.getKey();
+                    boolean reversed = entry.getValue();
+
+                    CFDefinition.Name name = cfDef.get(column);
+                    if (name == null)
+                        throw new InvalidRequestException(String.format("Order by on unknown
column %s", column));
+
+                    if (name.kind != CFDefinition.Name.Kind.COLUMN_ALIAS)
+                        throw new InvalidRequestException(String.format("Order by is currently
only supported on the clustered columns of the PRIMARY KEY, got %s", column));
+
+                    if (i++ != name.position)
+                        throw new InvalidRequestException(String.format("Order by currently
only support the ordering of columns following their declared order in the PRIMARY KEY"));
+
+                    if (reversed != isReversedType(name))
+                        reversedMap[name.position] = true;
+                }
 
-                if (name.kind != CFDefinition.Name.Kind.COLUMN_ALIAS || name.position !=
0)
-                    throw new InvalidRequestException(String.format("Order by is currently
only supported on the second column of the PRIMARY KEY (if any), got %s", stmt.parameters.orderBy));
+                // Check that all boolean in reversedMap agrees
+                Boolean isReversed = null;
+                for (boolean b : reversedMap)
+                {
+                    if (isReversed == null)
+                    {
+                        isReversed = b;
+                        continue;
+                    }
+                    if (isReversed != b)
+                        throw new InvalidRequestException(String.format("Unsupported order
by relation"));
+                }
+                stmt.isReversed = isReversed;
             }
 
             // Only allow reversed if the row key restriction is an equality,
             // since we don't know how to reverse otherwise
-            if (stmt.parameters.isColumnsReversed)
+            if (stmt.isReversed)
             {
                 if (stmt.keyRestriction == null || !stmt.keyRestriction.isEquality())
                     throw new InvalidRequestException("Descending order is only supported
is the first part of the PRIMARY KEY is restricted by an Equal or a IN");
@@ -976,6 +1006,11 @@ public class SelectStatement implements CQLStatement
             return new ParsedStatement.Prepared(stmt, Arrays.<AbstractType<?>>asList(types));
         }
 
+        private static boolean isReversedType(CFDefinition.Name name)
+        {
+            return name.type instanceof ReversedType;
+        }
+
         Restriction updateRestriction(ColumnIdentifier name, Restriction restriction, Relation
newRel) throws InvalidRequestException
         {
             switch (newRel.operator())
@@ -1145,16 +1180,14 @@ public class SelectStatement implements CQLStatement
     {
         private final int limit;
         private final ConsistencyLevel consistencyLevel;
-        private final ColumnIdentifier orderBy;
-        private final boolean isColumnsReversed;
+        private final Map<ColumnIdentifier, Boolean> orderings;
         private final boolean isCount;
 
-        public Parameters(ConsistencyLevel consistency, int limit, ColumnIdentifier orderBy,
boolean reversed, boolean isCount)
+        public Parameters(ConsistencyLevel consistency, int limit, Map<ColumnIdentifier,
Boolean> orderings, boolean isCount)
         {
             this.consistencyLevel = consistency;
             this.limit = limit;
-            this.orderBy = orderBy;
-            this.isColumnsReversed = reversed;
+            this.orderings = orderings;
             this.isCount = isCount;
         }
     }


Mime
View raw message