You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by yu...@apache.org on 2012/07/27 17:19:39 UTC
[27/50] [abbrv] git commit: Refactor set/list/map CQL3 code
Refactor set/list/map CQL3 code
patch by xedin; reviewed by slebresne for CASSANDRA-3647
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/2b62df24
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/2b62df24
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/2b62df24
Branch: refs/heads/cassandra-1.1
Commit: 2b62df244cb9e047d13c9c6dadcf44a26505b036
Parents: 1dadaa7
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Fri Jul 20 11:58:45 2012 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Fri Jul 20 11:58:45 2012 +0200
----------------------------------------------------------------------
src/java/org/apache/cassandra/cql3/Cql.g | 60 ++--
src/java/org/apache/cassandra/cql3/Operation.java | 108 ------
src/java/org/apache/cassandra/cql3/Term.java | 2 +-
src/java/org/apache/cassandra/cql3/Value.java | 121 -------
.../cassandra/cql3/operations/ColumnOperation.java | 136 ++++++++
.../cassandra/cql3/operations/ListOperation.java | 258 +++++++++++++++
.../cassandra/cql3/operations/MapOperation.java | 145 ++++++++
.../cassandra/cql3/operations/Operation.java | 53 +++
.../cassandra/cql3/operations/SetOperation.java | 127 +++++++
.../statements/CreateColumnFamilyStatement.java | 8 +-
.../cassandra/cql3/statements/DeleteStatement.java | 31 ++-
.../cassandra/cql3/statements/SelectStatement.java | 19 +-
.../cassandra/cql3/statements/UpdateStatement.java | 133 +++------
.../apache/cassandra/db/marshal/AbstractType.java | 5 +
.../cassandra/db/marshal/CollectionType.java | 40 +--
.../apache/cassandra/db/marshal/CompositeType.java | 15 +-
.../org/apache/cassandra/db/marshal/ListType.java | 155 +---------
.../org/apache/cassandra/db/marshal/MapType.java | 43 +---
.../org/apache/cassandra/db/marshal/SetType.java | 44 +---
19 files changed, 861 insertions(+), 642 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index 04c2391..e6aa09e 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -34,6 +34,7 @@ options {
import java.util.List;
import java.util.Map;
+ import org.apache.cassandra.cql3.operations.*;
import org.apache.cassandra.cql3.statements.*;
import org.apache.cassandra.config.ConfigurationException;
import org.apache.cassandra.db.marshal.CollectionType;
@@ -221,15 +222,15 @@ insertStatement returns [UpdateStatement expr]
@init {
Attributes attrs = new Attributes();
List<ColumnIdentifier> columnNames = new ArrayList<ColumnIdentifier>();
- List<Value> columnValues = new ArrayList<Value>();
+ List<Operation> columnOperations = new ArrayList<Operation>();
}
: K_INSERT K_INTO cf=columnFamilyName
'(' c1=cident { columnNames.add(c1); } ( ',' cn=cident { columnNames.add(cn); } )+ ')'
K_VALUES
- '(' v1=value { columnValues.add(v1); } ( ',' vn=value { columnValues.add(vn); } )+ ')'
+ '(' v1=set_operation { columnOperations.add(v1); } ( ',' vn=set_operation { columnOperations.add(vn); } )+ ')'
( usingClause[attrs] )?
{
- $expr = new UpdateStatement(cf, attrs, columnNames, columnValues);
+ $expr = new UpdateStatement(cf, attrs, columnNames, columnOperations);
}
;
@@ -471,29 +472,25 @@ cfOrKsName[CFName name, boolean isKs]
| k=unreserved_keyword { if (isKs) $name.setKeyspace(k, false); else $name.setColumnFamily(k, false); }
;
-// Values (includes prepared statement markers)
-value returns [Value value]
- : t=term { $value = t; }
- | c=collection_literal { $value = c; }
+set_operation returns [Operation op]
+ : t=term { $op = ColumnOperation.Set(t); }
+ | m=map_literal { $op = MapOperation.Set(m); }
+ | l=list_literal { $op = ListOperation.Set(l); }
+ | s=set_literal { $op = SetOperation.Set(s); }
;
-collection_literal returns [Value value]
- : ll=list_literal { $value = ll; }
- | sl=set_literal { $value = sl; }
- | ml=map_literal { $value = ml; }
+list_literal returns [List<Term> value]
+ : '[' { List<Term> l = new ArrayList<Term>(); } ( t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* )? ']' { $value = l; }
;
-list_literal returns [Value.ListLiteral value]
- : '[' { Value.ListLiteral l = new Value.ListLiteral(); } ( t1=term { l.add(t1); } ( ',' tn=term { l.add(tn); } )* )? ']' { $value = l; }
+set_literal returns [List<Term> value]
+ : '{' { List<Term> s = new ArrayList<Term>(); } ( t1=term { s.add(t1); } ( ',' tn=term { s.add(tn); } )* )? '}' { $value = s; }
;
-set_literal returns [Value.SetLiteral value]
- : '{' { Value.SetLiteral s = new Value.SetLiteral(); } ( t1=term { s.add(t1); } ( ',' tn=term { s.add(tn); } )* )? '}' { $value = s; }
- ;
-
-map_literal returns [Value.MapLiteral value]
+map_literal returns [Map<Term, Term> value]
// Note that we have an ambiguity between maps and set for "{}". So we force it to a set, and deal with it later based on the type of the column
- : '{' { Value.MapLiteral m = new Value.MapLiteral(); } k1=term ':' v1=term { m.put(k1, v1); } ( ',' kn=term ':' vn=term { m.put(kn, vn); } )* '}'
+ : '{' { Map<Term, Term> m = new HashMap<Term, Term>(); }
+ k1=term ':' v1=term { m.put(k1, v1); } ( ',' kn=term ':' vn=term { m.put(kn, vn); } )* '}'
{ $value = m; }
;
@@ -514,7 +511,7 @@ intTerm returns [Term integer]
termPairWithOperation[List<Pair<ColumnIdentifier, Operation>> columns]
: key=cident '='
- ( v=value { columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Set(v))); }
+ (set_op = set_operation { columns.add(Pair.<ColumnIdentifier, Operation>create(key, set_op)); }
| c=cident op=operation
{
if (!key.equals(c))
@@ -525,32 +522,35 @@ termPairWithOperation[List<Pair<ColumnIdentifier, Operation>> columns]
{
if (!key.equals(c))
addRecognitionError("Only expressions like X = <value> + X are supported.");
- columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Function(CollectionType.Function.PREPEND, ll)));
+ columns.add(Pair.<ColumnIdentifier, Operation>create(key, ListOperation.Prepend(ll)));
}
)
| key=cident '[' t=term ']' '=' vv=term
{
- List<Term> args = Arrays.asList(t, vv);
- columns.add(Pair.<ColumnIdentifier, Operation>create(key, new Operation.Function(CollectionType.Function.SET, args)));
+ Operation setOp = (t.getType() == Term.Type.INTEGER)
+ ? ListOperation.SetIndex(Arrays.asList(t, vv))
+ : MapOperation.Put(t, vv);
+
+ columns.add(Pair.<ColumnIdentifier, Operation>create(key, setOp));
}
;
operation returns [Operation op]
- : '+' v=intTerm { $op = new Operation.Counter(v, false); }
+ : '+' v=intTerm { $op = ColumnOperation.CounterInc(v); }
| sign='-'? v=intTerm
{
validateMinusSupplied(sign, v, input);
if (sign == null)
v = new Term(-(Long.valueOf(v.getText())), v.getType());
- $op = new Operation.Counter(v, true);
+ $op = ColumnOperation.CounterDec(v);
}
- | '+' ll=list_literal { $op = new Operation.Function(CollectionType.Function.APPEND, ll); }
- | '-' ll=list_literal { $op = new Operation.Function(CollectionType.Function.DISCARD_LIST, ll); }
+ | '+' ll=list_literal { $op = ListOperation.Append(ll); }
+ | '-' ll=list_literal { $op = ListOperation.Discard(ll); }
- | '+' sl=set_literal { $op = new Operation.Function(CollectionType.Function.ADD, sl.asList()); }
- | '-' sl=set_literal { $op = new Operation.Function(CollectionType.Function.DISCARD_SET, sl.asList()); }
+ | '+' sl=set_literal { $op = SetOperation.Add(sl); }
+ | '-' sl=set_literal { $op = SetOperation.Discard(sl); }
- | '+' ml=map_literal { $op = new Operation.Function(CollectionType.Function.SET, ml.asList()); }
+ | '+' ml=map_literal { $op = MapOperation.Put(ml); }
;
property returns [String str]
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Operation.java b/src/java/org/apache/cassandra/cql3/Operation.java
deleted file mode 100644
index e7291c3..0000000
--- a/src/java/org/apache/cassandra/cql3/Operation.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3;
-
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.thrift.InvalidRequestException;
-
-public abstract class Operation
-{
- public static enum Type { SET, COUNTER, FUNCTION }
-
- public final Type type;
-
- protected Operation(Type type)
- {
- this.type = type;
- }
-
- public abstract Iterable<Term> allTerms();
-
- public static class Set extends Operation
- {
- public final Value value;
-
- public Set(Value value)
- {
- super(Type.SET);
- this.value = value;
- }
-
- @Override
- public String toString()
- {
- return " = " + value;
- }
-
- public List<Term> allTerms()
- {
- return value.asList();
- }
- }
-
- public static class Counter extends Operation
- {
- public final Term value;
- public final boolean isSubstraction;
-
- public Counter(Term value, boolean isSubstraction)
- {
- super(Type.COUNTER);
- this.value = value;
- this.isSubstraction = isSubstraction;
- }
-
- @Override
- public String toString()
- {
- return (isSubstraction ? "-" : "+") + "= " + value;
- }
-
- public Iterable<Term> allTerms()
- {
- return Collections.singletonList(value);
- }
- }
-
- public static class Function extends Operation
- {
- public final CollectionType.Function fct;
- public final List<Term> arguments;
-
- public Function(CollectionType.Function fct, List<Term> arguments)
- {
- super(Type.FUNCTION);
- this.fct = fct;
- this.arguments = arguments;
- }
-
- @Override
- public String toString()
- {
- return "." + fct + arguments;
- }
-
- public Iterable<Term> allTerms()
- {
- return arguments;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Term.java b/src/java/org/apache/cassandra/cql3/Term.java
index 81be6de..a38260d 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -34,7 +34,7 @@ import org.apache.cassandra.db.marshal.MarshalException;
import org.apache.cassandra.thrift.InvalidRequestException;
/** A term parsed from a CQL statement. */
-public class Term implements Value
+public class Term
{
public enum Type
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/Value.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Value.java b/src/java/org/apache/cassandra/cql3/Value.java
deleted file mode 100644
index 64f588b..0000000
--- a/src/java/org/apache/cassandra/cql3/Value.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.cassandra.cql3;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.db.marshal.ListType;
-import org.apache.cassandra.db.marshal.MapType;
-import org.apache.cassandra.db.marshal.SetType;
-import org.apache.cassandra.thrift.InvalidRequestException;
-
-public interface Value
-{
- public List<Term> asList();
-
- public interface CollectionLiteral extends Value
- {
- /**
- * Validate that this literal is compatible with the provided column and
- * throws an InvalidRequestException if not.
- */
- public void validateType(CFDefinition.Name value) throws InvalidRequestException;
-
- /**
- * Returns whether this litteral is empty or not.
- */
- public boolean isEmpty();
-
- /**
- * Returns the internal function to use to construct this literal.
- */
- public CollectionType.Function constructionFunction();
- }
-
- public static class MapLiteral extends HashMap<Term, Term> implements CollectionLiteral
- {
- public List<Term> asList()
- {
- List<Term> l = new ArrayList<Term>(2 * size());
- for (Map.Entry<Term, Term> entry : entrySet())
- {
- l.add(entry.getKey());
- l.add(entry.getValue());
- }
- return l;
- }
-
- public void validateType(CFDefinition.Name value) throws InvalidRequestException
- {
- if (!(value.type instanceof MapType))
- throw new InvalidRequestException(String.format("Invalid value: %s is not a map", value.name));
- }
-
- public CollectionType.Function constructionFunction()
- {
- return CollectionType.Function.SET;
- }
- }
-
- public static class ListLiteral extends ArrayList<Term> implements CollectionLiteral
- {
- public List<Term> asList()
- {
- return this;
- }
-
- public void validateType(CFDefinition.Name value) throws InvalidRequestException
- {
- if (!(value.type instanceof ListType))
- throw new InvalidRequestException(String.format("Invalid value: %s is not a list", value.name));
- }
-
- public CollectionType.Function constructionFunction()
- {
- return CollectionType.Function.APPEND;
- }
- }
-
- public static class SetLiteral extends HashSet<Term> implements CollectionLiteral
- {
- public List<Term> asList()
- {
- return new ArrayList<Term>(this);
- }
-
- public void validateType(CFDefinition.Name value) throws InvalidRequestException
- {
- // The parser don't distinguish between empty set and empty map and always return an empty set
- if ((value.type instanceof MapType) && !isEmpty())
- throw new InvalidRequestException(String.format("Invalid value: %s is not a map", value.name));
- else if (!(value.type instanceof SetType))
- throw new InvalidRequestException(String.format("Invalid value: %s is not a set", value.name));
- }
-
- public CollectionType.Function constructionFunction()
- {
- return CollectionType.Function.ADD;
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java b/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
new file mode 100644
index 0000000..5e4f6b3
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/ColumnOperation.java
@@ -0,0 +1,136 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.operations;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.filter.QueryPath;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.Pair;
+
+public class ColumnOperation implements Operation
+{
+ enum Kind { SET, COUNTER_INC, COUNTER_DEC }
+
+ private final Term value;
+ private final Kind kind;
+
+ private ColumnOperation(Term value, Kind kind)
+ {
+ this.value = value;
+ this.kind = kind;
+ }
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ AbstractType<?> validator,
+ UpdateParameters params) throws InvalidRequestException
+ {
+ switch (kind)
+ {
+ case SET:
+ doSet(cf, builder, validator, params);
+ break;
+ case COUNTER_INC:
+ case COUNTER_DEC:
+ doCounter(cf, builder, params);
+ break;
+ default:
+ throw new AssertionError("Unsupported operation: " + kind);
+ }
+ }
+
+ public void execute(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ throw new InvalidRequestException("Column operations are only supported on simple types, but " + validator + " given.");
+ }
+
+ private void doSet(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+ {
+ ByteBuffer colName = builder.build();
+ QueryProcessor.validateColumnName(colName);
+
+ ByteBuffer valueBytes = value.getByteBuffer(validator, params.variables);
+ cf.addColumn(params.makeColumn(colName, valueBytes));
+ }
+
+ private void doCounter(ColumnFamily cf, ColumnNameBuilder builder, UpdateParameters params) throws InvalidRequestException
+ {
+ long val;
+
+ try
+ {
+ val = ByteBufferUtil.toLong(value.getByteBuffer(LongType.instance, params.variables));
+ }
+ catch (NumberFormatException e)
+ {
+ throw new InvalidRequestException(String.format("'%s' is an invalid value, should be a long.", value.getText()));
+ }
+
+ if (kind == Kind.COUNTER_DEC)
+ {
+ if (val == Long.MIN_VALUE)
+ throw new InvalidRequestException("The negation of " + val + " overflows supported integer precision (signed 8 bytes integer)");
+ else
+ val = -val;
+ }
+
+ cf.addCounter(new QueryPath(cf.metadata().cfName, null, builder.build()), val);
+ }
+
+ public List<Term> getValues()
+ {
+ return Collections.singletonList(value);
+ }
+
+ public boolean requiresRead()
+ {
+ return false;
+ }
+
+ public Type getType()
+ {
+ return kind == Kind.COUNTER_DEC || kind == Kind.COUNTER_INC ? Type.COUNTER : Type.COLUMN;
+ }
+
+ /* Utility methods */
+
+ public static Operation Set(Term value)
+ {
+ return new ColumnOperation(value, Kind.SET);
+ }
+
+ public static Operation CounterInc(Term value)
+ {
+ return new ColumnOperation(value, Kind.COUNTER_INC);
+ }
+
+ public static Operation CounterDec(Term value)
+ {
+ return new ColumnOperation(value, Kind.COUNTER_DEC);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/ListOperation.java b/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
new file mode 100644
index 0000000..b4ba021
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/ListOperation.java
@@ -0,0 +1,258 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.operations;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+import org.apache.cassandra.utils.UUIDGen;
+
+public class ListOperation implements Operation
+{
+ // Our reference time (1 jan 2010, 00:00:00) in milliseconds.
+ private static final long REFERENCE_TIME = 1262304000000L;
+
+ /*
+ * For prepend, we need to be able to generate unique but decreasing time
+ * UUID, which is a bit challenging. To do that, given a time in milliseconds,
+ * we adds a number representing the 100-nanoseconds precision and make sure
+ * that within the same millisecond, that number is always increasing. We
+ * do rely on the fact that the user will only provide decreasing
+ * milliseconds timestamp for that purpose.
+ */
+ private static class PrecisionTime
+ {
+ public final long millis;
+ public final int nanos;
+
+ public PrecisionTime(long millis, int nanos)
+ {
+ this.millis = millis;
+ this.nanos = nanos;
+ }
+ }
+
+ private static final AtomicReference<PrecisionTime> last = new AtomicReference<PrecisionTime>(new PrecisionTime(Long.MAX_VALUE, 0));
+
+ private static PrecisionTime getNextTime(long millis)
+ {
+ while (true)
+ {
+ PrecisionTime current = last.get();
+
+ assert millis <= current.millis;
+ PrecisionTime next = millis < current.millis
+ ? new PrecisionTime(millis, 0)
+ : new PrecisionTime(millis, current.nanos + 1);
+
+ if (last.compareAndSet(current, next))
+ return next;
+ }
+ }
+
+ enum Kind { SET, SET_IDX, APPEND, PREPEND, DISCARD, DISCARD_IDX }
+
+ private final List<Term> values;
+ private final Kind kind;
+
+ private ListOperation(List<Term> values, Kind kind)
+ {
+ this.values = Collections.unmodifiableList(values);
+ this.kind = kind;
+ }
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ CollectionType validator,
+ UpdateParameters params,
+ List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ if (validator.kind != CollectionType.Kind.LIST)
+ throw new InvalidRequestException("List operations are only supported on List typed columns, but " + validator + " given.");
+
+ switch (kind)
+ {
+ case SET:
+ cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+ doAppend(cf, builder, validator, params);
+ break;
+ case SET_IDX:
+ doSet(cf, builder, params, validator, list);
+ break;
+ case APPEND:
+ doAppend(cf, builder, validator, params);
+ break;
+ case PREPEND:
+ doPrepend(cf, builder, validator, params);
+ break;
+ case DISCARD:
+ doDiscard(cf, validator, params, list);
+ break;
+ case DISCARD_IDX:
+ doDiscardIdx(cf, params, list);
+ break;
+ default:
+ throw new AssertionError("Unsupported List operation: " + kind);
+ }
+ }
+
+ public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+ {
+ throw new InvalidRequestException("List operations are only supported on List typed columns, but " + validator + " given.");
+ }
+
+ private void doSet(ColumnFamily cf, ColumnNameBuilder builder, UpdateParameters params, CollectionType validator, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ int idx = validateListIdx(values.get(0), list);
+ Term value = values.get(1);
+
+ ByteBuffer name = list.get(idx).right.name();
+ cf.addColumn(params.makeColumn(name, value.getByteBuffer(validator.valueComparator(), params.variables)));
+ }
+
+ private void doAppend(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ for (int i = 0; i < values.size(); i++)
+ {
+ ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+ ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
+ ByteBuffer name = b.add(uuid).build();
+ cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(validator.valueComparator(), params.variables)));
+ }
+ }
+
+ private void doPrepend(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ long time = REFERENCE_TIME - (System.currentTimeMillis() - REFERENCE_TIME);
+
+ // We do the loop in reverse order because getNext() will create increasing time but we want the last
+ // value in the prepended list to have the lower time
+ for (int i = values.size() - 1; i >= 0; i--)
+ {
+ ColumnNameBuilder b = i == 0 ? builder : builder.copy();
+ PrecisionTime pt = getNextTime(time);
+ ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos));
+ ByteBuffer name = b.add(uuid).build();
+ cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(validator.valueComparator(), params.variables)));
+ }
+ }
+
+ private void doDiscard(ColumnFamily cf, CollectionType validator, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ if (list == null)
+ return;
+
+ Set<ByteBuffer> toDiscard = new HashSet<ByteBuffer>();
+
+ for (Term value : values)
+ toDiscard.add(value.getByteBuffer(validator.valueComparator(), params.variables));
+
+ for (Pair<ByteBuffer, IColumn> p : list)
+ {
+ IColumn c = p.right;
+ if (toDiscard.contains(c.value()))
+ cf.addColumn(params.makeTombstone(c.name()));
+ }
+ }
+
+ private void doDiscardIdx(ColumnFamily cf, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ int idx = validateListIdx(values.get(0), list);
+ cf.addColumn(params.makeTombstone(list.get(idx).right.name()));
+ }
+
+ public List<Term> getValues()
+ {
+ return values;
+ }
+
+ public boolean requiresRead()
+ {
+ return kind == Kind.DISCARD || kind == Kind.DISCARD_IDX || kind == Kind.SET || kind == Kind.SET_IDX;
+ }
+
+ public Type getType()
+ {
+ return Type.LIST;
+ }
+
+ /* Utility methods */
+
+ public static Operation Set(List<Term> values)
+ {
+ return new ListOperation(values, Kind.SET);
+ }
+
+ public static Operation SetIndex(List<Term> values)
+ {
+ return new ListOperation(values, Kind.SET_IDX);
+ }
+
+ public static Operation Append(List<Term> values)
+ {
+ return new ListOperation(values, Kind.APPEND);
+ }
+
+ public static Operation Prepend(List<Term> values)
+ {
+ return new ListOperation(values, Kind.PREPEND);
+ }
+
+ public static Operation Discard(List<Term> values)
+ {
+ return new ListOperation(values, Kind.DISCARD);
+ }
+
+ public static Operation DiscardKey(List<Term> values)
+ {
+ return new ListOperation(values, Kind.DISCARD_IDX);
+ }
+
+ private int validateListIdx(Term value, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ try
+ {
+ if (value.getType() != Term.Type.INTEGER)
+ throw new InvalidRequestException(String.format("Invalid argument %s for %s, must be an integer.", value.getText(), getType()));
+
+ int idx = Integer.parseInt(value.getText());
+ if (list == null || list.size() <= idx)
+ throw new InvalidRequestException(String.format("Invalid index %d, list has size %d", idx, list == null ? 0 : list.size()));
+
+ return idx;
+ }
+ catch (NumberFormatException e)
+ {
+ // This should not happen, unless we screwed up the parser
+ throw new RuntimeException();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/MapOperation.java b/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
new file mode 100644
index 0000000..d843fc7
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/MapOperation.java
@@ -0,0 +1,145 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.operations;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+
+public class MapOperation implements Operation
+{
+ enum Kind { SET, PUT, DISCARD }
+
+ private final Map<Term, Term> values;
+ private final Term discardKey;
+ private final Kind kind;
+
+ private MapOperation(Map<Term, Term> values, Kind kind)
+ {
+ this.values = values;
+ this.discardKey = null;
+ this.kind = kind;
+ }
+
+ private MapOperation(Term discardKey)
+ {
+ this.values = null;
+ this.discardKey = discardKey;
+ this.kind = Kind.DISCARD;
+ }
+
+ public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+ {
+ throw new InvalidRequestException("Map operations are only supported on Map typed columns, but " + validator + " given.");
+ }
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ CollectionType validator,
+ UpdateParameters params,
+ List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ if (validator.kind != CollectionType.Kind.MAP)
+ throw new InvalidRequestException("Map operations are only supported on Map typed columns, but " + validator + " given.");
+
+ switch (kind)
+ {
+ case SET: // fallthrough on purpose; remove previous Map before setting (PUT) the new one
+ cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+ case PUT:
+ doPut(cf, builder, validator, params);
+ break;
+ case DISCARD:
+ doDiscard(cf, builder, validator, params);
+ break;
+ default:
+ throw new AssertionError("Unsupported Map operation: " + kind);
+ }
+ }
+
+ private void doPut(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ for (Map.Entry<Term, Term> entry : values.entrySet())
+ {
+ ByteBuffer name = builder.copy().add(entry.getKey().getByteBuffer(validator.nameComparator(), params.variables)).build();
+ ByteBuffer value = entry.getValue().getByteBuffer(validator.valueComparator(), params.variables);
+ cf.addColumn(params.makeColumn(name, value));
+ }
+ }
+
+ private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ ByteBuffer name = builder.add(discardKey.getByteBuffer(validator.nameComparator(), params.variables)).build();
+ cf.addColumn(params.makeTombstone(name));
+ }
+
+ public List<Term> getValues()
+ {
+ List<Term> l = new ArrayList<Term>(2 * values.size());
+ for (Map.Entry<Term, Term> entry : values.entrySet())
+ {
+ l.add(entry.getKey());
+ l.add(entry.getValue());
+ }
+ return l;
+ }
+
+ public boolean requiresRead()
+ {
+ return kind == Kind.SET || kind == Kind.DISCARD;
+ }
+
+ public Type getType()
+ {
+ return Type.MAP;
+ }
+
+ /* Utility methods */
+
+ public static Operation Set(Map<Term, Term> values)
+ {
+ return new MapOperation(values, Kind.SET);
+ }
+
+ public static Operation Put(Map<Term, Term> values)
+ {
+ return new MapOperation(values, Kind.PUT);
+ }
+
+ public static Operation Put(final Term key, final Term value)
+ {
+ return Put(new HashMap<Term, Term>(1) {{ put(key, value); }});
+ }
+
+ public static Operation DiscardKey(Term discardKey)
+ {
+ return new MapOperation(discardKey);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/Operation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/Operation.java b/src/java/org/apache/cassandra/cql3/operations/Operation.java
new file mode 100644
index 0000000..13c341c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/Operation.java
@@ -0,0 +1,53 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.operations;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+
+public interface Operation
+{
+ public static enum Type { COLUMN, COUNTER, LIST, SET, MAP }
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ AbstractType<?> validator,
+ UpdateParameters params) throws InvalidRequestException;
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ CollectionType validator,
+ UpdateParameters params,
+ List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException;
+
+ public List<Term> getValues();
+
+ public boolean requiresRead();
+
+ public Type getType();
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/operations/SetOperation.java b/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
new file mode 100644
index 0000000..22b4517
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/operations/SetOperation.java
@@ -0,0 +1,127 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.operations;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.ColumnNameBuilder;
+import org.apache.cassandra.cql3.Term;
+import org.apache.cassandra.cql3.UpdateParameters;
+import org.apache.cassandra.db.ColumnFamily;
+import org.apache.cassandra.db.IColumn;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.CollectionType;
+import org.apache.cassandra.thrift.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+import org.apache.cassandra.utils.Pair;
+
+public class SetOperation implements Operation
+{
+ enum Kind { SET, ADD, DISCARD }
+
+ private final List<Term> values;
+ private final Kind kind;
+
+ private SetOperation(List<Term> values, Kind kind)
+ {
+ this.values = values;
+ this.kind = kind;
+ }
+
+ public void execute(ColumnFamily cf,
+ ColumnNameBuilder builder,
+ CollectionType validator,
+ UpdateParameters params,
+ List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
+ {
+ if (validator.kind != CollectionType.Kind.SET)
+ throw new InvalidRequestException("Set operations are only supported on Set typed columns, but " + validator + " given.");
+
+ switch (kind)
+ {
+ case SET: // fallthrough on purpose; remove previous Set before setting (ADD) the new one
+ cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+ case ADD:
+ doAdd(cf, builder, validator, params);
+ break;
+ case DISCARD:
+ doDiscard(cf, builder, validator, params);
+ break;
+ default:
+ throw new AssertionError("Unsupported Set operation: " + kind);
+ }
+ }
+
+ public void execute(ColumnFamily cf, ColumnNameBuilder builder, AbstractType<?> validator, UpdateParameters params) throws InvalidRequestException
+ {
+ throw new InvalidRequestException("Set operations are only supported on Set typed columns, but " + validator + " given.");
+ }
+
+ private void doAdd(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ for (int i = 0; i < values.size(); ++i)
+ {
+ ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+ ByteBuffer name = b.add(values.get(i).getByteBuffer(validator.nameComparator(), params.variables)).build();
+ cf.addColumn(params.makeColumn(name, ByteBufferUtil.EMPTY_BYTE_BUFFER));
+ }
+ }
+
+ private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, CollectionType validator, UpdateParameters params) throws InvalidRequestException
+ {
+ for (int i = 0; i < values.size(); ++i)
+ {
+ ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
+ ByteBuffer name = b.add(values.get(i).getByteBuffer(validator.nameComparator(), params.variables)).build();
+ cf.addColumn(params.makeTombstone(name));
+ }
+ }
+
+ public List<Term> getValues()
+ {
+ return values;
+ }
+
+ public boolean requiresRead()
+ {
+ return false;
+ }
+
+ public Type getType()
+ {
+ return Type.SET;
+ }
+
+ /* Utility methods */
+
+ public static Operation Set(List<Term> values)
+ {
+ return new SetOperation(values, Kind.SET);
+ }
+
+ public static Operation Add(List<Term> values)
+ {
+ return new SetOperation(values, Kind.ADD);
+ }
+
+ public static Operation Discard(List<Term> values)
+ {
+ return new SetOperation(values, Kind.DISCARD);
+ }
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
index 45a55da..bf7a82a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateColumnFamilyStatement.java
@@ -245,12 +245,16 @@ public class CreateColumnFamilyStatement extends SchemaAlteringStatement
if (useCompactStorage)
{
if (definedCollections != null)
- throw new InvalidRequestException("Collection types are not supported with non composite PRIMARY KEY");
+ throw new InvalidRequestException("Collection types are not supported with COMPACT STORAGE");
stmt.comparator = CFDefinition.definitionType;
}
else
{
- stmt.comparator = CompositeType.getInstance(Collections.<AbstractType<?>>singletonList(CFDefinition.definitionType));
+ List<AbstractType<?>> types = new ArrayList<AbstractType<?>>(definedCollections == null ? 1 : 2);
+ types.add(CFDefinition.definitionType);
+ if (definedCollections != null)
+ types.add(ColumnToCollectionType.getInstance(definedCollections));
+ stmt.comparator = CompositeType.getInstance(types);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
index eb96417..346fcf8 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java
@@ -23,6 +23,10 @@ import java.util.concurrent.TimeoutException;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.operations.ListOperation;
+import org.apache.cassandra.cql3.operations.MapOperation;
+import org.apache.cassandra.cql3.operations.Operation;
+import org.apache.cassandra.cql3.operations.SetOperation;
import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.DeletionInfo;
import org.apache.cassandra.db.IMutation;
@@ -160,9 +164,12 @@ public class DeleteStatement extends ModificationStatement
{
Pair<CFDefinition.Name, Term> p = iter.next();
CFDefinition.Name column = p.left;
- if (column.type instanceof CollectionType)
+
+ if (column.type.isCollection())
{
+ CollectionType validator = (CollectionType) column.type;
Term keySelected = p.right;
+
if (keySelected == null)
{
// Delete the whole collection
@@ -175,13 +182,25 @@ public class DeleteStatement extends ModificationStatement
else
{
builder.add(column.name.key);
- CollectionType.Function fct = CollectionType.Function.DISCARD_KEY;
List<Term> args = Collections.singletonList(keySelected);
- if (column.type instanceof ListType)
- ((ListType)column.type).execute(cf, builder, fct, args, params, group == null ? null : group.getCollection(column.name.key));
- else
- ((CollectionType)column.type).executeFunction(cf, builder, fct, args, params);
+ Operation op;
+ switch (validator.kind)
+ {
+ case LIST:
+ op = ListOperation.DiscardKey(args);
+ break;
+ case SET:
+ op = SetOperation.Discard(args);
+ break;
+ case MAP:
+ op = MapOperation.DiscardKey(keySelected);
+ break;
+ default:
+ throw new InvalidRequestException("Unknown collection type: " + validator.kind);
+ }
+
+ op.execute(cf, builder, validator, params, group == null ? null : group.getCollection(column.name.key));
}
}
else
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index dd729fb..97ff931 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -272,7 +272,7 @@ public class SelectStatement implements CQLStatement
{
// For sparse, we used to ask for 'defined columns' * 'asked limit' to account for the grouping of columns.
// Since that doesn't work for maps/sets/lists, we use the compositesToGroup option of SliceQueryFilter.
- // But we must preserver backward compatibility too.
+ // But we must preserve backward compatibility too.
int multiplier = cfDef.isCompact ? 1 : cfDef.metadata.size();
int toGroup = cfDef.isCompact ? -1 : cfDef.columns.size();
ColumnSlice slice = new ColumnSlice(getRequestedBound(isReversed ? Bound.END : Bound.START, variables),
@@ -419,6 +419,10 @@ public class SelectStatement implements CQLStatement
}
else
{
+ // Collections require doing a slice query because a given collection is a
+ // non-know set of columns, so we shouldn't get there
+ assert !cfDef.hasCollections;
+
// Adds all columns (even if the user selected a few columns, we
// need to query all columns to know if the row exists or not).
// Note that when we allow IS NOT NULL in queries and if all
@@ -702,7 +706,12 @@ public class SelectStatement implements CQLStatement
ColumnGroupMap.Builder builder = new ColumnGroupMap.Builder(composite, cfDef.hasCollections);
for (IColumn c : row.cf)
+ {
+ if (c.isMarkedForDelete())
+ continue;
+
builder.add(c);
+ }
for (ColumnGroupMap group : builder.groups())
handleGroup(selection, row.key.key, group, cqlRows);
@@ -801,9 +810,13 @@ public class SelectStatement implements CQLStatement
// This should not happen for SPARSE
throw new AssertionError();
case COLUMN_METADATA:
- if (name.type instanceof CollectionType)
+ if (name.type.isCollection())
{
- cqlRows.addColumnValue(((CollectionType)name.type).serializeForThrift(columns.getCollection(name.name.key)));
+ List<Pair<ByteBuffer, IColumn>> collection = columns.getCollection(name.name.key);
+ if (collection == null)
+ cqlRows.addColumnValue(null);
+ else
+ cqlRows.addColumnValue(((CollectionType)name.type).serializeForThrift(collection));
break;
}
IColumn c = columns.getSimple(name.name.key);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
index dc670dc..f84875a 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java
@@ -17,8 +17,6 @@
*/
package org.apache.cassandra.cql3.statements;
-import java.io.IOError;
-import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.TimeoutException;
@@ -27,17 +25,14 @@ import com.google.common.collect.ArrayListMultimap;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.operations.Operation;
import org.apache.cassandra.db.*;
-import org.apache.cassandra.db.filter.QueryPath;
import org.apache.cassandra.db.marshal.*;
import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.StorageProxy;
import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.thrift.UnavailableException;
-import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.Pair;
-import static org.apache.cassandra.cql.QueryProcessor.validateColumnName;
import static org.apache.cassandra.cql.QueryProcessor.validateKey;
import static org.apache.cassandra.thrift.ThriftValidation.validateColumnFamily;
@@ -52,7 +47,7 @@ public class UpdateStatement extends ModificationStatement
private CFDefinition cfDef;
private final List<Pair<ColumnIdentifier, Operation>> columns;
private final List<ColumnIdentifier> columnNames;
- private final List<Value> columnValues;
+ private final List<Operation> columnOperations;
private final List<Relation> whereClause;
private final ArrayListMultimap<CFDefinition.Name, Operation> processedColumns = ArrayListMultimap.create();
@@ -77,7 +72,7 @@ public class UpdateStatement extends ModificationStatement
this.columns = columns;
this.whereClause = whereClause;
this.columnNames = null;
- this.columnValues = null;
+ this.columnOperations = null;
}
/**
@@ -87,18 +82,18 @@ public class UpdateStatement extends ModificationStatement
*
* @param name column family being operated on
* @param columnNames list of column names
- * @param columnValues list of column values (corresponds to names)
+ * @param columnOperations list of column 'set' operations (corresponds to names)
* @param attrs additional attributes for statement (CL, timestamp, timeToLive)
*/
public UpdateStatement(CFName name,
Attributes attrs,
List<ColumnIdentifier> columnNames,
- List<Value> columnValues)
+ List<Operation> columnOperations)
{
super(name, attrs);
this.columnNames = columnNames;
- this.columnValues = columnValues;
+ this.columnOperations = columnOperations;
this.whereClause = null;
this.columns = null;
}
@@ -151,11 +146,7 @@ public class UpdateStatement extends ModificationStatement
if (!(name.type instanceof ListType))
continue;
- if (value == null || value.type != Operation.Type.FUNCTION)
- continue;
-
- Operation.Function fOp = (Operation.Function)value;
- if (fOp.fct.needsReading)
+ if (value.requiresRead())
{
needsReading = true;
break;
@@ -176,12 +167,6 @@ public class UpdateStatement extends ModificationStatement
/**
* Compute a row mutation for a single key
*
- * @param cfDef column family being operated on
- * @param clientState user/session state
- * @param key key to change
- * @param builder ongoing column name accumulator for the current statement
- * @param variables positional values
- *
* @return row mutation
*
* @throws InvalidRequestException on the wrong request
@@ -202,20 +187,18 @@ public class UpdateStatement extends ModificationStatement
if (builder.componentCount() == 0)
throw new InvalidRequestException(String.format("Missing PRIMARY KEY part %s", cfDef.columns.values().iterator().next()));
- List<Operation> value = processedColumns.get(cfDef.value);
- if (value.isEmpty())
+ List<Operation> operation = processedColumns.get(cfDef.value);
+ if (operation.isEmpty())
throw new InvalidRequestException(String.format("Missing mandatory column %s", cfDef.value));
- assert value.size() == 1;
- hasCounterColumn = addToMutation(cf, builder, cfDef.value, value.get(0), params, null);
+ assert operation.size() == 1;
+ hasCounterColumn = addToMutation(cf, builder, cfDef.value, operation.get(0), params, null);
}
else
{
for (Map.Entry<CFDefinition.Name, Operation> entry : processedColumns.entries())
{
CFDefinition.Name name = entry.getKey();
- Operation value = entry.getValue();
-
- hasCounterColumn |= addToMutation(cf, builder.copy().add(name.name.key), name, value, params, group == null ? null : group.getCollection(name.name.key));
+ hasCounterColumn |= addToMutation(cf, builder.copy().add(name.name.key), name, entry.getValue(), params, group == null ? null : group.getCollection(name.name.key));
}
}
@@ -225,69 +208,29 @@ public class UpdateStatement extends ModificationStatement
private boolean addToMutation(ColumnFamily cf,
ColumnNameBuilder builder,
CFDefinition.Name valueDef,
- Operation value,
+ Operation valueOperation,
UpdateParameters params,
List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
{
- switch (value.type)
- {
- case SET:
- Value v = ((Operation.Set)value).value;
- if (v instanceof Term)
- {
- ByteBuffer colName = builder.build();
- validateColumnName(colName);
- ByteBuffer valueBytes = ((Term)v).getByteBuffer(valueDef.type, params.variables);
- cf.addColumn(params.makeColumn(colName, valueBytes));
- }
- else
- {
- assert v instanceof Value.CollectionLiteral;
- Value.CollectionLiteral l = (Value.CollectionLiteral)v;
- l.validateType(valueDef);
- // Remove previous
- cf.addAtom(params.makeTombstoneForOverwrite(builder.copy().build(), builder.copy().buildAsEndOfRange()));
+ Operation.Type type = valueOperation.getType();
- if (!l.isEmpty())
- addToMutation(cf, builder, valueDef, new Operation.Function(l.constructionFunction(), l.asList()), params, null);
- }
- return false;
- case COUNTER:
- Operation.Counter cOp = (Operation.Counter)value;
- long val;
- try
- {
- val = ByteBufferUtil.toLong(cOp.value.getByteBuffer(LongType.instance, params.variables));
- }
- catch (NumberFormatException e)
- {
- throw new InvalidRequestException(String.format("'%s' is an invalid value, should be a long.",
- cOp.value.getText()));
- }
+ if (type == Operation.Type.COLUMN || type == Operation.Type.COUNTER)
+ {
+ if (valueDef.type.isCollection())
+ throw new InvalidRequestException("Can't apply operation on column with " + valueDef.type + " type.");
- if (cOp.isSubstraction)
- {
- if (val == Long.MIN_VALUE)
- throw new InvalidRequestException("The negation of " + val + " overflows supported integer precision (signed 8 bytes integer)");
- else
- val = -val;
- }
- cf.addCounter(new QueryPath(columnFamily(), null, builder.build()), val);
- return true;
- case FUNCTION:
- Operation.Function fOp = (Operation.Function)value;
- if (!(valueDef.type instanceof CollectionType))
- throw new InvalidRequestException(String.format("Invalid operation %s, %s is not a collection", fOp.fct, valueDef.name));
-
- if ((valueDef.type instanceof ListType) && fOp.fct.needsReading)
- ((ListType)valueDef.type).execute(cf, builder, fOp.fct, fOp.arguments, params, list);
- else
- ((CollectionType)valueDef.type).execute(cf, builder, fOp.fct, fOp.arguments, params);
-
- return false;
+ valueOperation.execute(cf, builder.copy(), valueDef.type, params);
}
- throw new AssertionError();
+ else
+ {
+ if (!valueDef.type.isCollection())
+ throw new InvalidRequestException("Can't apply collection operation on column with " + valueDef.type + " type.");
+
+ valueOperation.execute(cf, builder.copy(), (CollectionType) valueDef.type, params, list);
+ }
+
+ return valueOperation.getType() == Operation.Type.COUNTER;
}
public ParsedStatement.Prepared prepare(CFDefinition.Name[] boundNames) throws InvalidRequestException
@@ -298,10 +241,10 @@ public class UpdateStatement extends ModificationStatement
{
for (Pair<ColumnIdentifier, Operation> column : columns)
{
- if (column.right.type == Operation.Type.COUNTER)
+ if (column.right.getType() == Operation.Type.COUNTER)
hasCommutativeOperation = true;
- if (hasCommutativeOperation && column.right.type != Operation.Type.COUNTER)
+ if (hasCommutativeOperation && column.right.getType() != Operation.Type.COUNTER)
throw new InvalidRequestException("Mix of counter and non-counter operations is not allowed.");
}
}
@@ -317,7 +260,7 @@ public class UpdateStatement extends ModificationStatement
{
// Created from an INSERT
// Don't hate, validate.
- if (columnNames.size() != columnValues.size())
+ if (columnNames.size() != columnOperations.size())
throw new InvalidRequestException("unmatched column names/values");
if (columnNames.size() < 1)
throw new InvalidRequestException("no columns specified for INSERT");
@@ -328,8 +271,8 @@ public class UpdateStatement extends ModificationStatement
if (name == null)
throw new InvalidRequestException(String.format("Unknown identifier %s", columnNames.get(i)));
- Value value = columnValues.get(i);
- for (Term t : value.asList())
+ Operation operation = columnOperations.get(i);
+ for (Term t : operation.getValues())
if (t.isBindMarker())
boundNames[t.bindIndex] = name;
@@ -339,15 +282,15 @@ public class UpdateStatement extends ModificationStatement
case COLUMN_ALIAS:
if (processedKeys.containsKey(name.name))
throw new InvalidRequestException(String.format("Multiple definitions found for PRIMARY KEY part %s", name));
- if (!(value instanceof Term))
+ if (operation.getType() != Operation.Type.COLUMN)
throw new InvalidRequestException(String.format("Invalid definition for %s, not a collection type", name));
- processedKeys.put(name.name, Collections.singletonList((Term)value));
+ processedKeys.put(name.name, operation.getValues());
break;
case VALUE_ALIAS:
case COLUMN_METADATA:
if (processedColumns.containsKey(name))
throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
- processedColumns.put(name, new Operation.Set(value));
+ processedColumns.put(name, operation);
break;
}
}
@@ -369,11 +312,11 @@ public class UpdateStatement extends ModificationStatement
case VALUE_ALIAS:
case COLUMN_METADATA:
for (Operation op : processedColumns.get(name))
- if (op.type != Operation.Type.FUNCTION)
+ if (op.getType() == Operation.Type.COLUMN)
throw new InvalidRequestException(String.format("Multiple definitions found for column %s", name));
Operation op = entry.right;
- for (Term t : op.allTerms())
+ for (Term t : op.getValues())
if (t.isBindMarker())
boundNames[t.bindIndex] = name;
processedColumns.put(name, op);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index 148138a..2aa9578 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -226,6 +226,11 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
validate(bytes);
}
+ public boolean isCollection()
+ {
+ return false;
+ }
+
/**
* This must be overriden by subclasses if necessary so that for any
* AbstractType, this == TypeParser.parse(toString()).
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/CollectionType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CollectionType.java b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
index ab8f15b..d50fc7d 100644
--- a/src/java/org/apache/cassandra/db/marshal/CollectionType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CollectionType.java
@@ -45,26 +45,6 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
MAP, SET, LIST
}
- public enum Function
- {
- APPEND (false, Kind.LIST),
- PREPEND (false, Kind.LIST),
- SET ( true, Kind.LIST, Kind.MAP),
- ADD (false, Kind.SET),
- DISCARD_LIST ( true, Kind.LIST),
- DISCARD_SET (false, Kind.SET),
- DISCARD_KEY ( true, Kind.LIST, Kind.MAP);
-
- public final boolean needsReading;
- public final EnumSet<Kind> validReceivers;
-
- private Function(boolean needsReading, Kind ... validReceivers)
- {
- this.needsReading = needsReading;
- this.validReceivers = EnumSet.copyOf(Arrays.asList(validReceivers));
- }
- }
-
public final Kind kind;
protected CollectionType(Kind kind)
@@ -72,19 +52,10 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
this.kind = kind;
}
- protected abstract AbstractType<?> nameComparator();
- protected abstract AbstractType<?> valueComparator();
- protected abstract void appendToStringBuilder(StringBuilder sb);
-
- public void execute(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
- {
- if (!fct.validReceivers.contains(kind))
- throw new InvalidRequestException(String.format("Invalid operation %s for %s collection", fct, kind));
-
- executeFunction(cf, fullPath, fct, args, params);
- }
+ public abstract AbstractType<?> nameComparator();
+ public abstract AbstractType<?> valueComparator();
- public abstract void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException;
+ protected abstract void appendToStringBuilder(StringBuilder sb);
public abstract ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns);
@@ -132,4 +103,9 @@ public abstract class CollectionType extends AbstractType<ByteBuffer>
{
valueComparator().validate(bytes);
}
+
+ public boolean isCollection()
+ {
+ return true;
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/CompositeType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
index 516c44b..dfe79e2 100644
--- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
@@ -196,7 +196,6 @@ public class CompositeType extends AbstractCompositeType
public static class Builder implements ColumnNameBuilder
{
private final CompositeType composite;
- private int current;
private final List<ByteBuffer> components;
private final byte[] endOfComponents;
@@ -219,15 +218,15 @@ public class CompositeType extends AbstractCompositeType
private Builder(Builder b)
{
this(b.composite, new ArrayList<ByteBuffer>(b.components), Arrays.copyOf(b.endOfComponents, b.endOfComponents.length));
- this.current = b.current;
this.serializedSize = b.serializedSize;
}
public Builder add(Term t, Relation.Type op, List<ByteBuffer> variables) throws InvalidRequestException
{
- if (current >= composite.types.size())
+ if (components.size() >= composite.types.size())
throw new IllegalStateException("Composite column is already fully constructed");
+ int current = components.size();
AbstractType currentType = composite.types.get(current);
ByteBuffer buffer = t.getByteBuffer(currentType, variables);
components.add(buffer);
@@ -254,23 +253,23 @@ public class CompositeType extends AbstractCompositeType
endOfComponents[current] = (byte) 0;
break;
}
- ++current;
return this;
}
public Builder add(ByteBuffer bb)
{
+ int current = components.size();
if (current >= composite.types.size())
throw new IllegalStateException("Composite column is already fully constructed");
components.add(bb);
- endOfComponents[current++] = (byte) 0;
+ endOfComponents[current] = (byte) 0;
return this;
}
public int componentCount()
{
- return current;
+ return components.size();
}
public ByteBuffer build()
@@ -286,10 +285,10 @@ public class CompositeType extends AbstractCompositeType
public ByteBuffer buildAsEndOfRange()
{
- if (current >= composite.types.size())
+ if (components.size() >= composite.types.size())
throw new IllegalStateException("Composite column is already fully constructed");
- if (current == 0)
+ if (components.isEmpty())
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
ByteBuffer bb = build();
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/ListType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ListType.java b/src/java/org/apache/cassandra/db/marshal/ListType.java
index 8ad4590..ad1211d 100644
--- a/src/java/org/apache/cassandra/db/marshal/ListType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ListType.java
@@ -19,64 +19,18 @@ package org.apache.cassandra.db.marshal;
import java.nio.ByteBuffer;
import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
-import org.apache.cassandra.cql3.ColumnNameBuilder;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.cql3.UpdateParameters;
-import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.IColumn;
import org.apache.cassandra.config.ConfigurationException;
-import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.Pair;
-import org.apache.cassandra.utils.UUIDGen;
public class ListType extends CollectionType
{
// interning instances
private static final Map<AbstractType<?>, ListType> instances = new HashMap<AbstractType<?>, ListType>();
- // Our reference time (1 jan 2010, 00:00:00) in milliseconds.
- private static final long REFERENCE_TIME = 1262304000000L;
-
- /*
- * For prepend, we need to be able to generate unique but decreasing time
- * UUID, which is a bit challenging. To do that, given a time in milliseconds,
- * we adds a number represening the 100-nanoseconds precision and make sure
- * that within the same millisecond, that number is always increasing. We
- * do rely on the fact that the user will only provide decreasing
- * milliseconds timestamp for that purpose.
- */
- private static class PrecisionTime
- {
- public final long millis;
- public final int nanos;
-
- public PrecisionTime(long millis, int nanos)
- {
- this.millis = millis;
- this.nanos = nanos;
- }
- }
-
- private static final AtomicReference<PrecisionTime> last = new AtomicReference<PrecisionTime>(new PrecisionTime(Long.MAX_VALUE, 0));
-
- private static PrecisionTime getNextTime(long millis)
- {
- while (true)
- {
- PrecisionTime current = last.get();
- assert millis <= current.millis;
- PrecisionTime next = millis < current.millis
- ? new PrecisionTime(millis, 0)
- : new PrecisionTime(millis, current.nanos + 1);
- if (last.compareAndSet(current, next))
- return next;
- }
- }
-
public final AbstractType<?> elements;
public static ListType getInstance(TypeParser parser) throws ConfigurationException
@@ -105,12 +59,12 @@ public class ListType extends CollectionType
this.elements = elements;
}
- protected AbstractType<?> nameComparator()
+ public AbstractType<?> nameComparator()
{
return TimeUUIDType.instance;
}
- protected AbstractType<?> valueComparator()
+ public AbstractType<?> valueComparator()
{
return elements;
}
@@ -120,111 +74,6 @@ public class ListType extends CollectionType
sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Collections.<AbstractType<?>>singletonList(elements)));
}
- public void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
- {
- switch (fct)
- {
- case APPEND:
- doAppend(cf, fullPath, args, params);
- break;
- case PREPEND:
- doPrepend(cf, fullPath, args, params);
- break;
- default:
- throw new AssertionError("Unsupported function " + fct);
- }
- }
-
- public void execute(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
- {
- switch (fct)
- {
- case SET:
- doSet(cf, fullPath, validateIdx(fct, args.get(0), list), args.get(1), params, list);
- break;
- case DISCARD_LIST:
- // If list is empty, do nothing
- if (list != null)
- doDiscard(cf, fullPath, args, params, list);
- break;
- case DISCARD_KEY:
- doDiscardIdx(cf, fullPath, validateIdx(fct, args.get(0), list), params, list);
- break;
- default:
- throw new AssertionError();
- }
- }
-
- private int validateIdx(Function fct, Term value, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
- {
- try
- {
- if (value.getType() != Term.Type.INTEGER)
- throw new InvalidRequestException(String.format("Invalid argument %s for %s, must be an integer", value.getText(), fct));
- int idx = Integer.parseInt(value.getText());
- if (list == null || list.size() <= idx)
- throw new InvalidRequestException(String.format("Invalid index %d, list has size %d", idx, list == null ? 0 : list.size()));
- return idx;
- }
- catch (NumberFormatException e)
- {
- // This should not happen, unless we screwed up the parser
- throw new RuntimeException();
- }
- }
-
- private void doPrepend(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params) throws InvalidRequestException
- {
- long time = REFERENCE_TIME - (System.currentTimeMillis() - REFERENCE_TIME);
- // We do the loop in reverse order because getNext() will create increasing time but we want the last
- // value in the prepended list to have the lower time
- for (int i = values.size() - 1; i >= 0; i--)
- {
- ColumnNameBuilder b = i == 0 ? builder : builder.copy();
- PrecisionTime pt = getNextTime(time);
- ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos));
- ByteBuffer name = b.add(uuid).build();
- cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(elements, params.variables)));
- }
- }
-
- private void doAppend(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params) throws InvalidRequestException
- {
- for (int i = 0; i < values.size(); i++)
- {
- ColumnNameBuilder b = i == values.size() - 1 ? builder : builder.copy();
- ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes());
- ByteBuffer name = b.add(uuid).build();
- cf.addColumn(params.makeColumn(name, values.get(i).getByteBuffer(elements, params.variables)));
- }
- }
-
- public void doSet(ColumnFamily cf, ColumnNameBuilder builder, int idx, Term value, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
- {
- ByteBuffer name = list.get(idx).right.name();
- cf.addColumn(params.makeColumn(name, value.getByteBuffer(elements, params.variables)));
- }
-
- public void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, List<Term> values, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
- {
- Set<ByteBuffer> toDiscard = new HashSet<ByteBuffer>();
- for (Term value : values)
- toDiscard.add(value.getByteBuffer(elements, params.variables));
-
- for (Pair<ByteBuffer, IColumn> p : list)
- {
- IColumn c = p.right;
- if (toDiscard.contains(c.value()))
- cf.addColumn(params.makeTombstone(c.name()));
- }
- }
-
- public void doDiscardIdx(ColumnFamily cf, ColumnNameBuilder builder, int idx, UpdateParameters params, List<Pair<ByteBuffer, IColumn>> list) throws InvalidRequestException
- {
- ByteBuffer name = list.get(idx).right.name();
- cf.addColumn(params.makeTombstone(name));
- }
-
public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
{
List<Object> l = new ArrayList<Object>(columns.size());
http://git-wip-us.apache.org/repos/asf/cassandra/blob/2b62df24/src/java/org/apache/cassandra/db/marshal/MapType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/MapType.java b/src/java/org/apache/cassandra/db/marshal/MapType.java
index 8e29520..a5a6caa 100644
--- a/src/java/org/apache/cassandra/db/marshal/MapType.java
+++ b/src/java/org/apache/cassandra/db/marshal/MapType.java
@@ -19,19 +19,13 @@ package org.apache.cassandra.db.marshal;
import java.nio.ByteBuffer;
import java.util.Arrays;
-import java.util.Iterator;
import java.util.HashMap;
import java.util.List;
import java.util.LinkedHashMap;
import java.util.Map;
-import org.apache.cassandra.cql3.ColumnNameBuilder;
-import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.cql3.UpdateParameters;
-import org.apache.cassandra.db.ColumnFamily;
import org.apache.cassandra.db.IColumn;
import org.apache.cassandra.config.ConfigurationException;
-import org.apache.cassandra.thrift.InvalidRequestException;
import org.apache.cassandra.utils.ByteBufferUtil;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.Pair;
@@ -72,12 +66,12 @@ public class MapType extends CollectionType
this.values = values;
}
- protected AbstractType<?> nameComparator()
+ public AbstractType<?> nameComparator()
{
return keys;
}
- protected AbstractType<?> valueComparator()
+ public AbstractType<?> valueComparator()
{
return values;
}
@@ -87,39 +81,6 @@ public class MapType extends CollectionType
sb.append(getClass().getName()).append(TypeParser.stringifyTypeParameters(Arrays.asList(keys, values)));
}
- public void executeFunction(ColumnFamily cf, ColumnNameBuilder fullPath, Function fct, List<Term> args, UpdateParameters params) throws InvalidRequestException
- {
- switch (fct)
- {
- case SET:
- doPut(cf, fullPath, args, params);
- break;
- case DISCARD_KEY:
- doDiscard(cf, fullPath, args.get(0), params);
- break;
- default:
- throw new AssertionError("Unsupported function " + fct);
- }
- }
-
- private void doPut(ColumnFamily cf, ColumnNameBuilder builder, List<Term> args, UpdateParameters params) throws InvalidRequestException
- {
- assert args.size() % 2 == 0;
- Iterator<Term> iter = args.iterator();
- while (iter.hasNext())
- {
- ByteBuffer name = builder.copy().add(iter.next().getByteBuffer(keys, params.variables)).build();
- ByteBuffer value = iter.next().getByteBuffer(values, params.variables);
- cf.addColumn(params.makeColumn(name, value));
- }
- }
-
- private void doDiscard(ColumnFamily cf, ColumnNameBuilder builder, Term value, UpdateParameters params) throws InvalidRequestException
- {
- ByteBuffer name = builder.add(value.getByteBuffer(keys, params.variables)).build();
- cf.addColumn(params.makeTombstone(name));
- }
-
public ByteBuffer serializeForThrift(List<Pair<ByteBuffer, IColumn>> columns)
{
Map<String, Object> m = new LinkedHashMap<String, Object>();