You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sa...@apache.org on 2015/06/18 18:51:23 UTC
[07/12] cassandra git commit: Merge branch 'cassandra-2.0' into
cassandra-2.1
Merge branch 'cassandra-2.0' into cassandra-2.1
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0452e74f
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0452e74f
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0452e74f
Branch: refs/heads/trunk
Commit: 0452e74f59182aee515cc6920e35287def86c9fe
Parents: 9966419 f32cff8
Author: Sam Tunnicliffe <sa...@beobal.com>
Authored: Thu Jun 18 17:32:04 2015 +0100
Committer: Sam Tunnicliffe <sa...@beobal.com>
Committed: Thu Jun 18 17:34:27 2015 +0100
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../cassandra/cql3/ColumnSpecification.java | 22 ++
.../cql3/statements/SelectStatement.java | 44 +++-
.../cassandra/cql3/statements/Selection.java | 79 +++---
.../cql3/statements/SelectionColumnMapping.java | 107 ++++++++
.../cql3/statements/SelectionColumns.java | 18 ++
.../statements/SelectionColumnMappingTest.java | 252 +++++++++++++++++++
7 files changed, 492 insertions(+), 31 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 1d72c9a,a235528..899ea7c
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,6 -1,5 +1,7 @@@
-2.0.16:
+2.1.7
+ * Fix memory leak in Ref due to ConcurrentLinkedQueue.remove() behaviour (CASSANDRA-9549)
+Merged from 2.0
+ * Expose some internals of SelectStatement for inspection (CASSANDRA-9532)
* ArrivalWindow should use primitives (CASSANDRA-9496)
* Periodically submit background compaction tasks (CASSANDRA-9592)
* Set HAS_MORE_PAGES flag to false when PagingState is null (CASSANDRA-9571)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/ColumnSpecification.java
index d2e08f9,089a1c5..f5f921d
--- a/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
@@@ -33,4 -35,31 +35,24 @@@ public class ColumnSpecificatio
this.name = name;
this.type = type;
}
+
- @Override
- public String toString()
- {
- // Not fully conventional, but convenient (for error message to users in particular)
- return name.toString();
- }
-
+ public boolean equals(Object obj)
+ {
+ if (null == obj)
+ return false;
+
+ if(!(obj instanceof ColumnSpecification))
+ return false;
+
+ ColumnSpecification other = (ColumnSpecification)obj;
+ return Objects.equal(ksName, other.ksName)
+ && Objects.equal(cfName, other.cfName)
+ && Objects.equal(name, other.name)
+ && Objects.equal(type, other.type);
+ }
+
+ public int hashCode()
+ {
+ return Objects.hashCode(ksName, cfName, name, type);
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 51f4941,1c19760..d0566eb
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@@ -58,9 -60,12 +58,13 @@@ import org.slf4j.LoggerFactory
/**
* Encapsulates a completely parsed SELECT query, including the target
* column family, expression, result count, and ordering clause.
+ *
+ * A number of public methods here are only used internally. However,
+ * many of these are made accessible for the benefit of custom
+ * QueryHandler implementations, so before reducing their accessibility
+ * due consideration should be given.
*/
-public class SelectStatement implements CQLStatement, MeasurableForPreparedCache
+public class SelectStatement implements CQLStatement
{
private static final Logger logger = LoggerFactory.getLogger(SelectStatement.class);
@@@ -170,6 -168,20 +174,9 @@@
: selection.getResultMetadata();
}
- public long measureForPreparedCache(MemoryMeter meter)
- {
- return meter.measure(this)
- + meter.measureDeep(parameters)
- + meter.measureDeep(selection)
- + (limit == null ? 0 : meter.measureDeep(limit))
- + meter.measureDeep(keyRestrictions)
- + meter.measureDeep(columnRestrictions)
- + meter.measureDeep(metadataRestrictions)
- + meter.measureDeep(restrictedNames)
- + (sliceRestriction == null ? 0 : meter.measureDeep(sliceRestriction))
- + (orderingIndexes == null ? 0 : meter.measureDeep(orderingIndexes));
- }
-
++ /**
++ * May be used by custom QueryHandler implementations
++ */
public int getBoundTerms()
{
return boundTerms;
@@@ -367,9 -403,9 +382,12 @@@
: new RangeSliceCommand(keyspace(), columnFamily(), now, filter, keyBounds, expressions, limit, !parameters.isDistinct, false);
}
- private AbstractBounds<RowPosition> getKeyBounds(QueryOptions options) throws InvalidRequestException
- private AbstractBounds<RowPosition> getKeyBounds(CFDefinition cfDef, List<ByteBuffer> variables) throws InvalidRequestException
++ /**
++ * May be used by custom QueryHandler implementations
++ */
++ public AbstractBounds<RowPosition> getKeyBounds(QueryOptions options) throws InvalidRequestException
{
- IPartitioner<?> p = StorageService.getPartitioner();
+ IPartitioner p = StorageService.getPartitioner();
if (onToken)
{
@@@ -550,7 -591,10 +568,10 @@@
return new SliceQueryFilter(slices, isReversed, limit, toGroup);
}
- private int getLimit(QueryOptions options) throws InvalidRequestException
+ /**
+ * May be used by custom QueryHandler implementations
+ */
- public int getLimit(List<ByteBuffer> variables) throws InvalidRequestException
++ public int getLimit(QueryOptions options) throws InvalidRequestException
{
int l = Integer.MAX_VALUE;
if (limit != null)
@@@ -1024,21 -1064,29 +1045,24 @@@
{
Restriction.Slice slice = (Restriction.Slice)r;
assert slice.hasBound(b);
- return slice.bound(b, variables);
+ ByteBuffer val = slice.bound(b, options);
+ if (val == null)
+ throw new InvalidRequestException(String.format("Invalid null clustering key part %s", r));
+ return val;
}
- private List<ByteBuffer> getRequestedBound(CFDefinition cfDef,
- Bound b,
- List<ByteBuffer> variables) throws InvalidRequestException
+ private List<Composite> getRequestedBound(Bound b, QueryOptions options) throws InvalidRequestException
{
- assert isColumnRange(cfDef);
- return buildBound(b,
- new ArrayList<Name>(cfDef.clusteringColumns()),
- columnRestrictions,
- isReversed,
- cfDef,
- cfDef.getColumnNameBuilder(),
- variables);
+ assert isColumnRange();
+ return buildBound(b, cfm.clusteringColumns(), columnRestrictions, isReversed, cfm.comparator, options);
}
+ /**
+ * May be used by custom QueryHandler implementations
+ */
- public List<IndexExpression> getIndexExpressions(List<ByteBuffer> variables) throws InvalidRequestException
+ public List<IndexExpression> getValidatedIndexExpressions(QueryOptions options) throws InvalidRequestException
{
- if (!usesSecondaryIndexing || restrictedNames.isEmpty())
+ if (!usesSecondaryIndexing || restrictedColumns.isEmpty())
return Collections.emptyList();
List<IndexExpression> expressions = new ArrayList<IndexExpression>();
@@@ -1364,21 -1463,38 +1388,35 @@@
return true;
}
- private boolean hasClusteringColumnsRestriction()
+ /**
+ * May be used by custom QueryHandler implementations
+ */
- public boolean hasPartitionKeyRestriction()
++ public boolean hasClusteringColumnsRestriction()
{
- for (int i = 0; i < keyRestrictions.length; i++)
- if (keyRestrictions[i] != null)
+ for (int i = 0; i < columnRestrictions.length; i++)
+ if (columnRestrictions[i] != null)
return true;
return false;
}
+ /**
+ * May be used by custom QueryHandler implementations
+ */
- public boolean hasClusteringColumnsRestriction()
++ public boolean hasPartitionKeyRestriction()
+ {
- for (int i = 0; i < columnRestrictions.length; i++)
- if (columnRestrictions[i] != null)
++ for (int i = 0; i < keyRestrictions.length; i++)
++ if (keyRestrictions[i] != null)
+ return true;
+ return false;
+ }
+
- private void validateDistinctSelection(CFDefinition cfDef)
+ private void validateDistinctSelection()
throws InvalidRequestException
{
- Collection<CFDefinition.Name> requestedColumns = selection.getColumns();
- for (CFDefinition.Name name : requestedColumns)
- {
- if (name.kind != CFDefinition.Name.Kind.KEY_ALIAS && name.kind != CFDefinition.Name.Kind.STATIC)
- throw new InvalidRequestException(String.format(
- "SELECT DISTINCT queries must only request partition key columns and/or static columns (not %s)", name));
- }
+ Collection<ColumnDefinition> requestedColumns = selection.getColumns();
+ for (ColumnDefinition def : requestedColumns)
+ if (def.kind != ColumnDefinition.Kind.PARTITION_KEY && def.kind != ColumnDefinition.Kind.STATIC)
+ throw new InvalidRequestException(String.format("SELECT DISTINCT queries must only request partition key columns and/or static columns (not %s)", def.name));
// If it's a key range, we require that all partition key columns are selected so we don't have to bother with post-query grouping.
if (!isKeyRange)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/src/java/org/apache/cassandra/cql3/statements/Selection.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/Selection.java
index ff808bb,50a34bf..83cbfe8
--- a/src/java/org/apache/cassandra/cql3/statements/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Selection.java
@@@ -18,10 -18,9 +18,9 @@@
package org.apache.cassandra.cql3.statements;
import java.nio.ByteBuffer;
- import java.util.ArrayList;
- import java.util.List;
+ import java.util.*;
-import com.google.common.collect.*;
+import com.google.common.collect.Iterators;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.cql3.functions.Function;
@@@ -42,15 -37,15 +41,17 @@@ import org.apache.cassandra.utils.ByteB
public abstract class Selection
{
- private final List<CFDefinition.Name> columns;
- private final SelectionColumns columnMapping;
+ private final List<ColumnDefinition> columns;
++ private final SelectionColumnMapping columnMapping;
+ private final ResultSet.Metadata metadata;
private final boolean collectTimestamps;
private final boolean collectTTLs;
- protected Selection(List<ColumnDefinition> columns, List<ColumnSpecification> metadata, boolean collectTimestamps, boolean collectTTLs)
- protected Selection(List<CFDefinition.Name> columns, SelectionColumns columnMapping, boolean collectTimestamps, boolean collectTTLs)
++ protected Selection(List<ColumnDefinition> columns, SelectionColumnMapping columnMapping, boolean collectTimestamps, boolean collectTTLs)
{
this.columns = columns;
- this.metadata = new ResultSet.Metadata(metadata);
+ this.columnMapping = columnMapping;
++ this.metadata = new ResultSet.Metadata(columnMapping.getColumnSpecifications());
this.collectTimestamps = collectTimestamps;
this.collectTTLs = collectTTLs;
}
@@@ -106,74 -95,60 +107,80 @@@
return idx;
}
- private static Selector makeSelector(CFMetaData cfm, RawSelector raw, List<ColumnDefinition> defs, List<ColumnSpecification> metadata) throws InvalidRequestException
- private static Selector makeSelector(CFDefinition cfDef,
- RawSelector raw,
- List<CFDefinition.Name> names,
- SelectionColumnMapping columnMapping) throws InvalidRequestException
++ private static Selector makeSelector(CFMetaData cfm, RawSelector raw, List<ColumnDefinition> defs, SelectionColumnMapping columnMapping) throws InvalidRequestException
{
- Selectable selectable = raw.selectable.prepare(cfDef.cfm);
- return makeSelector(cfDef, selectable, raw.alias, names, columnMapping);
+ Selectable selectable = raw.selectable.prepare(cfm);
- return makeSelector(cfm, selectable, raw.alias, defs, metadata);
++ return makeSelector(cfm, selectable, raw.alias, defs, columnMapping);
}
- private static Selector makeSelector(CFMetaData cfm, Selectable selectable, ColumnIdentifier alias, List<ColumnDefinition> defs, List<ColumnSpecification> metadata) throws InvalidRequestException
- private static Selector makeSelector(CFDefinition cfDef,
- Selectable selectable,
- ColumnIdentifier alias,
- List<CFDefinition.Name> names,
- SelectionColumnMapping columnMapping) throws InvalidRequestException
++ private static Selector makeSelector(CFMetaData cfm, Selectable selectable, ColumnIdentifier alias, List<ColumnDefinition> defs, SelectionColumnMapping columnMapping) throws InvalidRequestException
{
if (selectable instanceof ColumnIdentifier)
{
- CFDefinition.Name name = cfDef.get((ColumnIdentifier) selectable);
- if (name == null)
+ ColumnDefinition def = cfm.getColumnDefinition((ColumnIdentifier)selectable);
+ if (def == null)
throw new InvalidRequestException(String.format("Undefined name %s in selection clause", selectable));
+
- if (metadata != null)
- metadata.add(alias == null ? def : makeAliasSpec(cfm, def.type, alias));
+ if (columnMapping != null)
- columnMapping.addMapping(alias == null ? name : makeAliasSpec(cfDef, name.type, alias), name);
- return new SimpleSelector(name.toString(), addAndGetIndex(name, names), name.type);
++ columnMapping.addMapping(alias == null ? def : makeAliasSpec(cfm, def.type, alias), def);
+ return new SimpleSelector(def.name.toString(), addAndGetIndex(def, defs), def.type);
}
else if (selectable instanceof Selectable.WritetimeOrTTL)
{
Selectable.WritetimeOrTTL tot = (Selectable.WritetimeOrTTL)selectable;
- CFDefinition.Name name = cfDef.get(tot.id);
- if (name == null)
+ ColumnDefinition def = cfm.getColumnDefinition(tot.id);
+ if (def == null)
throw new InvalidRequestException(String.format("Undefined name %s in selection clause", tot.id));
- if (name.isPrimaryKeyColumn())
- throw new InvalidRequestException(String.format("Cannot use selection function %s on PRIMARY KEY part %s", tot.isWritetime ? "writeTime" : "ttl", name));
- if (name.type.isCollection())
+ if (def.isPrimaryKeyColumn())
+ throw new InvalidRequestException(String.format("Cannot use selection function %s on PRIMARY KEY part %s", tot.isWritetime ? "writeTime" : "ttl", def.name));
+ if (def.type.isCollection())
throw new InvalidRequestException(String.format("Cannot use selection function %s on collections", tot.isWritetime ? "writeTime" : "ttl"));
+
- if (metadata != null)
- metadata.add(makeWritetimeOrTTLSpec(cfm, tot, alias));
+ if (columnMapping != null)
- columnMapping.addMapping(makeWritetimeOrTTLSpec(cfDef, tot, alias), name);
- return new WritetimeOrTTLSelector(name.toString(), addAndGetIndex(name, names), tot.isWritetime);
++ columnMapping.addMapping(makeWritetimeOrTTLSpec(cfm, tot, alias), def);
+ return new WritetimeOrTTLSelector(def.name.toString(), addAndGetIndex(def, defs), tot.isWritetime);
+ }
+ else if (selectable instanceof Selectable.WithFieldSelection)
+ {
+ Selectable.WithFieldSelection withField = (Selectable.WithFieldSelection)selectable;
- Selector selected = makeSelector(cfm, withField.selected, null, defs, null);
++ // use a temporary columns mapping to collect the underlying column from the type selectable
++ SelectionColumnMapping tmpMapping = SelectionColumnMapping.newMapping();
++ Selector selected = makeSelector(cfm, withField.selected, null, defs, tmpMapping);
+ AbstractType<?> type = selected.getType();
+ if (!(type instanceof UserType))
+ throw new InvalidRequestException(String.format("Invalid field selection: %s of type %s is not a user type", withField.selected, type.asCQL3Type()));
+
+ UserType ut = (UserType)type;
+ for (int i = 0; i < ut.size(); i++)
+ {
+ if (!ut.fieldName(i).equals(withField.field.bytes))
+ continue;
+
- if (metadata != null)
- metadata.add(makeFieldSelectSpec(cfm, withField, ut.fieldType(i), alias));
++ if (columnMapping != null)
++ columnMapping.addMapping(makeFieldSelectSpec(cfm, withField, ut.fieldType(i), alias),
++ tmpMapping.getMappings().values());
+ return new FieldSelector(ut, i, selected);
+ }
+ throw new InvalidRequestException(String.format("%s of type %s has no field %s", withField.selected, type.asCQL3Type(), withField.field));
}
else
{
Selectable.WithFunction withFun = (Selectable.WithFunction)selectable;
List<Selector> args = new ArrayList<Selector>(withFun.args.size());
- // use a temporary column mapping to collate the columns used by all the function args
++ // use a temporary columns mapping to collate the columns used by all the function args
+ SelectionColumnMapping tmpMapping = SelectionColumnMapping.newMapping();
- for (Selectable rawArg : withFun.args)
- args.add(makeSelector(cfDef, rawArg, null, names, tmpMapping));
+ for (Selectable arg : withFun.args)
- args.add(makeSelector(cfm, arg, null, defs, null));
++ args.add(makeSelector(cfm, arg, null, defs, tmpMapping));
- AbstractType<?> returnType = Functions.getReturnType(withFun.functionName, cfDef.cfm.ksName, cfDef.cfm.cfName);
+ AbstractType<?> returnType = Functions.getReturnType(withFun.functionName, cfm.ksName, cfm.cfName);
if (returnType == null)
throw new InvalidRequestException(String.format("Unknown function '%s'", withFun.functionName));
- ColumnSpecification spec = makeFunctionSpec(cfDef, withFun, returnType, alias);
- Function fun = Functions.get(withFun.functionName, args, spec);
+
+ ColumnSpecification spec = makeFunctionSpec(cfm, withFun, returnType, alias);
+ Function fun = Functions.get(cfm.ksName, withFun.functionName, args, spec);
- if (metadata != null)
- metadata.add(spec);
+ if (columnMapping != null)
+ columnMapping.addMapping(spec, tmpMapping.getMappings().values());
++
return new FunctionSelector(fun, args);
}
}
@@@ -208,44 -175,49 +215,48 @@@
returnType);
}
- private static ColumnSpecification makeAliasSpec(CFDefinition cfDef, AbstractType<?> type, ColumnIdentifier alias)
+ private static ColumnSpecification makeAliasSpec(CFMetaData cfm, AbstractType<?> type, ColumnIdentifier alias)
{
- return new ColumnSpecification(cfDef.cfm.ksName, cfDef.cfm.cfName, alias, type);
+ return new ColumnSpecification(cfm.ksName, cfm.cfName, alias, type);
}
- public static Selection fromSelectors(CFDefinition cfDef, List<RawSelector> rawSelectors) throws InvalidRequestException
+ public static Selection fromSelectors(CFMetaData cfm, List<RawSelector> rawSelectors) throws InvalidRequestException
{
- boolean needsProcessing = selectionsNeedProcessing(rawSelectors);
-
- if (needsProcessing)
+ if (requiresProcessing(rawSelectors))
{
- List<CFDefinition.Name> names = new ArrayList<CFDefinition.Name>();
+ List<ColumnDefinition> defs = new ArrayList<ColumnDefinition>();
- List<ColumnSpecification> metadata = new ArrayList<ColumnSpecification>(rawSelectors.size());
+ SelectionColumnMapping columnMapping = SelectionColumnMapping.newMapping();
List<Selector> selectors = new ArrayList<Selector>(rawSelectors.size());
boolean collectTimestamps = false;
boolean collectTTLs = false;
for (RawSelector rawSelector : rawSelectors)
{
- Selector selector = makeSelector(cfm, rawSelector, defs, metadata);
- Selector selector = makeSelector(cfDef, rawSelector, names, columnMapping);
++ Selector selector = makeSelector(cfm, rawSelector, defs, columnMapping);
selectors.add(selector);
collectTimestamps |= selector.usesTimestamps();
collectTTLs |= selector.usesTTLs();
}
- return new SelectionWithProcessing(defs, metadata, selectors, collectTimestamps, collectTTLs);
- return new SelectionWithProcessing(names, columnMapping, selectors, collectTimestamps, collectTTLs);
++ return new SelectionWithProcessing(defs, columnMapping, selectors, collectTimestamps, collectTTLs);
}
else
{
- List<CFDefinition.Name> names = new ArrayList<CFDefinition.Name>(rawSelectors.size());
+ List<ColumnDefinition> defs = new ArrayList<ColumnDefinition>(rawSelectors.size());
- List<ColumnSpecification> metadata = new ArrayList<ColumnSpecification>(rawSelectors.size());
+ SelectionColumnMapping columnMapping = SelectionColumnMapping.newMapping();
for (RawSelector rawSelector : rawSelectors)
{
assert rawSelector.selectable instanceof ColumnIdentifier.Raw;
- ColumnIdentifier id = ((ColumnIdentifier.Raw)rawSelector.selectable).prepare(cfDef.cfm);
- CFDefinition.Name name = cfDef.get(id);
- if (name == null)
+ ColumnIdentifier id = (ColumnIdentifier) rawSelector.selectable.prepare(cfm);
+ ColumnDefinition def = cfm.getColumnDefinition(id);
+ if (def == null)
throw new InvalidRequestException(String.format("Undefined name %s in selection clause", id));
- names.add(name);
- columnMapping.addMapping(rawSelector.alias == null ? name : makeAliasSpec(cfDef,
- name.type,
- rawSelector.alias),
- name);
++
+ defs.add(def);
- metadata.add(rawSelector.alias == null ? def : makeAliasSpec(cfm, def.type, rawSelector.alias));
++ columnMapping.addMapping(rawSelector.alias == null ? def : makeAliasSpec(cfm,
++ def.type,
++ rawSelector.alias),
++ def);
}
- return new SimpleSelection(defs, metadata, false);
- return new SimpleSelection(names, columnMapping, false);
++ return new SimpleSelection(defs, columnMapping, false);
}
}
@@@ -345,12 -339,12 +364,12 @@@
{
private final boolean isWildcard;
- public SimpleSelection(List<CFDefinition.Name> columns, boolean isWildcard)
+ public SimpleSelection(List<ColumnDefinition> columns, boolean isWildcard)
{
- this(columns, new ArrayList<ColumnSpecification>(columns), isWildcard);
+ this(columns, SelectionColumnMapping.simpleMapping(columns), isWildcard);
}
- public SimpleSelection(List<ColumnDefinition> columns, List<ColumnSpecification> metadata, boolean isWildcard)
- public SimpleSelection(List<CFDefinition.Name> columns, SelectionColumnMapping columnMapping, boolean isWildcard)
++ public SimpleSelection(List<ColumnDefinition> columns, SelectionColumnMapping columnMapping, boolean isWildcard)
{
/*
* In theory, even a simple selection could have multiple time the same column, so we
@@@ -414,34 -417,19 +433,38 @@@
return rs.current.get(idx);
}
- public boolean isAssignableTo(ColumnSpecification receiver)
+ public AbstractType<?> getType()
{
- return receiver.type.isValueCompatibleWith(type);
+ return type;
}
- public boolean usesTimestamps()
+ @Override
+ public String toString()
{
- return false;
+ return columnName;
}
+ }
- public boolean usesTTLs()
+ private static class SelectionWithProcessing extends Selection
+ {
+ private final List<Selector> selectors;
+
- public SelectionWithProcessing(List<ColumnDefinition> columns, List<ColumnSpecification> metadata, List<Selector> selectors, boolean collectTimestamps, boolean collectTTLs)
++ public SelectionWithProcessing(List<ColumnDefinition> columns,
++ SelectionColumnMapping columnMapping,
++ List<Selector> selectors,
++ boolean collectTimestamps,
++ boolean collectTTLs)
{
- super(columns, metadata, collectTimestamps, collectTTLs);
- return false;
++ super(columns, columnMapping, collectTimestamps, collectTTLs);
+ this.selectors = selectors;
+ }
+
+ protected List<ByteBuffer> handleRow(ResultSetBuilder rs) throws InvalidRequestException
+ {
+ List<ByteBuffer> result = new ArrayList<>();
+ for (Selector selector : selectors)
+ result.add(selector.compute(rs));
+ return result;
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/src/java/org/apache/cassandra/cql3/statements/SelectionColumnMapping.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SelectionColumnMapping.java
index 0000000,d09612f..4a6955f
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectionColumnMapping.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectionColumnMapping.java
@@@ -1,0 -1,106 +1,107 @@@
+ package org.apache.cassandra.cql3.statements;
+
+ import java.util.*;
+
+ import com.google.common.base.Function;
+ import com.google.common.base.Joiner;
++import com.google.common.base.Objects;
+ import com.google.common.collect.*;
+
-import org.apache.cassandra.cql3.CFDefinition;
++import org.apache.cassandra.config.ColumnDefinition;
+ import org.apache.cassandra.cql3.ColumnSpecification;
+
+ public class SelectionColumnMapping implements SelectionColumns
+ {
-
+ // Uses LinkedHashMultimap because ordering of keys must be maintained
- private final LinkedHashMultimap<ColumnSpecification, CFDefinition.Name> columnMappings;
++ private final LinkedHashMultimap<ColumnSpecification, ColumnDefinition> columnMappings;
+
+ private SelectionColumnMapping()
+ {
+ this.columnMappings = LinkedHashMultimap.create();
+ }
+
+ protected static SelectionColumnMapping newMapping()
+ {
+ return new SelectionColumnMapping();
+ }
+
- protected static SelectionColumnMapping simpleMapping(List<CFDefinition.Name> columnDefinitions)
++ protected static SelectionColumnMapping simpleMapping(List<ColumnDefinition> columnDefinitions)
+ {
+ SelectionColumnMapping mapping = new SelectionColumnMapping();
- for (CFDefinition.Name def: columnDefinitions)
++ for (ColumnDefinition def: columnDefinitions)
+ mapping.addMapping(def, def);
+ return mapping;
+ }
+
- protected SelectionColumnMapping addMapping(ColumnSpecification colSpec, CFDefinition.Name column)
++ protected SelectionColumnMapping addMapping(ColumnSpecification colSpec, ColumnDefinition column)
+ {
+ columnMappings.put(colSpec, column);
+ return this;
+ }
+
- protected SelectionColumnMapping addMapping(ColumnSpecification colSpec, Iterable<CFDefinition.Name> columns)
++ protected SelectionColumnMapping addMapping(ColumnSpecification colSpec, Iterable<ColumnDefinition> columns)
+ {
+ columnMappings.putAll(colSpec, columns);
+ return this;
+ }
+
+ public List<ColumnSpecification> getColumnSpecifications()
+ {
+ // return a mutable copy as we may add extra columns
+ // for ordering (CASSANDRA-4911 & CASSANDRA-8286)
- return new ArrayList(columnMappings.keySet());
++ return Lists.newArrayList(columnMappings.keySet());
+ }
+
- public Multimap<ColumnSpecification, CFDefinition.Name> getMappings()
++ public Multimap<ColumnSpecification, ColumnDefinition> getMappings()
+ {
+ return Multimaps.unmodifiableMultimap(columnMappings);
+ }
+
+ public boolean equals(Object obj)
+ {
+ if (obj == null)
+ return false;
+
- if (!(obj instanceof SelectionColumns))
++ if (!(obj instanceof SelectionColumnMapping))
+ return false;
+
- return Objects.equals(columnMappings, ((SelectionColumns) obj).getMappings());
++ return Objects.equal(this.columnMappings, ((SelectionColumnMapping) obj).columnMappings);
+ }
+
+ public int hashCode()
+ {
+ return Objects.hashCode(columnMappings);
+ }
+
+ public String toString()
+ {
- final Function<CFDefinition.Name, String> getDefName = new Function<CFDefinition.Name, String>()
++ final Function<ColumnDefinition, String> getDefName = new Function<ColumnDefinition, String>()
+ {
- public String apply(CFDefinition.Name name)
++ public String apply(ColumnDefinition columnDefinition)
+ {
- return name.toString();
++ return columnDefinition.name.toString();
+ }
+ };
- Function<Map.Entry<ColumnSpecification, Collection<CFDefinition.Name>>, String> mappingEntryToString =
- new Function<Map.Entry<ColumnSpecification, Collection<CFDefinition.Name>>, String>(){
- public String apply(Map.Entry<ColumnSpecification, Collection<CFDefinition.Name>> entry)
++ Function<Map.Entry<ColumnSpecification, Collection<ColumnDefinition>>, String> mappingEntryToString =
++ new Function<Map.Entry<ColumnSpecification, Collection<ColumnDefinition>>, String>(){
++ public String apply(Map.Entry<ColumnSpecification, Collection<ColumnDefinition>> entry)
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append(entry.getKey().name.toString());
+ builder.append(":[");
+ builder.append(Joiner.on(',').join(Iterables.transform(entry.getValue(), getDefName)));
+ builder.append("]");
+ return builder.toString();
+ }
+ };
+
+ StringBuilder builder = new StringBuilder();
+ builder.append("{ ");
+ builder.append(Joiner.on(", ")
+ .join(Iterables.transform(columnMappings.asMap().entrySet(),
+ mappingEntryToString)));
+ builder.append(" }");
+ return builder.toString();
+ }
++
+ }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/src/java/org/apache/cassandra/cql3/statements/SelectionColumns.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/SelectionColumns.java
index 0000000,3053f99..5b18eff
mode 000000,100644..100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectionColumns.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectionColumns.java
@@@ -1,0 -1,19 +1,18 @@@
+ package org.apache.cassandra.cql3.statements;
+
+ import java.util.List;
+
+ import com.google.common.collect.Multimap;
+
-import org.apache.cassandra.cql3.CFDefinition;
++import org.apache.cassandra.config.ColumnDefinition;
+ import org.apache.cassandra.cql3.ColumnSpecification;
+
+ /**
+ * Represents a mapping between the actual columns used to satisfy a Selection
+ * and the column definitions included in the resultset metadata for the query.
+ */
+ public interface SelectionColumns
+ {
+ List<ColumnSpecification> getColumnSpecifications();
- Multimap<ColumnSpecification, CFDefinition.Name> getMappings();
++ Multimap<ColumnSpecification, ColumnDefinition> getMappings();
+ }
-
http://git-wip-us.apache.org/repos/asf/cassandra/blob/0452e74f/test/unit/org/apache/cassandra/cql3/statements/SelectionColumnMappingTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/statements/SelectionColumnMappingTest.java
index 0000000,9c31653..09b2bdd
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/statements/SelectionColumnMappingTest.java
+++ b/test/unit/org/apache/cassandra/cql3/statements/SelectionColumnMappingTest.java
@@@ -1,0 -1,244 +1,252 @@@
+ package org.apache.cassandra.cql3.statements;
+
+ import java.util.ArrayList;
+ import java.util.List;
+
-import org.junit.BeforeClass;
+ import org.junit.Test;
+
-import org.apache.cassandra.SchemaLoader;
++import org.apache.cassandra.config.ColumnDefinition;
+ import org.apache.cassandra.config.Schema;
+ import org.apache.cassandra.cql3.*;
-import org.apache.cassandra.db.ConsistencyLevel;
+ import org.apache.cassandra.db.marshal.*;
+ import org.apache.cassandra.exceptions.RequestValidationException;
+ import org.apache.cassandra.service.ClientState;
+
-import static org.apache.cassandra.cql3.QueryProcessor.process;
+ import static org.junit.Assert.assertEquals;
+ import static org.junit.Assert.assertTrue;
+
-public class SelectionColumnMappingTest
++public class SelectionColumnMappingTest extends CQLTester
+ {
- static String KEYSPACE = "selection_column_mapping_test_ks";
- String tableName = "test_table";
-
- @BeforeClass
- public static void setupSchema() throws Throwable
- {
- SchemaLoader.loadSchema();
- executeSchemaChange(String.format("CREATE KEYSPACE IF NOT EXISTS %s " +
- "WITH replication = {'class': 'SimpleStrategy', " +
- " 'replication_factor': '1'}",
- KEYSPACE));
- }
++ String tableName;
++ String typeName;
+
+ @Test
+ public void testSelectionColumnMapping() throws Throwable
+ {
+ // Organised as a single test to avoid the overhead of
+ // table creation for each variant
- tableName = "table1";
- createTable("CREATE TABLE %s (" +
- " k int PRIMARY KEY," +
- " v1 int," +
- " v2 ascii)");
++
++ typeName = createType("CREATE TYPE %s (f1 int, f2 text)");
++ tableName = createTable("CREATE TABLE %s (" +
++ " k int PRIMARY KEY," +
++ " v1 int," +
++ " v2 ascii," +
++ " v3 frozen<" + typeName + ">)");
+ testSimpleTypes();
+ testWildcard();
+ testSimpleTypesWithAliases();
++ testUserTypes();
++ testUserTypesWithAliases();
+ testWritetimeAndTTL();
+ testWritetimeAndTTLWithAliases();
+ testFunction();
+ testFunctionWithAlias();
+ testMultipleAliasesOnSameColumn();
+ testMixedColumnTypes();
+ }
+
+ @Test
+ public void testMultipleArgumentFunction() throws Throwable
+ {
+ // token() is currently the only function which accepts multiple arguments
- tableName = "table2";
- createTable("CREATE TABLE %s (a int, b text, PRIMARY KEY ((a, b)))");
++ tableName = createTable("CREATE TABLE %s (a int, b text, PRIMARY KEY ((a, b)))");
+ ColumnSpecification tokenSpec = columnSpecification("token(a, b)", BytesType.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(tokenSpec, columnDefinitions("a", "b"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(tokenSpec, columnDefinitions("a", "b"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT token(a,b) FROM %s"));
+ }
+
+ private void testSimpleTypes() throws Throwable
+ {
+ // simple column identifiers without aliases are represented in
+ // ResultSet.Metadata by the underlying ColumnDefinition
- CFDefinition.Name kDef = columnDefinition("k");
- CFDefinition.Name v1Def = columnDefinition("v1");
- CFDefinition.Name v2Def = columnDefinition("v2");
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(kDef, columnDefinition("k"))
- .addMapping(v1Def, columnDefinition("v1"))
- .addMapping(v2Def, columnDefinition("v2"));
++ ColumnDefinition kDef = columnDefinition("k");
++ ColumnDefinition v1Def = columnDefinition("v1");
++ ColumnDefinition v2Def = columnDefinition("v2");
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(kDef, columnDefinition("k"))
++ .addMapping(v1Def, columnDefinition("v1"))
++ .addMapping(v2Def, columnDefinition("v2"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT k, v1, v2 FROM %s"));
+ }
+
+ private void testWildcard() throws Throwable
+ {
+ // Wildcard select should behave just as though we had
+ // explicitly selected each column
- CFDefinition.Name kDef = columnDefinition("k");
- CFDefinition.Name v1Def = columnDefinition("v1");
- CFDefinition.Name v2Def = columnDefinition("v2");
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(kDef, columnDefinition("k"))
- .addMapping(v1Def, columnDefinition("v1"))
- .addMapping(v2Def, columnDefinition("v2"));
++ ColumnDefinition kDef = columnDefinition("k");
++ ColumnDefinition v1Def = columnDefinition("v1");
++ ColumnDefinition v2Def = columnDefinition("v2");
++ ColumnDefinition v3Def = columnDefinition("v3");
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(kDef, columnDefinition("k"))
++ .addMapping(v1Def, columnDefinition("v1"))
++ .addMapping(v2Def, columnDefinition("v2"))
++ .addMapping(v3Def, columnDefinition("v3"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT * FROM %s"));
+ }
+
+ private void testSimpleTypesWithAliases() throws Throwable
+ {
+ // simple column identifiers with aliases are represented in ResultSet.Metadata
+ // by a ColumnSpecification based on the underlying ColumnDefinition
+ ColumnSpecification kSpec = columnSpecification("k_alias", Int32Type.instance);
+ ColumnSpecification v1Spec = columnSpecification("v1_alias", Int32Type.instance);
+ ColumnSpecification v2Spec = columnSpecification("v2_alias", AsciiType.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(kSpec, columnDefinition("k"))
- .addMapping(v1Spec, columnDefinition("v1"))
- .addMapping(v2Spec, columnDefinition("v2"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(kSpec, columnDefinition("k"))
++ .addMapping(v1Spec, columnDefinition("v1"))
++ .addMapping(v2Spec, columnDefinition("v2"));
++
++ assertEquals(expected, extractColumnMappingFromSelect("SELECT k AS k_alias, v1 AS v1_alias, v2 AS v2_alias FROM %s"));
++ }
++
++ private void testUserTypes() throws Throwable
++ {
++ // User type fields are represented in ResultSet.Metadata by a
++ // ColumnSpecification denoting the name and type of the particular field
++ ColumnSpecification f1Spec = columnSpecification("v3.f1", Int32Type.instance);
++ ColumnSpecification f2Spec = columnSpecification("v3.f2", UTF8Type.instance);
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(f1Spec, columnDefinition("v3"))
++ .addMapping(f2Spec, columnDefinition("v3"));
+
- assertEquals(expected, extractColumnMappingFromSelect(
- "SELECT k AS k_alias, v1 AS v1_alias, v2 AS v2_alias FROM %s"));
++ assertEquals(expected, extractColumnMappingFromSelect("SELECT v3.f1, v3.f2 FROM %s"));
++ }
++
++ private void testUserTypesWithAliases() throws Throwable
++ {
++ // User type fields with aliases are represented in ResultSet.Metadata
++ // by a ColumnSpecification with the alias name and the type of the actual field
++ ColumnSpecification f1Spec = columnSpecification("f1_alias", Int32Type.instance);
++ ColumnSpecification f2Spec = columnSpecification("f2_alias", UTF8Type.instance);
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(f1Spec, columnDefinition("v3"))
++ .addMapping(f2Spec, columnDefinition("v3"));
++
++ assertEquals(expected, extractColumnMappingFromSelect("SELECT v3.f1 AS f1_alias, v3.f2 AS f2_alias FROM %s"));
+ }
+
+ private void testWritetimeAndTTL() throws Throwable
+ {
+ // writetime and ttl are represented in ResultSet.Metadata by a ColumnSpecification
+ // with the function name plus argument and a long or int type respectively
+ ColumnSpecification wtSpec = columnSpecification("writetime(v1)", LongType.instance);
+ ColumnSpecification ttlSpec = columnSpecification("ttl(v2)", Int32Type.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(wtSpec, columnDefinition("v1"))
- .addMapping(ttlSpec, columnDefinition("v2"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(wtSpec, columnDefinition("v1"))
++ .addMapping(ttlSpec, columnDefinition("v2"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT writetime(v1), ttl(v2) FROM %s"));
+ }
+
+ private void testWritetimeAndTTLWithAliases() throws Throwable
+ {
+ // writetime and ttl with aliases are represented in ResultSet.Metadata
+ // by a ColumnSpecification with the alias name and the appropriate numeric type
+ ColumnSpecification wtSpec = columnSpecification("wt_alias", LongType.instance);
+ ColumnSpecification ttlSpec = columnSpecification("ttl_alias", Int32Type.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(wtSpec, columnDefinition("v1"))
- .addMapping(ttlSpec, columnDefinition("v2"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(wtSpec, columnDefinition("v1"))
++ .addMapping(ttlSpec, columnDefinition("v2"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT writetime(v1) AS wt_alias, ttl(v2) AS ttl_alias FROM %s"));
+ }
+
+ private void testFunction() throws Throwable
+ {
+ // a function such as intasblob(<col>) is represented in ResultSet.Metadata
+ // by a ColumnSpecification with the function name plus args and the type set
+ // to the function's return type
+ ColumnSpecification fnSpec = columnSpecification("intasblob(v1)", BytesType.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(fnSpec, columnDefinition("v1"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(fnSpec, columnDefinition("v1"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT intasblob(v1) FROM %s"));
+ }
+
+ private void testFunctionWithAlias() throws Throwable
+ {
+ // a function with an alias is represented in ResultSet.Metadata by a
+ // ColumnSpecification with the alias and the type set to the function's
+ // return type
+ ColumnSpecification fnSpec = columnSpecification("fn_alias", BytesType.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(fnSpec, columnDefinition("v1"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(fnSpec, columnDefinition("v1"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT intasblob(v1) AS fn_alias FROM %s"));
+ }
+
+ private void testMultipleAliasesOnSameColumn() throws Throwable
+ {
+ // Multiple result columns derived from the same underlying column are
+ // represented by ColumnSpecifications
+ ColumnSpecification alias1 = columnSpecification("alias_1", Int32Type.instance);
+ ColumnSpecification alias2 = columnSpecification("alias_2", Int32Type.instance);
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(alias1, columnDefinition("v1"))
- .addMapping(alias2, columnDefinition("v1"));
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(alias1, columnDefinition("v1"))
++ .addMapping(alias2, columnDefinition("v1"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT v1 AS alias_1, v1 AS alias_2 FROM %s"));
+ }
+
+ private void testMixedColumnTypes() throws Throwable
+ {
+ ColumnSpecification kSpec = columnSpecification("k_alias", Int32Type.instance);
+ ColumnSpecification v1Spec = columnSpecification("writetime(v1)", LongType.instance);
+ ColumnSpecification v2Spec = columnSpecification("ttl_alias", Int32Type.instance);
-
- SelectionColumns expected = SelectionColumnMapping.newMapping()
- .addMapping(kSpec, columnDefinition("k"))
- .addMapping(v1Spec, columnDefinition("v1"))
- .addMapping(v2Spec, columnDefinition("v2"));
++ ColumnSpecification f1Spec = columnSpecification("v3.f1", Int32Type.instance);
++ ColumnSpecification f2Spec = columnSpecification("f2_alias", UTF8Type.instance);
++
++ SelectionColumnMapping expected = SelectionColumnMapping.newMapping()
++ .addMapping(kSpec, columnDefinition("k"))
++ .addMapping(v1Spec, columnDefinition("v1"))
++ .addMapping(v2Spec, columnDefinition("v2"))
++ .addMapping(f1Spec, columnDefinition("v3"))
++ .addMapping(f2Spec, columnDefinition("v3"))
++ .addMapping(columnDefinition("v3"), columnDefinition(
++ "v3"));
+
+ assertEquals(expected, extractColumnMappingFromSelect("SELECT k AS k_alias," +
+ " writetime(v1)," +
- " ttl(v2) as ttl_alias" +
++ " ttl(v2) as ttl_alias," +
++ " v3.f1," +
++ " v3.f2 AS f2_alias," +
++ " v3" +
+ " FROM %s"));
+ }
+
+ private SelectionColumns extractColumnMappingFromSelect(String query) throws RequestValidationException
+ {
+ CQLStatement statement = QueryProcessor.getStatement(String.format(query, KEYSPACE + "." + tableName),
+ ClientState.forInternalCalls()).statement;
+ assertTrue(statement instanceof SelectStatement);
+ return ((SelectStatement)statement).getSelection().getColumnMapping();
+ }
+
- private CFDefinition.Name columnDefinition(String name)
++ private ColumnDefinition columnDefinition(String name)
+ {
+ return Schema.instance.getCFMetaData(KEYSPACE, tableName)
- .getCfDef()
- .get(new ColumnIdentifier(name, true));
++ .getColumnDefinition(new ColumnIdentifier(name, true));
+
+ }
+
- private Iterable<CFDefinition.Name> columnDefinitions(String...name)
++ private Iterable<ColumnDefinition> columnDefinitions(String...name)
+ {
- List<CFDefinition.Name> list = new ArrayList<>();
++ List<ColumnDefinition> list = new ArrayList<>();
+ for (String n : name)
+ list.add(columnDefinition(n));
+ return list;
+ }
+
+ private ColumnSpecification columnSpecification(String name, AbstractType<?> type)
+ {
+ return new ColumnSpecification(KEYSPACE,
+ tableName,
+ new ColumnIdentifier(name, true),
+ type);
+ }
-
- private void createTable(String query) throws Throwable
- {
- executeSchemaChange(String.format(query, KEYSPACE + "." + tableName));
- }
-
- private static void executeSchemaChange(String query) throws Throwable
- {
- try
- {
- process(query, ConsistencyLevel.ONE);
- }
- catch (RuntimeException exc)
- {
- throw exc.getCause();
- }
- }
+ }