cassandra-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ble...@apache.org
Subject [3/5] cassandra git commit: Add support for arithmetic operators
Date Mon, 21 Nov 2016 17:55:49 GMT
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java b/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
new file mode 100644
index 0000000..1f115a9
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/functions/OperationFcts.java
@@ -0,0 +1,380 @@
+/*
+ * 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.functions;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.apache.cassandra.config.SchemaConstants;
+import org.apache.cassandra.db.marshal.*;
+import org.apache.cassandra.exceptions.OperationExecutionException;
+import org.apache.cassandra.transport.ProtocolVersion;
+
+/**
+ * Operation functions (Mathematics).
+ *
+ */
+public final class OperationFcts
+{
+    private static enum OPERATION
+    {
+        ADDITION('+', "_add")
+        {
+            protected ByteBuffer execute(NumberType<?> resultType,
+                                         NumberType<?> leftType,
+                                         ByteBuffer left,
+                                         NumberType<?> rightType,
+                                         ByteBuffer right)
+            {
+                return resultType.add(leftType, left, rightType, right);
+            }
+        },
+        SUBSTRACTION('-', "_substract")
+        {
+            protected ByteBuffer execute(NumberType<?> resultType,
+                                         NumberType<?> leftType,
+                                         ByteBuffer left,
+                                         NumberType<?> rightType,
+                                         ByteBuffer right)
+            {
+                return resultType.substract(leftType, left, rightType, right);
+            }
+        },
+        MULTIPLICATION('*', "_multiply")
+        {
+            protected ByteBuffer execute(NumberType<?> resultType,
+                                         NumberType<?> leftType,
+                                         ByteBuffer left,
+                                         NumberType<?> rightType,
+                                         ByteBuffer right)
+            {
+                return resultType.multiply(leftType, left, rightType, right);
+            }
+        },
+        DIVISION('/', "_divide")
+        {
+            protected ByteBuffer execute(NumberType<?> resultType,
+                                         NumberType<?> leftType,
+                                         ByteBuffer left,
+                                         NumberType<?> rightType,
+                                         ByteBuffer right)
+            {
+                return resultType.divide(leftType, left, rightType, right);
+            }
+        },
+        MODULO('%', "_modulo")
+        {
+            protected ByteBuffer execute(NumberType<?> resultType,
+                                         NumberType<?> leftType,
+                                         ByteBuffer left,
+                                         NumberType<?> rightType,
+                                         ByteBuffer right)
+            {
+                return resultType.mod(leftType, left, rightType, right);
+            }
+        };
+
+        /**
+         * The operator symbol.
+         */
+        private final char symbol;
+
+        /**
+         * The name of the function associated to this operation
+         */
+        private final String functionName;
+
+        private OPERATION(char symbol, String functionName)
+        {
+            this.symbol = symbol;
+            this.functionName = functionName;
+        }
+
+        /**
+         * Executes the operation between the specified operand.
+         *
+         * @param resultType the result ype of the operation
+         * @param leftType the type of the left operand
+         * @param left the left operand
+         * @param rightType the type of the right operand
+         * @param right the right operand
+         * @return the operation result
+         */
+        protected abstract ByteBuffer execute(NumberType<?> resultType,
+                                              NumberType<?> leftType,
+                                              ByteBuffer left,
+                                              NumberType<?> rightType,
+                                              ByteBuffer right);
+
+        /**
+         * Returns the {@code OPERATOR} associated to the specified function.
+         * @param functionName the function name
+         * @return the {@code OPERATOR} associated to the specified function
+         */
+        public static OPERATION fromFunctionName(String functionName)
+        {
+            for (OPERATION operator : values())
+            {
+                if (operator.functionName.equals(functionName))
+                    return operator;
+            }
+            return null;
+        }
+
+        /**
+         * Returns the {@code OPERATOR} with the specified symbol.
+         * @param functionName the function name
+         * @return the {@code OPERATOR} with the specified symbol
+         */
+        public static OPERATION fromSymbol(char symbol)
+        {
+            for (OPERATION operator : values())
+            {
+                if (operator.symbol == symbol)
+                    return operator;
+            }
+            return null;
+        }
+    }
+
+    /**
+     * The name of the function used to perform negations
+     */
+    public static final String NEGATION_FUNCTION_NAME = "_negate";
+
+    public static Collection<Function> all()
+    {
+        List<Function> functions = new ArrayList<>();
+
+        final NumberType<?>[] numericTypes = new NumberType[] { ByteType.instance,
+                                                                ShortType.instance,
+                                                                Int32Type.instance,
+                                                                LongType.instance,
+                                                                FloatType.instance,
+                                                                DoubleType.instance,
+                                                                DecimalType.instance,
+                                                                IntegerType.instance,
+                                                                CounterColumnType.instance};
+
+        for (NumberType<?> left : numericTypes)
+        {
+            for (NumberType<?> right : numericTypes)
+            {
+                NumberType<?> returnType = returnType(left, right);
+                functions.add(new OperationFunction(returnType, left, OPERATION.ADDITION, right));
+                functions.add(new OperationFunction(returnType, left, OPERATION.SUBSTRACTION, right));
+                functions.add(new OperationFunction(returnType, left, OPERATION.MULTIPLICATION, right));
+                functions.add(new OperationFunction(returnType, left, OPERATION.DIVISION, right));
+                functions.add(new OperationFunction(returnType, left, OPERATION.MODULO, right));
+            }
+            functions.add(new NegationFunction(left));
+        }
+        return functions;
+    }
+
+    /**
+     * Checks if the function with the specified name is an operation.
+     *
+     * @param function the function name
+     * @return {@code true} if the function is an operation, {@code false} otherwise.
+     */
+    public static boolean isOperation(FunctionName function)
+    {
+        return SchemaConstants.SYSTEM_KEYSPACE_NAME.equals(function.keyspace)
+                && OPERATION.fromFunctionName(function.name) != null;
+    }
+
+    /**
+     * Checks if the function with the specified name is a negation.
+     *
+     * @param function the function name
+     * @return {@code true} if the function is an negation, {@code false} otherwise.
+     */
+    public static boolean isNegation(FunctionName function)
+    {
+        return SchemaConstants.SYSTEM_KEYSPACE_NAME.equals(function.keyspace)&& NEGATION_FUNCTION_NAME.equals(function.name);
+    }
+
+    /**
+     * Returns the operator associated to the specified function.
+     *
+     * @return the operator associated to the specified function.
+     */
+    public static char getOperator(FunctionName function)
+    {
+        assert SchemaConstants.SYSTEM_KEYSPACE_NAME.equals(function.keyspace);
+        return OPERATION.fromFunctionName(function.name).symbol;
+    }
+
+    /**
+     * Returns the name of the function associated to the specified operator.
+     *
+     * @param operator the operator
+     * @return the name of the function associated to the specified operator
+     */
+    public static FunctionName getFunctionNameFromOperator(char operator)
+    {
+        return FunctionName.nativeFunction(OPERATION.fromSymbol(operator).functionName);
+    }
+
+    /**
+     * Determine the return type for an operation between the specified types.
+     *
+     * @param left the type of the left operand
+     * @param right the type of the right operand
+     * @return the return type for an operation between the specified types
+     */
+    private static NumberType<?> returnType(NumberType<?> left, NumberType<?> right)
+    {
+        boolean isFloatingPoint = left.isFloatingPoint() || right.isFloatingPoint();
+        int size = Math.max(size(left), size(right));
+        return isFloatingPoint
+             ? floatPointType(size)
+             : integerType(size);
+    }
+
+    /**
+     * Returns the number of bytes used to represent a value of this type.
+     * @return the number of bytes used to represent a value of this type or {@code Integer.MAX} if the number of bytes
+     * is not limited.
+     */
+    private static int size(NumberType<?> type)
+    {
+        int size = type.valueLengthIfFixed();
+
+        if (size > 0)
+            return size;
+
+        if (type.isCounter())
+            return LongType.instance.valueLengthIfFixed();
+
+        return Integer.MAX_VALUE;
+    }
+
+    private static NumberType<?> floatPointType(int size)
+    {
+        switch (size)
+        {
+            case 4: return FloatType.instance;
+            case 8: return DoubleType.instance;
+            default: return DecimalType.instance;
+        }
+    }
+
+    private static NumberType<?> integerType(int size)
+    {
+        switch (size)
+        {
+            case 1: return ByteType.instance;
+            case 2: return ShortType.instance;
+            case 4: return Int32Type.instance;
+            case 8: return LongType.instance;
+            default: return IntegerType.instance;
+        }
+    }
+
+    /**
+     * The class must not be instantiated.
+     */
+    private OperationFcts()
+    {
+    }
+
+    /**
+     * Function that execute operations.
+     */
+    private static class OperationFunction extends NativeScalarFunction
+    {
+        private final OPERATION operation;
+
+        public OperationFunction(NumberType<?> returnType,
+                                 NumberType<?> left,
+                                 OPERATION operation,
+                                 NumberType<?> right)
+        {
+            super(operation.functionName, returnType, left, right);
+            this.operation = operation;
+        }
+
+        @Override
+        public final String columnName(List<String> columnNames)
+        {
+            return String.format("%s %s %s", columnNames.get(0), getOperator(), columnNames.get(1));
+        }
+
+        public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
+        {
+            ByteBuffer left = parameters.get(0);
+            ByteBuffer right = parameters.get(1);
+            if (left == null || !left.hasRemaining() || right == null || !right.hasRemaining())
+                return null;
+
+            NumberType<?> leftType = (NumberType<?>) argTypes().get(0);
+            NumberType<?> rightType = (NumberType<?>) argTypes().get(1);
+            NumberType<?> resultType = (NumberType<?>) returnType();
+
+            try
+            {
+                return operation.execute(resultType, leftType, left, rightType, right);
+            }
+            catch (Exception e)
+            {
+                throw OperationExecutionException.create(getOperator(), argTypes, e);
+            }
+        }
+
+        /**
+         * Returns the operator symbol.
+         * @return the operator symbol
+         */
+        private char getOperator()
+        {
+            return operation.symbol;
+        }
+    }
+
+    /**
+     * Function that negate a number.
+     */
+    private static class NegationFunction extends NativeScalarFunction
+    {
+        public NegationFunction(NumberType<?> inputType)
+        {
+            super(NEGATION_FUNCTION_NAME, inputType, inputType);
+        }
+
+        @Override
+        public final String columnName(List<String> columnNames)
+        {
+            return String.format("-%s", columnNames.get(0));
+        }
+
+        public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
+        {
+            ByteBuffer input = parameters.get(0);
+            if (input == null)
+                return null;
+
+            NumberType<?> inputType = (NumberType<?>) argTypes().get(0);
+
+            return inputType.negate(input);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/CollectionFactory.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/CollectionFactory.java b/src/java/org/apache/cassandra/cql3/selection/CollectionFactory.java
new file mode 100644
index 0000000..de5fd93
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/CollectionFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.selection.Selector.Factory;
+import org.apache.cassandra.db.marshal.AbstractType;
+
+/**
+ * A base <code>Selector.Factory</code> for collections or tuples.
+ */
+abstract class CollectionFactory extends Factory
+{
+    /**
+     * The collection or tuple type.
+     */
+    private final AbstractType<?> type;
+
+    /**
+     * The collection or tuple element factories.
+     */
+    private final SelectorFactories factories;
+
+    public CollectionFactory(AbstractType<?> type, SelectorFactories factories)
+    {
+        this.type = type;
+        this.factories = factories;
+    }
+
+    protected final AbstractType<?> getReturnType()
+    {
+        return type;
+    }
+
+    @Override
+    public final void addFunctionsTo(List<Function> functions)
+    {
+        factories.addFunctionsTo(functions);
+    }
+
+    @Override
+    public final boolean isAggregateSelectorFactory()
+    {
+        return factories.doesAggregation();
+    }
+
+    @Override
+    public final boolean isWritetimeSelectorFactory()
+    {
+        return factories.containsWritetimeSelectorFactory();
+    }
+
+    @Override
+    public final boolean isTTLSelectorFactory()
+    {
+        return factories.containsTTLSelectorFactory();
+    }
+
+    protected final void addColumnMapping(SelectionColumnMapping mapping, ColumnSpecification resultsColumn)
+    {
+        SelectionColumnMapping tmpMapping = SelectionColumnMapping.newMapping();
+        for (Factory factory : factories)
+           factory.addColumnMapping(tmpMapping, resultsColumn);
+
+        if (tmpMapping.getMappings().get(resultsColumn).isEmpty())
+            // add a null mapping for cases where the collection is empty
+            mapping.addMapping(resultsColumn, (ColumnDefinition)null);
+        else
+            // collate the mapped columns from the child factories & add those
+            mapping.addMapping(resultsColumn, tmpMapping.getMappings().values());
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/ForwardingFactory.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/ForwardingFactory.java b/src/java/org/apache/cassandra/cql3/selection/ForwardingFactory.java
new file mode 100644
index 0000000..50b3ded
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/ForwardingFactory.java
@@ -0,0 +1,90 @@
+/*
+ * 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.ColumnSpecification;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.selection.Selector.Factory;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+
+/**
+ * A <code>Selector.Factory</code> which forwards all its method calls to another factory.
+ * Subclasses should override one or more methods to modify the behavior of the backing factory as desired per
+ * the decorator pattern.
+ */
+abstract class ForwardingFactory extends Factory
+{
+    /**
+     * Returns the backing delegate instance that methods are forwarded to.
+     */
+    protected abstract Factory delegate();
+
+    public Selector newInstance(QueryOptions options) throws InvalidRequestException
+    {
+        return delegate().newInstance(options);
+    }
+
+    protected String getColumnName()
+    {
+        return delegate().getColumnName();
+    }
+
+    protected AbstractType<?> getReturnType()
+    {
+        return delegate().getReturnType();
+    }
+
+    protected void addColumnMapping(SelectionColumnMapping mapping, ColumnSpecification resultsColumn)
+    {
+        delegate().addColumnMapping(mapping, resultsColumn);
+    }
+
+    @Override
+    public void addFunctionsTo(List<Function> functions)
+    {
+        delegate().addFunctionsTo(functions);
+    }
+
+    @Override
+    public boolean isAggregateSelectorFactory()
+    {
+        return delegate().isAggregateSelectorFactory();
+    }
+
+    @Override
+    public boolean isWritetimeSelectorFactory()
+    {
+        return delegate().isWritetimeSelectorFactory();
+    }
+
+    @Override
+    public boolean isTTLSelectorFactory()
+    {
+        return delegate().isTTLSelectorFactory();
+    }
+
+    @Override
+    public boolean isSimpleSelectorFactory(int index)
+    {
+        return delegate().isSimpleSelectorFactory(index);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/ListSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/ListSelector.java b/src/java/org/apache/cassandra/cql3/selection/ListSelector.java
new file mode 100644
index 0000000..940bd9c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/ListSelector.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 java.util.ArrayList;
+import java.util.List;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.Lists;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.serializers.CollectionSerializer;
+import org.apache.cassandra.transport.ProtocolVersion;
+
+/**
+ * <code>Selector</code> for literal list (e.g. [min(value), max(value), count(value)]).
+ *
+ */
+final class ListSelector extends Selector
+{
+    /**
+     * The list type.
+     */
+    private final AbstractType<?> type;
+
+    /**
+     * The list elements
+     */
+    private final List<Selector> elements;
+
+    public static Factory newFactory(final AbstractType<?> type, final SelectorFactories factories)
+    {
+        return new CollectionFactory(type, factories)
+        {
+            protected String getColumnName()
+            {
+                return Lists.listToString(factories, Factory::getColumnName);
+            }
+
+            public Selector newInstance(final QueryOptions options)
+            {
+                return new ListSelector(type, factories.newInstances(options));
+            }
+        };
+    }
+
+    public void addInput(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).addInput(protocolVersion, rs);
+    }
+
+    public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
+    {
+        List<ByteBuffer> buffers = new ArrayList<>(elements.size());
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            buffers.add(elements.get(i).getOutput(protocolVersion));
+        }
+        return CollectionSerializer.pack(buffers, buffers.size(), protocolVersion);
+    }
+
+    public void reset()
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).reset();
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return Lists.listToString(elements);
+    }
+
+    private ListSelector(AbstractType<?> type, List<Selector> elements)
+    {
+        this.type = type;
+        this.elements = elements;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/MapSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/MapSelector.java b/src/java/org/apache/cassandra/cql3/selection/MapSelector.java
new file mode 100644
index 0000000..8bbae8c
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/MapSelector.java
@@ -0,0 +1,195 @@
+/*
+ * 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.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.Maps;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.MapType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.serializers.CollectionSerializer;
+import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.utils.Pair;
+
+/**
+ * <code>Selector</code> for literal map (e.g. {'min' : min(value), 'max' : max(value), 'count' : count(value)}).
+ *
+ */
+final class MapSelector extends Selector
+{
+    /**
+     * The map type.
+     */
+    private final MapType<?, ?> type;
+
+    /**
+     * The map elements
+     */
+    private final List<Pair<Selector, Selector>> elements;
+
+    public static Factory newFactory(final AbstractType<?> type, final List<Pair<Factory, Factory>> factories)
+    {
+        return new Factory()
+        {
+            protected String getColumnName()
+            {
+                return Maps.mapToString(factories, Factory::getColumnName);
+            }
+
+            protected AbstractType<?> getReturnType()
+            {
+                return type;
+            }
+
+            protected final void addColumnMapping(SelectionColumnMapping mapping, ColumnSpecification resultsColumn)
+            {
+                SelectionColumnMapping tmpMapping = SelectionColumnMapping.newMapping();
+                for (Pair<Factory, Factory> entry : factories)
+                {
+                    entry.left.addColumnMapping(tmpMapping, resultsColumn);
+                    entry.right.addColumnMapping(tmpMapping, resultsColumn);
+                }
+
+                if (tmpMapping.getMappings().get(resultsColumn).isEmpty())
+                    // add a null mapping for cases where the collection is empty
+                    mapping.addMapping(resultsColumn, (ColumnDefinition)null);
+                else
+                    // collate the mapped columns from the child factories & add those
+                    mapping.addMapping(resultsColumn, tmpMapping.getMappings().values());
+            }
+
+            public Selector newInstance(final QueryOptions options)
+            {
+                return new MapSelector(type,
+                                        factories.stream()
+                                                 .map(p -> Pair.create(p.left.newInstance(options),
+                                                                       p.right.newInstance(options)))
+                                                 .collect(Collectors.toList()));
+            }
+
+            @Override
+            public boolean isAggregateSelectorFactory()
+            {
+                for (Pair<Factory, Factory> entry : factories)
+                {
+                    if (entry.left.isAggregateSelectorFactory() || entry.right.isAggregateSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void addFunctionsTo(List<Function> functions)
+            {
+                for (Pair<Factory, Factory> entry : factories)
+                {
+                    entry.left.addFunctionsTo(functions);
+                    entry.right.addFunctionsTo(functions);
+                }
+            }
+
+            @Override
+            public boolean isWritetimeSelectorFactory()
+            {
+                for (Pair<Factory, Factory> entry : factories)
+                {
+                    if (entry.left.isWritetimeSelectorFactory() || entry.right.isWritetimeSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+
+            @Override
+            public boolean isTTLSelectorFactory()
+            {
+                for (Pair<Factory, Factory> entry : factories)
+                {
+                    if (entry.left.isTTLSelectorFactory() || entry.right.isTTLSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+        };
+    }
+
+    public void addInput(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            Pair<Selector, Selector> pair = elements.get(i);
+            pair.left.addInput(protocolVersion, rs);
+            pair.right.addInput(protocolVersion, rs);
+        }
+    }
+
+    public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
+    {
+        Map<ByteBuffer, ByteBuffer> map = new TreeMap<>(type.getKeysType());
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            Pair<Selector, Selector> pair = elements.get(i);
+            map.put(pair.left.getOutput(protocolVersion), pair.right.getOutput(protocolVersion));
+        }
+
+        List<ByteBuffer> buffers = new ArrayList<>(elements.size() * 2);
+        for (Map.Entry<ByteBuffer, ByteBuffer> entry : map.entrySet())
+        {
+            buffers.add(entry.getKey());
+            buffers.add(entry.getValue());
+        }
+        return CollectionSerializer.pack(buffers, elements.size(), protocolVersion);
+    }
+
+    public void reset()
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            Pair<Selector, Selector> pair = elements.get(i);
+            pair.left.reset();
+            pair.right.reset();
+        }
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return Maps.mapToString(elements);
+    }
+
+    private MapSelector(AbstractType<?> type, List<Pair<Selector, Selector>> elements)
+    {
+        this.type = (MapType<?, ?>) type;
+        this.elements = elements;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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
index c05cdaa..15e0210 100644
--- a/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/ScalarFunctionSelector.java
@@ -28,15 +28,6 @@ import org.apache.cassandra.transport.ProtocolVersion;
 
 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(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
     {
         for (int i = 0, m = argSelectors.size(); i < m; i++)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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
index 80e2ae8..20719ea 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selectable.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selectable.java
@@ -18,17 +18,22 @@
  */
 package org.apache.cassandra.cql3.selection;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.text.StrBuilder;
+
 import org.apache.cassandra.config.CFMetaData;
 import org.apache.cassandra.config.ColumnDefinition;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.cql3.functions.*;
+import org.apache.cassandra.cql3.selection.Selector.Factory;
 import org.apache.cassandra.db.marshal.*;
 import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.utils.Pair;
+
+import static org.apache.cassandra.cql3.selection.SelectorFactories.createFactoriesAndCollectColumnDefinitions;
+import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
 
 public interface Selectable extends AssignmentTestable
 {
@@ -154,7 +159,7 @@ public interface Selectable extends AssignmentTestable
         @Override
         public String toString()
         {
-            return rawTerm.toString();
+            return rawTerm.getText();
         }
 
         public static class Raw extends Selectable.Raw
@@ -244,11 +249,7 @@ public interface Selectable extends AssignmentTestable
         @Override
         public String toString()
         {
-            return new StrBuilder().append(function.name())
-                                   .append("(")
-                                   .appendWithSeparators(args, ", ")
-                                   .append(")")
-                                   .toString();
+            return function.columnName(args.stream().map(Object::toString).collect(Collectors.toList()));
         }
 
         public Selector.Factory newSelectorFactory(CFMetaData cfm, AbstractType<?> expectedType, List<ColumnDefinition> defs, VariableSpecifications boundNames)
@@ -279,6 +280,18 @@ public interface Selectable extends AssignmentTestable
                                Collections.emptyList());
             }
 
+            public static Raw newOperation(char operator, Selectable.Raw left, Selectable.Raw right)
+            {
+                return new Raw(OperationFcts.getFunctionNameFromOperator(operator),
+                               Arrays.asList(left, right));
+            }
+
+            public static Raw newNegation(Selectable.Raw arg)
+            {
+                return new Raw(FunctionName.nativeFunction(OperationFcts.NEGATION_FUNCTION_NAME),
+                               Collections.singletonList(arg));
+            }
+
             public Selectable prepare(CFMetaData cfm)
             {
                 List<Selectable> preparedArgs = new ArrayList<>(args.size());
@@ -433,7 +446,16 @@ public interface Selectable extends AssignmentTestable
 
         public Selector.Factory newSelectorFactory(CFMetaData cfm, AbstractType<?> expectedType, List<ColumnDefinition> defs, VariableSpecifications boundNames)
         {
-            Selector.Factory factory = selected.newSelectorFactory(cfm, null, defs, boundNames);
+            AbstractType<?> expectedUdtType = null;
+
+            // If the UDT is between parentheses, we know that it is not a tuple with a single element.
+            if (selected instanceof BetweenParenthesesOrWithTuple)
+            {
+                BetweenParenthesesOrWithTuple betweenParentheses = (BetweenParenthesesOrWithTuple) selected;
+                expectedUdtType = betweenParentheses.selectables.get(0).getExactTypeIfKnown(cfm.ksName);
+            }
+
+            Selector.Factory factory = selected.newSelectorFactory(cfm, expectedUdtType, defs, boundNames);
             AbstractType<?> type = factory.getColumnSpecification(cfm).type;
             if (!type.isUDT())
             {
@@ -485,4 +507,609 @@ public interface Selectable extends AssignmentTestable
             }
         }
     }
+
+    /**
+     * {@code Selectable} for {@code Selectable} between parentheses or tuples.
+     * <p>The parser cannot differentiate between a single element between parentheses or a single element tuple.
+     * By consequence, we are forced to wait until the type is known to be able to differentiate them.</p>
+     */
+    public static class BetweenParenthesesOrWithTuple implements Selectable
+    {
+        /**
+         * The tuple elements or the element between the parentheses
+         */
+        private final List<Selectable> selectables;
+
+        public BetweenParenthesesOrWithTuple(List<Selectable> selectables)
+        {
+            this.selectables = selectables;
+        }
+
+        @Override
+        public TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+        {
+            if (selectables.size() == 1 && !receiver.type.isTuple())
+                return selectables.get(0).testAssignment(keyspace, receiver);
+
+            return Tuples.testTupleAssignment(receiver, selectables);
+        }
+
+        @Override
+        public Factory newSelectorFactory(CFMetaData cfm,
+                                          AbstractType<?> expectedType,
+                                          List<ColumnDefinition> defs,
+                                          VariableSpecifications boundNames)
+        {
+            AbstractType<?> type = getExactTypeIfKnown(cfm.ksName);
+            if (type == null)
+            {
+                type = expectedType;
+                if (type == null)
+                    throw invalidRequest("Cannot infer type for term %s in selection clause (try using a cast to force a type)",
+                                         this);
+            }
+
+            if (selectables.size() == 1 && !type.isTuple())
+                return newBetweenParenthesesSelectorFactory(cfm, expectedType, defs, boundNames);
+
+            return newTupleSelectorFactory(cfm, (TupleType) type, defs, boundNames);
+        }
+
+        private Factory newBetweenParenthesesSelectorFactory(CFMetaData cfm,
+                                                             AbstractType<?> expectedType,
+                                                             List<ColumnDefinition> defs,
+                                                             VariableSpecifications boundNames)
+        {
+            Selectable selectable = selectables.get(0);
+            final Factory factory = selectable.newSelectorFactory(cfm, expectedType, defs, boundNames);
+
+            return new ForwardingFactory()
+            {
+                protected Factory delegate()
+                {
+                    return factory;
+                }
+
+                protected String getColumnName()
+                {
+                    return String.format("(%s)", factory.getColumnName());
+                }
+            };
+        }
+
+        private Factory newTupleSelectorFactory(CFMetaData cfm,
+                                                TupleType tupleType,
+                                                List<ColumnDefinition> defs,
+                                                VariableSpecifications boundNames)
+        {
+            SelectorFactories factories = createFactoriesAndCollectColumnDefinitions(selectables,
+                                                                                     tupleType.allTypes(),
+                                                                                     cfm,
+                                                                                     defs,
+                                                                                     boundNames);
+
+            return TupleSelector.newFactory(tupleType, factories);
+        }
+
+        @Override
+        public AbstractType<?> getExactTypeIfKnown(String keyspace)
+        {
+            // If there is only one element we cannot know if it is an element between parentheses or a tuple
+            // with only one element. By consequence, we need to force the user to specify the type.
+            if (selectables.size() == 1)
+                return null;
+
+            return Tuples.getExactTupleTypeIfKnown(selectables, p -> p.getExactTypeIfKnown(keyspace));
+        }
+
+        @Override
+        public String toString()
+        {
+            return Tuples.tupleToString(selectables);
+        }
+
+        public static class Raw extends Selectable.Raw
+        {
+            private final List<Selectable.Raw> raws;
+
+            public Raw(List<Selectable.Raw> raws)
+            {
+                this.raws = raws;
+            }
+
+            public Selectable prepare(CFMetaData cfm)
+            {
+                return new BetweenParenthesesOrWithTuple(raws.stream().map(p -> p.prepare(cfm)).collect(Collectors.toList()));
+            }
+        }
+    }
+
+    /**
+     * <code>Selectable</code> for literal Lists.
+     */
+    public static class WithList implements Selectable
+    {
+        /**
+         * The list elements
+         */
+        private final List<Selectable> selectables;
+
+        public WithList(List<Selectable> selectables)
+        {
+            this.selectables = selectables;
+        }
+
+        @Override
+        public TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+        {
+            return Lists.testListAssignment(receiver, selectables);
+        }
+
+        @Override
+        public Factory newSelectorFactory(CFMetaData cfm,
+                                          AbstractType<?> expectedType,
+                                          List<ColumnDefinition> defs,
+                                          VariableSpecifications boundNames)
+        {
+            AbstractType<?> type = getExactTypeIfKnown(cfm.ksName);
+            if (type == null)
+            {
+                type = expectedType;
+                if (type == null)
+                    throw invalidRequest("Cannot infer type for term %s in selection clause (try using a cast to force a type)",
+                                         this);
+            }
+
+            ListType<?> listType = (ListType<?>) type;
+
+            List<AbstractType<?>> expectedTypes = new ArrayList<>(selectables.size());
+            for (int i = 0, m = selectables.size(); i < m; i++)
+                expectedTypes.add(listType.getElementsType());
+
+            SelectorFactories factories = createFactoriesAndCollectColumnDefinitions(selectables,
+                                                                                     expectedTypes,
+                                                                                     cfm,
+                                                                                     defs,
+                                                                                     boundNames);
+            return ListSelector.newFactory(type, factories);
+        }
+
+        @Override
+        public AbstractType<?> getExactTypeIfKnown(String keyspace)
+        {
+            return Lists.getExactListTypeIfKnown(selectables, p -> p.getExactTypeIfKnown(keyspace));
+        }
+
+        @Override
+        public String toString()
+        {
+            return Lists.listToString(selectables);
+        }
+
+        public static class Raw extends Selectable.Raw
+        {
+            private final List<Selectable.Raw> raws;
+
+            public Raw(List<Selectable.Raw> raws)
+            {
+                this.raws = raws;
+            }
+
+            public Selectable prepare(CFMetaData cfm)
+            {
+                return new WithList(raws.stream().map(p -> p.prepare(cfm)).collect(Collectors.toList()));
+            }
+        }
+    }
+
+    /**
+     * <code>Selectable</code> for literal Sets.
+     */
+    public static class WithSet implements Selectable
+    {
+        /**
+         * The set elements
+         */
+        private final List<Selectable> selectables;
+
+        public WithSet(List<Selectable> selectables)
+        {
+            this.selectables = selectables;
+        }
+
+        @Override
+        public TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+        {
+            return Sets.testSetAssignment(receiver, selectables);
+        }
+
+        @Override
+        public Factory newSelectorFactory(CFMetaData cfm,
+                                          AbstractType<?> expectedType,
+                                          List<ColumnDefinition> defs,
+                                          VariableSpecifications boundNames)
+        {
+            AbstractType<?> type = getExactTypeIfKnown(cfm.ksName);
+            if (type == null)
+            {
+                type = expectedType;
+                if (type == null)
+                    throw invalidRequest("Cannot infer type for term %s in selection clause (try using a cast to force a type)",
+                                         this);
+            }
+
+            // The parser treats empty Maps as Sets so if the type is a MapType we know that the Map is empty
+            if (type instanceof MapType)
+                return MapSelector.newFactory(type, Collections.emptyList());
+
+            SetType<?> setType = (SetType<?>) type;
+
+            if (setType.getElementsType() == DurationType.instance)
+                throw invalidRequest("Durations are not allowed inside sets: %s", setType.asCQL3Type());
+
+            List<AbstractType<?>> expectedTypes = new ArrayList<>(selectables.size());
+            for (int i = 0, m = selectables.size(); i < m; i++)
+                expectedTypes.add(setType.getElementsType());
+
+            SelectorFactories factories = createFactoriesAndCollectColumnDefinitions(selectables,
+                                                                                     expectedTypes,
+                                                                                     cfm,
+                                                                                     defs,
+                                                                                     boundNames);
+
+            return SetSelector.newFactory(type, factories);
+        }
+
+        @Override
+        public AbstractType<?> getExactTypeIfKnown(String keyspace)
+        {
+            return Sets.getExactSetTypeIfKnown(selectables, p -> p.getExactTypeIfKnown(keyspace));
+        }
+
+        @Override
+        public String toString()
+        {
+            return Sets.setToString(selectables);
+        }
+
+        public static class Raw extends Selectable.Raw
+        {
+            private final List<Selectable.Raw> raws;
+
+            public Raw(List<Selectable.Raw> raws)
+            {
+                this.raws = raws;
+            }
+
+            public Selectable prepare(CFMetaData cfm)
+            {
+                return new WithSet(raws.stream().map(p -> p.prepare(cfm)).collect(Collectors.toList()));
+            }
+        }
+    }
+
+    /**
+     * {@code Selectable} for literal Maps or UDTs.
+     * <p>The parser cannot differentiate between a Map or a UDT in the selection cause because a
+     * {@code ColumnDefinition} is equivalent to a {@code FieldIdentifier} from a syntax point of view.
+     * By consequence, we are forced to wait until the type is known to be able to differentiate them.</p>
+     */
+    public static class WithMapOrUdt implements Selectable
+    {
+        /**
+         * The column family metadata. We need to store them to be able to build the proper data once the type has been
+         * identified.
+         */
+        private final CFMetaData cfm;
+
+        /**
+         * The Map or UDT raw elements.
+         */
+        private final List<Pair<Selectable.Raw, Selectable.Raw>> raws;
+
+        public WithMapOrUdt(CFMetaData cfm, List<Pair<Selectable.Raw, Selectable.Raw>> raws)
+        {
+            this.cfm = cfm;
+            this.raws = raws;
+        }
+
+        @Override
+        public TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+        {
+            return receiver.type.isUDT() ? UserTypes.testUserTypeAssignment(receiver, getUdtFields((UserType) receiver.type))
+                                         : Maps.testMapAssignment(receiver, getMapEntries(cfm));
+        }
+
+        @Override
+        public Factory newSelectorFactory(CFMetaData cfm,
+                                          AbstractType<?> expectedType,
+                                          List<ColumnDefinition> defs,
+                                          VariableSpecifications boundNames)
+        {
+            AbstractType<?> type = getExactTypeIfKnown(cfm.ksName);
+            if (type == null)
+            {
+                type = expectedType;
+                if (type == null)
+                    throw invalidRequest("Cannot infer type for term %s in selection clause (try using a cast to force a type)",
+                                         this);
+            }
+
+            if (type.isUDT())
+                return newUdtSelectorFactory(cfm, expectedType, defs, boundNames);
+
+            return newMapSelectorFactory(cfm, defs, boundNames, type);
+        }
+
+        private Factory newMapSelectorFactory(CFMetaData cfm,
+                                              List<ColumnDefinition> defs,
+                                              VariableSpecifications boundNames,
+                                              AbstractType<?> type)
+        {
+            MapType<?, ?> mapType = (MapType<?, ?>) type;
+
+            if (mapType.getKeysType() == DurationType.instance)
+                throw invalidRequest("Durations are not allowed as map keys: %s", mapType.asCQL3Type());
+
+            return MapSelector.newFactory(type, getMapEntries(cfm).stream()
+                                                                  .map(p -> Pair.create(p.left.newSelectorFactory(cfm, mapType.getKeysType(), defs, boundNames),
+                                                                                        p.right.newSelectorFactory(cfm, mapType.getValuesType(), defs, boundNames)))
+                                                                  .collect(Collectors.toList()));
+        }
+
+        private Factory newUdtSelectorFactory(CFMetaData cfm,
+                                              AbstractType<?> expectedType,
+                                              List<ColumnDefinition> defs,
+                                              VariableSpecifications boundNames)
+        {
+            UserType ut = (UserType) expectedType;
+            Map<FieldIdentifier, Factory> factories = new LinkedHashMap<>(ut.size());
+
+            for (Pair<Selectable.Raw, Selectable.Raw> raw : raws)
+            {
+                if (!(raw.left instanceof RawIdentifier))
+                    throw invalidRequest("%s is not a valid field identifier of type %s ",
+                                         raw.left,
+                                         ut.getNameAsString());
+
+                FieldIdentifier fieldName = ((RawIdentifier) raw.left).toFieldIdentifier();
+                int fieldPosition = ut.fieldPosition(fieldName);
+
+                if (fieldPosition == -1)
+                    throw invalidRequest("Unknown field '%s' in value of user defined type %s",
+                                         fieldName,
+                                         ut.getNameAsString());
+
+                AbstractType<?> fieldType = ut.fieldType(fieldPosition);
+                factories.put(fieldName,
+                              raw.right.prepare(cfm).newSelectorFactory(cfm, fieldType, defs, boundNames));
+            }
+
+            return UserTypeSelector.newFactory(expectedType, factories);
+        }
+
+        @Override
+        public AbstractType<?> getExactTypeIfKnown(String keyspace)
+        {
+            // Lets force the user to specify the type.
+            return null;
+        }
+
+        @Override
+        public String toString()
+        {
+            return raws.stream()
+                       .map(p -> String.format("%s: %s",
+                                               p.left instanceof RawIdentifier ? p.left : p.left.prepare(cfm),
+                                               p.right.prepare(cfm)))
+                       .collect(Collectors.joining(", ", "{", "}"));
+        }
+
+        private List<Pair<Selectable, Selectable>> getMapEntries(CFMetaData cfm)
+        {
+            return raws.stream()
+                       .map(p -> Pair.create(p.left.prepare(cfm), p.right.prepare(cfm)))
+                       .collect(Collectors.toList());
+        }
+
+        private Map<FieldIdentifier, Selectable> getUdtFields(UserType ut)
+        {
+            Map<FieldIdentifier, Selectable> fields = new LinkedHashMap<>(ut.size());
+
+            for (Pair<Selectable.Raw, Selectable.Raw> raw : raws)
+            {
+                if (!(raw.left instanceof RawIdentifier))
+                    throw invalidRequest("%s is not a valid field identifier of type %s ",
+                                         raw.left,
+                                         ut.getNameAsString());
+
+                FieldIdentifier fieldName = ((RawIdentifier) raw.left).toFieldIdentifier();
+                int fieldPosition = ut.fieldPosition(fieldName);
+
+                if (fieldPosition == -1)
+                    throw invalidRequest("Unknown field '%s' in value of user defined type %s",
+                                         fieldName,
+                                         ut.getNameAsString());
+
+                fields.put(fieldName, raw.right.prepare(cfm));
+            }
+
+            return fields;
+        }
+
+        public static class Raw extends Selectable.Raw
+        {
+            private final List<Pair<Selectable.Raw, Selectable.Raw>> raws;
+
+            public Raw(List<Pair<Selectable.Raw, Selectable.Raw>> raws)
+            {
+                this.raws = raws;
+            }
+
+            public Selectable prepare(CFMetaData cfm)
+            {
+                return new WithMapOrUdt(cfm, raws);
+            }
+        }
+    }
+
+    /**
+     * <code>Selectable</code> for type hints (e.g. (int) ?).
+     */
+    public static class WithTypeHint implements Selectable
+    {
+
+        /**
+         * The name of the type as specified in the query.
+         */
+        private final String typeName;
+
+        /**
+         * The type specified by the hint.
+         */
+        private final AbstractType<?> type;
+
+       /**
+         * The selectable to which the hint should be applied.
+         */
+        private final Selectable selectable;
+
+        public WithTypeHint(String typeName, AbstractType<?> type, Selectable selectable)
+        {
+            this.typeName = typeName;
+            this.type = type;
+            this.selectable = selectable;
+        }
+
+        @Override
+        public TestResult testAssignment(String keyspace, ColumnSpecification receiver)
+        {
+            if (receiver.type.equals(type))
+                return AssignmentTestable.TestResult.EXACT_MATCH;
+            else if (receiver.type.isValueCompatibleWith(type))
+                return AssignmentTestable.TestResult.WEAKLY_ASSIGNABLE;
+            else
+                return AssignmentTestable.TestResult.NOT_ASSIGNABLE;
+        }
+
+        @Override
+        public Factory newSelectorFactory(CFMetaData cfm,
+                                          AbstractType<?> expectedType,
+                                          List<ColumnDefinition> defs,
+                                          VariableSpecifications boundNames)
+        {
+            final ColumnSpecification receiver = new ColumnSpecification(cfm.ksName, cfm.cfName, new ColumnIdentifier(toString(), true), type);
+
+            if (!selectable.testAssignment(cfm.ksName, receiver).isAssignable())
+                throw new InvalidRequestException(String.format("Cannot assign value %s to %s of type %s", this, receiver.name, receiver.type.asCQL3Type()));
+
+            final Factory factory = selectable.newSelectorFactory(cfm, type, defs, boundNames);
+
+            return new ForwardingFactory()
+            {
+                protected Factory delegate()
+                {
+                    return factory;
+                }
+
+                protected AbstractType<?> getReturnType()
+                {
+                    return type;
+                }
+
+                protected String getColumnName()
+                {
+                    return String.format("(%s)%s", typeName, factory.getColumnName());
+                }
+            };
+        }
+
+        @Override
+        public AbstractType<?> getExactTypeIfKnown(String keyspace)
+        {
+            return type;
+        }
+
+        @Override
+        public String toString()
+        {
+            return String.format("(%s)%s", typeName, selectable);
+        }
+
+        public static class Raw extends Selectable.Raw
+        {
+            private final CQL3Type.Raw typeRaw;
+
+            private final Selectable.Raw raw;
+
+            public Raw( CQL3Type.Raw typeRaw, Selectable.Raw raw)
+            {
+                this.typeRaw = typeRaw;
+                this.raw = raw;
+            }
+
+            public Selectable prepare(CFMetaData cfm)
+            {
+                Selectable selectable = raw.prepare(cfm);
+                AbstractType<?> type = this.typeRaw.prepare(cfm.ksName).getType();
+                if (type.isFreezable())
+                    type = type.freeze();
+                return new WithTypeHint(typeRaw.toString(), type, selectable);
+            }
+        }
+    }
+
+    /**
+     * In the selection clause, the parser cannot differentiate between Maps and UDTs as a column identifier and field
+     * identifier have the same syntax. By consequence, we need to wait until the type is known to create the proper
+     * Object: {@code ColumnDefinition} or {@code FieldIdentifier}.
+     */
+    public static final class RawIdentifier extends Selectable.Raw
+    {
+        private final String text;
+
+        private final boolean quoted;
+
+        /**
+         * Creates a {@code RawIdentifier} from an unquoted identifier string.
+         */
+        public static Raw forUnquoted(String text)
+        {
+            return new RawIdentifier(text, false);
+        }
+
+        /**
+         * Creates a {@code RawIdentifier} from a quoted identifier string.
+         */
+        public static Raw forQuoted(String text)
+        {
+            return new RawIdentifier(text, true);
+        }
+
+        private RawIdentifier(String text, boolean quoted)
+        {
+            this.text = text;
+            this.quoted = quoted;
+        }
+
+        @Override
+        public Selectable prepare(CFMetaData cfm)
+        {
+            ColumnDefinition.Raw raw = quoted ? ColumnDefinition.Raw.forQuoted(text)
+                                              : ColumnDefinition.Raw.forUnquoted(text);
+            return raw.prepare(cfm);
+        }
+
+        public FieldIdentifier toFieldIdentifier()
+        {
+            return quoted ? FieldIdentifier.forQuoted(text)
+                          : FieldIdentifier.forUnquoted(text);
+        }
+
+        @Override
+        public String toString()
+        {
+            return text;
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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
index 922b57f..6f83dfc 100644
--- a/src/java/org/apache/cassandra/cql3/selection/Selector.java
+++ b/src/java/org/apache/cassandra/cql3/selection/Selector.java
@@ -172,17 +172,6 @@ public abstract class Selector
     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();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/SetSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/SetSelector.java b/src/java/org/apache/cassandra/cql3/selection/SetSelector.java
new file mode 100644
index 0000000..34de078
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/SetSelector.java
@@ -0,0 +1,106 @@
+/*
+ * 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 java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.Sets;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.SetType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.serializers.CollectionSerializer;
+import org.apache.cassandra.transport.ProtocolVersion;
+
+/**
+ * <code>Selector</code> for literal set (e.g. {min(value), max(value), count(value)}).
+ *
+ */
+final class SetSelector extends Selector
+{
+    /**
+     * The set type.
+     */
+    private final SetType<?> type;
+
+    /**
+     * The set elements
+     */
+    private final List<Selector> elements;
+
+    public static Factory newFactory(final AbstractType<?> type, final SelectorFactories factories)
+    {
+        return new CollectionFactory(type, factories)
+        {
+            protected String getColumnName()
+            {
+                return Sets.setToString(factories, Factory::getColumnName);
+            }
+
+            public Selector newInstance(final QueryOptions options)
+            {
+                return new SetSelector(type, factories.newInstances(options));
+            }
+        };
+    }
+
+    public void addInput(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).addInput(protocolVersion, rs);
+    }
+
+    public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
+    {
+        Set<ByteBuffer> buffers = new TreeSet<>(type.getElementsType());
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            buffers.add(elements.get(i).getOutput(protocolVersion));
+        }
+        return CollectionSerializer.pack(buffers, buffers.size(), protocolVersion);
+    }
+
+    public void reset()
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).reset();
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return Sets.setToString(elements);
+    }
+
+    private SetSelector(AbstractType<?> type, List<Selector> elements)
+    {
+        this.type = (SetType<?>) type;
+        this.elements = elements;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/TupleSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/TupleSelector.java b/src/java/org/apache/cassandra/cql3/selection/TupleSelector.java
new file mode 100644
index 0000000..9f4c381
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/TupleSelector.java
@@ -0,0 +1,101 @@
+/*
+ * 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.QueryOptions;
+import org.apache.cassandra.cql3.Tuples;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.TupleType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.ProtocolVersion;
+
+/**
+ * <code>Selector</code> for literal tuples (e.g. (min(value), max(value), count(value))).
+ *
+ */
+final class TupleSelector extends Selector
+{
+    /**
+     * The tuple type.
+     */
+    private final AbstractType<?> type;
+
+    /**
+     * The tuple elements
+     */
+    private final List<Selector> elements;
+
+    public static Factory newFactory(final AbstractType<?> type, final SelectorFactories factories)
+    {
+        return new CollectionFactory(type, factories)
+        {
+            protected String getColumnName()
+            {
+                return Tuples.tupleToString(factories, Factory::getColumnName);
+            }
+
+            public Selector newInstance(final QueryOptions options)
+            {
+                return new TupleSelector(type, factories.newInstances(options));
+            }
+        };
+    }
+
+    public void addInput(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).addInput(protocolVersion, rs);
+    }
+
+    public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
+    {
+        ByteBuffer[] buffers = new ByteBuffer[elements.size()];
+        for (int i = 0, m = elements.size(); i < m; i++)
+        {
+            buffers[i] = elements.get(i).getOutput(protocolVersion);
+        }
+        return TupleType.buildValue(buffers);
+    }
+
+    public void reset()
+    {
+        for (int i = 0, m = elements.size(); i < m; i++)
+            elements.get(i).reset();
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return Tuples.tupleToString(elements);
+    }
+
+    private TupleSelector(AbstractType<?> type, List<Selector> elements)
+    {
+        this.type = type;
+        this.elements = elements;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/cql3/selection/UserTypeSelector.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/selection/UserTypeSelector.java b/src/java/org/apache/cassandra/cql3/selection/UserTypeSelector.java
new file mode 100644
index 0000000..3c298b5
--- /dev/null
+++ b/src/java/org/apache/cassandra/cql3/selection/UserTypeSelector.java
@@ -0,0 +1,177 @@
+/*
+ * 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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.cql3.ColumnSpecification;
+import org.apache.cassandra.cql3.FieldIdentifier;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.UserTypes;
+import org.apache.cassandra.cql3.functions.Function;
+import org.apache.cassandra.cql3.selection.Selection.ResultSetBuilder;
+import org.apache.cassandra.db.marshal.AbstractType;
+import org.apache.cassandra.db.marshal.TupleType;
+import org.apache.cassandra.db.marshal.UserType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.transport.ProtocolVersion;
+
+/**
+ * <code>Selector</code> for literal map (e.g. {'min' : min(value), 'max' : max(value), 'count' : count(value)}).
+ *
+ */
+final class UserTypeSelector extends Selector
+{
+    /**
+     * The map type.
+     */
+    private final AbstractType<?> type;
+
+    /**
+     * The user type fields
+     */
+    private final Map<FieldIdentifier, Selector> fields;
+
+    public static Factory newFactory(final AbstractType<?> type, final Map<FieldIdentifier, Factory> factories)
+    {
+        return new Factory()
+        {
+            protected String getColumnName()
+            {
+                return UserTypes.userTypeToString(factories, Factory::getColumnName);
+            }
+
+            protected AbstractType<?> getReturnType()
+            {
+                return type;
+            }
+
+            protected final void addColumnMapping(SelectionColumnMapping mapping, ColumnSpecification resultsColumn)
+            {
+                SelectionColumnMapping tmpMapping = SelectionColumnMapping.newMapping();
+                for (Factory factory : factories.values())
+                {
+                    factory.addColumnMapping(tmpMapping, resultsColumn);
+                }
+
+                if (tmpMapping.getMappings().get(resultsColumn).isEmpty())
+                    // add a null mapping for cases where the collection is empty
+                    mapping.addMapping(resultsColumn, (ColumnDefinition)null);
+                else
+                    // collate the mapped columns from the child factories & add those
+                    mapping.addMapping(resultsColumn, tmpMapping.getMappings().values());
+            }
+
+            public Selector newInstance(final QueryOptions options)
+            {
+                Map<FieldIdentifier, Selector> fields = new HashMap<>(factories.size());
+                for (Entry<FieldIdentifier, Factory> factory : factories.entrySet())
+                    fields.put(factory.getKey(), factory.getValue().newInstance(options));
+
+                return new UserTypeSelector(type, fields);
+            }
+
+            @Override
+            public boolean isAggregateSelectorFactory()
+            {
+                for (Factory factory : factories.values())
+                {
+                    if (factory.isAggregateSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+
+            @Override
+            public void addFunctionsTo(List<Function> functions)
+            {
+                for (Factory factory : factories.values())
+                    factory.addFunctionsTo(functions);
+            }
+
+            @Override
+            public boolean isWritetimeSelectorFactory()
+            {
+                for (Factory factory : factories.values())
+                {
+                    if (factory.isWritetimeSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+
+            @Override
+            public boolean isTTLSelectorFactory()
+            {
+                for (Factory factory : factories.values())
+                {
+                    if (factory.isTTLSelectorFactory())
+                        return true;
+                }
+                return false;
+            }
+        };
+    }
+
+    public void addInput(ProtocolVersion protocolVersion, ResultSetBuilder rs) throws InvalidRequestException
+    {
+        for (Selector field : fields.values())
+            field.addInput(protocolVersion, rs);
+    }
+
+    public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
+    {
+        UserType userType = (UserType) type;
+        ByteBuffer[] buffers = new ByteBuffer[userType.size()];
+        for (int i = 0, m = userType.size(); i < m; i++)
+        {
+            Selector selector = fields.get(userType.fieldName(i));
+            if (selector != null)
+                buffers[i] = selector.getOutput(protocolVersion);
+        }
+        return TupleType.buildValue(buffers);
+    }
+
+    public void reset()
+    {
+        for (Selector field : fields.values())
+            field.reset();
+    }
+
+    public AbstractType<?> getType()
+    {
+        return type;
+    }
+
+    @Override
+    public String toString()
+    {
+        return UserTypes.userTypeToString(fields);
+    }
+
+    private UserTypeSelector(AbstractType<?> type, Map<FieldIdentifier, Selector> fields)
+    {
+        this.type = type;
+        this.fields = fields;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/SystemKeyspace.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/SystemKeyspace.java b/src/java/org/apache/cassandra/db/SystemKeyspace.java
index 7f6b6ab..31a461b 100644
--- a/src/java/org/apache/cassandra/db/SystemKeyspace.java
+++ b/src/java/org/apache/cassandra/db/SystemKeyspace.java
@@ -477,6 +477,7 @@ public final class SystemKeyspace
                         .add(BytesConversionFcts.all())
                         .add(AggregateFcts.all())
                         .add(CastFcts.all())
+                        .add(OperationFcts.all())
                         .build();
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index 37a1959..99df8a2 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -319,6 +319,11 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
         return false;
     }
 
+    public boolean isTuple()
+    {
+        return false;
+    }
+
     public boolean isMultiCell()
     {
         return false;
@@ -384,7 +389,7 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
     /**
      * The length of values for this type if all values are of fixed length, -1 otherwise.
      */
-    protected int valueLengthIfFixed()
+    public int valueLengthIfFixed()
     {
         return -1;
     }
@@ -487,9 +492,13 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
 
     public final AssignmentTestable.TestResult testAssignment(String keyspace, ColumnSpecification receiver)
     {
+        return testAssignment(receiver.type);
+    }
+
+    public final AssignmentTestable.TestResult testAssignment(AbstractType<?> receiverType)
+    {
         // We should ignore the fact that the output type is frozen in our comparison as functions do not support
         // frozen types for arguments
-        AbstractType<?> receiverType = receiver.type;
         if (isFreezable() && !isMultiCell())
             receiverType = receiverType.freeze();
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/BooleanType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/BooleanType.java b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
index 1dbd1af..475cae6 100644
--- a/src/java/org/apache/cassandra/db/marshal/BooleanType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BooleanType.java
@@ -97,7 +97,7 @@ public class BooleanType extends AbstractType<Boolean>
     }
 
     @Override
-    protected int valueLengthIfFixed()
+    public int valueLengthIfFixed()
     {
         return 1;
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/ByteType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ByteType.java b/src/java/org/apache/cassandra/db/marshal/ByteType.java
index 55aea8f..517e734 100644
--- a/src/java/org/apache/cassandra/db/marshal/ByteType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ByteType.java
@@ -28,7 +28,7 @@ import org.apache.cassandra.serializers.TypeSerializer;
 import org.apache.cassandra.transport.ProtocolVersion;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
-public class ByteType extends AbstractType<Byte>
+public class ByteType extends NumberType<Byte>
 {
     public static final ByteType instance = new ByteType();
 
@@ -84,8 +84,62 @@ public class ByteType extends AbstractType<Byte>
     }
 
     @Override
+    public int valueLengthIfFixed()
+    {
+        return 1;
+    }
+
+    @Override
     public TypeSerializer<Byte> getSerializer()
     {
         return ByteSerializer.instance;
     }
+
+    @Override
+    public byte toByte(ByteBuffer value)
+    {
+        return ByteBufferUtil.toByte(value);
+    }
+
+    @Override
+    public short toShort(ByteBuffer value)
+    {
+        return toByte(value);
+    }
+
+    @Override
+    protected int toInt(ByteBuffer value)
+    {
+        return toByte(value);
+    }
+
+    public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes((byte) (leftType.toByte(left) + rightType.toByte(right)));
+    }
+
+    public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes((byte) (leftType.toByte(left) - rightType.toByte(right)));
+    }
+
+    public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes((byte) (leftType.toByte(left) * rightType.toByte(right)));
+    }
+
+    public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes((byte) (leftType.toByte(left) / rightType.toByte(right)));
+    }
+
+    public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes((byte) (leftType.toByte(left) % rightType.toByte(right)));
+    }
+
+    public ByteBuffer negate(ByteBuffer input)
+    {
+        return ByteBufferUtil.bytes((byte) -toByte(input));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
index 8bb1a25..8777e0e 100644
--- a/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CounterColumnType.java
@@ -22,13 +22,13 @@ import java.nio.ByteBuffer;
 import org.apache.cassandra.cql3.CQL3Type;
 import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.db.context.CounterContext;
-import org.apache.cassandra.serializers.TypeSerializer;
 import org.apache.cassandra.serializers.CounterSerializer;
 import org.apache.cassandra.serializers.MarshalException;
 import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.serializers.TypeSerializer;
 import org.apache.cassandra.utils.ByteBufferUtil;
 
-public class CounterColumnType extends AbstractType<Long>
+public class CounterColumnType extends NumberType<Long>
 {
     public static final CounterColumnType instance = new CounterColumnType();
 
@@ -93,4 +93,40 @@ public class CounterColumnType extends AbstractType<Long>
     {
         return CounterSerializer.instance;
     }
+
+    @Override
+    protected long toLong(ByteBuffer value)
+    {
+        return ByteBufferUtil.toLong(value);
+    }
+
+    public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes(leftType.toLong(left) + rightType.toLong(right));
+    }
+
+    public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes(leftType.toLong(left) - rightType.toLong(right));
+    }
+
+    public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes(leftType.toLong(left) * rightType.toLong(right));
+    }
+
+    public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes(leftType.toLong(left) / rightType.toLong(right));
+    }
+
+    public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+    {
+        return ByteBufferUtil.bytes(leftType.toLong(left) % rightType.toLong(right));
+    }
+
+    public ByteBuffer negate(ByteBuffer input)
+    {
+        return ByteBufferUtil.bytes(-toLong(input));
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/DateType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DateType.java b/src/java/org/apache/cassandra/db/marshal/DateType.java
index 87b2cad..473cedf 100644
--- a/src/java/org/apache/cassandra/db/marshal/DateType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DateType.java
@@ -119,7 +119,7 @@ public class DateType extends AbstractType<Date>
     }
 
     @Override
-    protected int valueLengthIfFixed()
+    public int valueLengthIfFixed()
     {
         return 8;
     }


Mime
View raw message