http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/ColumnCondition.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/ColumnCondition.java b/src/java/org/apache/cassandra/cql3/ColumnCondition.java index c7b5ddb..50f79f4 100644 --- a/src/java/org/apache/cassandra/cql3/ColumnCondition.java +++ b/src/java/org/apache/cassandra/cql3/ColumnCondition.java @@ -20,18 +20,12 @@ package org.apache.cassandra.cql3; import java.nio.ByteBuffer; import java.util.*; -import com.google.common.base.Predicate; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.Cell; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.composites.CellNameType; -import org.apache.cassandra.db.composites.Composite; -import org.apache.cassandra.db.filter.ColumnSlice; +import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.transport.Server; @@ -160,20 +154,19 @@ public class ColumnCondition /** * Validates whether this condition applies to {@code current}. */ - public abstract boolean appliesTo(Composite rowPrefix, ColumnFamily current, long now) throws InvalidRequestException; + public abstract boolean appliesTo(Row row) throws InvalidRequestException; public ByteBuffer getCollectionElementValue() { return null; } - protected boolean isSatisfiedByValue(ByteBuffer value, Cell c, AbstractType<?> type, Operator operator, long now) throws InvalidRequestException + protected boolean isSatisfiedByValue(ByteBuffer value, Cell c, AbstractType<?> type, Operator operator) throws InvalidRequestException { - ByteBuffer columnValue = (c == null || !c.isLive(now)) ? null : c.value(); - return compareWithOperator(operator, type, value, columnValue); + return compareWithOperator(operator, type, value, c == null ? null : c.value()); } - /** Returns true if the operator is satisfied (i.e. "value operator otherValue == true"), false otherwise. */ + /** Returns true if the operator is satisfied (i.e. "otherValue operator value == true"), false otherwise. */ protected boolean compareWithOperator(Operator operator, AbstractType<?> type, ByteBuffer value, ByteBuffer otherValue) throws InvalidRequestException { if (value == ByteBufferUtil.UNSET_BYTE_BUFFER) @@ -195,41 +188,29 @@ public class ColumnCondition // the condition value is not null, so only NEQ can return true return operator == Operator.NEQ; } - int comparison = type.compare(otherValue, value); - switch (operator) - { - case EQ: - return comparison == 0; - case LT: - return comparison < 0; - case LTE: - return comparison <= 0; - case GT: - return comparison > 0; - case GTE: - return comparison >= 0; - case NEQ: - return comparison != 0; - default: - // we shouldn't get IN, CONTAINS, or CONTAINS KEY here - throw new AssertionError(); - } + return operator.isSatisfiedBy(type, otherValue, value); } + } - 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[]{ collection.slice() }; - // Filter live columns, this makes things simpler afterwards - return Iterators.filter(cf.iterator(collectionSlice), new Predicate<Cell>() - { - public boolean apply(Cell c) - { - // we only care about live columns - return c.isLive(now); - } - }); - } + private static Cell getCell(Row row, ColumnDefinition column) + { + // If we're asking for a given cell, and we didn't got any row from our read, it's + // the same as not having said cell. + return row == null ? null : row.getCell(column); + } + + private static Cell getCell(Row row, ColumnDefinition column, CellPath path) + { + // If we're asking for a given cell, and we didn't got any row from our read, it's + // the same as not having said cell. + return row == null ? null : row.getCell(column, path); + } + + private static Iterator<Cell> getCells(Row row, ColumnDefinition column) + { + // If we're asking for a complex cells, and we didn't got any row from our read, it's + // the same as not having any cells for that column. + return row == null ? Collections.<Cell>emptyIterator() : row.getCells(column); } /** @@ -247,10 +228,9 @@ public class ColumnCondition this.value = condition.value.bindAndGet(options); } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { - CellName name = current.metadata().comparator.create(rowPrefix, column); - return isSatisfiedByValue(value, current.getColumn(name), column.type, operator, now); + return isSatisfiedByValue(value, getCell(row, column), column.type, operator); } } @@ -276,12 +256,12 @@ public class ColumnCondition } } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { - CellName name = current.metadata().comparator.create(rowPrefix, column); + Cell c = getCell(row, column); for (ByteBuffer value : inValues) { - if (isSatisfiedByValue(value, current.getColumn(name), column.type, Operator.EQ, now)) + if (isSatisfiedByValue(value, c, column.type, Operator.EQ)) return true; } return false; @@ -303,7 +283,7 @@ public class ColumnCondition this.value = condition.value.bindAndGet(options); } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { if (collectionElement == null) throw new InvalidRequestException("Invalid null value for " + (column.type instanceof MapType ? "map" : "list") + " element access"); @@ -313,14 +293,13 @@ public class ColumnCondition MapType mapType = (MapType) column.type; if (column.type.isMultiCell()) { - Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column, collectionElement)); - return isSatisfiedByValue(value, cell, mapType.getValuesType(), operator, now); + Cell cell = getCell(row, column, CellPath.create(collectionElement)); + return isSatisfiedByValue(value, cell, ((MapType) column.type).getValuesType(), operator); } else { - Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column)); - ByteBuffer mapElementValue = cell.isLive(now) ? mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType()) - : null; + Cell cell = getCell(row, column); + ByteBuffer mapElementValue = mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType()); return compareWithOperator(operator, mapType.getValuesType(), value, mapElementValue); } } @@ -329,16 +308,13 @@ public class ColumnCondition ListType listType = (ListType) column.type; if (column.type.isMultiCell()) { - ByteBuffer columnValue = getListItem( - collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now), - getListIndex(collectionElement)); - return compareWithOperator(operator, listType.getElementsType(), value, columnValue); + ByteBuffer columnValue = getListItem(getCells(row, column), getListIndex(collectionElement)); + return compareWithOperator(operator, ((ListType)column.type).getElementsType(), value, columnValue); } else { - Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column)); - ByteBuffer listElementValue = cell.isLive(now) ? listType.getSerializer().getElement(cell.value(), getListIndex(collectionElement)) - : null; + Cell cell = getCell(row, column); + ByteBuffer listElementValue = listType.getSerializer().getElement(cell.value(), getListIndex(collectionElement)); return compareWithOperator(operator, listType.getElementsType(), value, listElementValue); } } @@ -387,33 +363,31 @@ public class ColumnCondition } } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { if (collectionElement == null) throw new InvalidRequestException("Invalid null value for " + (column.type instanceof MapType ? "map" : "list") + " element access"); - CellNameType nameType = current.metadata().comparator; if (column.type instanceof MapType) { MapType mapType = (MapType) column.type; AbstractType<?> valueType = mapType.getValuesType(); if (column.type.isMultiCell()) { - CellName name = nameType.create(rowPrefix, column, collectionElement); - Cell item = current.getColumn(name); + Cell item = getCell(row, column, CellPath.create(collectionElement)); for (ByteBuffer value : inValues) { - if (isSatisfiedByValue(value, item, valueType, Operator.EQ, now)) + if (isSatisfiedByValue(value, item, valueType, Operator.EQ)) return true; } return false; } else { - Cell cell = current.getColumn(nameType.create(rowPrefix, column)); - ByteBuffer mapElementValue = null; - if (cell != null && cell.isLive(now)) - mapElementValue = mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType()); + Cell cell = getCell(row, column); + ByteBuffer mapElementValue = cell == null + ? null + : mapType.getSerializer().getSerializedValue(cell.value(), collectionElement, mapType.getKeysType()); for (ByteBuffer value : inValues) { if (value == null) @@ -433,9 +407,7 @@ public class ColumnCondition AbstractType<?> elementsType = listType.getElementsType(); if (column.type.isMultiCell()) { - ByteBuffer columnValue = ElementAccessBound.getListItem( - collectionColumns(nameType.create(rowPrefix, column), current, now), - ElementAccessBound.getListIndex(collectionElement)); + ByteBuffer columnValue = ElementAccessBound.getListItem(getCells(row, column), ElementAccessBound.getListIndex(collectionElement)); for (ByteBuffer value : inValues) { @@ -445,10 +417,10 @@ public class ColumnCondition } else { - Cell cell = current.getColumn(nameType.create(rowPrefix, column)); - ByteBuffer listElementValue = null; - if (cell != null && cell.isLive(now)) - listElementValue = listType.getSerializer().getElement(cell.value(), ElementAccessBound.getListIndex(collectionElement)); + Cell cell = getCell(row, column); + ByteBuffer listElementValue = cell == null + ? null + : listType.getSerializer().getElement(cell.value(), ElementAccessBound.getListIndex(collectionElement)); for (ByteBuffer value : inValues) { @@ -479,13 +451,13 @@ public class ColumnCondition this.value = condition.value.bind(options); } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { CollectionType type = (CollectionType)column.type; if (type.isMultiCell()) { - Iterator<Cell> iter = collectionColumns(current.metadata().comparator.create(rowPrefix, column), current, now); + Iterator<Cell> iter = getCells(row, column); if (value == null) { if (operator == Operator.EQ) @@ -500,13 +472,13 @@ public class ColumnCondition } // frozen collections - Cell cell = current.getColumn(current.metadata().comparator.create(rowPrefix, column)); + Cell cell = getCell(row, column); if (value == null) { if (operator == Operator.EQ) - return cell == null || !cell.isLive(now); + return cell == null; else if (operator == Operator.NEQ) - return cell != null && cell.isLive(now); + return cell != null; else throw new InvalidRequestException(String.format("Invalid comparison with null for operator \"%s\"", operator)); } @@ -551,7 +523,7 @@ public class ColumnCondition return (operator == Operator.GT) || (operator == Operator.GTE) || (operator == Operator.NEQ); // for lists we use the cell value; for sets we use the cell name - ByteBuffer cellValue = isSet? iter.next().name().collectionElement() : iter.next().value(); + ByteBuffer cellValue = isSet ? iter.next().path().get(0) : iter.next().value(); int comparison = type.compare(cellValue, conditionIter.next()); if (comparison != 0) return evaluateComparisonWithOperator(comparison, operator); @@ -609,7 +581,7 @@ public class ColumnCondition Cell c = iter.next(); // compare the keys - int comparison = type.getKeysType().compare(c.name().collectionElement(), conditionEntry.getKey()); + int comparison = type.getKeysType().compare(c.path().get(0), conditionEntry.getKey()); if (comparison != 0) return evaluateComparisonWithOperator(comparison, operator); @@ -683,29 +655,27 @@ public class ColumnCondition } } - public boolean appliesTo(Composite rowPrefix, ColumnFamily current, final long now) throws InvalidRequestException + public boolean appliesTo(Row row) throws InvalidRequestException { CollectionType type = (CollectionType)column.type; - CellName name = current.metadata().comparator.create(rowPrefix, column); if (type.isMultiCell()) { // copy iterator contents so that we can properly reuse them for each comparison with an IN value - List<Cell> cells = newArrayList(collectionColumns(name, current, now)); for (Term.Terminal value : inValues) { - if (CollectionBound.valueAppliesTo(type, cells.iterator(), value, Operator.EQ)) + if (CollectionBound.valueAppliesTo(type, getCells(row, column), value, Operator.EQ)) return true; } return false; } else { - Cell cell = current.getColumn(name); + Cell cell = getCell(row, column); for (Term.Terminal value : inValues) { if (value == null) { - if (cell == null || !cell.isLive(now)) + if (cell == null) return true; } else if (type.compare(value.get(Server.VERSION_3), cell.value()) == 0)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java index 823af94..eafcf8d 100644 --- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java +++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java @@ -20,6 +20,10 @@ package org.apache.cassandra.cql3; import java.nio.ByteBuffer; import java.util.List; import java.util.Locale; +import java.nio.ByteBuffer; +import java.util.concurrent.ConcurrentMap; + +import com.google.common.collect.MapMaker; import org.apache.cassandra.cache.IMeasurableMemory; import org.apache.cassandra.config.CFMetaData; @@ -28,7 +32,7 @@ import org.apache.cassandra.cql3.selection.Selectable; import org.apache.cassandra.cql3.selection.Selector; import org.apache.cassandra.cql3.selection.SimpleSelector; import org.apache.cassandra.db.marshal.AbstractType; -import org.apache.cassandra.db.marshal.CompositeType; +import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.utils.ByteBufferUtil; @@ -43,25 +47,57 @@ public class ColumnIdentifier extends org.apache.cassandra.cql3.selection.Select { public final ByteBuffer bytes; private final String text; + private final boolean interned; - private static final long EMPTY_SIZE = ObjectSizes.measure(new ColumnIdentifier("", true)); + private static final long EMPTY_SIZE = ObjectSizes.measure(new ColumnIdentifier(ByteBufferUtil.EMPTY_BYTE_BUFFER, "", false)); + + private static final ConcurrentMap<ByteBuffer, ColumnIdentifier> internedInstances = new MapMaker().weakValues().makeMap(); public ColumnIdentifier(String rawText, boolean keepCase) { this.text = keepCase ? rawText : rawText.toLowerCase(Locale.US); this.bytes = ByteBufferUtil.bytes(this.text); + this.interned = false; } public ColumnIdentifier(ByteBuffer bytes, AbstractType<?> type) { - this.bytes = bytes; - this.text = type.getString(bytes); + this(bytes, type.getString(bytes), false); } - public ColumnIdentifier(ByteBuffer bytes, String text) + private ColumnIdentifier(ByteBuffer bytes, String text, boolean interned) { this.bytes = bytes; this.text = text; + this.interned = interned; + } + + public static ColumnIdentifier getInterned(ByteBuffer bytes, AbstractType<?> type) + { + return getInterned(bytes, type.getString(bytes)); + } + + public static ColumnIdentifier getInterned(String rawText, boolean keepCase) + { + String text = keepCase ? rawText : rawText.toLowerCase(Locale.US); + ByteBuffer bytes = ByteBufferUtil.bytes(text); + return getInterned(bytes, text); + } + + public static ColumnIdentifier getInterned(ByteBuffer bytes, String text) + { + ColumnIdentifier id = internedInstances.get(bytes); + if (id != null) + return id; + + ColumnIdentifier created = new ColumnIdentifier(bytes, text, true); + ColumnIdentifier previous = internedInstances.putIfAbsent(bytes, created); + return previous == null ? created : previous; + } + + public boolean isInterned() + { + return interned; } @Override @@ -73,8 +109,6 @@ public class ColumnIdentifier extends org.apache.cassandra.cql3.selection.Select @Override public final boolean equals(Object o) { - // Note: it's worth checking for reference equality since we intern those - // in SparseCellNameType if (this == o) return true; @@ -106,7 +140,7 @@ public class ColumnIdentifier extends org.apache.cassandra.cql3.selection.Select public ColumnIdentifier clone(AbstractAllocator allocator) { - return new ColumnIdentifier(allocator.clone(bytes), text); + return interned ? this : new ColumnIdentifier(allocator.clone(bytes), text, false); } public Selector.Factory newSelectorFactory(CFMetaData cfm, List<ColumnDefinition> defs) throws InvalidRequestException @@ -137,20 +171,22 @@ public class ColumnIdentifier extends org.apache.cassandra.cql3.selection.Select public ColumnIdentifier prepare(CFMetaData cfm) { - AbstractType<?> comparator = cfm.comparator.asAbstractType(); - if (cfm.getIsDense() || comparator instanceof CompositeType || comparator instanceof UTF8Type) - return new ColumnIdentifier(text, true); + if (!cfm.isStaticCompactTable()) + return getInterned(text, true); + + AbstractType<?> thriftColumnNameType = cfm.thriftColumnNameType(); + if (thriftColumnNameType instanceof UTF8Type) + return getInterned(text, true); - // We have a Thrift-created table with a non-text comparator. We need to parse column names with the comparator - // to get the correct ByteBuffer representation. However, this doesn't apply to key aliases, so we need to - // make a special check for those and treat them normally. See CASSANDRA-8178. + // We have a Thrift-created table with a non-text comparator. Check if we have a match column, otherwise assume we should use + // thriftColumnNameType ByteBuffer bufferName = ByteBufferUtil.bytes(text); - for (ColumnDefinition def : cfm.partitionKeyColumns()) + for (ColumnDefinition def : cfm.allColumns()) { if (def.name.bytes.equals(bufferName)) - return new ColumnIdentifier(text, true); + return def.name; } - return new ColumnIdentifier(comparator.fromString(rawText), text); + return getInterned(thriftColumnNameType.fromString(rawText), text); } public boolean processesSelection() http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/Constants.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Constants.java b/src/java/org/apache/cassandra/cql3/Constants.java index 07b848c..859b1b5 100644 --- a/src/java/org/apache/cassandra/cql3/Constants.java +++ b/src/java/org/apache/cassandra/cql3/Constants.java @@ -23,8 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.db.*; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.composites.Composite; +import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.db.marshal.CounterColumnType; @@ -319,14 +318,13 @@ public abstract class Constants super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { ByteBuffer value = t.bindAndGet(params.options); - if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) // use reference equality and not object equality - { - CellName cname = cf.getComparator().create(prefix, column); - cf.addColumn(value == null ? params.makeTombstone(cname) : params.makeColumn(cname, value)); - } + if (value == null) + params.addTombstone(column, writer); + else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) // use reference equality and not object equality + params.addCell(clustering, column, writer, value); } } @@ -337,7 +335,7 @@ public abstract class Constants super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { ByteBuffer bytes = t.bindAndGet(params.options); if (bytes == null) @@ -346,8 +344,7 @@ public abstract class Constants return; long increment = ByteBufferUtil.toLong(bytes); - CellName cname = cf.getComparator().create(prefix, column); - cf.addColumn(params.makeCounter(cname, increment)); + params.addCounter(column, writer, increment); } } @@ -358,7 +355,7 @@ public abstract class Constants super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { ByteBuffer bytes = t.bindAndGet(params.options); if (bytes == null) @@ -370,8 +367,7 @@ public abstract class Constants if (increment == Long.MIN_VALUE) throw new InvalidRequestException("The negation of " + increment + " overflows supported counter precision (signed 8 bytes integer)"); - CellName cname = cf.getComparator().create(prefix, column); - cf.addColumn(params.makeCounter(cname, -increment)); + params.addCounter(column, writer, -increment); } } @@ -384,13 +380,12 @@ public abstract class Constants super(column, null); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { - CellName cname = cf.getComparator().create(prefix, column); if (column.type.isMultiCell()) - cf.addAtom(params.makeRangeTombstone(cname.slice())); + params.setComplexDeletionTime(column, writer); else - cf.addColumn(params.makeTombstone(cname)); + params.addTombstone(column, writer); } }; } http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/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 094b72e..093a47c 100644 --- a/src/java/org/apache/cassandra/cql3/Cql.g +++ b/src/java/org/apache/cassandra/cql3/Cql.g @@ -318,7 +318,7 @@ selectClause returns [List<RawSelector> expr] selector returns [RawSelector s] @init{ ColumnIdentifier alias = null; } - : us=unaliasedSelector (K_AS c=ident { alias = c; })? { $s = new RawSelector(us, alias); } + : us=unaliasedSelector (K_AS c=noncol_ident { alias = c; })? { $s = new RawSelector(us, alias); } ; unaliasedSelector returns [Selectable.Raw s] @@ -339,7 +339,7 @@ selectionFunctionArgs returns [List<Selectable.Raw> a] selectCountClause returns [List<RawSelector> expr] @init{ ColumnIdentifier alias = new ColumnIdentifier("count", false); } - : K_COUNT '(' countArgument ')' (K_AS c=ident { alias = c; })? { $expr = new ArrayList<RawSelector>(); $expr.add( new RawSelector(new Selectable.WithFunction.Raw(FunctionName.nativeFunction("countRows"), Collections.<Selectable.Raw>emptyList()), alias));} + : K_COUNT '(' countArgument ')' (K_AS c=noncol_ident { alias = c; })? { $expr = new ArrayList<RawSelector>(); $expr.add( new RawSelector(new Selectable.WithFunction.Raw(FunctionName.nativeFunction("countRows"), Collections.<Selectable.Raw>emptyList()), alias));} ; countArgument @@ -404,7 +404,7 @@ jsonInsertStatement [CFName cf] returns [UpdateStatement.ParsedInsertJson expr] jsonValue returns [Json.Raw value] : | s=STRING_LITERAL { $value = new Json.Literal($s.text); } - | ':' id=ident { $value = newJsonBindVariables(id); } + | ':' id=noncol_ident { $value = newJsonBindVariables(id); } | QMARK { $value = newJsonBindVariables(null); } ; @@ -604,8 +604,8 @@ createFunctionStatement returns [CreateFunctionStatement expr] fn=functionName '(' ( - k=ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } - ( ',' k=ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } )* + k=noncol_ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } + ( ',' k=noncol_ident v=comparatorType { argsNames.add(k); argsTypes.add(v); } )* )? ')' ( (K_RETURNS K_NULL) | (K_CALLED { calledOnNullInput=true; })) K_ON K_NULL K_INPUT @@ -706,7 +706,7 @@ createTypeStatement returns [CreateTypeStatement expr] ; typeColumns[CreateTypeStatement expr] - : k=ident v=comparatorType { $expr.addDefinition(k, v); } + : k=noncol_ident v=comparatorType { $expr.addDefinition(k, v); } ; @@ -801,12 +801,12 @@ alterTableStatement returns [AlterTableStatement expr] */ alterTypeStatement returns [AlterTypeStatement expr] : K_ALTER K_TYPE name=userTypeName - ( K_ALTER f=ident K_TYPE v=comparatorType { $expr = AlterTypeStatement.alter(name, f, v); } - | K_ADD f=ident v=comparatorType { $expr = AlterTypeStatement.addition(name, f, v); } + ( K_ALTER f=noncol_ident K_TYPE v=comparatorType { $expr = AlterTypeStatement.alter(name, f, v); } + | K_ADD f=noncol_ident v=comparatorType { $expr = AlterTypeStatement.addition(name, f, v); } | K_RENAME { Map<ColumnIdentifier, ColumnIdentifier> renames = new HashMap<ColumnIdentifier, ColumnIdentifier>(); } - id1=ident K_TO toId1=ident { renames.put(id1, toId1); } - ( K_AND idn=ident K_TO toIdn=ident { renames.put(idn, toIdn); } )* + id1=noncol_ident K_TO toId1=noncol_ident { renames.put(id1, toId1); } + ( K_AND idn=noncol_ident K_TO toIdn=noncol_ident { renames.put(idn, toIdn); } )* { $expr = AlterTypeStatement.renames(name, renames); } ) ; @@ -1112,8 +1112,15 @@ cident returns [ColumnIdentifier.Raw id] | k=unreserved_keyword { $id = new ColumnIdentifier.Raw(k, false); } ; -// Identifiers that do not refer to columns or where the comparator is known to be text +// Column identifiers where the comparator is known to be text ident returns [ColumnIdentifier id] + : t=IDENT { $id = ColumnIdentifier.getInterned($t.text, false); } + | t=QUOTED_NAME { $id = ColumnIdentifier.getInterned($t.text, true); } + | k=unreserved_keyword { $id = ColumnIdentifier.getInterned(k, false); } + ; + +// Identifiers that do not refer to columns +noncol_ident returns [ColumnIdentifier id] : t=IDENT { $id = new ColumnIdentifier($t.text, false); } | t=QUOTED_NAME { $id = new ColumnIdentifier($t.text, true); } | k=unreserved_keyword { $id = new ColumnIdentifier(k, false); } @@ -1136,7 +1143,7 @@ columnFamilyName returns [CFName name] ; userTypeName returns [UTName name] - : (ks=ident '.')? ut=non_type_ident { return new UTName(ks, ut); } + : (ks=noncol_ident '.')? ut=non_type_ident { return new UTName(ks, ut); } ; userOrRoleName returns [RoleName name] @@ -1211,7 +1218,7 @@ usertypeLiteral returns [UserTypes.Literal ut] @init{ Map<ColumnIdentifier, Term.Raw> m = new HashMap<ColumnIdentifier, Term.Raw>(); } @after{ $ut = new UserTypes.Literal(m); } // We don't allow empty literals because that conflicts with sets/maps and is currently useless since we don't allow empty user types - : '{' k1=ident ':' v1=term { m.put(k1, v1); } ( ',' kn=ident ':' vn=term { m.put(kn, vn); } )* '}' + : '{' k1=noncol_ident ':' v1=term { m.put(k1, v1); } ( ',' kn=noncol_ident ':' vn=term { m.put(kn, vn); } )* '}' ; tupleLiteral returns [Tuples.Literal tt] @@ -1226,14 +1233,14 @@ value returns [Term.Raw value] | u=usertypeLiteral { $value = u; } | t=tupleLiteral { $value = t; } | K_NULL { $value = Constants.NULL_LITERAL; } - | ':' id=ident { $value = newBindVariables(id); } + | ':' id=noncol_ident { $value = newBindVariables(id); } | QMARK { $value = newBindVariables(null); } ; intValue returns [Term.Raw value] : | t=INTEGER { $value = Constants.Literal.integer($t.text); } - | ':' id=ident { $value = newBindVariables(id); } + | ':' id=noncol_ident { $value = newBindVariables(id); } | QMARK { $value = newBindVariables(null); } ; @@ -1334,8 +1341,8 @@ properties[PropertyDefinitions props] ; property[PropertyDefinitions props] - : k=ident '=' simple=propertyValue { try { $props.addProperty(k.toString(), simple); } catch (SyntaxException e) { addRecognitionError(e.getMessage()); } } - | k=ident '=' map=mapLiteral { try { $props.addProperty(k.toString(), convertPropertyMap(map)); } catch (SyntaxException e) { addRecognitionError(e.getMessage()); } } + : k=noncol_ident '=' simple=propertyValue { try { $props.addProperty(k.toString(), simple); } catch (SyntaxException e) { addRecognitionError(e.getMessage()); } } + | k=noncol_ident '=' map=mapLiteral { try { $props.addProperty(k.toString(), convertPropertyMap(map)); } catch (SyntaxException e) { addRecognitionError(e.getMessage()); } } ; propertyValue returns [String str] @@ -1388,7 +1395,7 @@ relation[List<Relation> clauses] inMarker returns [AbstractMarker.INRaw marker] : QMARK { $marker = newINBindVariables(null); } - | ':' name=ident { $marker = newINBindVariables(name); } + | ':' name=noncol_ident { $marker = newINBindVariables(name); } ; tupleOfIdentifiers returns [List<ColumnIdentifier.Raw> ids] @@ -1408,7 +1415,7 @@ tupleOfTupleLiterals returns [List<Tuples.Literal> literals] markerForTuple returns [Tuples.Raw marker] : QMARK { $marker = newTupleBindVariables(null); } - | ':' name=ident { $marker = newTupleBindVariables(name); } + | ':' name=noncol_ident { $marker = newTupleBindVariables(name); } ; tupleOfMarkersForTuples returns [List<Tuples.Raw> markers] @@ -1418,7 +1425,7 @@ tupleOfMarkersForTuples returns [List<Tuples.Raw> markers] inMarkerForTuple returns [Tuples.INRaw marker] : QMARK { $marker = newTupleINBindVariables(null); } - | ':' name=ident { $marker = newTupleINBindVariables(name); } + | ':' name=noncol_ident { $marker = newTupleINBindVariables(name); } ; comparatorType returns [CQL3Type.Raw t] http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/Lists.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Lists.java b/src/java/org/apache/cassandra/cql3/Lists.java index da8c48a..5da2b37 100644 --- a/src/java/org/apache/cassandra/cql3/Lists.java +++ b/src/java/org/apache/cassandra/cql3/Lists.java @@ -21,15 +21,16 @@ import static org.apache.cassandra.cql3.Constants.UNSET_VALUE; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicReference; +import com.google.common.collect.Iterators; + import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.Cell; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.composites.Composite; +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.db.marshal.ListType; import org.apache.cassandra.exceptions.InvalidRequestException; @@ -299,20 +300,37 @@ public abstract class Lists super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { Term.Terminal value = t.bind(params.options); - if (column.type.isMultiCell() && value != UNSET_VALUE) - { - // delete + append - CellName name = cf.getComparator().create(prefix, column); - cf.addAtom(params.makeTombstoneForOverwrite(name.slice())); - } - if (value != UNSET_VALUE) - Appender.doAppend(cf, prefix, column, params, value); + if (value == UNSET_VALUE) + return; + + // delete + append + if (column.type.isMultiCell()) + params.setComplexDeletionTimeForOverwrite(column, writer); + Appender.doAppend(value, clustering, writer, column, params); } } + private static int existingSize(Row row, ColumnDefinition column) + { + if (row == null) + return 0; + + Iterator<Cell> cells = row.getCells(column); + return cells == null ? 0 : Iterators.size(cells); + } + + private static Cell existingElement(Row row, ColumnDefinition column, int idx) + { + assert row != null; + Iterator<Cell> cells = row.getCells(column); + assert cells != null; + + return Iterators.get(cells, idx); + } + public static class SetterByIndex extends Operation { private final Term idx; @@ -336,7 +354,7 @@ public abstract class Lists idx.collectMarkerSpecification(boundNames); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { // we should not get here for frozen lists assert column.type.isMultiCell() : "Attempted to set an individual element on a frozen list"; @@ -349,17 +367,18 @@ public abstract class Lists if (index == ByteBufferUtil.UNSET_BYTE_BUFFER) throw new InvalidRequestException("Invalid unset value for list index"); - List<Cell> existingList = params.getPrefetchedList(rowKey, column.name); + Row existingRow = params.getPrefetchedRow(partitionKey, clustering); + int existingSize = existingSize(existingRow, column); int idx = ByteBufferUtil.toInt(index); - if (existingList == null || existingList.size() == 0) + if (existingSize == 0) throw new InvalidRequestException("Attempted to set an element on a list which is null"); - if (idx < 0 || idx >= existingList.size()) - throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingList.size())); + if (idx < 0 || idx >= existingSize) + throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingSize)); - CellName elementName = existingList.get(idx).name(); + CellPath elementPath = existingElement(existingRow, column, idx).path(); if (value == null) { - cf.addColumn(params.makeTombstone(elementName)); + params.addTombstone(column, writer); } else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) { @@ -369,7 +388,7 @@ public abstract class Lists FBUtilities.MAX_UNSIGNED_SHORT, value.remaining())); - cf.addColumn(params.makeColumn(elementName, value)); + params.addCell(clustering, column, writer, elementPath, value); } } } @@ -381,15 +400,14 @@ public abstract class Lists super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to append to a frozen list"; Term.Terminal value = t.bind(params.options); - if (value != UNSET_VALUE) - doAppend(cf, prefix, column, params, value); + doAppend(value, clustering, writer, column, params); } - static void doAppend(ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params, Term.Terminal value) throws InvalidRequestException + static void doAppend(Term.Terminal value, Clustering clustering, Row.Writer writer, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException { if (column.type.isMultiCell()) { @@ -401,17 +419,16 @@ public abstract class Lists for (ByteBuffer buffer : ((Value) value).elements) { ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes()); - cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), buffer)); + params.addCell(clustering, column, writer, CellPath.create(uuid), buffer); } } else { // for frozen lists, we're overwriting the whole cell value - CellName name = cf.getComparator().create(prefix, column); if (value == null) - cf.addAtom(params.makeTombstone(name)); + params.addTombstone(column, writer); else - cf.addColumn(params.makeColumn(name, value.get(Server.CURRENT_VERSION))); + params.addCell(clustering, column, writer, value.get(Server.CURRENT_VERSION)); } } } @@ -423,7 +440,7 @@ public abstract class Lists super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to prepend to a frozen list"; Term.Terminal value = t.bind(params.options); @@ -437,7 +454,7 @@ public abstract class Lists { PrecisionTime pt = PrecisionTime.getNext(time); ByteBuffer uuid = ByteBuffer.wrap(UUIDGen.getTimeUUIDBytes(pt.millis, pt.nanos)); - cf.addColumn(params.makeColumn(cf.getComparator().create(prefix, column, uuid), toAdd.get(i))); + params.addCell(clustering, column, writer, CellPath.create(uuid), toAdd.get(i)); } } } @@ -455,30 +472,28 @@ public abstract class Lists return true; } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to delete from a frozen list"; - List<Cell> existingList = params.getPrefetchedList(rowKey, column.name); + // We want to call bind before possibly returning to reject queries where the value provided is not a list. Term.Terminal value = t.bind(params.options); - if (existingList == null) - throw new InvalidRequestException("Attempted to delete an element from a list which is null"); - if (existingList.isEmpty()) - return; - - if (value == null || value == UNSET_VALUE) + Row existingRow = params.getPrefetchedRow(partitionKey, clustering); + Iterator<Cell> cells = existingRow == null ? null : existingRow.getCells(column); + if (value == null || value == UNSET_VALUE || cells == null) return; // Note: below, we will call 'contains' on this toDiscard list for each element of existingList. // Meaning that if toDiscard is big, converting it to a HashSet might be more efficient. However, // the read-before-write this operation requires limits its usefulness on big lists, so in practice // toDiscard will be small and keeping a list will be more efficient. - List<ByteBuffer> toDiscard = ((Value) value).elements; - for (Cell cell : existingList) + List<ByteBuffer> toDiscard = ((Value)value).elements; + while (cells.hasNext()) { + Cell cell = cells.next(); if (toDiscard.contains(cell.value())) - cf.addColumn(params.makeTombstone(cell.name())); + params.addTombstone(column, writer, cell.path()); } } } @@ -496,7 +511,7 @@ public abstract class Lists return true; } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to delete an item by index from a frozen list"; Term.Terminal index = t.bind(params.options); @@ -505,15 +520,15 @@ public abstract class Lists if (index == Constants.UNSET_VALUE) return; - List<Cell> existingList = params.getPrefetchedList(rowKey, column.name); + Row existingRow = params.getPrefetchedRow(partitionKey, clustering); + int existingSize = existingSize(existingRow, column); int idx = ByteBufferUtil.toInt(index.get(params.options.getProtocolVersion())); - if (existingList == null || existingList.size() == 0) + if (existingSize == 0) throw new InvalidRequestException("Attempted to delete an element from a list which is null"); - if (idx < 0 || idx >= existingList.size()) - throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingList.size())); + if (idx < 0 || idx >= existingSize) + throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingSize)); - CellName elementName = existingList.get(idx).name(); - cf.addColumn(params.makeTombstone(elementName)); + params.addTombstone(column, writer, existingElement(existingRow, column, idx).path()); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/Maps.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Maps.java b/src/java/org/apache/cassandra/cql3/Maps.java index 5bb3a48..2644108 100644 --- a/src/java/org/apache/cassandra/cql3/Maps.java +++ b/src/java/org/apache/cassandra/cql3/Maps.java @@ -26,9 +26,9 @@ import com.google.common.collect.Iterables; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.composites.Composite; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.DecoratedKey; +import org.apache.cassandra.db.rows.*; import org.apache.cassandra.db.marshal.MapType; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.serializers.CollectionSerializer; @@ -290,17 +290,16 @@ public abstract class Maps super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { Term.Terminal value = t.bind(params.options); - if (column.type.isMultiCell() && value != UNSET_VALUE) - { - // delete + put - CellName name = cf.getComparator().create(prefix, column); - cf.addAtom(params.makeTombstoneForOverwrite(name.slice())); - } - if (value != UNSET_VALUE) - Putter.doPut(cf, prefix, column, params, value); + if (value == UNSET_VALUE) + return; + + // delete + put + if (column.type.isMultiCell()) + params.setComplexDeletionTimeForOverwrite(column, writer); + Putter.doPut(value, clustering, writer, column, params); } } @@ -321,7 +320,7 @@ public abstract class Maps k.collectMarkerSpecification(boundNames); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to set a value for a single key on a frozen map"; ByteBuffer key = k.bindAndGet(params.options); @@ -331,11 +330,11 @@ public abstract class Maps if (key == ByteBufferUtil.UNSET_BYTE_BUFFER) throw new InvalidRequestException("Invalid unset map key"); - CellName cellName = cf.getComparator().create(prefix, column, key); + CellPath path = CellPath.create(key); if (value == null) { - cf.addColumn(params.makeTombstone(cellName)); + params.addTombstone(column, writer, path); } else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) { @@ -345,7 +344,7 @@ public abstract class Maps FBUtilities.MAX_UNSIGNED_SHORT, value.remaining())); - cf.addColumn(params.makeColumn(cellName, value)); + params.addCell(clustering, column, writer, path, value); } } } @@ -357,15 +356,15 @@ public abstract class Maps super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to add items to a frozen map"; Term.Terminal value = t.bind(params.options); if (value != UNSET_VALUE) - doPut(cf, prefix, column, params, value); + doPut(value, clustering, writer, column, params); } - static void doPut(ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params, Term.Terminal value) throws InvalidRequestException + static void doPut(Term.Terminal value, Clustering clustering, Row.Writer writer, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException { if (column.type.isMultiCell()) { @@ -374,19 +373,15 @@ public abstract class Maps Map<ByteBuffer, ByteBuffer> elements = ((Value) value).map; for (Map.Entry<ByteBuffer, ByteBuffer> entry : elements.entrySet()) - { - CellName cellName = cf.getComparator().create(prefix, column, entry.getKey()); - cf.addColumn(params.makeColumn(cellName, entry.getValue())); - } + params.addCell(clustering, column, writer, CellPath.create(entry.getKey()), entry.getValue()); } else { // for frozen maps, we're overwriting the whole cell - CellName cellName = cf.getComparator().create(prefix, column); if (value == null) - cf.addAtom(params.makeTombstone(cellName)); + params.addTombstone(column, writer); else - cf.addColumn(params.makeColumn(cellName, value.get(Server.CURRENT_VERSION))); + params.addCell(clustering, column, writer, value.get(Server.CURRENT_VERSION)); } } } @@ -398,7 +393,7 @@ public abstract class Maps super(column, k); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to delete a single key in a frozen map"; Term.Terminal key = t.bind(params.options); @@ -407,8 +402,7 @@ public abstract class Maps if (key == Constants.UNSET_VALUE) throw new InvalidRequestException("Invalid unset map key"); - CellName cellName = cf.getComparator().create(prefix, column, key.get(params.options.getProtocolVersion())); - cf.addColumn(params.makeTombstone(cellName)); + params.addTombstone(column, writer, CellPath.create(key.get(params.options.getProtocolVersion()))); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java b/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java index b54bdd0..7735c57 100644 --- a/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java +++ b/src/java/org/apache/cassandra/cql3/MultiColumnRelation.java @@ -131,7 +131,7 @@ public class MultiColumnRelation extends Relation { List<ColumnDefinition> receivers = receivers(cfm); Term term = toTerm(receivers, getValue(), cfm.ksName, boundNames); - return new MultiColumnRestriction.EQ(receivers, term); + return new MultiColumnRestriction.EQRestriction(receivers, term); } @Override @@ -143,9 +143,9 @@ public class MultiColumnRelation extends Relation if (terms == null) { Term term = toTerm(receivers, getValue(), cfm.ksName, boundNames); - return new MultiColumnRestriction.InWithMarker(receivers, (AbstractMarker) term); + return new MultiColumnRestriction.InRestrictionWithMarker(receivers, (AbstractMarker) term); } - return new MultiColumnRestriction.InWithValues(receivers, terms); + return new MultiColumnRestriction.InRestrictionWithValues(receivers, terms); } @Override @@ -156,7 +156,7 @@ public class MultiColumnRelation extends Relation { List<ColumnDefinition> receivers = receivers(cfm); Term term = toTerm(receivers(cfm), getValue(), cfm.ksName, boundNames); - return new MultiColumnRestriction.Slice(receivers, bound, inclusive, term); + return new MultiColumnRestriction.SliceRestriction(receivers, bound, inclusive, term); } @Override @@ -214,4 +214,4 @@ public class MultiColumnRelation extends Relation .append(valuesOrMarker) .toString(); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/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 index 4701a96..5e72e7f 100644 --- a/src/java/org/apache/cassandra/cql3/Operation.java +++ b/src/java/org/apache/cassandra/cql3/Operation.java @@ -17,13 +17,13 @@ */ package org.apache.cassandra.cql3; -import java.nio.ByteBuffer; import java.util.Collections; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.composites.Composite; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.DecoratedKey; +import org.apache.cassandra.db.rows.Row; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.exceptions.InvalidRequestException; @@ -86,12 +86,12 @@ public abstract class Operation /** * Execute the operation. * - * @param rowKey row key for the update. - * @param cf the column family to which to add the updates generated by this operation. - * @param prefix the prefix that identify the CQL3 row this operation applies to. + * @param partitionKey partition key for the update. + * @param clustering the clustering for the row on which the operation applies + * @param writer the row update to which to add the updates generated by this operation. * @param params parameters of the update. */ - public abstract void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException; + public abstract void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException; /** * A parsed raw UPDATE operation. http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/Operator.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Operator.java b/src/java/org/apache/cassandra/cql3/Operator.java index 86bcbd3..5ae9885 100644 --- a/src/java/org/apache/cassandra/cql3/Operator.java +++ b/src/java/org/apache/cassandra/cql3/Operator.java @@ -20,6 +20,9 @@ package org.apache.cassandra.cql3; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.cassandra.db.marshal.AbstractType; public enum Operator { @@ -38,12 +41,6 @@ public enum Operator { return "<"; } - - @Override - public Operator reverse() - { - return GT; - } }, LTE(3) { @@ -52,12 +49,6 @@ public enum Operator { return "<="; } - - @Override - public Operator reverse() - { - return GTE; - } }, GTE(1) { @@ -66,12 +57,6 @@ public enum Operator { return ">="; } - - @Override - public Operator reverse() - { - return LTE; - } }, GT(2) { @@ -80,12 +65,6 @@ public enum Operator { return ">"; } - - @Override - public Operator reverse() - { - return LT; - } }, IN(7) { @@ -152,19 +131,42 @@ public enum Operator throw new IOException(String.format("Cannot resolve Relation.Type from binary representation: %s", b)); } - @Override - public String toString() - { - return this.name(); - } - /** - * Returns the reverse operator if this one. + * Whether 2 values satisfy this operator (given the type they should be compared with). * - * @return the reverse operator of this one. + * @throws AssertionError for IN, CONTAINS and CONTAINS_KEY as this doesn't make sense for this function. */ - public Operator reverse() + public boolean isSatisfiedBy(AbstractType<?> type, ByteBuffer leftOperand, ByteBuffer rightOperand) { - return this; + int comparison = type.compareForCQL(leftOperand, rightOperand); + switch (this) + { + case EQ: + return comparison == 0; + case LT: + return comparison < 0; + case LTE: + return comparison <= 0; + case GT: + return comparison > 0; + case GTE: + return comparison >= 0; + case NEQ: + return comparison != 0; + default: + // we shouldn't get IN, CONTAINS, or CONTAINS KEY here + throw new AssertionError(); + } + } + + public int serializedSize() + { + return 4; + } + + @Override + public String toString() + { + return this.name(); } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/QueryProcessor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java index a071eb9..afe2269 100644 --- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java +++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java @@ -41,13 +41,14 @@ import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.Functions; import org.apache.cassandra.cql3.statements.*; import org.apache.cassandra.db.*; -import org.apache.cassandra.db.composites.*; +import org.apache.cassandra.db.rows.RowIterator; +import org.apache.cassandra.db.partitions.PartitionIterator; +import org.apache.cassandra.db.partitions.PartitionIterators; import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.exceptions.*; import org.apache.cassandra.metrics.CQLMetrics; import org.apache.cassandra.service.*; import org.apache.cassandra.service.pager.QueryPager; -import org.apache.cassandra.service.pager.QueryPagers; import org.apache.cassandra.thrift.ThriftClientState; import org.apache.cassandra.tracing.Tracing; import org.apache.cassandra.transport.messages.ResultMessage; @@ -192,28 +193,6 @@ public class QueryProcessor implements QueryHandler } } - public static void validateCellNames(Iterable<CellName> cellNames, CellNameType type) throws InvalidRequestException - { - for (CellName name : cellNames) - validateCellName(name, type); - } - - public static void validateCellName(CellName name, CellNameType type) throws InvalidRequestException - { - validateComposite(name, type); - if (name.isEmpty()) - throw new InvalidRequestException("Invalid empty value for clustering column of COMPACT TABLE"); - } - - public static void validateComposite(Composite name, CType type) throws InvalidRequestException - { - long serializedSize = type.serializer().serializedSize(name, TypeSizes.NATIVE); - if (serializedSize > Cell.MAX_NAME_LENGTH) - throw new InvalidRequestException(String.format("The sum of all clustering columns is too long (%s > %s)", - serializedSize, - Cell.MAX_NAME_LENGTH)); - } - public ResultMessage processStatement(CQLStatement statement, QueryState queryState, QueryOptions options) throws RequestExecutionException, RequestValidationException { @@ -277,6 +256,11 @@ public class QueryProcessor implements QueryHandler private static QueryOptions makeInternalOptions(ParsedStatement.Prepared prepared, Object[] values) { + return makeInternalOptions(prepared, values, ConsistencyLevel.ONE); + } + + private static QueryOptions makeInternalOptions(ParsedStatement.Prepared prepared, Object[] values, ConsistencyLevel cl) + { if (prepared.boundNames.size() != values.length) throw new IllegalArgumentException(String.format("Invalid number of values. Expecting %d but got %d", prepared.boundNames.size(), values.length)); @@ -287,7 +271,7 @@ public class QueryProcessor implements QueryHandler AbstractType type = prepared.boundNames.get(i).type; boundValues.add(value instanceof ByteBuffer || value == null ? (ByteBuffer)value : type.decompose(value)); } - return QueryOptions.forInternalCalls(boundValues); + return QueryOptions.forInternalCalls(cl, boundValues); } private static ParsedStatement.Prepared prepareInternal(String query) throws RequestValidationException @@ -313,6 +297,24 @@ public class QueryProcessor implements QueryHandler return null; } + public static UntypedResultSet execute(String query, ConsistencyLevel cl, QueryState state, Object... values) + throws RequestExecutionException + { + try + { + ParsedStatement.Prepared prepared = prepareInternal(query); + ResultMessage result = prepared.statement.execute(state, makeInternalOptions(prepared, values)); + if (result instanceof ResultMessage.Rows) + return UntypedResultSet.create(((ResultMessage.Rows)result).result); + else + return null; + } + catch (RequestValidationException e) + { + throw new RuntimeException("Error validating " + query, e); + } + } + public static UntypedResultSet executeInternalWithPaging(String query, int pageSize, Object... values) { ParsedStatement.Prepared prepared = prepareInternal(query); @@ -320,7 +322,7 @@ public class QueryProcessor implements QueryHandler throw new IllegalArgumentException("Only SELECTs can be paged"); SelectStatement select = (SelectStatement)prepared.statement; - QueryPager pager = QueryPagers.localPager(select.getPageableCommand(makeInternalOptions(prepared, values))); + QueryPager pager = select.getQuery(makeInternalOptions(prepared, values), FBUtilities.nowInSeconds()).getPager(null); return UntypedResultSet.create(select, pager, pageSize); } @@ -339,16 +341,19 @@ public class QueryProcessor implements QueryHandler return null; } - public static UntypedResultSet resultify(String query, Row row) + public static UntypedResultSet resultify(String query, RowIterator partition) { - return resultify(query, Collections.singletonList(row)); + return resultify(query, PartitionIterators.singletonIterator(partition)); } - public static UntypedResultSet resultify(String query, List<Row> rows) + public static UntypedResultSet resultify(String query, PartitionIterator partitions) { - SelectStatement ss = (SelectStatement) getStatement(query, null).statement; - ResultSet cqlRows = ss.process(rows); - return UntypedResultSet.create(cqlRows); + try (PartitionIterator iter = partitions) + { + SelectStatement ss = (SelectStatement) getStatement(query, null).statement; + ResultSet cqlRows = ss.process(iter, FBUtilities.nowInSeconds()); + return UntypedResultSet.create(cqlRows); + } } public ResultMessage.Prepared prepare(String query, http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/Sets.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Sets.java b/src/java/org/apache/cassandra/cql3/Sets.java index 093f1dc..c03005d 100644 --- a/src/java/org/apache/cassandra/cql3/Sets.java +++ b/src/java/org/apache/cassandra/cql3/Sets.java @@ -26,12 +26,10 @@ import com.google.common.base.Joiner; import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.functions.Function; -import org.apache.cassandra.db.ColumnFamily; -import org.apache.cassandra.db.composites.CellName; -import org.apache.cassandra.db.composites.Composite; -import org.apache.cassandra.db.marshal.AbstractType; -import org.apache.cassandra.db.marshal.MapType; -import org.apache.cassandra.db.marshal.SetType; +import org.apache.cassandra.db.Clustering; +import org.apache.cassandra.db.DecoratedKey; +import org.apache.cassandra.db.rows.*; +import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.serializers.CollectionSerializer; import org.apache.cassandra.serializers.MarshalException; @@ -259,17 +257,16 @@ public abstract class Sets super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { Term.Terminal value = t.bind(params.options); - if (column.type.isMultiCell() && value != UNSET_VALUE) - { - // delete + add - CellName name = cf.getComparator().create(prefix, column); - cf.addAtom(params.makeTombstoneForOverwrite(name.slice())); - } - if (value != UNSET_VALUE) - Adder.doAdd(cf, prefix, column, params, value); + if (value == UNSET_VALUE) + return; + + // delete + add + if (column.type.isMultiCell()) + params.setComplexDeletionTimeForOverwrite(column, writer); + Adder.doAdd(value, clustering, writer, column, params); } } @@ -280,15 +277,15 @@ public abstract class Sets super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to add items to a frozen set"; Term.Terminal value = t.bind(params.options); if (value != UNSET_VALUE) - doAdd(cf, prefix, column, params, value); + doAdd(value, clustering, writer, column, params); } - static void doAdd(ColumnFamily cf, Composite prefix, ColumnDefinition column, UpdateParameters params, Term.Terminal value) throws InvalidRequestException + static void doAdd(Term.Terminal value, Clustering clustering, Row.Writer writer, ColumnDefinition column, UpdateParameters params) throws InvalidRequestException { if (column.type.isMultiCell()) { @@ -299,18 +296,17 @@ public abstract class Sets { if (bb == ByteBufferUtil.UNSET_BYTE_BUFFER) continue; - CellName cellName = cf.getComparator().create(prefix, column, bb); - cf.addColumn(params.makeColumn(cellName, ByteBufferUtil.EMPTY_BYTE_BUFFER)); + + params.addCell(clustering, column, writer, CellPath.create(bb), ByteBufferUtil.EMPTY_BYTE_BUFFER); } } else { // for frozen sets, we're overwriting the whole cell - CellName cellName = cf.getComparator().create(prefix, column); if (value == null) - cf.addAtom(params.makeTombstone(cellName)); + params.addTombstone(column, writer); else - cf.addColumn(params.makeColumn(cellName, value.get(Server.CURRENT_VERSION))); + params.addCell(clustering, column, writer, value.get(Server.CURRENT_VERSION)); } } } @@ -323,7 +319,7 @@ public abstract class Sets super(column, t); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to remove items from a frozen set"; @@ -337,7 +333,7 @@ public abstract class Sets : Collections.singleton(value.get(params.options.getProtocolVersion())); for (ByteBuffer bb : toDiscard) - cf.addColumn(params.makeTombstone(cf.getComparator().create(prefix, column, bb))); + params.addTombstone(column, writer, CellPath.create(bb)); } } @@ -348,15 +344,14 @@ public abstract class Sets super(column, k); } - public void execute(ByteBuffer rowKey, ColumnFamily cf, Composite prefix, UpdateParameters params) throws InvalidRequestException + public void execute(DecoratedKey partitionKey, Clustering clustering, Row.Writer writer, UpdateParameters params) throws InvalidRequestException { assert column.type.isMultiCell() : "Attempted to delete a single element in a frozen set"; Term.Terminal elt = t.bind(params.options); if (elt == null) throw new InvalidRequestException("Invalid null set element"); - CellName cellName = cf.getComparator().create(prefix, column, elt.get(params.options.getProtocolVersion())); - cf.addColumn(params.makeTombstone(cellName)); + params.addTombstone(column, writer, CellPath.create(elt.get(params.options.getProtocolVersion()))); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java index c4c48aa..885a2e2 100644 --- a/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java +++ b/src/java/org/apache/cassandra/cql3/SingleColumnRelation.java @@ -140,13 +140,13 @@ public final class SingleColumnRelation extends Relation ColumnDefinition columnDef = toColumnDefinition(cfm, entity); if (mapKey == null) { - Term term = toTerm(toReceivers(columnDef), value, cfm.ksName, boundNames); - return new SingleColumnRestriction.EQ(columnDef, term); + Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames); + return new SingleColumnRestriction.EQRestriction(columnDef, term); } - List<? extends ColumnSpecification> receivers = toReceivers(columnDef); + List<? extends ColumnSpecification> receivers = toReceivers(columnDef, cfm.isDense()); Term entryKey = toTerm(Collections.singletonList(receivers.get(0)), mapKey, cfm.ksName, boundNames); Term entryValue = toTerm(Collections.singletonList(receivers.get(1)), value, cfm.ksName, boundNames); - return new SingleColumnRestriction.Contains(columnDef, entryKey, entryValue); + return new SingleColumnRestriction.ContainsRestriction(columnDef, entryKey, entryValue); } @Override @@ -154,14 +154,14 @@ public final class SingleColumnRelation extends Relation VariableSpecifications boundNames) throws InvalidRequestException { ColumnDefinition columnDef = cfm.getColumnDefinition(getEntity().prepare(cfm)); - List<? extends ColumnSpecification> receivers = toReceivers(columnDef); + List<? extends ColumnSpecification> receivers = toReceivers(columnDef, cfm.isDense()); List<Term> terms = toTerms(receivers, inValues, cfm.ksName, boundNames); if (terms == null) { Term term = toTerm(receivers, value, cfm.ksName, boundNames); - return new SingleColumnRestriction.InWithMarker(columnDef, (Lists.Marker) term); + return new SingleColumnRestriction.InRestrictionWithMarker(columnDef, (Lists.Marker) term); } - return new SingleColumnRestriction.InWithValues(columnDef, terms); + return new SingleColumnRestriction.InRestrictionWithValues(columnDef, terms); } @Override @@ -171,8 +171,8 @@ public final class SingleColumnRelation extends Relation boolean inclusive) throws InvalidRequestException { ColumnDefinition columnDef = toColumnDefinition(cfm, entity); - Term term = toTerm(toReceivers(columnDef), value, cfm.ksName, boundNames); - return new SingleColumnRestriction.Slice(columnDef, bound, inclusive, term); + Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames); + return new SingleColumnRestriction.SliceRestriction(columnDef, bound, inclusive, term); } @Override @@ -181,22 +181,23 @@ public final class SingleColumnRelation extends Relation boolean isKey) throws InvalidRequestException { ColumnDefinition columnDef = toColumnDefinition(cfm, entity); - Term term = toTerm(toReceivers(columnDef), value, cfm.ksName, boundNames); - return new SingleColumnRestriction.Contains(columnDef, term, isKey); + Term term = toTerm(toReceivers(columnDef, cfm.isDense()), value, cfm.ksName, boundNames); + return new SingleColumnRestriction.ContainsRestriction(columnDef, term, isKey); } /** * Returns the receivers for this relation. * @param columnDef the column definition + * @param isDense whether the table is a dense one * * @return the receivers for the specified relation. * @throws InvalidRequestException if the relation is invalid */ - private List<? extends ColumnSpecification> toReceivers(ColumnDefinition columnDef) throws InvalidRequestException + private List<? extends ColumnSpecification> toReceivers(ColumnDefinition columnDef, boolean isDense) throws InvalidRequestException { ColumnSpecification receiver = columnDef; - checkFalse(columnDef.isCompactValue(), + checkFalse(!columnDef.isPrimaryKeyColumn() && isDense, "Predicates on the non-primary-key column (%s) of a COMPACT table are not yet supported", columnDef.name); http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/TokenRelation.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/TokenRelation.java b/src/java/org/apache/cassandra/cql3/TokenRelation.java index 5896fae..14bd5e0 100644 --- a/src/java/org/apache/cassandra/cql3/TokenRelation.java +++ b/src/java/org/apache/cassandra/cql3/TokenRelation.java @@ -69,7 +69,7 @@ public final class TokenRelation extends Relation { List<ColumnDefinition> columnDefs = getColumnDefinitions(cfm); Term term = toTerm(toReceivers(cfm, columnDefs), value, cfm.ksName, boundNames); - return new TokenRestriction.EQ(cfm.getKeyValidatorAsCType(), columnDefs, term); + return new TokenRestriction.EQRestriction(cfm.getKeyValidatorAsClusteringComparator(), columnDefs, term); } @Override @@ -86,7 +86,7 @@ public final class TokenRelation extends Relation { List<ColumnDefinition> columnDefs = getColumnDefinitions(cfm); Term term = toTerm(toReceivers(cfm, columnDefs), value, cfm.ksName, boundNames); - return new TokenRestriction.Slice(cfm.getKeyValidatorAsCType(), columnDefs, bound, inclusive, term); + return new TokenRestriction.SliceRestriction(cfm.getKeyValidatorAsClusteringComparator(), columnDefs, bound, inclusive, term); } @Override http://git-wip-us.apache.org/repos/asf/cassandra/blob/a991b648/src/java/org/apache/cassandra/cql3/UntypedResultSet.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java index 49e0d86..f481f5c 100644 --- a/src/java/org/apache/cassandra/cql3/UntypedResultSet.java +++ b/src/java/org/apache/cassandra/cql3/UntypedResultSet.java @@ -24,9 +24,16 @@ import java.util.*; import com.google.common.collect.AbstractIterator; +import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.config.ColumnDefinition; import org.apache.cassandra.cql3.statements.SelectStatement; +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.rows.*; +import org.apache.cassandra.db.partitions.PartitionIterator; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.service.pager.QueryPager; +import org.apache.cassandra.transport.Server; +import org.apache.cassandra.utils.FBUtilities; /** a utility for doing internal cql-based queries */ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row> @@ -174,11 +181,16 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row> protected Row computeNext() { + int nowInSec = FBUtilities.nowInSeconds(); while (currentPage == null || !currentPage.hasNext()) { if (pager.isExhausted()) return endOfData(); - currentPage = select.process(pager.fetchPage(pageSize)).rows.iterator(); + + try (ReadOrderGroup orderGroup = pager.startOrderGroup(); PartitionIterator iter = pager.fetchPageInternal(pageSize, orderGroup)) + { + currentPage = select.process(iter, nowInSec).rows.iterator(); + } } return new Row(metadata, currentPage.next()); } @@ -208,6 +220,37 @@ public abstract class UntypedResultSet implements Iterable<UntypedResultSet.Row> data.put(names.get(i).name.toString(), columns.get(i)); } + public static Row fromInternalRow(CFMetaData metadata, DecoratedKey key, org.apache.cassandra.db.rows.Row row) + { + Map<String, ByteBuffer> data = new HashMap<>(); + + ByteBuffer[] keyComponents = SelectStatement.getComponents(metadata, key); + for (ColumnDefinition def : metadata.partitionKeyColumns()) + data.put(def.name.toString(), keyComponents[def.position()]); + + Clustering clustering = row.clustering(); + for (ColumnDefinition def : metadata.clusteringColumns()) + data.put(def.name.toString(), clustering.get(def.position())); + + for (ColumnDefinition def : metadata.partitionColumns()) + { + if (def.isComplex()) + { + Iterator<Cell> cells = row.getCells(def); + if (cells != null) + data.put(def.name.toString(), ((CollectionType)def.type).serializeForNativeProtocol(def, cells, Server.VERSION_3)); + } + else + { + Cell cell = row.getCell(def); + if (cell != null) + data.put(def.name.toString(), cell.value()); + } + } + + return new Row(data); + } + public boolean has(String column) { // Note that containsKey won't work because we may have null values
