You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/01/27 20:23:30 UTC

[29/51] [partial] Initial commit

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java b/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
new file mode 100644
index 0000000..b90fd7c
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
@@ -0,0 +1,70 @@
+package org.apache.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.StringUtil;
+
+@BuiltInFunction(name=ReverseFunction.NAME,  args={
+        @Argument(allowedTypes={PDataType.VARCHAR})} )
+public class ReverseFunction extends ScalarFunction {
+    public static final String NAME = "REVERSE";
+    
+    public ReverseFunction() {
+    }
+
+    public ReverseFunction(List<Expression> children) throws SQLException {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression arg = getChildren().get(0);
+        if (!arg.evaluate(tuple, ptr)) {
+            return false;
+        }
+
+        int targetOffset = ptr.getLength();
+        if (targetOffset == 0) {
+            return true;
+        }
+
+        byte[] source = ptr.get();
+        byte[] target = new byte[targetOffset];
+        int sourceOffset = ptr.getOffset(); 
+        int endOffset = sourceOffset + ptr.getLength();
+        ColumnModifier modifier = arg.getColumnModifier();
+        while (sourceOffset < endOffset) {
+            int nBytes = StringUtil.getBytesInChar(source[sourceOffset], modifier);
+            targetOffset -= nBytes;
+            System.arraycopy(source, sourceOffset, target, targetOffset, nBytes);
+            sourceOffset += nBytes;
+        }
+        ptr.set(target);
+        return true;
+    }
+
+    @Override
+    public ColumnModifier getColumnModifier() {
+        return getChildren().get(0).getColumnModifier();
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java b/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
new file mode 100644
index 0000000..23adb62
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.sql.Date;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PDataType.PDataCodec;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ * 
+ * Function used to bucketize date/time values by rounding them to
+ * an even increment.  Usage:
+ * ROUND(<date/time col ref>,<'day'|'hour'|'minute'|'second'|'millisecond'>,<optional integer multiplier>)
+ * The integer multiplier is optional and is used to do rollups to a partial time unit (i.e. 10 minute rollup)
+ * The function returns a {@link org.apache.phoenix.schema.PDataType#DATE}
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=RoundFunction.NAME, args= {
+    @Argument(allowedTypes={PDataType.DATE}),
+    @Argument(enumeration="TimeUnit"),
+    @Argument(allowedTypes={PDataType.INTEGER}, isConstant=true, defaultValue="1")} )
+public class RoundFunction extends ScalarFunction {
+    public static final String NAME = "ROUND";
+    private long divBy;
+    
+    private static final long[] TIME_UNIT_MS = new long[] {
+        24 * 60 * 60 * 1000,
+        60 * 60 * 1000,
+        60 * 1000,
+        1000,
+        1
+    };
+
+    public RoundFunction() {
+    }
+    
+    public RoundFunction(List<Expression> children) throws SQLException {
+        super(children.subList(0, 1));
+        Object timeUnitValue = ((LiteralExpression)children.get(1)).getValue();
+        Object multiplierValue = ((LiteralExpression)children.get(2)).getValue();
+        if (timeUnitValue != null && multiplierValue != null) {
+            TimeUnit timeUnit = TimeUnit.valueOf(timeUnitValue.toString().toUpperCase());
+            int multiplier = ((Number)multiplierValue).intValue();
+            divBy = multiplier * TIME_UNIT_MS[timeUnit.ordinal()];
+        }
+    }
+    
+    protected long getRoundUpAmount() {
+        return divBy/2;
+    }
+    
+    private long roundTime(long time) {
+        long value;
+        long halfDivBy = getRoundUpAmount();
+        if (time <= Long.MAX_VALUE - halfDivBy) { // If no overflow, add
+            value = (time + halfDivBy) / divBy;
+        } else { // Else subtract and add one
+            value = (time - halfDivBy) / divBy + 1;
+        }
+        return value * divBy;
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        // If divBy is 0 this means <time unit> or <multiplier> was null
+        if (divBy != 0 && children.get(0).evaluate(tuple, ptr)) {
+            long time = getDataType().getCodec().decodeLong(ptr, children.get(0).getColumnModifier());
+            long value = roundTime(time);
+            // TODO: use temporary buffer instead and have way for caller to check if copying is necessary
+            byte[] byteValue = getDataType().toBytes(new Date(value));
+            ptr.set(byteValue);
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        long roundUpAmount = this.getRoundUpAmount();
+        result = prime * result + (int)(divBy ^ (divBy >>> 32));
+        result = prime * result + (int)(roundUpAmount ^ (roundUpAmount >>> 32));
+        result = prime * result + children.get(0).hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        RoundFunction other = (RoundFunction)obj;
+        if (divBy != other.divBy) return false;
+        if (getRoundUpAmount() != other.getRoundUpAmount()) return false;
+        return children.get(0).equals(other.children.get(0));
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        divBy = WritableUtils.readVLong(input);
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        WritableUtils.writeVLong(output, divBy);
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.DATE;
+    }
+    
+    @Override
+    public Integer getByteSize() {
+        return children.get(0).getByteSize();
+    }
+
+    @Override
+    public boolean isNullable() {
+        return children.get(0).isNullable() || divBy == 0;
+    }
+    
+    @Override
+    public OrderPreserving preservesOrder() {
+        return OrderPreserving.YES;
+    }
+
+    @Override
+    public int getKeyFormationTraversalIndex() {
+        return 0;
+    }
+
+    /**
+     * Form the key range from the key to the key right before or at the
+     * next rounded value.
+     */
+    @Override
+    public KeyPart newKeyPart(final KeyPart childPart) {
+        return new KeyPart() {
+            private final List<Expression> extractNodes = Collections.<Expression>singletonList(RoundFunction.this);
+
+            @Override
+            public PColumn getColumn() {
+                return childPart.getColumn();
+            }
+
+            @Override
+            public List<Expression> getExtractNodes() {
+                return extractNodes;
+            }
+
+            @Override
+            public KeyRange getKeyRange(CompareOp op, Expression rhs) {
+                PDataType type = getColumn().getDataType();
+                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+                rhs.evaluate(null, ptr);
+                byte[] key = ByteUtil.copyKeyBytesIfNecessary(ptr);
+                // No need to take into account column modifier, because ROUND
+                // always forces the value to be in ascending order
+                PDataCodec codec = type.getCodec();
+                int offset = ByteUtil.isInclusive(op) ? 1 : 0;
+                long value = codec.decodeLong(key, 0, null);
+                byte[] nextKey = new byte[type.getByteSize()];
+                switch (op) {
+                case EQUAL:
+                    // If the value isn't evenly divisible by the div amount, then it
+                    // can't possibly be equal to any rounded value. For example, if you
+                    // had ROUND(dateCol,'DAY') = TO_DATE('2013-01-01 23:00:00')
+                    // it could never be equal, since date constant isn't at a day
+                    // boundary.
+                    if (value % divBy != 0) {
+                        return KeyRange.EMPTY_RANGE;
+                    }
+                    codec.encodeLong(value + divBy, nextKey, 0);
+                    return type.getKeyRange(key, true, nextKey, false);
+                case GREATER:
+                case GREATER_OR_EQUAL:
+                    codec.encodeLong((value + divBy - offset)/divBy*divBy, nextKey, 0);
+                    return type.getKeyRange(nextKey, true, KeyRange.UNBOUND, false);
+                case LESS:
+                case LESS_OR_EQUAL:
+                    codec.encodeLong((value + divBy - (1 -offset))/divBy*divBy, nextKey, 0);
+                    return type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false);
+                default:
+                    return childPart.getKeyRange(op, rhs);
+                }
+            }
+        };
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java b/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
new file mode 100644
index 0000000..1d1059b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.util.List;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+public abstract class ScalarFunction extends FunctionExpression {
+    public static final int NO_TRAVERSAL = -1;
+    
+    public ScalarFunction() {
+    }
+    
+    public ScalarFunction(List<Expression> children) {
+        super(children);
+    }
+    
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        List<T> l = acceptChildren(visitor, visitor.visitEnter(this));
+        T t = visitor.visitLeave(this, l);
+        if (t == null) {
+            t = visitor.defaultReturn(this, l);
+        }
+        return t;
+    }
+    
+    /**
+     * Determines whether or not a function may be used to form
+     * the start/stop key of a scan
+     * @return the zero-based position of the argument to traverse
+     *  into to look for a primary key column reference, or
+     *  {@value #NO_TRAVERSAL} if the function cannot be used to
+     *  form the scan key.
+     */
+    public int getKeyFormationTraversalIndex() {
+        return NO_TRAVERSAL;
+    }
+
+    /**
+     * Manufactures a KeyPart used to construct the KeyRange given
+     * a constant and a comparison operator.
+     * @param childPart the KeyPart formulated for the child expression
+     *  at the {@link #getKeyFormationTraversalIndex()} position.
+     * @return the KeyPart for constructing the KeyRange for this
+     *  function.
+     */
+    public KeyPart newKeyPart(KeyPart childPart) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
new file mode 100644
index 0000000..82dcb8b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.aggregator.Aggregator;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Base class for aggregate functions that calculate an aggregation
+ * using a single {{@link Aggregator}
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class SingleAggregateFunction extends AggregateFunction {
+    private static final List<Expression> DEFAULT_EXPRESSION_LIST = Arrays.<Expression>asList(LiteralExpression.newConstant(1));
+    protected boolean isConstant;
+    private Aggregator aggregator;
+    
+    /**
+     * Sort aggregate functions with nullable fields last. This allows us not to have to store trailing null values.
+     * Within non-nullable/nullable groups, put fixed width values first since we can access those more efficiently
+     * (i.e. we can skip over groups of them in-mass instead of reading the length of each one to skip over as
+     * required by a variable length value).
+     */
+    public static final Comparator<SingleAggregateFunction> SCHEMA_COMPARATOR = new Comparator<SingleAggregateFunction>() {
+
+        @Override
+        public int compare(SingleAggregateFunction o1, SingleAggregateFunction o2) {
+            boolean isNullable1 = o1.isNullable();
+            boolean isNullable2 = o2.isNullable();
+            if (isNullable1 != isNullable2) {
+                return isNullable1 ? 1 : -1;
+            }
+            isNullable1 = o1.getAggregatorExpression().isNullable();
+            isNullable2 = o2.getAggregatorExpression().isNullable();
+            if (isNullable1 != isNullable2) {
+                return isNullable1 ? 1 : -1;
+            }
+            // Ensures COUNT(1) sorts first TODO: unit test for this
+            boolean isConstant1 = o1.isConstantExpression();
+            boolean isConstant2 = o2.isConstantExpression();
+            if (isConstant1 != isConstant2) {
+                return isConstant1 ? 1 : -1;
+            }
+            PDataType r1 = o1.getAggregator().getDataType();
+            PDataType r2 = o2.getAggregator().getDataType();
+            if (r1.isFixedWidth() != r2.isFixedWidth()) {
+                return r1.isFixedWidth() ? -1 : 1;
+            }
+            return r1.compareTo(r2);
+        }
+    };
+    
+    protected SingleAggregateFunction() {
+        this(DEFAULT_EXPRESSION_LIST, true);
+    }
+
+    public SingleAggregateFunction(List<Expression> children) {
+        this(children, children.get(0) instanceof LiteralExpression);
+    }
+    
+    private SingleAggregateFunction(List<Expression> children, boolean isConstant) {
+        super(children);
+        this.isConstant = children.get(0) instanceof LiteralExpression;
+        this.aggregator = newClientAggregator();
+    }
+
+    public boolean isConstantExpression() {
+        return isConstant;
+    }
+    
+    @Override
+    public PDataType getDataType() {
+        return children.get(0).getDataType();
+    }
+    
+    public Expression getAggregatorExpression() {
+        return children.get(0);
+    }
+    
+    public Aggregator getAggregator() {
+        return aggregator;
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        return getAggregator().evaluate(tuple, ptr);
+    }
+
+    /**
+     * Create the aggregator to do server-side aggregation.
+     * The data type of the returned Aggregator must match
+     * the data type returned by {@link #newClientAggregator()}
+     * @param conf HBase configuration.
+     * @return the aggregator to use on the server-side
+     */
+    abstract public Aggregator newServerAggregator(Configuration conf);
+    /**
+     * Create the aggregator to do client-side aggregation
+     * based on the results returned from the aggregating
+     * coprocessor. The data type of the returned Aggregator
+     * must match the data type returned by {@link #newServerAggregator(Configuration)}
+     * @return the aggregator to use on the client-side
+     */
+    public Aggregator newClientAggregator() {
+        return newServerAggregator(null);
+    }
+    
+    public void readFields(DataInput input, Configuration conf) throws IOException {
+        super.readFields(input);
+        aggregator = newServerAggregator(conf);
+    }
+
+    @Override
+    public boolean isNullable() {
+        return true;
+    }
+    
+    protected SingleAggregateFunction getDelegate() {
+        return this;
+    }
+
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        SingleAggregateFunction function = getDelegate();
+        List<T> l = acceptChildren(visitor, visitor.visitEnter(function));
+        T t = visitor.visitLeave(function, l);
+        if (t == null) {
+            t = visitor.defaultReturn(function, l);
+        }
+        return t;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java b/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
new file mode 100644
index 0000000..9ffbd90
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Function used to get the SQL table type name from the serialized table type.
+ * Usage:
+ * SqlTableType('v') will return 'VIEW' based on
+ * {@link java.sql.DatabaseMetaData#getTableTypes()}
+ * 
+ * @author jtaylor
+ * @since 2.2
+ */
+@BuiltInFunction(name=SqlTableType.NAME, args= {
+    @Argument(allowedTypes=PDataType.CHAR)} )
+public class SqlTableType extends ScalarFunction {
+    public static final String NAME = "SqlTableType";
+
+    public SqlTableType() {
+    }
+    
+    public SqlTableType(List<Expression> children) throws SQLException {
+        super(children);
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression child = children.get(0);
+        if (!child.evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            return true;
+        }
+        PTableType tableType = PTableType.fromSerializedValue(ptr.get()[ptr.getOffset()]);
+        ptr.set(tableType.getValue().getBytes());
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+    
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java b/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java
new file mode 100644
index 0000000..e0d9807
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.IllegalDataException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ * 
+ * Function used to get the SQL type name from the SQL type integer.
+ * Usage:
+ * SqlTypeName(12)
+ * will return 'VARCHAR' based on {@link java.sql.Types#VARCHAR} being 12
+ * 
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SqlTypeNameFunction.NAME, args= {
+    @Argument(allowedTypes=PDataType.INTEGER)} )
+public class SqlTypeNameFunction extends ScalarFunction {
+    public static final String NAME = "SqlTypeName";
+
+    public SqlTypeNameFunction() {
+    }
+    
+    public SqlTypeNameFunction(List<Expression> children) throws SQLException {
+        super(children);
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression child = children.get(0);
+        if (!child.evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            return true;
+        }
+        int sqlType = child.getDataType().getCodec().decodeInt(ptr, child.getColumnModifier());
+        try {
+            byte[] sqlTypeNameBytes = PDataType.fromSqlType(sqlType).getSqlTypeNameBytes();
+            ptr.set(sqlTypeNameBytes);
+        } catch (IllegalDataException e) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+        }
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+    
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java b/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java
new file mode 100644
index 0000000..675b34b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+/**
+ * 
+ * Built-in function for STDDEV_POP(<expression>) aggregate function
+ * 
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = StddevPopFunction.NAME, args = { @Argument(allowedTypes={PDataType.DECIMAL})})
+public class StddevPopFunction extends SingleAggregateFunction {
+    public static final String NAME = "STDDEV_POP";
+
+    public StddevPopFunction() {
+
+    }
+
+    public StddevPopFunction(List<Expression> childern) {
+        super(childern);
+    }
+
+    @Override
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new DistinctValueWithCountServerAggregator(conf);
+    }
+
+    @Override
+    public Aggregator newClientAggregator() {
+        if (children.get(0).getDataType() == PDataType.DECIMAL) {
+            // Special Aggregators for DECIMAL datatype for more precision than double
+            return new DecimalStddevPopAggregator(children, getAggregatorExpression().getColumnModifier());
+        }
+        return new StddevPopAggregator(children, getAggregatorExpression().getColumnModifier());
+    }
+    
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DECIMAL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java b/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java
new file mode 100644
index 0000000..53e9595
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+/**
+ * 
+ * Built-in function for STDDEV_SAMP(<expression>) aggregate function
+ * 
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = StddevSampFunction.NAME, args = { @Argument(allowedTypes={PDataType.DECIMAL})})
+public class StddevSampFunction extends SingleAggregateFunction {
+    public static final String NAME = "STDDEV_SAMP";
+
+    public StddevSampFunction() {
+
+    }
+
+    public StddevSampFunction(List<Expression> childern) {
+        super(childern);
+    }
+
+    @Override
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new DistinctValueWithCountServerAggregator(conf);
+    }
+
+    @Override
+    public Aggregator newClientAggregator() {
+        if (children.get(0).getDataType() == PDataType.DECIMAL) {
+            // Special Aggregators for DECIMAL datatype for more precision than double
+            return new DecimalStddevSampAggregator(children, getAggregatorExpression().getColumnModifier());
+        }
+        return new StddevSampAggregator(children, getAggregatorExpression().getColumnModifier());
+    }
+    
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DECIMAL;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java b/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
new file mode 100644
index 0000000..90aa3c8
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * 
+ * Implementation of the SUBSTR(<string>,<offset>[,<length>]) built-in function
+ * where <offset> is the offset from the start of <string>. A positive offset
+ * is treated as 1-based, a zero offset is treated as 0-based, and a negative
+ * offset starts from the end of the string working backwards. The optional
+ * <length> argument is the number of characters to return. In the absence of the
+ * <length> argument, the rest of the string starting from <offset> is returned.
+ * If <length> is less than 1, null is returned.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SubstrFunction.NAME,  args={
+    @Argument(allowedTypes={PDataType.VARCHAR}),
+    @Argument(allowedTypes={PDataType.LONG}), // These are LONG because negative numbers end up as longs
+    @Argument(allowedTypes={PDataType.LONG},defaultValue="null")} )
+public class SubstrFunction extends PrefixFunction {
+    public static final String NAME = "SUBSTR";
+    private boolean hasLengthExpression;
+    private boolean isOffsetConstant;
+    private boolean isLengthConstant;
+    private boolean isFixedWidth;
+    private Integer byteSize;
+
+    public SubstrFunction() {
+    }
+
+    public SubstrFunction(List<Expression> children) {
+        super(children);
+        init();
+    }
+
+    private void init() {
+        // TODO: when we have ColumnModifier.REVERSE, we'll need to negate offset,
+        // since the bytes are reverse and we'll want to work from the end.
+        isOffsetConstant = getOffsetExpression() instanceof LiteralExpression;
+        isLengthConstant = getLengthExpression() instanceof LiteralExpression;
+        hasLengthExpression = !isLengthConstant || ((LiteralExpression)getLengthExpression()).getValue() != null;
+        isFixedWidth = getStrExpression().getDataType().isFixedWidth() && ((hasLengthExpression && isLengthConstant) || (!hasLengthExpression && isOffsetConstant));
+        if (hasLengthExpression && isLengthConstant) {
+            Integer maxLength = ((Number)((LiteralExpression)getLengthExpression()).getValue()).intValue();
+            this.byteSize = maxLength >= 0 ? maxLength : 0;
+        } else if (isOffsetConstant) {
+            Number offsetNumber = (Number)((LiteralExpression)getOffsetExpression()).getValue();
+            if (offsetNumber != null) {
+                int offset = offsetNumber.intValue();
+                if (getStrExpression().getDataType().isFixedWidth()) {
+                    if (offset >= 0) {
+                        byteSize = getStrExpression().getByteSize() - offset + (offset == 0 ? 0 : 1);
+                    } else {
+                        byteSize = -offset;
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression offsetExpression = getOffsetExpression();
+        if (!offsetExpression.evaluate(tuple,  ptr)) {
+            return false;
+        }
+        int offset = offsetExpression.getDataType().getCodec().decodeInt(ptr, offsetExpression.getColumnModifier());
+        
+        int length = -1;
+        if (hasLengthExpression) {
+            Expression lengthExpression = getLengthExpression();
+            if (!lengthExpression.evaluate(tuple, ptr)) {
+                return false;
+            }
+            length = lengthExpression.getDataType().getCodec().decodeInt(ptr, lengthExpression.getColumnModifier());
+            if (length <= 0) {
+                return false;
+            }
+        }
+        
+        if (!getStrExpression().evaluate(tuple, ptr)) {
+            return false;
+        }
+        
+        try {
+            boolean isCharType = getStrExpression().getDataType() == PDataType.CHAR;
+            ColumnModifier columnModifier = getStrExpression().getColumnModifier();
+            int strlen = isCharType ? ptr.getLength() : StringUtil.calculateUTF8Length(ptr.get(), ptr.getOffset(), ptr.getLength(), columnModifier);
+            
+            // Account for 1 versus 0-based offset
+            offset = offset - (offset <= 0 ? 0 : 1);
+            if (offset < 0) { // Offset < 0 means get from end
+                offset = strlen + offset;
+            }
+            if (offset < 0 || offset >= strlen) {
+                return false;
+            }
+            int maxLength = strlen - offset;
+            length = length == -1 ? maxLength : Math.min(length,maxLength);
+            
+            int byteOffset = isCharType ? offset : StringUtil.getByteLengthForUtf8SubStr(ptr.get(), ptr.getOffset(), offset, columnModifier);
+            int byteLength = isCharType ? length : StringUtil.getByteLengthForUtf8SubStr(ptr.get(), ptr.getOffset() + byteOffset, length, columnModifier);
+            ptr.set(ptr.get(), ptr.getOffset() + byteOffset, byteLength);
+            return true;
+        } catch (UnsupportedEncodingException e) {
+            return false;
+        }
+    }
+
+    @Override
+    public PDataType getDataType() {
+        // If fixed width, then return child expression type.
+        // If not fixed width, then we don't know how big this will be across the board
+        return isFixedWidth ? getStrExpression().getDataType() : PDataType.VARCHAR;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return getStrExpression().isNullable() || !isFixedWidth || getOffsetExpression().isNullable();
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return byteSize;
+    }
+    
+    // TODO: we shouldn't need both getByteSize() and getMaxLength()
+    @Override
+    public Integer getMaxLength() {
+        return byteSize;
+    }
+    
+    @Override
+    public ColumnModifier getColumnModifier() {
+        return getStrExpression().getColumnModifier();
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        init();
+    }
+
+    private Expression getStrExpression() {
+        return children.get(0);
+    }
+
+    private Expression getOffsetExpression() {
+        return children.get(1);
+    }
+
+    private Expression getLengthExpression() {
+        return children.get(2);
+    }
+
+    @Override
+    public OrderPreserving preservesOrder() {
+        if (isOffsetConstant) {
+            LiteralExpression literal = (LiteralExpression) getOffsetExpression();
+            Number offsetNumber = (Number) literal.getValue();
+            if (offsetNumber != null) { 
+                int offset = offsetNumber.intValue();
+                if ((offset == 0 || offset == 1) && (!hasLengthExpression || isLengthConstant)) {
+                    return OrderPreserving.YES_IF_LAST;
+                }
+            }
+        }
+        return OrderPreserving.NO;
+    }
+
+    @Override
+    protected boolean extractNode() {
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
new file mode 100644
index 0000000..b6143bb
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Built-in function for SUM aggregation function.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SumAggregateFunction.NAME, nodeClass=SumAggregateParseNode.class, args= {@Argument(allowedTypes={PDataType.DECIMAL})} )
+public class SumAggregateFunction extends DelegateConstantToCountAggregateFunction {
+    public static final String NAME = "SUM";
+    
+    public SumAggregateFunction() {
+    }
+    
+    // TODO: remove when not required at built-in func register time
+    public SumAggregateFunction(List<Expression> childExpressions){
+        super(childExpressions, null);
+    }
+    
+    public SumAggregateFunction(List<Expression> childExpressions, CountAggregateFunction delegate){
+        super(childExpressions, delegate);
+    }
+    
+    @Override
+    public Aggregator newServerAggregator(Configuration conf) {
+        final PDataType type = getAggregatorExpression().getDataType();
+        ColumnModifier columnModifier = getAggregatorExpression().getColumnModifier();
+        switch( type ) {
+            case DECIMAL:
+                return new DecimalSumAggregator(columnModifier);
+            case UNSIGNED_DOUBLE:
+            case UNSIGNED_FLOAT:
+            case DOUBLE:
+            case FLOAT:
+                return new DoubleSumAggregator(columnModifier) {
+                    @Override
+                    protected PDataType getInputDataType() {
+                        return type;
+                    }
+                };
+            default:
+                return new NumberSumAggregator(columnModifier) {
+                    @Override
+                    protected PDataType getInputDataType() {
+                        return type;
+                    }
+                };
+        }
+    }
+    
+    @Override
+    public Aggregator newClientAggregator() {
+        switch( getDataType() ) {
+            case DECIMAL:
+                // On the client, we'll always aggregate over non modified column values,
+                // because we always get them back from the server in their non modified
+                // form.
+                return new DecimalSumAggregator(null);
+            case LONG:
+                return new LongSumAggregator(null);
+            case DOUBLE:
+                return new DoubleSumAggregator(null);
+            default:
+                throw new IllegalStateException("Unexpected SUM type: " + getDataType());
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!super.evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (isConstantExpression()) {
+            PDataType type = getDataType();
+            Object constantValue = ((LiteralExpression)children.get(0)).getValue();
+            if (type == PDataType.DECIMAL) {
+                BigDecimal value = ((BigDecimal)constantValue).multiply((BigDecimal)PDataType.DECIMAL.toObject(ptr, PDataType.LONG));
+                ptr.set(PDataType.DECIMAL.toBytes(value));
+            } else {
+                long constantLongValue = ((Number)constantValue).longValue();
+                long value = constantLongValue * type.getCodec().decodeLong(ptr, null);
+                ptr.set(new byte[type.getByteSize()]);
+                type.getCodec().encodeLong(value, ptr);
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        switch(super.getDataType()) {
+        case DECIMAL:
+            return PDataType.DECIMAL;
+        case UNSIGNED_FLOAT:
+        case UNSIGNED_DOUBLE:
+        case FLOAT:
+        case DOUBLE:
+            return PDataType.DOUBLE;
+        default:
+            return PDataType.LONG;
+        }
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java b/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
new file mode 100644
index 0000000..ffe19fe
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+public enum TimeUnit{DAY, HOUR, MINUTE, SECOND, MILLISECOND}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
new file mode 100644
index 0000000..d6cdc99
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.io.*;
+import java.sql.SQLException;
+import java.text.Format;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.base.Preconditions;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Implementation of the TO_CHAR(&lt;date&gt;/&lt;number&gt;,[&lt;format-string&gt;] built-in function.
+ * The first argument must be of type DATE or TIME or TIMESTAMP or DECIMAL or INTEGER, and the second argument must be a constant string. 
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToCharFunction.NAME, nodeClass=ToCharParseNode.class, args={
+    @Argument(allowedTypes={PDataType.TIMESTAMP, PDataType.DECIMAL}),
+    @Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null") } )
+public class ToCharFunction extends ScalarFunction {
+    public static final String NAME = "TO_CHAR";
+    private String formatString;
+    private Format formatter;
+    private FunctionArgumentType type;
+    
+    public ToCharFunction() {
+    }
+
+    public ToCharFunction(List<Expression> children, FunctionArgumentType type, String formatString, Format formatter) throws SQLException {
+        super(children.subList(0, 1));
+        Preconditions.checkNotNull(formatString);
+        Preconditions.checkNotNull(formatter);
+        Preconditions.checkNotNull(type);
+        this.type = type;
+        this.formatString = formatString;
+        this.formatter = formatter;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + formatString.hashCode();
+        result = prime * result + getExpression().hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        ToCharFunction other = (ToCharFunction)obj;
+        if (!getExpression().equals(other.getExpression())) return false;
+        if (!formatString.equals(other.formatString)) return false;
+        return true;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression expression = getExpression();
+        if (!expression.evaluate(tuple, ptr)) {
+            return false;
+        }
+        PDataType type = expression.getDataType();
+        Object value = formatter.format(type.toObject(ptr, expression.getColumnModifier()));
+        byte[] b = getDataType().toBytes(value);
+        ptr.set(b);
+        return true;
+     }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return getExpression().isNullable();
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        formatString = WritableUtils.readString(input);
+        type = WritableUtils.readEnum(input, FunctionArgumentType.class);
+        formatter = type.getFormatter(formatString);
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        WritableUtils.writeString(output, formatString);
+        WritableUtils.writeEnum(output, type);
+    }
+
+    private Expression getExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
new file mode 100644
index 0000000..5ef0034
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.io.*;
+import java.sql.SQLException;
+import java.text.Format;
+import java.text.ParseException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.DateUtil;
+
+
+/**
+ * 
+ * Implementation of the TO_DATE(<string>,[<format-string>]) built-in function.
+ * The second argument is optional and defaults to the phoenix.query.dateFormat value
+ * from the HBase config. If present it must be a constant string.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToDateFunction.NAME, nodeClass=ToDateParseNode.class, args= {@Argument(allowedTypes={PDataType.VARCHAR}),@Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null")} )
+public class ToDateFunction extends ScalarFunction {
+    public static final String NAME = "TO_DATE";
+    private Format dateParser;
+    private String dateFormat;
+
+    public ToDateFunction() {
+    }
+
+    public ToDateFunction(List<Expression> children, String dateFormat, Format dateParser) throws SQLException {
+        super(children.subList(0, 1));
+        this.dateFormat = dateFormat;
+        this.dateParser = dateParser;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + dateFormat.hashCode();
+        result = prime * result + getExpression().hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        ToDateFunction other = (ToDateFunction)obj;
+        if (!getExpression().equals(other.getExpression())) return false;
+        if (!dateFormat.equals(other.dateFormat)) return false;
+        return true;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression expression = getExpression();
+        if (!expression.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+            return false;
+        }
+        PDataType type = expression.getDataType();
+        String dateStr = (String)type.toObject(ptr, expression.getColumnModifier());
+        try {
+            Object value = dateParser.parseObject(dateStr);
+            byte[] byteValue = getDataType().toBytes(value);
+            ptr.set(byteValue);
+            return true;
+        } catch (ParseException e) {
+            throw new IllegalStateException("to_date('" + dateStr + ")' did not match expected date format of '" + dateFormat + "'.");
+        }
+     }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DATE;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return getExpression().isNullable();
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        dateFormat = WritableUtils.readString(input);
+        dateParser = DateUtil.getDateParser(dateFormat);
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        WritableUtils.writeString(output, dateFormat);
+    }
+
+    private Expression getExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
new file mode 100644
index 0000000..84cc2b4
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import static org.apache.phoenix.util.ByteUtil.EMPTY_BYTE_ARRAY;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.text.*;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.base.Preconditions;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+/**
+ * 
+ * Implementation of TO_NUMBER(&lt;string&gt;/&lt;date&gt;/&lt;timestamp&gt;, [&lt;pattern-string&gt;]) built-in function.  The format for the optional
+ * <code>pattern_string</code> param is specified in {@link DecimalFormat}.
+ *
+ * @author elevine
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToNumberFunction.NAME,  nodeClass=ToNumberParseNode.class, args= {
+        @Argument(allowedTypes={PDataType.VARCHAR, PDataType.TIMESTAMP}),
+        @Argument(allowedTypes={PDataType.VARCHAR}, isConstant=true, defaultValue="null")} )
+public class ToNumberFunction extends ScalarFunction {
+	public static final String NAME = "TO_NUMBER";
+    
+    private String formatString = null;
+    private Format format = null;
+	private FunctionArgumentType type;
+    
+    public ToNumberFunction() {}
+
+    public ToNumberFunction(List<Expression> children, FunctionArgumentType type, String formatString, Format formatter) throws SQLException {
+        super(children.subList(0, 1));
+        Preconditions.checkNotNull(type);
+        this.type = type;
+        this.formatString = formatString;
+        this.format = formatter;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression expression = getExpression();
+        if (!expression.evaluate(tuple, ptr)) {
+            return false;
+        } else if (ptr.getLength() == 0) {
+            return true;
+        }
+
+        PDataType type = expression.getDataType();
+        if (type.isCoercibleTo(PDataType.TIMESTAMP)) {
+        	Date date = (Date) type.toObject(ptr, expression.getColumnModifier());
+        	BigDecimal time = new BigDecimal(date.getTime());
+            byte[] byteValue = getDataType().toBytes(time);
+            ptr.set(byteValue);
+            return true;
+        }
+        
+        String stringValue = (String)type.toObject(ptr, expression.getColumnModifier());
+        if (stringValue == null) {
+            ptr.set(EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        stringValue = stringValue.trim();
+        BigDecimal decimalValue;
+        if (format == null) {
+            decimalValue = (BigDecimal) getDataType().toObject(stringValue);
+        } else {
+            ParsePosition parsePosition = new ParsePosition(0);
+            Number number = ((DecimalFormat) format).parse(stringValue, parsePosition);
+            if (parsePosition.getErrorIndex() > -1) {
+                ptr.set(EMPTY_BYTE_ARRAY);
+                return true;
+            }
+            
+            if (number instanceof BigDecimal) { 
+                // since we set DecimalFormat.setParseBigDecimal(true) we are guaranteeing result to be 
+                // of type BigDecimal in most cases.  see java.text.DecimalFormat.parse() JavaDoc.
+                decimalValue = (BigDecimal)number;
+            } else {
+                ptr.set(EMPTY_BYTE_ARRAY);
+                return true;
+            }
+        }
+        byte[] byteValue = getDataType().toBytes(decimalValue);
+        ptr.set(byteValue);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+    	return PDataType.DECIMAL;
+    }
+    
+    @Override
+    public boolean isNullable() {
+        return getExpression().isNullable();
+    }
+
+    private Expression getExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+    
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        formatString = WritableUtils.readString(input);
+        type = WritableUtils.readEnum(input, FunctionArgumentType.class);
+        if (formatString != null) {
+        	format = type.getFormatter(formatString);
+        }
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        WritableUtils.writeString(output, formatString);
+        WritableUtils.writeEnum(output, type);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((formatString == null) ? 0 : formatString.hashCode());
+        result = prime * result + getExpression().hashCode();
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (!super.equals(obj)) return false;
+        if (getClass() != obj.getClass()) return false;
+        ToNumberFunction other = (ToNumberFunction)obj;
+        if (formatString == null) {
+            if (other.formatString != null) return false;
+        } else if (!formatString.equals(other.formatString)) return false;
+        if (!getExpression().equals(other.getExpression())) return false;
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java b/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
new file mode 100644
index 0000000..b8c06cd
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * Implementation of the Trim(<string>) build-in function. It removes from both end of <string>
+ * space character and other function bytes in single byte utf8 characters set.
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=TrimFunction.NAME, args={
+    @Argument(allowedTypes={PDataType.VARCHAR})} )
+public class TrimFunction extends ScalarFunction {
+    public static final String NAME = "TRIM";
+
+    private Integer byteSize;
+
+    public TrimFunction() { }
+
+    public TrimFunction(List<Expression> children) throws SQLException {
+        super(children);
+        if (getStringExpression().getDataType().isFixedWidth()) {
+            byteSize = getStringExpression().getByteSize();
+        }
+    }
+
+    private Expression getStringExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public ColumnModifier getColumnModifier() {
+        return children.get(0).getColumnModifier();
+    }    
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!getStringExpression().evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        byte[] string = ptr.get();
+        int offset = ptr.getOffset();
+        int length = ptr.getLength();
+        
+        ColumnModifier columnModifier = getColumnModifier();
+        int end = StringUtil.getFirstNonBlankCharIdxFromEnd(string, offset, length, columnModifier);
+        if (end == offset - 1) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true; 
+        }
+        int head = StringUtil.getFirstNonBlankCharIdxFromStart(string, offset, length, columnModifier);
+        ptr.set(string, head, end - head + 1);
+        return true;
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return byteSize;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java b/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
new file mode 100644
index 0000000..59f7e66
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+
+/**
+ * 
+ * Function used to bucketize date/time values by truncating them to
+ * an even increment.  Usage:
+ * TRUNC(<date/time col ref>,<'day'|'hour'|'minute'|'second'|'millisecond'>,[<optional integer multiplier>])
+ * The integer multiplier is optional and is used to do rollups to a partial time unit (i.e. 10 minute rollup)
+ * The function returns a {@link org.apache.phoenix.schema.PDataType#DATE}
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name="TRUNC", args= {
+    @Argument(allowedTypes={PDataType.TIME}),
+    @Argument(enumeration="TimeUnit"),
+    @Argument(allowedTypes={PDataType.INTEGER}, isConstant=true, defaultValue="1")} )
+public class TruncFunction extends RoundFunction {
+    public TruncFunction() {
+    }
+    
+    public TruncFunction(List<Expression> node) throws SQLException {
+        super(node);
+    }
+    
+    @Override
+    protected long getRoundUpAmount() {
+        return 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java b/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
new file mode 100644
index 0000000..484430f
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.visitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.phoenix.expression.AddExpression;
+import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.CaseExpression;
+import org.apache.phoenix.expression.CoerceExpression;
+import org.apache.phoenix.expression.ComparisonExpression;
+import org.apache.phoenix.expression.DivideExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.InListExpression;
+import org.apache.phoenix.expression.IsNullExpression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LikeExpression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.MultiplyExpression;
+import org.apache.phoenix.expression.NotExpression;
+import org.apache.phoenix.expression.OrExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.StringConcatExpression;
+import org.apache.phoenix.expression.SubtractExpression;
+import org.apache.phoenix.expression.function.ScalarFunction;
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+
+
+public abstract class BaseExpressionVisitor<E> implements ExpressionVisitor<E> {
+    @Override
+    public E visit(Expression node) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(Expression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(Expression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public E defaultReturn(Expression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(AndExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(AndExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(OrExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(OrExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(ScalarFunction node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(ScalarFunction node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(ComparisonExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(ComparisonExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(LikeExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(LikeExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(SingleAggregateFunction node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(SingleAggregateFunction node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(CaseExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(CaseExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(NotExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(NotExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(IsNullExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(IsNullExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(InListExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(InListExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public E visit(LiteralExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visit(RowKeyColumnExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visit(KeyValueColumnExpression node) {
+        return null;
+    }
+    @Override
+    public Iterator<Expression> visitEnter(SubtractExpression node) {
+        return null;
+    }
+
+    @Override
+    public E visitLeave(SubtractExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(AddExpression node) {
+        return null;
+    }
+    @Override
+    public E visitLeave(AddExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(MultiplyExpression node) {
+        return null;
+    }
+    @Override
+    public E visitLeave(MultiplyExpression node, List<E> l) {
+        return null;
+    }
+
+    @Override
+    public Iterator<Expression> visitEnter(DivideExpression node) {
+        return null;
+    }
+    @Override
+    public E visitLeave(DivideExpression node, List<E> l) {
+        return null;
+    }
+    
+    @Override
+    public Iterator<Expression> visitEnter(StringConcatExpression node) {
+        return null;
+    }
+    @Override
+    public E visitLeave(StringConcatExpression node, List<E> l) {
+        return null;
+    }
+    
+    @Override
+    public Iterator<Expression> visitEnter(RowValueConstructorExpression node) {
+        return null;
+    }
+    @Override
+    public E visitLeave(RowValueConstructorExpression node, List<E> l) {
+        return null;
+    }
+    
+    @Override
+    public Iterator<Expression> visitEnter(CoerceExpression node) {
+        return null;
+    }
+    
+    @Override
+    public E visitLeave(CoerceExpression node, List<E> l) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java b/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
new file mode 100644
index 0000000..951e9f3
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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.phoenix.expression.visitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.phoenix.expression.AddExpression;
+import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.CaseExpression;
+import org.apache.phoenix.expression.CoerceExpression;
+import org.apache.phoenix.expression.ComparisonExpression;
+import org.apache.phoenix.expression.DivideExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.InListExpression;
+import org.apache.phoenix.expression.IsNullExpression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LikeExpression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.MultiplyExpression;
+import org.apache.phoenix.expression.NotExpression;
+import org.apache.phoenix.expression.OrExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.StringConcatExpression;
+import org.apache.phoenix.expression.SubtractExpression;
+import org.apache.phoenix.expression.function.ScalarFunction;
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+
+
+/**
+ * 
+ * Visitor for an expression (which may contain other nested expressions)
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public interface ExpressionVisitor<E> {
+    /**
+     * Default visit method when an expression subclass doesn't
+     * define an accept method of its own. This will end up calling
+     * the {@link #defaultIterator(Expression)} to iterate over the
+     * children calling accept on them
+     */
+    public E visit(Expression node);
+    /**
+     * Default visitEnter method when an expression subclass doesn't
+     * define an accept method of its own. This will end up calling
+     * the {@link #defaultIterator(Expression)} to iterate over the
+     * children calling accept on them
+     */
+    public Iterator<Expression> visitEnter(Expression node);
+    /**
+     * Default visitLeave method when an expression subclass doesn't
+     * define an accept method of its own.  This will end up calling
+     * the {@link #defaultReturn(Expression, List)} with the list from
+     * the iteration over the children.
+     */
+    public E visitLeave(Expression node, List<E> l);
+
+    public E defaultReturn(Expression node, List<E> l);
+    public Iterator<Expression> defaultIterator(Expression node);
+    
+    public Iterator<Expression> visitEnter(AndExpression node);
+    public E visitLeave(AndExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(OrExpression node);
+    public E visitLeave(OrExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(ScalarFunction node);
+    public E visitLeave(ScalarFunction node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(ComparisonExpression node);
+    public E visitLeave(ComparisonExpression node, List<E> l);
+
+    public Iterator<Expression> visitEnter(LikeExpression node);
+    public E visitLeave(LikeExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(SingleAggregateFunction node);
+    public E visitLeave(SingleAggregateFunction node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(CaseExpression node);
+    public E visitLeave(CaseExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(NotExpression node);
+    public E visitLeave(NotExpression node, List<E> l);
+
+    public Iterator<Expression> visitEnter(InListExpression node);
+    public E visitLeave(InListExpression node, List<E> l);
+
+    public Iterator<Expression> visitEnter(IsNullExpression node);
+    public E visitLeave(IsNullExpression node, List<E> l);
+
+    public Iterator<Expression> visitEnter(SubtractExpression node);
+    public E visitLeave(SubtractExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(MultiplyExpression node);
+    public E visitLeave(MultiplyExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(AddExpression node);
+    public E visitLeave(AddExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(DivideExpression node);
+    public E visitLeave(DivideExpression node, List<E> l);
+    
+    public Iterator<Expression> visitEnter(CoerceExpression node);
+    public E visitLeave(CoerceExpression node, List<E> l);
+    
+    public E visit(LiteralExpression node);
+    public E visit(RowKeyColumnExpression node);
+    public E visit(KeyValueColumnExpression node);
+    
+	public Iterator<Expression> visitEnter(StringConcatExpression node);
+	public E visitLeave(StringConcatExpression node, List<E> l);
+	
+	public Iterator<Expression> visitEnter(RowValueConstructorExpression node);
+    public E visitLeave(RowValueConstructorExpression node, List<E> l);
+    
+}