Merge branch 'cassandra-2.0' into cassandra-2.1

Conflicts:
        src/java/org/apache/cassandra/cql3/ColumnCondition.java
        src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
        src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
        src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
        src/java/org/apache/cassandra/cql3/statements/Selection.java
        src/java/org/apache/cassandra/db/marshal/CollectionType.java
        src/java/org/apache/cassandra/db/marshal/DynamicCompositeType.java
        src/java/org/apache/cassandra/db/marshal/ListType.java
        src/java/org/apache/cassandra/db/marshal/MapType.java
        src/java/org/apache/cassandra/db/marshal/SetType.java
        src/java/org/apache/cassandra/serializers/CollectionSerializer.java
        src/java/org/apache/cassandra/serializers/ListSerializer.java
        src/java/org/apache/cassandra/serializers/MapSerializer.java
        src/java/org/apache/cassandra/serializers/SetSerializer.java
        test/unit/org/apache/cassandra/db/marshal/CollectionTypeTest.java


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

Branch: refs/heads/cassandra-2.1
Commit: 33bd8c207a2b59990019c2cbfcbeceb9b6f8456e
Parents: 07dc6b5 9d06ea6
Author: Sylvain Lebresne <sylv...@datastax.com>
Authored: Mon May 19 12:26:32 2014 +0200
Committer: Sylvain Lebresne <sylv...@datastax.com>
Committed: Mon May 19 12:26:32 2014 +0200

----------------------------------------------------------------------
 .../apache/cassandra/cql3/ColumnCondition.java  | 277 +++++++++++++------
 src/java/org/apache/cassandra/cql3/Lists.java   |  13 +
 src/java/org/apache/cassandra/cql3/Maps.java    |  20 ++
 src/java/org/apache/cassandra/cql3/Sets.java    |  15 +
 .../cql3/statements/CQL3CasConditions.java      |  10 +-
 .../cql3/statements/ModificationStatement.java  |   4 +-
 .../cql3/statements/SelectStatement.java        |  16 +-
 .../cassandra/cql3/statements/Selection.java    |  39 +--
 8 files changed, 272 insertions(+), 122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/ColumnCondition.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/ColumnCondition.java
index c2617fe,adc8e3a..ed2b6b4
--- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java
@@@ -74,122 -73,209 +75,196 @@@ public class ColumnConditio
          value.collectMarkerSpecification(boundNames);
      }
  
-     public ColumnCondition.WithOptions with(QueryOptions options)
 -    public ColumnCondition.Bound bind(List<ByteBuffer> variables) throws 
InvalidRequestException
++    public ColumnCondition.Bound bind(QueryOptions options) throws 
InvalidRequestException
      {
-         return new WithOptions(options);
+         return column.type instanceof CollectionType
 -             ? (collectionElement == null ? new CollectionBound(this, 
variables) : new ElementAccessBound(this, variables))
 -             : new SimpleBound(this, variables);
++             ? (collectionElement == null ? new CollectionBound(this, 
options) : new ElementAccessBound(this, options))
++             : new SimpleBound(this, options);
      }
  
-     public class WithOptions
+     public static abstract class Bound
      {
-         private final QueryOptions options;
 -        public final CFDefinition.Name column;
++        public final ColumnDefinition column;
  
-         private WithOptions(QueryOptions options)
 -        protected Bound(CFDefinition.Name column)
++        protected Bound(ColumnDefinition column)
          {
-             this.options = options;
+             this.column = column;
          }
  
-         public boolean equalsTo(WithOptions other) throws 
InvalidRequestException
+         /**
+          * Validates whether this condition applies to {@code current}.
+          */
 -        public abstract boolean appliesTo(ColumnNameBuilder rowPrefix, 
ColumnFamily current, long now) throws InvalidRequestException;
++        public abstract boolean appliesTo(Composite rowPrefix, ColumnFamily 
current, long now) throws InvalidRequestException;
+ 
+         public ByteBuffer getCollectionElementValue()
          {
-             if (!column().equals(other.column()))
-                 return false;
+             return null;
+         }
  
-             if ((collectionElement() == null) != (other.collectionElement() 
== null))
-                 return false;
 -        protected ColumnNameBuilder copyOrUpdatePrefix(CFMetaData cfm, 
ColumnNameBuilder rowPrefix)
 -        {
 -            return column.kind == CFDefinition.Name.Kind.STATIC ? 
cfm.getStaticColumnNameBuilder() : rowPrefix.copy();
 -        }
 -
 -        protected boolean equalsValue(ByteBuffer value, Column c, 
AbstractType<?> type, long now)
++        protected boolean equalsValue(ByteBuffer value, Cell c, 
AbstractType<?> type, long now)
+         {
+             return value == null
+                  ? c == null || !c.isLive(now)
+                  : c != null && c.isLive(now) && type.compare(c.value(), 
value) == 0;
+         }
  
-             if (collectionElement() != null)
 -        protected Iterator<Column> collectionColumns(ColumnNameBuilder 
collectionPrefix, ColumnFamily cf, final long now)
++        protected Iterator<Cell> collectionColumns(CellName collection, 
ColumnFamily cf, final long now)
+         {
+             // We are testing for collection equality, so we need to have the 
expected values *and* only those.
 -            ColumnSlice[] collectionSlice = new ColumnSlice[]{ new 
ColumnSlice(collectionPrefix.build(), collectionPrefix.buildAsEndOfRange()) };
++            ColumnSlice[] collectionSlice = new ColumnSlice[]{ 
collection.slice() };
+             // Filter live columns, this makes things simpler afterwards
 -            return Iterators.filter(cf.iterator(collectionSlice), new 
Predicate<Column>()
++            return Iterators.filter(cf.iterator(collectionSlice), new 
Predicate<Cell>()
              {
-                 assert column.type instanceof ListType || column.type 
instanceof MapType;
-                 AbstractType<?> comparator = column.type instanceof ListType
-                                            ? Int32Type.instance
-                                            : ((MapType)column.type).keys;
 -                public boolean apply(Column c)
++                public boolean apply(Cell c)
+                 {
+                     // we only care about live columns
+                     return c.isLive(now);
+                 }
+             });
+         }
+     }
  
-                 if 
(comparator.compare(collectionElement().bindAndGet(options), 
other.collectionElement().bindAndGet(options)) != 0)
-                     return false;
-             }
+     private static class SimpleBound extends Bound
+     {
+         public final ByteBuffer value;
  
-             return 
value().bindAndGet(options).equals(other.value().bindAndGet(other.options));
 -        private SimpleBound(ColumnCondition condition, List<ByteBuffer> 
variables) throws InvalidRequestException
++        private SimpleBound(ColumnCondition condition, QueryOptions options) 
throws InvalidRequestException
+         {
+             super(condition.column);
+             assert !(column.type instanceof CollectionType) && 
condition.collectionElement == null;
 -            this.value = condition.value.bindAndGet(variables);
++            this.value = condition.value.bindAndGet(options);
          }
  
-         private ColumnDefinition column()
 -        public boolean appliesTo(ColumnNameBuilder rowPrefix, ColumnFamily 
current, long now) throws InvalidRequestException
++        public boolean appliesTo(Composite rowPrefix, ColumnFamily current, 
long now) throws InvalidRequestException
          {
-             return column;
 -            ColumnNameBuilder prefix = copyOrUpdatePrefix(current.metadata(), 
rowPrefix);
 -            ByteBuffer columnName = column.kind == 
CFDefinition.Name.Kind.VALUE_ALIAS
 -                                  ? prefix.build()
 -                                  : prefix.add(column.name.key).build();
 -
 -            return equalsValue(value, current.getColumn(columnName), 
column.type, now);
++            CellName name = current.metadata().comparator.create(rowPrefix, 
column);
++            return equalsValue(value, current.getColumn(name), column.type, 
now);
          }
  
-         private Term collectionElement()
+         @Override
+         public boolean equals(Object o)
          {
-             return collectionElement;
+             if (!(o instanceof SimpleBound))
+                 return false;
+ 
+             SimpleBound that = (SimpleBound)o;
+             if (!column.equals(that.column))
+                 return false;
+ 
+             return value == null || that.value == null
+                  ? value == null && that.value == null
+                  : column.type.compare(value, that.value) == 0;
          }
  
-         private Term value()
+         @Override
+         public int hashCode()
          {
-             return value;
+             return Objects.hashCode(column, value);
          }
+     }
  
-         public ByteBuffer getCollectionElementValue() throws 
InvalidRequestException
+     private static class ElementAccessBound extends Bound
+     {
+         public final ByteBuffer collectionElement;
+         public final ByteBuffer value;
+ 
 -        private ElementAccessBound(ColumnCondition condition, 
List<ByteBuffer> variables) throws InvalidRequestException
++        private ElementAccessBound(ColumnCondition condition, QueryOptions 
options) throws InvalidRequestException
          {
-             return collectionElement == null ? null : 
collectionElement.bindAndGet(options);
+             super(condition.column);
+             assert column.type instanceof CollectionType && 
condition.collectionElement != null;
 -            this.collectionElement = 
condition.collectionElement.bindAndGet(variables);
 -            this.value = condition.value.bindAndGet(variables);
++            this.collectionElement = 
condition.collectionElement.bindAndGet(options);
++            this.value = condition.value.bindAndGet(options);
          }
  
-         /**
-          * Validates whether this condition applies to {@code current}.
-          */
-         public boolean appliesTo(Composite rowPrefix, ColumnFamily current, 
long now) throws InvalidRequestException
 -        public boolean appliesTo(ColumnNameBuilder rowPrefix, ColumnFamily 
current, final long now) throws InvalidRequestException
++        public boolean appliesTo(Composite rowPrefix, ColumnFamily current, 
final long now) throws InvalidRequestException
          {
-             if (column.type instanceof CollectionType)
-                 return collectionAppliesTo((CollectionType)column.type, 
rowPrefix, current, now);
+             if (collectionElement == null)
+                 throw new InvalidRequestException("Invalid null value for " + 
(column.type instanceof MapType ? "map" : "list") + " element access");
  
-             assert collectionElement == null;
-             Cell c = 
current.getColumn(current.metadata().comparator.create(rowPrefix, column));
-             ByteBuffer v = value.bindAndGet(options);
-             return v == null
-                  ? c == null || !c.isLive(now)
-                  : c != null && c.isLive(now) && c.value().equals(v);
 -            ColumnNameBuilder collectionPrefix = 
copyOrUpdatePrefix(current.metadata(), rowPrefix).add(column.name.key);
+             if (column.type instanceof MapType)
 -                return equalsValue(value, 
current.getColumn(collectionPrefix.add(collectionElement).build()), 
((MapType)column.type).values, now);
++                return equalsValue(value, 
current.getColumn(current.metadata().comparator.create(rowPrefix, column, 
collectionElement)), ((MapType)column.type).values, now);
+ 
+             assert column.type instanceof ListType;
+             int idx = ByteBufferUtil.toInt(collectionElement);
+             if (idx < 0)
+                 throw new InvalidRequestException(String.format("Invalid 
negative list index %d", idx));
+ 
 -            Iterator<Column> iter = collectionColumns(collectionPrefix, 
current, now);
++            Iterator<Cell> iter = 
collectionColumns(current.metadata().comparator.create(rowPrefix, column), 
current, now);
+             int adv = Iterators.advance(iter, idx);
+             if (adv != idx || !iter.hasNext())
+                 throw new InvalidRequestException(String.format("List index 
%d out of bound, list has size %d", idx, adv));
+ 
+             // We don't support null values inside collections, so a 
condition like 'IF l[3] = null' can only
+             // be false. We do special case though, as the compare below 
might mind getting a null.
+             if (value == null)
+                 return false;
+ 
+             return 
((ListType)column.type).elements.compare(iter.next().value(), value) == 0;
          }
  
-         private boolean collectionAppliesTo(CollectionType type, Composite 
rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException
+         public ByteBuffer getCollectionElementValue()
          {
-             Term.Terminal v = value.bind(options);
+             return collectionElement;
+         }
  
-             // For map element access, we won't iterate over the collection, 
so deal with that first. In other case, we do.
-             if (collectionElement != null && type instanceof MapType)
-             {
-                 ByteBuffer e = collectionElement.bindAndGet(options);
-                 if (e == null)
-                     throw new InvalidRequestException("Invalid null value for 
map access");
-                 return mapElementAppliesTo((MapType)type, current, rowPrefix, 
e, v.get(options), now);
-             }
+         @Override
+         public boolean equals(Object o)
+         {
+             if (!(o instanceof ElementAccessBound))
+                 return false;
  
-             CellName name = current.metadata().comparator.create(rowPrefix, 
column);
-             // We are testing for collection equality, so we need to have the 
expected values *and* only those.
-             ColumnSlice[] collectionSlice = new ColumnSlice[]{ name.slice() };
-             // Filter live columns, this makes things simpler afterwards
-             Iterator<Cell> iter = 
Iterators.filter(current.iterator(collectionSlice), new Predicate<Cell>()
-             {
-                 public boolean apply(Cell c)
-                 {
-                     // we only care about live columns
-                     return c.isLive(now);
-                 }
-             });
+             ElementAccessBound that = (ElementAccessBound)o;
+             if (!column.equals(that.column))
+                 return false;
  
-             if (v == null)
-                 return !iter.hasNext();
+             if ((collectionElement == null) != (that.collectionElement == 
null))
+                 return false;
  
              if (collectionElement != null)
              {
-                 assert type instanceof ListType;
-                 ByteBuffer e = collectionElement.bindAndGet(options);
-                 if (e == null)
-                     throw new InvalidRequestException("Invalid null value for 
list access");
+                 assert column.type instanceof ListType || column.type 
instanceof MapType;
+                 AbstractType<?> comparator = column.type instanceof ListType
+                                            ? Int32Type.instance
+                                            : ((MapType)column.type).keys;
  
-                 return listElementAppliesTo((ListType)type, iter, e, 
v.get(options));
+                 if (comparator.compare(collectionElement, 
that.collectionElement) != 0)
+                     return false;
              }
  
+             return column.type.compare(value, that.value) == 0;
+         }
+ 
+         @Override
+         public int hashCode()
+         {
+             return Objects.hashCode(column, collectionElement, value);
+         }
+     }
+ 
+     private static class CollectionBound extends Bound
+     {
+         public final Term.Terminal value;
+ 
 -        private CollectionBound(ColumnCondition condition, List<ByteBuffer> 
variables) throws InvalidRequestException
++        private CollectionBound(ColumnCondition condition, QueryOptions 
options) throws InvalidRequestException
+         {
+             super(condition.column);
+             assert column.type instanceof CollectionType && 
condition.collectionElement == null;
 -            this.value = condition.value.bind(variables);
++            this.value = condition.value.bind(options);
+         }
+ 
 -        public boolean appliesTo(ColumnNameBuilder rowPrefix, ColumnFamily 
current, final long now) throws InvalidRequestException
++        public boolean appliesTo(Composite rowPrefix, ColumnFamily current, 
final long now) throws InvalidRequestException
+         {
+             CollectionType type = (CollectionType)column.type;
 -            CFMetaData cfm = current.metadata();
+ 
 -            ColumnNameBuilder collectionPrefix = copyOrUpdatePrefix(cfm, 
rowPrefix).add(column.name.key);
 -
 -            Iterator<Column> iter = collectionColumns(collectionPrefix, 
current, now);
++            Iterator<Cell> iter = 
collectionColumns(current.metadata().comparator.create(rowPrefix, column), 
current, now);
+             if (value == null)
+                 return !iter.hasNext();
+ 
              switch (type.kind)
              {
-                 case LIST: return listAppliesTo((ListType)type, iter, 
((Lists.Value)v).elements);
-                 case SET: return setAppliesTo((SetType)type, iter, 
((Sets.Value)v).elements);
-                 case MAP: return mapAppliesTo((MapType)type, iter, 
((Maps.Value)v).map);
 -                case LIST: return listAppliesTo((ListType)type, cfm, iter, 
((Lists.Value)value).elements);
 -                case SET: return setAppliesTo((SetType)type, cfm, iter, 
((Sets.Value)value).elements);
 -                case MAP: return mapAppliesTo((MapType)type, cfm, iter, 
((Maps.Value)value).map);
++                case LIST: return listAppliesTo((ListType)type, iter, 
((Lists.Value)value).elements);
++                case SET: return setAppliesTo((SetType)type, iter, 
((Sets.Value)value).elements);
++                case MAP: return mapAppliesTo((MapType)type, iter, 
((Maps.Value)value).map);
              }
              throw new AssertionError();
          }
@@@ -203,20 -295,7 +278,7 @@@
              return !iter.hasNext();
          }
  
-         private boolean listElementAppliesTo(ListType type, Iterator<Cell> 
iter, ByteBuffer element, ByteBuffer value) throws InvalidRequestException
-         {
-             int idx = ByteBufferUtil.toInt(element);
-             if (idx < 0)
-                 throw new InvalidRequestException(String.format("Invalid 
negative list index %d", idx));
- 
-             int adv = Iterators.advance(iter, idx);
-             if (adv != idx || !iter.hasNext())
-                 throw new InvalidRequestException(String.format("List index 
%d out of bound, list has size %d", idx, adv));
- 
-             return type.elements.compare(iter.next().value(), value) == 0;
-         }
- 
 -        private boolean setAppliesTo(SetType type, CFMetaData cfm, 
Iterator<Column> iter, Set<ByteBuffer> elements)
 +        private boolean setAppliesTo(SetType type, Iterator<Cell> iter, 
Set<ByteBuffer> elements)
          {
              Set<ByteBuffer> remaining = new TreeSet<>(type.elements);
              remaining.addAll(elements);
@@@ -248,11 -327,31 +310,48 @@@
              return remaining.isEmpty();
          }
  
-         private boolean mapElementAppliesTo(MapType type, ColumnFamily 
current, Composite rowPrefix, ByteBuffer element, ByteBuffer value, long now)
+         @Override
+         public boolean equals(Object o)
          {
-             CellName name = current.getComparator().create(rowPrefix, column, 
element);
-             Cell c = current.getColumn(name);
-             return c != null && c.isLive(now) && 
type.values.compare(c.value(), value) == 0;
+             if (!(o instanceof CollectionBound))
+                 return false;
+ 
+             CollectionBound that = (CollectionBound)o;
+             if (!column.equals(that.column))
+                 return false;
+ 
 -            // Slightly inefficient because it serialize the collection just 
for the sake of comparison.
 -            // We could improve by adding an equals() method to Lists.Value, 
Sets.Value and Maps.Value but
 -            // this method is only called when there is 2 conditions on the 
same collection to make sure
 -            // both are not incompatible, so overall it's probably not worth 
the effort.
 -            ByteBuffer thisVal = value.get();
 -            ByteBuffer thatVal = that.value.get();
 -            return thisVal == null || thatVal == null
 -                 ? thisVal == null && thatVal == null
 -                 : column.type.compare(thisVal, thatVal) == 0;
++            if (value == null || that.value == null)
++                return value == null && that.value == null;
++
++            switch (((CollectionType)column.type).kind)
++            {
++                case LIST: return 
((Lists.Value)value).equals((ListType)column.type, (Lists.Value)that.value);
++                case SET: return 
((Sets.Value)value).equals((SetType)column.type, (Sets.Value)that.value);
++                case MAP: return 
((Maps.Value)value).equals((MapType)column.type, (Maps.Value)that.value);
++            }
++            throw new AssertionError();
+         }
+ 
+         @Override
+         public int hashCode()
+         {
 -            return Objects.hashCode(column, value.get());
++            Object val = null;
++            if (value != null)
++            {
++                switch (((CollectionType)column.type).kind)
++                {
++                    case LIST:
++                        val = ((Lists.Value)value).elements.hashCode();
++                        break;
++                    case SET:
++                        val = ((Sets.Value)value).elements.hashCode();
++                        break;
++                    case MAP:
++                        val = ((Maps.Value)value).map.hashCode();
++                        break;
++                }
++            }
++            return Objects.hashCode(column, val);
          }
      }
  

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Lists.java
index 751ccdb,4ad39db..f12af88
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@@ -20,6 -20,6 +20,7 @@@ package org.apache.cassandra.cql3
  import java.nio.ByteBuffer;
  import java.util.ArrayList;
  import java.util.Collections;
++import java.util.Iterator;
  import java.util.List;
  import java.util.concurrent.atomic.AtomicReference;
  
@@@ -146,10 -144,10 +147,22 @@@ public abstract class List
              }
          }
  
 -        public ByteBuffer get()
 +        public ByteBuffer get(QueryOptions options)
          {
 -            return CollectionType.pack(elements, elements.size());
 +            return CollectionSerializer.pack(elements, elements.size(), 
options.getProtocolVersion());
 +        }
++
++        public boolean equals(ListType lt, Value v)
++        {
++            if (elements.size() != v.elements.size())
++                return false;
++
++            for (int i = 0; i < elements.size(); i++)
++                if (lt.elements.compare(elements.get(i), v.elements.get(i)) 
!= 0)
++                    return false;
++
++            return true;
+         }
      }
  
      /*

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Maps.java
index 0c4980c,c332999..e6beb7e
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@@ -22,6 -22,6 +22,7 @@@ import java.util.ArrayList
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashMap;
++import java.util.Iterator;
  import java.util.LinkedHashMap;
  import java.util.List;
  import java.util.Map;
@@@ -168,8 -165,8 +169,27 @@@ public abstract class Map
                  buffers.add(entry.getKey());
                  buffers.add(entry.getValue());
              }
 -            return CollectionType.pack(buffers, map.size());
 +            return CollectionSerializer.pack(buffers, map.size(), 
options.getProtocolVersion());
 +        }
++
++        public boolean equals(MapType mt, Value v)
++        {
++            if (map.size() != v.map.size())
++                return false;
++
++            // We use the fact that we know the maps iteration will both be 
in comparator order
++            Iterator<Map.Entry<ByteBuffer, ByteBuffer>> thisIter = 
map.entrySet().iterator();
++            Iterator<Map.Entry<ByteBuffer, ByteBuffer>> thatIter = 
v.map.entrySet().iterator();
++            while (thisIter.hasNext())
++            {
++                Map.Entry<ByteBuffer, ByteBuffer> thisEntry = thisIter.next();
++                Map.Entry<ByteBuffer, ByteBuffer> thatEntry = thatIter.next();
++                if (mt.keys.compare(thisEntry.getKey(), thatEntry.getKey()) 
!= 0 || mt.values.compare(thisEntry.getValue(), thatEntry.getValue()) != 0)
++                    return false;
++            }
++
++            return true;
+         }
      }
  
      // See Lists.DelayedValue

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/Sets.java
index 92a3510,69bc3d3..1acaacb
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@@ -22,6 -22,6 +22,7 @@@ import java.util.ArrayList
  import java.util.Collections;
  import java.util.Comparator;
  import java.util.HashSet;
++import java.util.Iterator;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Set;
@@@ -158,10 -155,10 +159,24 @@@ public abstract class Set
              }
          }
  
 -        public ByteBuffer get()
 +        public ByteBuffer get(QueryOptions options)
          {
 -            return CollectionType.pack(new ArrayList<ByteBuffer>(elements), 
elements.size());
 +            return CollectionSerializer.pack(new 
ArrayList<ByteBuffer>(elements), elements.size(), options.getProtocolVersion());
 +        }
++
++        public boolean equals(SetType st, Value v)
++        {
++            if (elements.size() != v.elements.size())
++                return false;
++
++            Iterator<ByteBuffer> thisIter = elements.iterator();
++            Iterator<ByteBuffer> thatIter = v.elements.iterator();
++            while (thisIter.hasNext())
++                if (st.elements.compare(thisIter.next(), thatIter.next()) != 
0)
++                    return false;
++
++            return true;
+         }
      }
  
      // See Lists.DelayedValue

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
index 5005d2f,775a236..b06b2ee
--- a/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CQL3CasConditions.java
@@@ -167,9 -167,9 +167,9 @@@ public class CQL3CasConditions implemen
  
      private static class ColumnsConditions extends RowCondition
      {
-         private final Map<Pair<ColumnIdentifier, ByteBuffer>, 
ColumnCondition.WithOptions> conditions = new HashMap<>();
+         private final Map<Pair<ColumnIdentifier, ByteBuffer>, 
ColumnCondition.Bound> conditions = new HashMap<>();
  
 -        private ColumnsConditions(ColumnNameBuilder rowPrefix, long now)
 +        private ColumnsConditions(Composite rowPrefix, long now)
          {
              super(rowPrefix, now);
          }
@@@ -180,10 -180,10 +180,10 @@@
              {
                  // We will need the variables in appliesTo but with protocol 
batches, each condition in this object can have a
                  // different list of variables.
-                 ColumnCondition.WithOptions current = condition.with(options);
-                 ColumnCondition.WithOptions previous = 
conditions.put(Pair.create(condition.column.name, 
current.getCollectionElementValue()), current);
 -                ColumnCondition.Bound current = condition.bind(variables);
++                ColumnCondition.Bound current = condition.bind(options);
+                 ColumnCondition.Bound previous = 
conditions.put(Pair.create(condition.column.name, 
current.getCollectionElementValue()), current);
                  // If 2 conditions are actually equal, let it slide
-                 if (previous != null && !previous.equalsTo(current))
+                 if (previous != null && !previous.equals(current))
                      throw new InvalidRequestException("Duplicate and 
incompatible conditions for column " + condition.column.name);
              }
          }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --cc 
src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 7f8b678,448722e..03d4264
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@@ -599,7 -649,9 +599,9 @@@ public abstract class ModificationState
          }
          else
          {
-             List<ColumnDefinition> defs = new ArrayList<>();
+             // We can have multiple conditions on the same columns (for 
collections) so use a set
+             // to avoid duplicate, but preserve the order just to it follows 
the order of IF in the query in general
 -            Set<CFDefinition.Name> names = new 
LinkedHashSet<CFDefinition.Name>();
++            Set<ColumnDefinition> defs = new LinkedHashSet<>();
              // Adding the partition key for batches to disambiguate if the 
conditions span multipe rows (we don't add them outside
              // of batches for compatibility sakes).
              if (isBatch)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index b9ccd1a,2468eb9..55ce6f9
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@@ -126,11 -128,11 +126,11 @@@ public class SelectStatement implement
          }
  
          // Otherwise, check the selected columns
-         selectsStaticColumns = 
!Iterables.isEmpty(Iterables.filter(selection.getColumnsList(), 
isStaticFilter));
+         selectsStaticColumns = 
!Iterables.isEmpty(Iterables.filter(selection.getColumns(), isStaticFilter));
          selectsOnlyStaticColumns = true;
-         for (ColumnDefinition def : selection.getColumnsList())
 -        for (CFDefinition.Name name : selection.getColumns())
++        for (ColumnDefinition def : selection.getColumns())
          {
 -            if (name.kind != CFDefinition.Name.Kind.KEY_ALIAS && name.kind != 
CFDefinition.Name.Kind.STATIC)
 +            if (def.kind != ColumnDefinition.Kind.PARTITION_KEY && def.kind 
!= ColumnDefinition.Kind.STATIC)
              {
                  selectsOnlyStaticColumns = false;
                  break;
@@@ -733,15 -744,14 +733,15 @@@
              // column (for the case where the row exists but has no columns 
outside the PK)
              // Two exceptions are "static CF" (non-composite non-compact CF) 
and "super CF"
              // that don't have marker and for which we must query all columns 
instead
 -            if (cfDef.isComposite && !cfDef.cfm.isSuper())
 +            if (cfm.comparator.isCompound() && !cfm.isSuper())
              {
                  // marker
 -                
columns.add(builder.copy().add(ByteBufferUtil.EMPTY_BYTE_BUFFER).build());
 +                columns.add(cfm.comparator.rowMarker(prefix));
  
                  // selected columns
-                 for (ColumnDefinition def : selection.getColumnsList())
 -                for (ColumnIdentifier id : 
selection.regularAndStaticColumnsToFetch())
 -                    columns.add(builder.copy().add(id.key).build());
++                for (ColumnDefinition def : selection.getColumns())
 +                    if (def.kind == ColumnDefinition.Kind.REGULAR || def.kind 
== ColumnDefinition.Kind.STATIC)
 +                        columns.add(cfm.comparator.create(prefix, def));
              }
              else
              {
@@@ -755,12 -771,12 +755,12 @@@
  
      private boolean selectACollection()
      {
 -        if (!cfDef.hasCollections)
 +        if (!cfm.comparator.hasCollections())
              return false;
  
-         for (ColumnDefinition def : selection.getColumnsList())
 -        for (CFDefinition.Name name : selection.getColumns())
++        for (ColumnDefinition def : selection.getColumns())
          {
 -            if (name.type instanceof CollectionType)
 +            if (def.type instanceof CollectionType)
                  return true;
          }
  
@@@ -1024,77 -975,122 +1024,77 @@@
      }
  
      // Used by ModificationStatement for CAS operations
 -    void processColumnFamily(ByteBuffer key, ColumnFamily cf, 
List<ByteBuffer> variables, long now, Selection.ResultSetBuilder result)
 +    void processColumnFamily(ByteBuffer key, ColumnFamily cf, QueryOptions 
options, long now, Selection.ResultSetBuilder result)
      throws InvalidRequestException
      {
 -        ByteBuffer[] keyComponents = cfDef.hasCompositeKey
 -                                   ? 
((CompositeType)cfDef.cfm.getKeyValidator()).split(key)
 -                                   : new ByteBuffer[]{ key };
 -
 -        if (parameters.isDistinct)
 +        CFMetaData cfm = cf.metadata();
 +        ByteBuffer[] keyComponents = null;
 +        if (cfm.getKeyValidator() instanceof CompositeType)
          {
 -            if (!cf.hasOnlyTombstones(now))
 -            {
 -                result.newRow();
 -                // selection.getColumns() will contain only the partition key 
components - all of them.
 -                for (CFDefinition.Name name : selection.getColumns())
 -                    result.add(keyComponents[name.position]);
 -            }
 +            keyComponents = ((CompositeType)cfm.getKeyValidator()).split(key);
          }
 -        else if (cfDef.isCompact)
 +        else
          {
 -            // One cqlRow per column
 -            for (Column c : cf)
 -            {
 -                if (c.isMarkedForDelete(now))
 -                    continue;
 -
 -                ByteBuffer[] components = null;
 -                if (cfDef.isComposite)
 -                {
 -                    components = 
((CompositeType)cfDef.cfm.comparator).split(c.name());
 -                }
 -                else if (sliceRestriction != null)
 -                {
 -                    Comparator<ByteBuffer> comp = cfDef.cfm.comparator;
 -                    // For dynamic CF, the column could be out of the 
requested bounds, filter here
 -                    if (!sliceRestriction.isInclusive(Bound.START) && 
comp.compare(c.name(), sliceRestriction.bound(Bound.START, variables)) == 0)
 -                        continue;
 -                    if (!sliceRestriction.isInclusive(Bound.END) && 
comp.compare(c.name(), sliceRestriction.bound(Bound.END, variables)) == 0)
 -                        continue;
 -                }
 -
 -                result.newRow();
 -                // Respect selection order
 -                for (CFDefinition.Name name : selection.getColumns())
 -                {
 -                    switch (name.kind)
 -                    {
 -                        case KEY_ALIAS:
 -                            result.add(keyComponents[name.position]);
 -                            break;
 -                        case COLUMN_ALIAS:
 -                            ByteBuffer val = cfDef.isComposite
 -                                           ? (name.position < 
components.length ? components[name.position] : null)
 -                                           : c.name();
 -                            result.add(val);
 -                            break;
 -                        case VALUE_ALIAS:
 -                            result.add(c);
 -                            break;
 -                        case COLUMN_METADATA:
 -                        case STATIC:
 -                            // This should not happen for compact CF
 -                            throw new AssertionError();
 -                        default:
 -                            throw new AssertionError();
 -                    }
 -                }
 -            }
 +            keyComponents = new ByteBuffer[]{ key };
          }
 -        else if (cfDef.isComposite)
 -        {
 -            // Sparse case: group column in cqlRow when composite prefix is 
equal
 -            CompositeType composite = (CompositeType)cfDef.cfm.comparator;
  
 -            ColumnGroupMap.Builder builder = new 
ColumnGroupMap.Builder(composite, cfDef.hasCollections, now);
 +        Iterator<Cell> cells = cf.getSortedColumns().iterator();
 +        if (sliceRestriction != null)
 +            cells = applySliceRestriction(cells, options);
  
 -            for (Column c : cf)
 -            {
 -                if (c.isMarkedForDelete(now))
 -                    continue;
 +        CQL3Row.RowIterator iter = cfm.comparator.CQL3RowBuilder(cfm, 
now).group(cells);
  
 -                builder.add(c);
 -            }
 -
 -            ColumnGroupMap staticGroup = null;
 -            // Gather up static values first
 -            if (!builder.isEmpty() && builder.firstGroup().isStatic)
 +        // If there is static columns but there is no non-static row, then 
provided the select was a full
 +        // partition selection (i.e. not a 2ndary index search and there was 
no condition on clustering columns)
 +        // then we want to include the static columns in the result set (and 
we're done).
 +        CQL3Row staticRow = iter.getStaticRow();
 +        if (staticRow != null && !iter.hasNext() && !usesSecondaryIndexing && 
hasNoClusteringColumnsRestriction())
 +        {
 +            result.newRow();
-             for (ColumnDefinition def : selection.getColumnsList())
++            for (ColumnDefinition def : selection.getColumns())
              {
 -                staticGroup = builder.firstGroup();
 -                builder.discardFirst();
 -
 -                // If there was static columns but there is no actual row, 
then provided the select was a full
 -                // partition selection (i.e. not a 2ndary index search and 
there was no condition on clustering columns)
 -                // then we want to include the static columns in the result 
set.
 -                if (builder.isEmpty() && !usesSecondaryIndexing && 
hasNoClusteringColumnsRestriction() && hasValueForQuery(staticGroup))
 +                switch (def.kind)
                  {
 -                    handleGroup(result, keyComponents, ColumnGroupMap.EMPTY, 
staticGroup);
 -                    return;
 +                    case PARTITION_KEY:
 +                        result.add(keyComponents[def.position()]);
 +                        break;
 +                    case STATIC:
 +                        addValue(result, def, staticRow, options);
 +                        break;
 +                    default:
 +                        result.add((ByteBuffer)null);
                  }
              }
 -
 -            for (ColumnGroupMap group : builder.groups())
 -                handleGroup(result, keyComponents, group, staticGroup);
 +            return;
          }
 -        else
 +
 +        while (iter.hasNext())
          {
 -            if (cf.hasOnlyTombstones(now))
 -                return;
 +            CQL3Row cql3Row = iter.next();
  
 -            // Static case: One cqlRow for all columns
 +            // Respect requested order
              result.newRow();
 -            for (CFDefinition.Name name : selection.getColumns())
 +            // Respect selection order
-             for (ColumnDefinition def : selection.getColumnsList())
++            for (ColumnDefinition def : selection.getColumns())
              {
 -                if (name.kind == CFDefinition.Name.Kind.KEY_ALIAS)
 -                    result.add(keyComponents[name.position]);
 -                else
 -                    result.add(cf.getColumn(name.name.key));
 +                switch (def.kind)
 +                {
 +                    case PARTITION_KEY:
 +                        result.add(keyComponents[def.position()]);
 +                        break;
 +                    case CLUSTERING_COLUMN:
 +                        
result.add(cql3Row.getClusteringColumn(def.position()));
 +                        break;
 +                    case COMPACT_VALUE:
 +                        result.add(cql3Row.getColumn(null));
 +                        break;
 +                    case REGULAR:
 +                        addValue(result, def, cql3Row, options);
 +                        break;
 +                    case STATIC:
 +                        addValue(result, def, staticRow, options);
 +                        break;
 +                }
              }
          }
      }
@@@ -1210,11 -1254,11 +1210,11 @@@
                  throw new InvalidRequestException("Only COUNT(*) and COUNT(1) 
operations are currently supported.");
  
              Selection selection = selectClause.isEmpty()
 -                                ? Selection.wildcard(cfDef)
 -                                : Selection.fromSelectors(cfDef, 
selectClause);
 +                                ? Selection.wildcard(cfm)
 +                                : Selection.fromSelectors(cfm, selectClause);
  
              if (parameters.isDistinct)
-                 validateDistinctSelection(selection.getColumnsList(), 
cfm.partitionKeyColumns());
 -                validateDistinctSelection(selection.getColumns(), 
cfDef.partitionKeys());
++                validateDistinctSelection(selection.getColumns(), 
cfm.partitionKeyColumns());
  
              Term prepLimit = null;
              if (limit != null)
@@@ -1537,32 -1606,16 +1537,32 @@@
              return new ParsedStatement.Prepared(stmt, names);
          }
  
 -        private void validateDistinctSelection(Collection<CFDefinition.Name> 
requestedColumns, Collection<CFDefinition.Name> partitionKey)
 +        private int indexOf(ColumnDefinition def, Selection selection)
 +        {
-             return indexOf(def, selection.getColumnsList().iterator());
++            return indexOf(def, selection.getColumns().iterator());
 +        }
 +
 +        private int indexOf(final ColumnDefinition def, 
Iterator<ColumnDefinition> defs)
 +        {
 +            return Iterators.indexOf(defs, new Predicate<ColumnDefinition>()
 +                                           {
 +                                               public boolean 
apply(ColumnDefinition n)
 +                                               {
 +                                                   return 
def.name.equals(n.name);
 +                                               }
 +                                           });
 +        }
 +
 +        private void validateDistinctSelection(Collection<ColumnDefinition> 
requestedColumns, Collection<ColumnDefinition> partitionKey)
          throws InvalidRequestException
          {
 -            for (CFDefinition.Name name : requestedColumns)
 -                if (!partitionKey.contains(name))
 -                    throw new InvalidRequestException(String.format("SELECT 
DISTINCT queries must only request partition key columns (not %s)", name));
 +            for (ColumnDefinition def : requestedColumns)
 +                if (!partitionKey.contains(def))
 +                    throw new InvalidRequestException(String.format("SELECT 
DISTINCT queries must only request partition key columns (not %s)", def.name));
  
 -            for (CFDefinition.Name name : partitionKey)
 -                if (!requestedColumns.contains(name))
 -                    throw new InvalidRequestException(String.format("SELECT 
DISTINCT queries must request all the partition key columns (missing %s)", 
name));
 +            for (ColumnDefinition def : partitionKey)
 +                if (!requestedColumns.contains(def))
 +                    throw new InvalidRequestException(String.format("SELECT 
DISTINCT queries must request all the partition key columns (missing %s)", 
def.name));
          }
  
          private boolean containsAlias(final ColumnIdentifier name)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/33bd8c20/src/java/org/apache/cassandra/cql3/statements/Selection.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/Selection.java
index af1e621,123ddc3..3769e97
--- a/src/java/org/apache/cassandra/cql3/statements/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Selection.java
@@@ -19,10 -19,9 +19,11 @@@ package org.apache.cassandra.cql3.state
  
  import java.nio.ByteBuffer;
  import java.util.ArrayList;
+ import java.util.Collection;
  import java.util.List;
  
 +import com.google.common.collect.Iterators;
 +
  import org.apache.cassandra.cql3.*;
  import org.apache.cassandra.cql3.functions.Function;
  import org.apache.cassandra.cql3.functions.Functions;
@@@ -42,15 -37,15 +43,15 @@@ import org.apache.cassandra.utils.ByteB
  
  public abstract class Selection
  {
-     private final List<ColumnDefinition> columnsList;
 -    private final Collection<CFDefinition.Name> columns;
 -    private final List<ColumnSpecification> metadata;
++    private final Collection<ColumnDefinition> columns;
 +    private final ResultSet.Metadata metadata;
      private final boolean collectTimestamps;
      private final boolean collectTTLs;
  
-     protected Selection(List<ColumnDefinition> columnsList, 
List<ColumnSpecification> metadata, boolean collectTimestamps, boolean 
collectTTLs)
 -    protected Selection(Collection<CFDefinition.Name> columns, 
List<ColumnSpecification> metadata, boolean collectTimestamps, boolean 
collectTTLs)
++    protected Selection(Collection<ColumnDefinition> columns, 
List<ColumnSpecification> metadata, boolean collectTimestamps, boolean 
collectTTLs)
      {
-         this.columnsList = columnsList;
+         this.columns = columns;
 -        this.metadata = metadata;
 +        this.metadata = new ResultSet.Metadata(metadata);
          this.collectTimestamps = collectTimestamps;
          this.collectTTLs = collectTTLs;
      }
@@@ -73,18 -69,11 +74,18 @@@
          return new SimpleSelection(all, true);
      }
  
-     public static Selection forColumns(List<ColumnDefinition> columnsList)
 -    public static Selection forColumns(Collection<CFDefinition.Name> columns)
++    public static Selection forColumns(Collection<ColumnDefinition> columns)
      {
-         return new SimpleSelection(columnsList, false);
+         return new SimpleSelection(columns, false);
      }
  
 +    public int addColumnForOrdering(ColumnDefinition c)
 +    {
-         columnsList.add(c);
++        columns.add(c);
 +        metadata.addNonSerializedColumn(c);
-         return columnsList.size() - 1;
++        return columns.size() - 1;
 +    }
 +
      private static boolean isUsingFunction(List<RawSelector> rawSelectors)
      {
          for (RawSelector rawSelector : rawSelectors)
@@@ -248,11 -209,25 +249,11 @@@
      protected abstract List<ByteBuffer> handleRow(ResultSetBuilder rs) throws 
InvalidRequestException;
  
      /**
 -     * @return the list of CQL3 "regular" (the "COLUMN_METADATA" ones) column 
names to fetch.
 -     */
 -    public List<ColumnIdentifier> regularAndStaticColumnsToFetch()
 -    {
 -        List<ColumnIdentifier> toFetch = new ArrayList<ColumnIdentifier>();
 -        for (CFDefinition.Name name : columns)
 -        {
 -            if (name.kind == CFDefinition.Name.Kind.COLUMN_METADATA || 
name.kind == CFDefinition.Name.Kind.STATIC)
 -                toFetch.add(name.name);
 -        }
 -        return toFetch;
 -    }
 -
 -    /**
       * @return the list of CQL3 columns value this SelectionClause needs.
       */
-     public List<ColumnDefinition> getColumnsList()
 -    public Collection<CFDefinition.Name> getColumns()
++    public Collection<ColumnDefinition> getColumns()
      {
-         return columnsList;
+         return columns;
      }
  
      public ResultSetBuilder resultSetBuilder(long now)
@@@ -286,9 -261,9 +287,9 @@@
  
          private ResultSetBuilder(long now)
          {
 -            this.resultSet = new ResultSet(metadata);
 +            this.resultSet = new ResultSet(getResultMetadata(), new 
ArrayList<List<ByteBuffer>>());
-             this.timestamps = collectTimestamps ? new 
long[columnsList.size()] : null;
-             this.ttls = collectTTLs ? new int[columnsList.size()] : null;
+             this.timestamps = collectTimestamps ? new long[columns.size()] : 
null;
+             this.ttls = collectTTLs ? new int[columns.size()] : null;
              this.now = now;
          }
  
@@@ -341,12 -316,12 +342,12 @@@
      {
          private final boolean isWildcard;
  
-         public SimpleSelection(List<ColumnDefinition> columnsList, boolean 
isWildcard)
 -        public SimpleSelection(Collection<CFDefinition.Name> columns, boolean 
isWildcard)
++        public SimpleSelection(Collection<ColumnDefinition> columns, boolean 
isWildcard)
          {
-             this(columnsList, new 
ArrayList<ColumnSpecification>(columnsList), isWildcard);
+             this(columns, new ArrayList<ColumnSpecification>(columns), 
isWildcard);
          }
  
-         public SimpleSelection(List<ColumnDefinition> columnsList, 
List<ColumnSpecification> metadata, boolean isWildcard)
 -        public SimpleSelection(Collection<CFDefinition.Name> columns, 
List<ColumnSpecification> metadata, boolean isWildcard)
++        public SimpleSelection(Collection<ColumnDefinition> columns, 
List<ColumnSpecification> metadata, boolean isWildcard)
          {
              /*
               * In theory, even a simple selection could have multiple time 
the same column, so we
@@@ -522,9 -460,9 +523,9 @@@
      {
          private final List<Selector> selectors;
  
-         public SelectionWithFunctions(List<ColumnDefinition> columnsList, 
List<ColumnSpecification> metadata, List<Selector> selectors, boolean 
collectTimestamps, boolean collectTTLs)
 -        public SelectionWithFunctions(Collection<CFDefinition.Name> columns, 
List<ColumnSpecification> metadata, List<Selector> selectors, boolean 
collectTimestamps, boolean collectTTLs)
++        public SelectionWithFunctions(Collection<ColumnDefinition> columns, 
List<ColumnSpecification> metadata, List<Selector> selectors, boolean 
collectTimestamps, boolean collectTTLs)
          {
-             super(columnsList, metadata, collectTimestamps, collectTTLs);
+             super(columns, metadata, collectTimestamps, collectTTLs);
              this.selectors = selectors;
          }
  

Reply via email to