cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From slebre...@apache.org
Subject [2/2] git commit: Fix NPE when preparing statements
Date Thu, 23 Oct 2014 09:05:21 GMT
Fix NPE when preparing statements

patch by blere; reviewed by slebresne for CASSANDRA-8090


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

Branch: refs/heads/trunk
Commit: 7e53db0b927ad2f7bd25dbebc6c01a942afd79da
Parents: a1f7ccf
Author: blerer <b_lerer@hotmail.com>
Authored: Tue Oct 14 13:17:57 2014 +0200
Committer: Sylvain Lebresne <sylvain@datastax.com>
Committed: Thu Oct 23 11:04:30 2014 +0200

----------------------------------------------------------------------
 .../apache/cassandra/cql3/ColumnIdentifier.java |  18 +-
 .../cassandra/cql3/ColumnSpecification.java     |  11 +
 src/java/org/apache/cassandra/cql3/Cql.g        |   1 +
 .../selection/AbstractFunctionSelector.java     | 111 +++
 .../selection/AggregateFunctionSelector.java    |  66 ++
 .../cassandra/cql3/selection/FieldSelector.java | 104 +++
 .../cassandra/cql3/selection/RawSelector.java   |  55 ++
 .../cql3/selection/ScalarFunctionSelector.java  |  67 ++
 .../cassandra/cql3/selection/Selectable.java    | 166 ++++
 .../cassandra/cql3/selection/Selection.java     | 390 ++++++++++
 .../cassandra/cql3/selection/Selector.java      | 140 ++++
 .../cql3/selection/SelectorFactories.java       | 151 ++++
 .../cql3/selection/SimpleSelector.java          |  87 +++
 .../cql3/selection/WritetimeOrTTLSelector.java  | 110 +++
 .../cql3/statements/ModificationStatement.java  |   1 +
 .../cassandra/cql3/statements/RawSelector.java  |  33 -
 .../cql3/statements/SelectStatement.java        |   2 +
 .../cassandra/cql3/statements/Selectable.java   |  89 ---
 .../cassandra/cql3/statements/Selection.java    | 770 -------------------
 19 files changed, 1478 insertions(+), 894 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/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 fa151d2..9b4f29f 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnIdentifier.java
@@ -17,12 +17,18 @@
  */
 package org.apache.cassandra.cql3;
 
+import java.util.List;
 import java.util.Locale;
 import java.nio.ByteBuffer;
 
 import org.apache.cassandra.cache.IMeasurableMemory;
-import org.apache.cassandra.cql3.statements.Selectable;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+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.exceptions.InvalidRequestException;
 import org.apache.cassandra.utils.ByteBufferUtil;
 import org.apache.cassandra.utils.ObjectSizes;
 import org.apache.cassandra.utils.memory.AbstractAllocator;
@@ -31,7 +37,7 @@ import org.apache.cassandra.utils.memory.AbstractAllocator;
  * Represents an identifer for a CQL column definition.
  * TODO : should support light-weight mode without text representation for when not interned
  */
-public class ColumnIdentifier implements Selectable, IMeasurableMemory
+public class ColumnIdentifier extends Selectable implements IMeasurableMemory
 {
     public final ByteBuffer bytes;
     private final String text;
@@ -101,4 +107,12 @@ public class ColumnIdentifier implements Selectable, IMeasurableMemory
         return new ColumnIdentifier(allocator.clone(bytes), text);
     }
 
+    public Selector.Factory newSelectorFactory(CFMetaData cfm, List<ColumnDefinition> defs) throws InvalidRequestException
+    {
+        ColumnDefinition def = cfm.getColumnDefinition(this);
+        if (def == null)
+            throw new InvalidRequestException(String.format("Undefined name %s in selection clause", this));
+
+        return SimpleSelector.newFactory(def.name.toString(), addAndGetIndex(def, defs), def.type);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/ColumnSpecification.java b/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
index d2e08f9..2584f85 100644
--- a/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
+++ b/src/java/org/apache/cassandra/cql3/ColumnSpecification.java
@@ -33,4 +33,15 @@ public class ColumnSpecification
         this.name = name;
         this.type = type;
     }
+
+    /**
+     * Returns a new <code>ColumnSpecification</code> for the same column but with the specified alias.
+     *
+     * @param alias the column alias
+     * @return a new <code>ColumnSpecification</code> for the same column but with the specified alias.
+     */
+    public ColumnSpecification withAlias(ColumnIdentifier alias)
+    {
+        return new ColumnSpecification(ksName, cfName, alias, type);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/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 81f7d25..7634a48 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -42,6 +42,7 @@ options {
     import org.apache.cassandra.auth.IResource;
     import org.apache.cassandra.cql3.*;
     import org.apache.cassandra.cql3.statements.*;
+    import org.apache.cassandra.cql3.selection.*;
     import org.apache.cassandra.cql3.functions.*;
     import org.apache.cassandra.db.marshal.CollectionType;
     import org.apache.cassandra.exceptions.ConfigurationException;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
new file mode 100644
index 0000000..b04f346
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/AbstractFunctionSelector.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.commons.lang3.text.StrBuilder;
+
+abstract class AbstractFunctionSelector<T extends Function> extends Selector
+{
+    protected final T fun;
+
+    /**
+     * The list used to pass the function arguments is recycled to avoid the cost of instantiating a new list
+     * with each function call.
+     */
+    protected final List<ByteBuffer> args;
+    protected final List<Selector> argSelectors;
+
+    public static Factory newFactory(final Function fun, final SelectorFactories factories) throws InvalidRequestException
+    {
+        if (fun.isAggregate())
+        {
+            if (factories.doesAggregation())
+                throw new InvalidRequestException("aggregate functions cannot be used as arguments of aggregate functions");
+        }
+        else
+        {
+            if (factories.doesAggregation() && !factories.containsOnlyAggregateFunctions())
+                throw new InvalidRequestException(String.format("the %s function arguments must be either all aggregates or all none aggregates",
+                                                                fun.name().name));
+        }
+
+        return new Factory()
+        {
+            public ColumnSpecification getColumnSpecification(CFMetaData cfm)
+            {
+                return new ColumnSpecification(cfm.ksName,
+                                               cfm.cfName,
+                                               new ColumnIdentifier(fun.toString(), true),
+                                               fun.returnType());
+            }
+
+            public Selector newInstance()
+            {
+                return fun.isAggregate() ? new AggregateFunctionSelector(fun, factories.newInstances())
+                                         : new ScalarFunctionSelector(fun, factories.newInstances());
+            }
+
+            public boolean isWritetimeSelectorFactory()
+            {
+                return factories.containsWritetimeSelectorFactory();
+            }
+
+            public boolean isTTLSelectorFactory()
+            {
+                return factories.containsTTLSelectorFactory();
+            }
+
+            public boolean isAggregateSelectorFactory()
+            {
+                return fun.isAggregate() || factories.containsOnlyAggregateFunctions();
+            }
+        };
+    }
+
+    protected AbstractFunctionSelector(T fun, List<Selector> argSelectors)
+    {
+        this.fun = fun;
+        this.argSelectors = argSelectors;
+        this.args = Arrays.asList(new ByteBuffer[argSelectors.size()]);
+    }
+
+    public AbstractType<?> getType()
+    {
+        return fun.returnType();
+    }
+
+    @Override
+    public String toString()
+    {
+        return new StrBuilder().append(fun.name())
+                               .append("(")
+                               .appendWithSeparators(argSelectors, ", ")
+                               .append(")")
+                               .toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/AggregateFunctionSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/AggregateFunctionSelector.java b/src/java/org/apache/cassandra/cql3/selection/AggregateFunctionSelector.java
new file mode 100644
index 0000000..6ea9716
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/AggregateFunctionSelector.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.functions.AggregateFunction;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+final class AggregateFunctionSelector extends AbstractFunctionSelector<AggregateFunction>
+{
+    private final AggregateFunction.Aggregate aggregate;
+
+    public boolean isAggregate()
+    {
+        return true;
+    }
+
+    public void addInput(ResultSetBuilder rs) throws InvalidRequestException
+    {
+        // Aggregation of aggregation is not supported
+        for (int i = 0, m = argSelectors.size(); i < m; i++)
+        {
+            Selector s = argSelectors.get(i);
+            s.addInput(rs);
+            args.set(i, s.getOutput());
+            s.reset();
+        }
+        this.aggregate.addInput(args);
+    }
+
+    public ByteBuffer getOutput() throws InvalidRequestException
+    {
+        return aggregate.compute();
+    }
+
+    public void reset()
+    {
+        aggregate.reset();
+    }
+
+    AggregateFunctionSelector(Function fun, List<Selector> argSelectors)
+    {
+        super((AggregateFunction) fun, argSelectors);
+
+        this.aggregate = this.fun.newAggregate();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/FieldSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/FieldSelector.java b/src/java/org/apache/cassandra/cql3/selection/FieldSelector.java
new file mode 100644
index 0000000..0bba56c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/FieldSelector.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+final class FieldSelector extends Selector
+{
+    private final UserType type;
+    private final int field;
+    private final Selector selected;
+
+    public static Factory newFactory(final UserType type, final int field, final Selector.Factory factory)
+    {
+        return new Factory()
+        {
+            public ColumnSpecification getColumnSpecification(CFMetaData cfm)
+            {
+                ColumnIdentifier identifier =
+                        new ColumnIdentifier(String.format("%s.%s",
+                                                           factory.getColumnSpecification(cfm).name,
+                                                           UTF8Type.instance.getString(type.fieldName(field))), true);
+
+                return new ColumnSpecification(cfm.ksName, cfm.cfName, identifier, type.fieldType(field));
+            }
+
+            public Selector newInstance()
+            {
+                return new FieldSelector(type, field, factory.newInstance());
+            }
+
+            public boolean isAggregateSelectorFactory()
+            {
+                return factory.isAggregateSelectorFactory();
+            }
+        };
+    }
+
+    public boolean isAggregate()
+    {
+        return false;
+    }
+
+    public void addInput(ResultSetBuilder rs) throws InvalidRequestException
+    {
+        selected.addInput(rs);
+    }
+
+    public ByteBuffer getOutput() throws InvalidRequestException
+    {
+        ByteBuffer value = selected.getOutput();
+        if (value == null)
+            return null;
+        ByteBuffer[] buffers = type.split(value);
+        return field < buffers.length ? buffers[field] : null;
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type.fieldType(field);
+    }
+
+    public void reset()
+    {
+        selected.reset();
+    }
+
+    @Override
+    public String toString()
+    {
+        return String.format("%s.%s", selected, UTF8Type.instance.getString(type.fieldName(field)));
+    }
+
+    private FieldSelector(UserType type, int field, Selector selected)
+    {
+        this.type = type;
+        this.field = field;
+        this.selected = selected;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/RawSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/RawSelector.java b/src/java/org/apache/cassandra/cql3/selection/RawSelector.java
new file mode 100644
index 0000000..372c4b3
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/RawSelector.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.util.List;
+
+import org.apache.cassandra.cql3.ColumnIdentifier;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Lists;
+
+public class RawSelector
+{
+    public final Selectable selectable;
+    public final ColumnIdentifier alias;
+
+    public RawSelector(Selectable selectable, ColumnIdentifier alias)
+    {
+        this.selectable = selectable;
+        this.alias = alias;
+    }
+
+    /**
+     * Converts the specified list of <code>RawSelector</code>s into a list of <code>Selectable</code>s.
+     *
+     * @param raws the <code>RawSelector</code>s to converts.
+     * @return a list of <code>Selectable</code>s
+     */
+    public static List<Selectable> toSelectables(List<RawSelector> raws)
+    {
+        return Lists.transform(raws, new Function<RawSelector, Selectable>()
+        {
+            public Selectable apply(RawSelector raw)
+            {
+                return raw.selectable;
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java b/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java
new file mode 100644
index 0000000..4ceadb9
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.functions.ScalarFunction;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFunction>
+{
+    public boolean isAggregate()
+    {
+        // We cannot just return true as it is possible to have a scalar function wrapping an aggregation function
+        if (argSelectors.isEmpty())
+            return false;
+
+        return argSelectors.get(0).isAggregate();
+    }
+
+    public void addInput(ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (int i = 0, m = argSelectors.size(); i < m; i++)
+        {
+            Selector s = argSelectors.get(i);
+            s.addInput(rs);
+        }
+    }
+
+    public void reset()
+    {
+    }
+
+    public ByteBuffer getOutput() throws InvalidRequestException
+    {
+        for (int i = 0, m = argSelectors.size(); i < m; i++)
+        {
+            Selector s = argSelectors.get(i);
+            args.set(i, s.getOutput());
+            s.reset();
+        }
+        return fun.execute(args);
+    }
+
+    ScalarFunctionSelector(Function fun, List<Selector> argSelectors)
+    {
+        super((ScalarFunction) fun, argSelectors);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/Selectable.java b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
new file mode 100644
index 0000000..9324647
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.util.List;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.functions.FunctionName;
+import org.apache.cassandra.cql3.functions.Functions;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.commons.lang3.text.StrBuilder;
+
+public abstract class Selectable
+{
+    public abstract Selector.Factory newSelectorFactory(CFMetaData cfm, List<ColumnDefinition> defs)
+            throws InvalidRequestException;
+
+    protected static int addAndGetIndex(ColumnDefinition def, List<ColumnDefinition> l)
+    {
+        int idx = l.indexOf(def);
+        if (idx < 0)
+        {
+            idx = l.size();
+            l.add(def);
+        }
+        return idx;
+    }
+
+    public static class WritetimeOrTTL extends Selectable
+    {
+        public final ColumnIdentifier id;
+        public final boolean isWritetime;
+
+        public WritetimeOrTTL(ColumnIdentifier id, boolean isWritetime)
+        {
+            this.id = id;
+            this.isWritetime = isWritetime;
+        }
+
+        @Override
+        public String toString()
+        {
+            return (isWritetime ? "writetime" : "ttl") + "(" + id + ")";
+        }
+
+        public Selector.Factory newSelectorFactory(CFMetaData cfm,
+                                                   List<ColumnDefinition> defs) throws InvalidRequestException
+        {
+            ColumnDefinition def = cfm.getColumnDefinition(id);
+            if (def == null)
+                throw new InvalidRequestException(String.format("Undefined name %s in selection clause", id));
+            if (def.isPrimaryKeyColumn())
+                throw new InvalidRequestException(
+                        String.format("Cannot use selection function %s on PRIMARY KEY part %s",
+                                      isWritetime ? "writeTime" : "ttl",
+                                      def.name));
+            if (def.type.isCollection())
+                throw new InvalidRequestException(String.format("Cannot use selection function %s on collections",
+                                                                isWritetime ? "writeTime" : "ttl"));
+
+            return WritetimeOrTTLSelector.newFactory(def.name.toString(), addAndGetIndex(def, defs), isWritetime);
+        }
+    }
+
+    public static class WithFunction extends Selectable
+    {
+        public final FunctionName functionName;
+        public final List<Selectable> args;
+
+        public WithFunction(FunctionName functionName, List<Selectable> args)
+        {
+            this.functionName = functionName;
+            this.args = args;
+        }
+
+        @Override
+        public String toString()
+        {
+            return new StrBuilder().append(functionName)
+                                   .append("(")
+                                   .appendWithSeparators(args, ", ")
+                                   .append(")")
+                                   .toString();
+        }
+
+        public Selector.Factory newSelectorFactory(CFMetaData cfm,
+                                                   List<ColumnDefinition> defs) throws InvalidRequestException
+        {
+            SelectorFactories factories  =
+                    SelectorFactories.createFactoriesAndCollectColumnDefinitions(args, cfm, defs);
+
+            // resolve built-in functions before user defined functions
+            Function fun = Functions.get(cfm.ksName, functionName, factories.newInstances(), cfm.ksName, cfm.cfName);
+            if (fun == null)
+                throw new InvalidRequestException(String.format("Unknown function '%s'", functionName));
+            if (fun.returnType() == null)
+                throw new InvalidRequestException(String.format("Unknown function %s called in selection clause",
+                                                                functionName));
+
+            return AbstractFunctionSelector.newFactory(fun, factories);
+        }
+    }
+
+    public static class WithFieldSelection extends Selectable
+    {
+        public final Selectable selected;
+        public final ColumnIdentifier field;
+
+        public WithFieldSelection(Selectable selected, ColumnIdentifier field)
+        {
+            this.selected = selected;
+            this.field = field;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("%s.%s", selected, field);
+        }
+
+        public Selector.Factory newSelectorFactory(CFMetaData cfm,
+                                                   List<ColumnDefinition> defs) throws InvalidRequestException
+        {
+            Selector.Factory factory = selected.newSelectorFactory(cfm, defs);
+            AbstractType<?> type = factory.newInstance().getType();
+            if (!(type instanceof UserType))
+                throw new InvalidRequestException(
+                        String.format("Invalid field selection: %s of type %s is not a user type",
+                                      selected,
+                                      type.asCQL3Type()));
+
+            UserType ut = (UserType) type;
+            for (int i = 0; i < ut.size(); i++)
+            {
+                if (!ut.fieldName(i).equals(field.bytes))
+                    continue;
+                return FieldSelector.newFactory(ut, i, factory);
+            }
+            throw new InvalidRequestException(String.format("%s of type %s has no field %s",
+                                                            selected,
+                                                            type.asCQL3Type(),
+                                                            field));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/Selection.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/Selection.java b/src/java/org/apache/cassandra/cql3/selection/Selection.java
new file mode 100644
index 0000000..67cce72
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/Selection.java
@@ -0,0 +1,390 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.ResultSet;
+import org.apache.cassandra.db.Cell;
+import org.apache.cassandra.db.CounterCell;
+import org.apache.cassandra.db.ExpiringCell;
+import org.apache.cassandra.db.context.CounterContext;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+import com.google.common.collect.Iterators;
+
+public abstract class Selection
+{
+    private final Collection<ColumnDefinition> columns;
+    private final ResultSet.Metadata metadata;
+    private final boolean collectTimestamps;
+    private final boolean collectTTLs;
+
+    protected Selection(Collection<ColumnDefinition> columns, List<ColumnSpecification> metadata, boolean collectTimestamps, boolean collectTTLs)
+    {
+        this.columns = columns;
+        this.metadata = new ResultSet.Metadata(metadata);
+        this.collectTimestamps = collectTimestamps;
+        this.collectTTLs = collectTTLs;
+    }
+
+    // Overriden by SimpleSelection when appropriate.
+    public boolean isWildcard()
+    {
+        return false;
+    }
+
+    public ResultSet.Metadata getResultMetadata()
+    {
+        return metadata;
+    }
+
+    public static Selection wildcard(CFMetaData cfm)
+    {
+        List<ColumnDefinition> all = new ArrayList<ColumnDefinition>(cfm.allColumns().size());
+        Iterators.addAll(all, cfm.allColumnsInSelectOrder());
+        return new SimpleSelection(all, true);
+    }
+
+    public static Selection forColumns(Collection<ColumnDefinition> columns)
+    {
+        return new SimpleSelection(columns, false);
+    }
+
+    public int addColumnForOrdering(ColumnDefinition c)
+    {
+        columns.add(c);
+        metadata.addNonSerializedColumn(c);
+        return columns.size() - 1;
+    }
+
+    private static boolean isUsingFunction(List<RawSelector> rawSelectors)
+    {
+        for (RawSelector rawSelector : rawSelectors)
+        {
+            if (!(rawSelector.selectable instanceof ColumnIdentifier))
+                return true;
+        }
+        return false;
+    }
+
+    public static Selection fromSelectors(CFMetaData cfm, List<RawSelector> rawSelectors) throws InvalidRequestException
+    {
+        List<ColumnDefinition> defs = new ArrayList<ColumnDefinition>();
+
+        SelectorFactories factories =
+                SelectorFactories.createFactoriesAndCollectColumnDefinitions(RawSelector.toSelectables(rawSelectors), cfm, defs);
+        List<ColumnSpecification> metadata = collectMetadata(cfm, rawSelectors, factories);
+
+        return isUsingFunction(rawSelectors) ? new SelectionWithFunctions(defs, metadata, factories)
+                                             : new SimpleSelection(defs, metadata, false);
+    }
+
+    private static List<ColumnSpecification> collectMetadata(CFMetaData cfm,
+                                                             List<RawSelector> rawSelectors,
+                                                             SelectorFactories factories)
+    {
+        List<ColumnSpecification> metadata = new ArrayList<ColumnSpecification>(rawSelectors.size());
+        Iterator<RawSelector> iter = rawSelectors.iterator();
+        for (Selector.Factory factory : factories)
+        {
+            ColumnSpecification colSpec = factory.getColumnSpecification(cfm);
+            ColumnIdentifier alias = iter.next().alias;
+            metadata.add(alias == null ? colSpec : colSpec.withAlias(alias));
+        }
+        return metadata;
+    }
+
+    protected abstract Selectors newSelectors();
+
+    /**
+     * @return the list of CQL3 columns value this SelectionClause needs.
+     */
+    public Collection<ColumnDefinition> getColumns()
+    {
+        return columns;
+    }
+
+    public ResultSetBuilder resultSetBuilder(long now)
+    {
+        return new ResultSetBuilder(now);
+    }
+
+    public abstract boolean isAggregate();
+
+    /**
+     * Checks that selectors are either all aggregates or that none of them is.
+     *
+     * @param selectors the selectors to test.
+     * @param msgTemplate the error message template
+     * @param messageArgs the error message arguments
+     * @throws InvalidRequestException if some of the selectors are aggregate but not all of them
+     */
+    static void validateSelectors(List<Selector> selectors, String messageTemplate, Object... messageArgs)
+            throws InvalidRequestException
+    {
+        int aggregates = 0;
+        for (Selector s : selectors)
+            if (s.isAggregate())
+                ++aggregates;
+
+        if (aggregates != 0 && aggregates != selectors.size())
+            throw new InvalidRequestException(String.format(messageTemplate, messageArgs));
+    }
+
+    public class ResultSetBuilder
+    {
+        private final ResultSet resultSet;
+
+        /**
+         * As multiple thread can access a <code>Selection</code> instance each <code>ResultSetBuilder</code> will use
+         * its own <code>Selectors</code> instance.
+         */
+        private final Selectors selectors;
+
+        /*
+         * We'll build CQL3 row one by one.
+         * The currentRow is the values for the (CQL3) columns we've fetched.
+         * We also collect timestamps and ttls for the case where the writetime and
+         * ttl functions are used. Note that we might collect timestamp and/or ttls
+         * we don't care about, but since the array below are allocated just once,
+         * it doesn't matter performance wise.
+         */
+        List<ByteBuffer> current;
+        final long[] timestamps;
+        final int[] ttls;
+        final long now;
+
+        private ResultSetBuilder(long now)
+        {
+            this.resultSet = new ResultSet(getResultMetadata().copy(), new ArrayList<List<ByteBuffer>>());
+            this.selectors = newSelectors();
+            this.timestamps = collectTimestamps ? new long[columns.size()] : null;
+            this.ttls = collectTTLs ? new int[columns.size()] : null;
+            this.now = now;
+        }
+
+        public void add(ByteBuffer v)
+        {
+            current.add(v);
+        }
+
+        public void add(Cell c)
+        {
+            current.add(isDead(c) ? null : value(c));
+            if (timestamps != null)
+            {
+                timestamps[current.size() - 1] = isDead(c) ? -1 : c.timestamp();
+            }
+            if (ttls != null)
+            {
+                int ttl = -1;
+                if (!isDead(c) && c instanceof ExpiringCell)
+                    ttl = c.getLocalDeletionTime() - (int) (now / 1000);
+                ttls[current.size() - 1] = ttl;
+            }
+        }
+
+        private boolean isDead(Cell c)
+        {
+            return c == null || !c.isLive(now);
+        }
+
+        public void newRow() throws InvalidRequestException
+        {
+            if (current != null)
+            {
+                selectors.addInputRow(this);
+                if (!selectors.isAggregate())
+                {
+                    resultSet.addRow(selectors.getOutputRow());
+                    selectors.reset();
+                }
+            }
+            current = new ArrayList<ByteBuffer>(columns.size());
+        }
+
+        public ResultSet build() throws InvalidRequestException
+        {
+            if (current != null)
+            {
+                selectors.addInputRow(this);
+                resultSet.addRow(selectors.getOutputRow());
+                selectors.reset();
+                current = null;
+            }
+            return resultSet;
+        }
+
+        private ByteBuffer value(Cell c)
+        {
+            return (c instanceof CounterCell)
+                ? ByteBufferUtil.bytes(CounterContext.instance().total(c.value()))
+                : c.value();
+        }
+    }
+
+    private static interface Selectors
+    {
+        public boolean isAggregate();
+
+        /**
+         * Adds the current row of the specified <code>ResultSetBuilder</code>.
+         *
+         * @param rs the <code>ResultSetBuilder</code>
+         * @throws InvalidRequestException
+         */
+        public void addInputRow(ResultSetBuilder rs) throws InvalidRequestException;
+
+        public List<ByteBuffer> getOutputRow() throws InvalidRequestException;
+
+        public void reset();
+    }
+
+    // Special cased selection for when no function is used (this save some allocations).
+    private static class SimpleSelection extends Selection
+    {
+        private final boolean isWildcard;
+
+        public SimpleSelection(Collection<ColumnDefinition> columns, boolean isWildcard)
+        {
+            this(columns, new ArrayList<ColumnSpecification>(columns), isWildcard);
+        }
+
+        public SimpleSelection(Collection<ColumnDefinition> columns, List<ColumnSpecification> metadata, boolean isWildcard)
+        {
+            /*
+             * In theory, even a simple selection could have multiple time the same column, so we
+             * could filter those duplicate out of columns. But since we're very unlikely to
+             * get much duplicate in practice, it's more efficient not to bother.
+             */
+            super(columns, metadata, false, false);
+            this.isWildcard = isWildcard;
+        }
+
+        @Override
+        public boolean isWildcard()
+        {
+            return isWildcard;
+        }
+
+        public boolean isAggregate()
+        {
+            return false;
+        }
+
+        protected Selectors newSelectors()
+        {
+            return new Selectors()
+            {
+                private List<ByteBuffer> current;
+
+                public void reset()
+                {
+                    current = null;
+                }
+
+                public List<ByteBuffer> getOutputRow()
+                {
+                    return current;
+                }
+
+                public void addInputRow(ResultSetBuilder rs) throws InvalidRequestException
+                {
+                    current = rs.current;
+                }
+
+                public boolean isAggregate()
+                {
+                    return false;
+                }
+            };
+        }
+    }
+
+    private static class SelectionWithFunctions extends Selection
+    {
+        private final SelectorFactories factories;
+
+        public SelectionWithFunctions(Collection<ColumnDefinition> columns,
+                                      List<ColumnSpecification> metadata,
+                                      SelectorFactories factories) throws InvalidRequestException
+        {
+            super(columns, metadata, factories.containsWritetimeSelectorFactory(), factories.containsTTLSelectorFactory());
+            this.factories = factories;
+
+            if (factories.doesAggregation() && !factories.containsOnlyAggregateFunctions())
+                throw new InvalidRequestException("the select clause must either contains only aggregates or none");
+        }
+
+        public boolean isAggregate()
+        {
+            return factories.containsOnlyAggregateFunctions();
+        }
+
+        protected Selectors newSelectors()
+        {
+            return new Selectors()
+            {
+                private final List<Selector> selectors = factories.newInstances();
+
+                public void reset()
+                {
+                    for (int i = 0, m = selectors.size(); i < m; i++)
+                    {
+                        selectors.get(i).reset();
+                    }
+                }
+
+                public boolean isAggregate()
+                {
+                    return factories.containsOnlyAggregateFunctions();
+                }
+
+                public List<ByteBuffer> getOutputRow() throws InvalidRequestException
+                {
+                    List<ByteBuffer> outputRow = new ArrayList<>(selectors.size());
+
+                    for (int i = 0, m = selectors.size(); i < m; i++)
+                    {
+                        outputRow.add(selectors.get(i).getOutput());
+                    }
+                    return outputRow;
+                }
+
+                public void addInputRow(ResultSetBuilder rs) throws InvalidRequestException
+                {
+                    for (int i = 0, m = selectors.size(); i < m; i++)
+                    {
+                        selectors.get(i).addInput(rs);
+                    }
+                }
+            };
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/Selector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/Selector.java b/src/java/org/apache/cassandra/cql3/selection/Selector.java
new file mode 100644
index 0000000..310e175
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/Selector.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.AssignmentTestable;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+/**
+ * A <code>Selector</code> is used to convert the data returned by the storage engine into the data requested by the 
+ * user. They correspond to the &lt;selector&gt; elements from the select clause.
+ * <p>Since the introduction of aggregation, <code>Selector</code>s cannot be called anymore by multiple threads 
+ * as they have an internal state.</p>
+ */
+public abstract class Selector implements AssignmentTestable
+{
+    /**
+     * A factory for <code>Selector</code> instances.
+     */
+    public static abstract class Factory
+    {
+        /**
+         * Returns the column specification corresponding to the output value of the selector instances created by
+         * this factory.
+         *
+         * @param cfm the column family meta data
+         * @return a column specification
+         */
+        public abstract ColumnSpecification getColumnSpecification(CFMetaData cfm);
+
+        /**
+         * Creates a new <code>Selector</code> instance.
+         *
+         * @return a new <code>Selector</code> instance
+         */
+        public abstract Selector newInstance();
+
+        /**
+         * Checks if this factory creates selectors instances that creates aggregates.
+         *
+         * @return <code>true</code> if this factory creates selectors instances that creates aggregates,
+         * <code>false</code> otherwise
+         */
+        public boolean isAggregateSelectorFactory()
+        {
+            return false;
+        }
+
+        /**
+         * Checks if this factory creates <code>writetime</code> selectors instances.
+         *
+         * @return <code>true</code> if this factory creates <code>writetime</code> selectors instances,
+         * <code>false</code> otherwise
+         */
+        public boolean isWritetimeSelectorFactory()
+        {
+            return false;
+        }
+
+        /**
+         * Checks if this factory creates <code>TTL</code> selectors instances.
+         *
+         * @return <code>true</code> if this factory creates <code>TTL</code> selectors instances,
+         * <code>false</code> otherwise
+         */
+        public boolean isTTLSelectorFactory()
+        {
+            return false;
+        }
+    }
+
+    /**
+     * Add the current value from the specified <code>ResultSetBuilder</code>.
+     *
+     * @param rs the <code>ResultSetBuilder</code>
+     * @throws InvalidRequestException if a problem occurs while add the input value
+     */
+    public abstract void addInput(ResultSetBuilder rs) throws InvalidRequestException;
+
+    /**
+     * Returns the selector output.
+     *
+     * @return the selector output
+     * @throws InvalidRequestException if a problem occurs while computing the output value
+     */
+    public abstract ByteBuffer getOutput() throws InvalidRequestException;
+
+    /**
+     * Returns the <code>Selector</code> output type.
+     *
+     * @return the <code>Selector</code> output type.
+     */
+    public abstract AbstractType<?> getType();
+
+    /**
+     * Checks if this <code>Selector</code> is creating aggregates.
+     *
+     * @return <code>true</code> if this <code>Selector</code> is creating aggregates <code>false</code>
+     * otherwise.
+     */
+    public boolean isAggregate()
+    {
+        return false;
+    }
+
+    /**
+     * Reset the internal state of this <code>Selector</code>.
+     */
+    public abstract void reset();
+
+    public AssignmentTestable.TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+    {
+        if (receiver.type.equals(getType()))
+            return AssignmentTestable.TestResult.EXACT_MATCH;
+        else if (receiver.type.isValueCompatibleWith(getType()))
+            return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
+        else
+            return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
new file mode 100644
index 0000000..e033556
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/SelectorFactories.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.selection.Selector.Factory;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+/**
+ * A set of <code>Selector</code> factories.
+ */
+final class SelectorFactories implements Iterable<Selector.Factory>
+{
+    /**
+     * The <code>Selector</code> factories.
+     */
+    private final List<Selector.Factory> factories;
+
+    /**
+     * <code>true</code> if one of the factory creates writetime selectors.
+     */
+    private boolean containsWritetimeFactory;
+
+    /**
+     * <code>true</code> if one of the factory creates TTL selectors.
+     */
+    private boolean containsTTLFactory;
+
+    /**
+     * The number of factories creating aggregates.
+     */
+    private int numberOfAggregateFactories;
+
+    /**
+     * Creates a new <code>SelectorFactories</code> instance and collect the column definitions.
+     *
+     * @param selectables the <code>Selectable</code>s for which the factories must be created
+     * @param cfm the Column Family Definition
+     * @param defs the collector parameter for the column definitions
+     * @return a new <code>SelectorFactories</code> instance
+     * @throws InvalidRequestException if a problem occurs while creating the factories
+     */
+    public static SelectorFactories createFactoriesAndCollectColumnDefinitions(List<Selectable> selectables,
+                                                                               CFMetaData cfm,
+                                                                               List<ColumnDefinition> defs)
+                                                                               throws InvalidRequestException
+    {
+        return new SelectorFactories(selectables, cfm, defs);
+    }
+
+    private SelectorFactories(List<Selectable> selectables,
+                              CFMetaData cfm,
+                              List<ColumnDefinition> defs)
+                              throws InvalidRequestException
+    {
+        factories = new ArrayList<>(selectables.size());
+
+        for (Selectable selectable : selectables)
+        {
+            Factory factory = selectable.newSelectorFactory(cfm, defs);
+            containsWritetimeFactory |= factory.isWritetimeSelectorFactory();
+            containsTTLFactory |= factory.isTTLSelectorFactory();
+            if (factory.isAggregateSelectorFactory())
+                ++numberOfAggregateFactories;
+            factories.add(factory);
+        }
+    }
+
+    /**
+     * Checks if this <code>SelectorFactories</code> contains only factories for aggregates.
+     *
+     * @return <code>true</code> if this <code>SelectorFactories</code> contains only factories for aggregates,
+     * <code>false</code> otherwise.
+     */
+    public boolean containsOnlyAggregateFunctions()
+    {
+        int size = factories.size();
+        return  size != 0 && numberOfAggregateFactories == size;
+    }
+
+    /**
+     * Whether the selector built by this factory does aggregation or not (either directly or in a sub-selector).
+     *
+     * @return <code>true</code> if the selector built by this factor does aggregation, <code>false</code> otherwise.
+     */
+    public boolean doesAggregation()
+    {
+        return numberOfAggregateFactories > 0;
+    }
+
+    /**
+     * Checks if this <code>SelectorFactories</code> contains at least one factory for writetime selectors.
+     *
+     * @return <code>true</code> if this <code>SelectorFactories</code> contains at least one factory for writetime
+     * selectors, <code>false</code> otherwise.
+     */
+    public boolean containsWritetimeSelectorFactory()
+    {
+        return containsWritetimeFactory;
+    }
+
+    /**
+     * Checks if this <code>SelectorFactories</code> contains at least one factory for TTL selectors.
+     *
+     * @return <code>true</code> if this <code>SelectorFactories</code> contains at least one factory for TTL
+     * selectors, <code>false</code> otherwise.
+     */
+    public boolean containsTTLSelectorFactory()
+    {
+        return containsTTLFactory;
+    }
+
+    /**
+     * Creates a list of new <code>Selector</code> instances.
+     * @return a list of new <code>Selector</code> instances.
+     */
+    public List<Selector> newInstances()
+    {
+        List<Selector> selectors = new ArrayList<>(factories.size());
+        for (Selector.Factory factory : factories)
+        {
+            selectors.add(factory.newInstance());
+        }
+        return selectors;
+    }
+
+    public Iterator<Factory> iterator()
+    {
+        return factories.iterator();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/SimpleSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/SimpleSelector.java b/src/java/org/apache/cassandra/cql3/selection/SimpleSelector.java
new file mode 100644
index 0000000..37459d2
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/SimpleSelector.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+public final class SimpleSelector extends Selector
+{
+    private final String columnName;
+    private final int idx;
+    private final AbstractType<?> type;
+    private ByteBuffer current;
+
+    public static Factory newFactory(final String columnName, final int idx, final AbstractType<?> type)
+    {
+        return new Factory()
+        {
+            public ColumnSpecification getColumnSpecification(CFMetaData cfm)
+            {
+                return new ColumnSpecification(cfm.ksName,
+                                               cfm.cfName,
+                                               new ColumnIdentifier(columnName, true),
+                                               type);
+            }
+
+            public Selector newInstance()
+            {
+                return new SimpleSelector(columnName, idx, type);
+            }
+        };
+    }
+
+    public void addInput(ResultSetBuilder rs) throws InvalidRequestException
+    {
+        current = rs.current.get(idx);
+    }
+
+    public ByteBuffer getOutput() throws InvalidRequestException
+    {
+        return current;
+    }
+
+    public void reset()
+    {
+        current = null;
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return columnName;
+    }
+
+    private SimpleSelector(String columnName, int idx, AbstractType<?> type)
+    {
+        this.columnName = columnName;
+        this.idx = idx;
+        this.type = type;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/selection/WritetimeOrTTLSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/WritetimeOrTTLSelector.java b/src/java/org/apache/cassandra/cql3/selection/WritetimeOrTTLSelector.java
new file mode 100644
index 0000000..6d6edd3
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/WritetimeOrTTLSelector.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3.selection;
+
+import java.nio.ByteBuffer;
+
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.Int32Type;
+import org.apache.cassandra.db.marshal.LongType;
+import org.apache.cassandra.utils.ByteBufferUtil;
+
+final class WritetimeOrTTLSelector extends Selector
+{
+    private final String columnName;
+    private final int idx;
+    private final boolean isWritetime;
+    private ByteBuffer current;
+
+    public static Factory newFactory(final String columnName, final int idx, final boolean isWritetime)
+    {
+        return new Factory()
+        {
+            public ColumnSpecification getColumnSpecification(CFMetaData cfm)
+            {
+                String text = String.format("%s(%s)", isWritetime ? "writetime" : "ttl", columnName);
+                return new ColumnSpecification(cfm.ksName,
+                                               cfm.cfName,
+                                               new ColumnIdentifier(text, true),
+                                               isWritetime ? LongType.instance : Int32Type.instance);
+            }
+
+            public Selector newInstance()
+            {
+                return new WritetimeOrTTLSelector(columnName, idx, isWritetime);
+            }
+
+            public boolean isWritetimeSelectorFactory()
+            {
+                return isWritetime;
+            }
+
+            public boolean isTTLSelectorFactory()
+            {
+                return !isWritetime;
+            }
+        };
+    }
+
+    public void addInput(ResultSetBuilder rs)
+    {
+        if (isWritetime)
+        {
+            long ts = rs.timestamps[idx];
+            current = ts >= 0 ? ByteBufferUtil.bytes(ts) : null;
+        }
+        else
+        {
+            int ttl = rs.ttls[idx];
+            current = ttl > 0 ? ByteBufferUtil.bytes(ttl) : null;
+        }
+    }
+
+    public ByteBuffer getOutput()
+    {
+        return current;
+    }
+
+    public void reset()
+    {
+        current = null;
+    }
+
+    public AbstractType<?> getType()
+    {
+        return isWritetime ? LongType.instance : Int32Type.instance;
+    }
+
+    @Override
+    public String toString()
+    {
+        return columnName;
+    }
+
+    private WritetimeOrTTLSelector(String columnName, int idx, boolean isWritetime)
+    {
+        this.columnName = columnName;
+        this.idx = idx;
+        this.isWritetime = isWritetime;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index b556044..32dd1c7 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -28,6 +28,7 @@ import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.cql3.selection.Selection;
 import org.apache.cassandra.db.*;
 import org.apache.cassandra.db.composites.CBuilder;
 import org.apache.cassandra.db.composites.Composite;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/statements/RawSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/RawSelector.java b/src/java/org/apache/cassandra/cql3/statements/RawSelector.java
deleted file mode 100644
index 01fe9e4..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/RawSelector.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cassandra.cql3.statements;
-
-import org.apache.cassandra.cql3.ColumnIdentifier;
-
-public class RawSelector
-{
-    public final Selectable selectable;
-    public final ColumnIdentifier alias;
-
-    public RawSelector(Selectable selectable, ColumnIdentifier alias)
-    {
-        this.selectable = selectable;
-        this.alias = alias;
-    }
-}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 30c5390..44bd23c 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -32,6 +32,8 @@ import org.github.jamm.MemoryMeter;
 import org.apache.cassandra.auth.Permission;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.cql3.statements.SingleColumnRestriction.Contains;
+import org.apache.cassandra.cql3.selection.RawSelector;
+import org.apache.cassandra.cql3.selection.Selection;
 import org.apache.cassandra.db.composites.*;
 import org.apache.cassandra.db.composites.Composite.EOC;
 import org.apache.cassandra.transport.messages.ResultMessage;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/7e53db0b/src/java/org/apache/cassandra/cql3/statements/Selectable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/Selectable.java b/src/java/org/apache/cassandra/cql3/statements/Selectable.java
deleted file mode 100644
index be47d17..0000000
--- a/src/java/org/apache/cassandra/cql3/statements/Selectable.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.cassandra.cql3.statements;
-
-import java.util.List;
-
-import org.apache.cassandra.cql3.ColumnIdentifier;
-import org.apache.cassandra.cql3.functions.FunctionName;
-
-public interface Selectable
-{
-    public static class WritetimeOrTTL implements Selectable
-    {
-        public final ColumnIdentifier id;
-        public final boolean isWritetime;
-
-        public WritetimeOrTTL(ColumnIdentifier id, boolean isWritetime)
-        {
-            this.id = id;
-            this.isWritetime = isWritetime;
-        }
-
-        @Override
-        public String toString()
-        {
-            return (isWritetime ? "writetime" : "ttl") + "(" + id + ")";
-        }
-    }
-
-    public static class WithFunction implements Selectable
-    {
-        public final FunctionName functionName;
-        public final List<Selectable> args;
-
-        public WithFunction(FunctionName functionName, List<Selectable> args)
-        {
-            this.functionName = functionName;
-            this.args = args;
-        }
-
-        @Override
-        public String toString()
-        {
-            StringBuilder sb = new StringBuilder();
-            sb.append(functionName).append("(");
-            for (int i = 0; i < args.size(); i++)
-            {
-                if (i > 0)
-                    sb.append(", ");
-                sb.append(args.get(i));
-            }
-            return sb.append(")").toString();
-        }
-    }
-
-    public static class WithFieldSelection implements Selectable
-    {
-        public final Selectable selected;
-        public final ColumnIdentifier field;
-
-        public WithFieldSelection(Selectable selected, ColumnIdentifier field)
-        {
-            this.selected = selected;
-            this.field = field;
-        }
-
-        @Override
-        public String toString()
-        {
-            return String.format("%s.%s", selected, field);
-        }
-    }
-}


Mime
View raw message