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 <[email protected]>
Authored: Mon May 19 12:26:32 2014 +0200
Committer: Sylvain Lebresne <[email protected]>
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;
}