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:33 UTC

[32/51] [partial] Initial commit

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LikeExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LikeExpression.java b/src/main/java/org/apache/phoenix/expression/LikeExpression.java
new file mode 100644
index 0000000..038f705
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LikeExpression.java
@@ -0,0 +1,302 @@
+/*
+ * 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;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * 
+ * Implementation for LIKE operation where the first child expression is the string
+ * and the second is the pattern. The pattern supports '_' character for single 
+ * character wildcard match and '%' for zero or more character match. where these
+ * characters may be escaped by preceding them with a '\'.
+ * 
+ * Example: foo LIKE 'ab%' will match a row in which foo starts with 'ab'
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LikeExpression extends BaseCompoundExpression {
+    private static final Logger logger = LoggerFactory.getLogger(LikeExpression.class);
+    
+    private static final String ZERO_OR_MORE = "\\E.*\\Q";
+    private static final String ANY_ONE = "\\E.\\Q";
+    
+    public static String unescapeLike(String s) {
+        return StringUtil.replace(s, StringUtil.LIKE_ESCAPE_SEQS, StringUtil.LIKE_UNESCAPED_SEQS);
+    }
+
+    /**
+     * @return the substring of s for which we have a literal string
+     *  that we can potentially use to set the start/end key, or null
+     *  if there is none.
+     */
+    public static String getStartsWithPrefix(String s) {
+        int i = indexOfWildcard(s);
+        return i == -1 ? s : s.substring(0,i);
+    }
+
+    public static boolean hasWildcards(String s) {
+        return indexOfWildcard(s) != -1;
+    }
+    
+    /**
+     * Replace unescaped '*' and '?' in s with '%' and '_' respectively
+     * such that the returned string may be used in a LIKE expression.
+     * Provides an alternate way of expressing a LIKE pattern which is
+     * more friendly for wildcard matching when the source string is
+     * likely to contain an '%' or '_' character.
+     * @param s wildcard pattern that may use '*' for multi character
+     * match and '?' for single character match, escaped by the backslash
+     * character
+     * @return replaced 
+     */
+    public static String wildCardToLike(String s) {
+        s = StringUtil.escapeLike(s);
+        StringBuilder buf = new StringBuilder();
+        // Look for another unprotected * or ? in the middle
+        int i = 0;
+        int j = 0;
+        while (true) {
+            int pctPos = s.indexOf(StringUtil.MULTI_CHAR_WILDCARD, i);
+            int underPos = s.indexOf(StringUtil.SINGLE_CHAR_WILDCARD, i);
+            if (pctPos == -1 && underPos == -1) {
+                return i == 0 ? s : buf.append(s.substring(i)).toString();
+            }
+            i = pctPos;
+            if (underPos != -1 && (i == -1 || underPos < i)) {
+                i = underPos;
+            }
+            
+            if (i > 0 && s.charAt(i - 1) == '\\') {
+                // If we found protection then keep looking
+                buf.append(s.substring(j,i-1));
+                buf.append(s.charAt(i));
+            } else {
+                // We found an unprotected % or _ in the middle
+                buf.append(s.substring(j,i));
+                buf.append(s.charAt(i) == StringUtil.MULTI_CHAR_WILDCARD ? StringUtil.MULTI_CHAR_LIKE : StringUtil.SINGLE_CHAR_LIKE);
+            }
+            j = ++i;
+        }
+    }
+    
+    public static int indexOfWildcard(String s) {
+        // Look for another unprotected % or _ in the middle
+        if (s == null) {
+            return -1;
+        }
+        int i = 0;
+        while (true) {
+            int pctPos = s.indexOf(StringUtil.MULTI_CHAR_LIKE, i);
+            int underPos = s.indexOf(StringUtil.SINGLE_CHAR_LIKE, i);
+            if (pctPos == -1 && underPos == -1) {
+                return -1;
+            }
+            i = pctPos;
+            if (underPos != -1 && (i == -1 || underPos < i)) {
+                i = underPos;
+            }
+            
+            if (i > 0 && s.charAt(i - 1) == '\\') {
+                // If we found protection then keep looking
+                i++;
+            } else {
+                // We found an unprotected % or _ in the middle
+                return i;
+            }
+        }
+    }
+
+    private static String toPattern(String s) {
+        StringBuilder sb = new StringBuilder(s.length());
+
+        // From the JDK doc: \Q and \E protect everything between them
+        sb.append("\\Q");
+        boolean wasSlash = false;
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i);
+            if (wasSlash) {
+                sb.append(c);
+                wasSlash = false;
+            } else if (c == StringUtil.SINGLE_CHAR_LIKE) {
+                sb.append(ANY_ONE);
+            } else if (c == StringUtil.MULTI_CHAR_LIKE) {
+                sb.append(ZERO_OR_MORE);
+            } else if (c == '\\') {
+                wasSlash = true;
+            } else {
+                sb.append(c);
+            }
+        }
+        sb.append("\\E");
+        // Found nothing interesting
+        return sb.toString();
+    }
+
+//    private static String fromPattern(String s) {
+//        StringBuilder sb = new StringBuilder(s.length());
+//
+//        for (int i = 0; i < s.length(); i++) {
+//            if (s.substring(i).startsWith("\\Q")) {
+//                while (s.substring(i + "\\Q".length()).startsWith("\\E")) {
+//                    sb.append(s.charAt(i++ + "\\Q".length()));
+//                }
+//                i+= "\\E".length();
+//            }
+//            if (s.charAt(i) == '.') {
+//                if (s.charAt(i+1) == '*') {
+//                    sb.append('%');
+//                    i+=2;                    
+//                } else {
+//                    sb.append('_');
+//                    i++;
+//                }
+//            }
+//        }
+//        return sb.toString();
+//    }
+
+    private Pattern pattern;
+    
+    public LikeExpression() {
+    }
+
+    public LikeExpression(List<Expression> children) {
+        super(children);
+        init();
+    }
+    
+    public boolean startsWithWildcard() {
+        return pattern != null && pattern.pattern().startsWith("\\Q\\E");
+    }
+    
+    private void init() {
+        Expression e = getPatternExpression();
+        if (e instanceof LiteralExpression) {
+            LiteralExpression patternExpression = (LiteralExpression)e;
+            String value = (String)patternExpression.getValue();
+            pattern = Pattern.compile(toPattern(value));
+        }
+    }
+
+    private Expression getStrExpression() {
+        return children.get(0);
+    }
+
+    private Expression getPatternExpression() {
+        return children.get(1);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Pattern pattern = this.pattern;
+        if (pattern == null) { // TODO: don't allow? this is going to be slooowwww
+            if (!getPatternExpression().evaluate(tuple, ptr)) {
+                if (logger.isDebugEnabled()) {
+                    logger.debug("LIKE is FALSE: pattern is null");
+                }
+                return false;
+            }
+            String value = (String)PDataType.VARCHAR.toObject(ptr, getPatternExpression().getColumnModifier());
+            pattern = Pattern.compile(toPattern(value));
+            if (logger.isDebugEnabled()) {
+                logger.debug("LIKE pattern is expression: " + pattern.pattern());
+            }
+        }
+        
+        if (!getStrExpression().evaluate(tuple, ptr)) {
+            if (logger.isDebugEnabled()) {
+                logger.debug("LIKE is FALSE: child expression is null");
+            }
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            return true;
+        }
+        
+        String value = (String)PDataType.VARCHAR.toObject(ptr, getStrExpression().getColumnModifier());
+        boolean matched = pattern.matcher(value).matches();
+        ptr.set(matched ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
+        if (logger.isDebugEnabled()) {
+            logger.debug("LIKE(value='" + value + "'pattern='" + pattern.pattern() + "' is " + matched);
+        }
+        return true;
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        init();
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.BOOLEAN;
+    }
+    
+    @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;
+    }
+
+    public String getLiteralPrefix() {
+        if (pattern == null) {
+            return "";
+        }
+        String pattern = this.pattern.pattern();
+        int fromIndex = "\\Q".length();
+        return pattern.substring(fromIndex, pattern.indexOf("\\E", fromIndex));
+    }
+
+    public boolean endsWithOnlyWildcard() {
+        if (pattern == null) {
+            return false;
+        }
+        String pattern = this.pattern.pattern();
+        String endsWith = ZERO_OR_MORE + "\\E";
+        return pattern.endsWith(endsWith) && 
+        pattern.lastIndexOf(ANY_ONE, pattern.length() - endsWith.length() - 1) == -1 &&
+        pattern.lastIndexOf(ZERO_OR_MORE, pattern.length() - endsWith.length() - 1) == -1;
+    }
+    
+    @Override
+    public String toString() {
+        return (children.get(0) + " LIKE " + children.get(1));
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LiteralExpression.java b/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
new file mode 100644
index 0000000..c86387d
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
@@ -0,0 +1,260 @@
+/*
+ * 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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.sql.SQLException;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.exception.SQLExceptionInfo;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.IllegalDataException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.TypeMismatchException;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.StringUtil;
+
+
+
+/**
+ * 
+ * Accessor for a literal value.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class LiteralExpression extends BaseTerminalExpression {
+    public static final LiteralExpression NULL_EXPRESSION = new LiteralExpression(null);
+    private static final LiteralExpression[] TYPED_NULL_EXPRESSIONS = new LiteralExpression[PDataType.values().length];
+    static {
+        for (int i = 0; i < TYPED_NULL_EXPRESSIONS.length; i++) {
+            TYPED_NULL_EXPRESSIONS[i] = new LiteralExpression(PDataType.values()[i]);
+        }
+    }
+    public static final LiteralExpression FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE));
+    public static final LiteralExpression TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE));
+
+    private Object value;
+    private PDataType type;
+    private byte[] byteValue;
+    private Integer byteSize;
+    private Integer maxLength;
+    private Integer scale;
+    private ColumnModifier columnModifier;
+
+    // TODO: cache?
+    public static LiteralExpression newConstant(Object value) {
+        if (Boolean.FALSE.equals(value)) {
+            return FALSE_EXPRESSION;
+        }
+        if (Boolean.TRUE.equals(value)) {
+            return TRUE_EXPRESSION;
+        }
+        if (value == null) {
+            return NULL_EXPRESSION;
+        }
+        PDataType type = PDataType.fromLiteral(value);
+        byte[] b = type.toBytes(value);
+        if (b.length == 0) {
+            return TYPED_NULL_EXPRESSIONS[type.ordinal()];
+        }
+        if (type == PDataType.VARCHAR) {
+            String s = (String) value;
+            if (s.length() == b.length) { // single byte characters only
+                type = PDataType.CHAR;
+            }
+        }
+        return new LiteralExpression(value, type, b);
+    }
+
+    public static LiteralExpression newConstant(Object value, PDataType type) throws SQLException {
+        return newConstant(value, type, null);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, ColumnModifier columnModifier) throws SQLException {
+        return newConstant(value, type, null, null, columnModifier);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale) throws SQLException { // remove?
+        return newConstant(value, type, maxLength, scale, null);
+    }
+
+    // TODO: cache?
+    public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, ColumnModifier columnModifier)
+            throws SQLException {
+        if (value == null) {
+            if (type == null) {
+                return NULL_EXPRESSION;
+            }
+            return TYPED_NULL_EXPRESSIONS[type.ordinal()];
+        }
+        PDataType actualType = PDataType.fromLiteral(value);
+        if (!actualType.isCoercibleTo(type, value)) {
+            throw new TypeMismatchException(type, actualType, value.toString());
+        }
+        value = type.toObject(value, actualType);
+        try {
+            byte[] b = type.toBytes(value, columnModifier);
+            if (type == PDataType.VARCHAR || type == PDataType.CHAR) {
+                if (type == PDataType.CHAR && maxLength != null  && b.length < maxLength) {
+                    b = StringUtil.padChar(b, maxLength);
+                } else if (value != null) {
+                    maxLength = ((String)value).length();
+                }
+            }
+            if (b.length == 0) {
+                return TYPED_NULL_EXPRESSIONS[type.ordinal()];
+            }
+            return new LiteralExpression(value, type, b, maxLength, scale, columnModifier);
+        } catch (IllegalDataException e) {
+            throw new SQLExceptionInfo.Builder(SQLExceptionCode.ILLEGAL_DATA).setRootCause(e).build().buildException();
+        }
+    }
+
+    public LiteralExpression() {
+    }
+
+    private LiteralExpression(PDataType type) {
+        this(null, type, ByteUtil.EMPTY_BYTE_ARRAY);
+    }
+
+    private LiteralExpression(Object value, PDataType type, byte[] byteValue) {
+        this(value, type, byteValue, type == null? null : type.getMaxLength(value), type == null? null : type.getScale(value), null);
+    }
+
+    private LiteralExpression(Object value, PDataType type, byte[] byteValue,
+            Integer maxLength, Integer scale, ColumnModifier columnModifier) {
+        this.value = value;
+        this.type = type;
+        this.byteValue = byteValue;
+        this.byteSize = byteValue.length;
+        this.maxLength = maxLength;
+        this.scale = scale;
+        this.columnModifier = columnModifier;
+    }
+
+    @Override
+    public String toString() {
+        return type != null && type.isCoercibleTo(PDataType.VARCHAR) ? "'" + value + "'" : "" + value;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((value == null) ? 0 : value.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;
+        LiteralExpression other = (LiteralExpression)obj;
+        if (value == null) {
+            if (other.value != null) return false;
+        } else if (!value.equals(other.value)) return false;
+        return true;
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        this.byteValue = Bytes.readByteArray(input);
+        columnModifier = ColumnModifier.fromSystemValue(WritableUtils.readVInt(input));
+        if (this.byteValue.length > 0) {
+            this.type = PDataType.values()[WritableUtils.readVInt(input)];
+            this.value = this.type.toObject(byteValue, 0, byteValue.length, this.type, columnModifier);
+        }
+        byteSize = this.byteValue.length;
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        Bytes.writeByteArray(output, byteValue);
+        WritableUtils.writeVInt(output, ColumnModifier.toSystemValue(columnModifier));
+        if (this.byteValue.length > 0) {
+            WritableUtils.writeVInt(output, this.type.ordinal());
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        // Literal always evaluates, even when it returns null
+        ptr.set(byteValue);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return type;
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return byteSize;
+    }
+
+    @Override
+    public Integer getMaxLength() {
+        return maxLength;
+    }
+
+    @Override
+    public Integer getScale() {
+        return scale;
+    }
+    
+    @Override
+    public ColumnModifier getColumnModifier() {
+        return columnModifier;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return value == null;
+    }
+
+    public Object getValue() {
+        return value;
+    }
+
+    public byte[] getBytes() {
+        return byteValue;
+    }
+
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        return visitor.visit(this);
+    }
+    
+    @Override
+    public boolean isConstant() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LongAddExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LongAddExpression.java b/src/main/java/org/apache/phoenix/expression/LongAddExpression.java
new file mode 100644
index 0000000..a14286d
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LongAddExpression.java
@@ -0,0 +1,62 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+public class LongAddExpression extends AddExpression {
+
+    public LongAddExpression() {
+    }
+
+    public LongAddExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        long finalResult=0;
+        
+        for(int i=0;i<children.size();i++) {
+            Expression child = children.get(i);
+            if (!child.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+                return false;
+            }
+            long childvalue = child.getDataType().getCodec().decodeLong(ptr, child.getColumnModifier());
+            finalResult += childvalue;
+        }
+        byte[] resultPtr=new byte[PDataType.LONG.getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeLong(finalResult, ptr);
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.LONG;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java b/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java
new file mode 100644
index 0000000..68560a6
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java
@@ -0,0 +1,66 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+public class LongDivideExpression extends DivideExpression {
+
+    public LongDivideExpression() {
+    }
+
+    public LongDivideExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        long finalResult=0;
+        
+        for(int i=0;i<children.size();i++) {
+            Expression child = children.get(i);
+            if (!child.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+                return false;
+            }
+            long childvalue = child.getDataType().getCodec().decodeLong(ptr, child.getColumnModifier()); 
+            if (i == 0) {
+                finalResult = childvalue;
+            } else {
+                finalResult /= childvalue;
+            }
+        }
+        byte[] resultPtr=new byte[PDataType.LONG.getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeLong(finalResult, ptr);
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.LONG;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java b/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java
new file mode 100644
index 0000000..508d33c
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java
@@ -0,0 +1,65 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+public class LongMultiplyExpression extends MultiplyExpression {
+
+    public LongMultiplyExpression() {
+    }
+
+    public LongMultiplyExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        long finalResult=1;
+        
+        for(int i=0;i<children.size();i++) {
+            Expression child = children.get(i);
+            if (!child.evaluate(tuple, ptr)) {
+                return false;
+            }
+            if (ptr.getLength() == 0) {
+                return false;
+            }
+            long childvalue = child.getDataType().getCodec().decodeLong(ptr, child.getColumnModifier());
+            finalResult *= childvalue;
+        }
+        byte[] resultPtr=new byte[getDataType().getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeLong(finalResult, ptr);
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.LONG;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java b/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java
new file mode 100644
index 0000000..56317d6
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java
@@ -0,0 +1,83 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+
+/**
+ * 
+ * Subtract expression implementation
+ *
+ * @author kmahadik
+ * @since 0.1
+ */
+public class LongSubtractExpression extends SubtractExpression {
+    public LongSubtractExpression() {
+    }
+
+    public LongSubtractExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+	public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+		long finalResult=0;
+		
+		for(int i=0;i<children.size();i++) {
+		    Expression child = children.get(i);
+            if (!child.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+                return false;
+            }
+            PDataType childType = child.getDataType();
+            boolean isDate = childType.isCoercibleTo(PDataType.DATE);
+            long childvalue = childType.getCodec().decodeLong(ptr, child.getColumnModifier());
+            if (i == 0) {
+                finalResult = childvalue;
+            } else {
+                finalResult -= childvalue;
+                /*
+                 * Special case for date subtraction - note that only first two expression may be dates.
+                 * We need to convert the date to a unit of "days" because that's what sql expects.
+                 */
+                if (isDate) {
+                    finalResult /= QueryConstants.MILLIS_IN_DAY;
+                }
+            }
+		}
+		byte[] resultPtr=new byte[getDataType().getByteSize()];
+		ptr.set(resultPtr);
+		getDataType().getCodec().encodeLong(finalResult, ptr);
+		return true;
+	}
+
+	@Override
+	public final PDataType getDataType() {
+		return PDataType.LONG;
+	}
+	
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java b/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java
new file mode 100644
index 0000000..fa815a2
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java
@@ -0,0 +1,98 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+
+
+/**
+ * 
+ * Subtract expression implementation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class MultiplyExpression extends ArithmeticExpression {
+    private Integer maxLength;
+    private Integer scale;
+
+    public MultiplyExpression() {
+    }
+
+    public MultiplyExpression(List<Expression> children) {
+        super(children);
+        for (int i=0; i<children.size(); i++) {
+            Expression childExpr = children.get(i);
+            if (i == 0) {
+                maxLength = childExpr.getMaxLength();
+                scale = childExpr.getScale();
+            } else {
+                maxLength = getPrecision(maxLength, childExpr.getMaxLength(), scale, childExpr.getScale());
+                scale = getScale(maxLength, childExpr.getMaxLength(), scale, childExpr.getScale());
+            }
+        }
+    }
+
+    @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;
+    }
+
+    @Override
+    public String getOperatorString() {
+        return " * ";
+    }
+    
+    private static Integer getPrecision(Integer lp, Integer rp, Integer ls, Integer rs) {
+    	if (ls == null || rs == null) {
+    		return PDataType.MAX_PRECISION;
+    	}
+        int val = lp + rp;
+        return Math.min(PDataType.MAX_PRECISION, val);
+    }
+
+    private static Integer getScale(Integer lp, Integer rp, Integer ls, Integer rs) {
+    	// If we are adding a decimal with scale and precision to a decimal
+    	// with no precision nor scale, the scale system does not apply.
+    	if (ls == null || rs == null) {
+    		return null;
+    	}
+        int val = ls + rs;
+        return Math.min(PDataType.MAX_PRECISION, val);
+    }
+    
+    @Override
+    public Integer getScale() {
+        return scale;
+    }
+
+    @Override
+    public Integer getMaxLength() {
+        return maxLength;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/NotExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/NotExpression.java b/src/main/java/org/apache/phoenix/expression/NotExpression.java
new file mode 100644
index 0000000..c3a07c9
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/NotExpression.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;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Implementation of the NOT operator that negates it's
+ * single boolean child expression.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class NotExpression extends BaseSingleExpression {
+
+    public NotExpression() {
+    }
+
+    public NotExpression(Expression expression) {
+        super(expression);
+        if (expression == null || expression.getDataType() != PDataType.BOOLEAN) {
+            throw new IllegalArgumentException("NOT expectes a single BOOLEAN expression, but got " + expression);
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!getChild().evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            return true;
+        }
+        
+        ptr.set(Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr)) ? PDataType.FALSE_BYTES : PDataType.TRUE_BYTES);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.BOOLEAN;
+    }
+    
+    @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;
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("NOT (");
+        buf.append(children.get(0).toString());
+        buf.append(")");
+        return buf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/OrExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/OrExpression.java b/src/main/java/org/apache/phoenix/expression/OrExpression.java
new file mode 100644
index 0000000..7339852
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/OrExpression.java
@@ -0,0 +1,67 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+/**
+ * 
+ * OR expression implementation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class OrExpression extends AndOrExpression {
+    public OrExpression() {
+    }
+
+    public OrExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    protected boolean getStopValue() {
+        return Boolean.TRUE;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("(");
+        for (int i = 0; i < children.size() - 1; i++) {
+            buf.append(children.get(i) + " OR ");
+        }
+        buf.append(children.get(children.size()-1));
+        buf.append(')');
+        return buf.toString();
+    }
+    
+    @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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/OrderByExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/OrderByExpression.java b/src/main/java/org/apache/phoenix/expression/OrderByExpression.java
new file mode 100644
index 0000000..67d7e99
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/OrderByExpression.java
@@ -0,0 +1,87 @@
+package org.apache.phoenix.expression;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.io.Writable;
+import org.apache.hadoop.io.WritableUtils;
+
+/**
+ * A container for a column that appears in ORDER BY clause.
+ */
+public class OrderByExpression implements Writable {
+    private Expression expression;
+    private boolean isNullsLast;
+    private boolean isAscending;
+    
+    public OrderByExpression() {
+    }
+    
+    public OrderByExpression(Expression expression, boolean isNullsLast, boolean isAcending) {
+        checkNotNull(expression);
+        this.expression = expression;
+        this.isNullsLast = isNullsLast;
+        this.isAscending = isAcending;
+    }
+
+    public Expression getExpression() {
+        return expression;
+    }
+    
+    public boolean isNullsLast() {
+        return isNullsLast;
+    }
+    
+    public boolean isAscending() {
+        return isAscending;
+    }
+    
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o != null && this.getClass() == o.getClass()) {
+            OrderByExpression that = (OrderByExpression)o;
+            return isNullsLast == that.isNullsLast
+                && isAscending == that.isAscending
+                && expression.equals(that.expression);
+        }
+        return false;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (isNullsLast ? 0 : 1);
+        result = prime * result + (isAscending ? 0 : 1);
+        result = prime * result + expression.hashCode();
+        return result;
+    }
+    
+    @Override
+    public String toString() {
+        return this.getExpression() + (isAscending ? "" : " DESC") + (isNullsLast ? " NULLS LAST" : "");
+    }
+    
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        this.isNullsLast = input.readBoolean();
+        this.isAscending = input.readBoolean();
+        expression = ExpressionType.values()[WritableUtils.readVInt(input)].newInstance();
+        expression.readFields(input);
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        output.writeBoolean(isNullsLast);
+        output.writeBoolean(isAscending);
+        WritableUtils.writeVInt(output, ExpressionType.valueOf(expression).ordinal());
+        expression.write(output);
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/RowKeyColumnExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/RowKeyColumnExpression.java b/src/main/java/org/apache/phoenix/expression/RowKeyColumnExpression.java
new file mode 100644
index 0000000..383ef2e
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/RowKeyColumnExpression.java
@@ -0,0 +1,150 @@
+/*
+ * 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;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PDatum;
+import org.apache.phoenix.schema.RowKeyValueAccessor;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ * 
+ * Class to access a value stored in the row key
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class RowKeyColumnExpression  extends ColumnExpression {
+    private PDataType fromType;
+    private RowKeyValueAccessor accessor;
+    protected final String name;
+    
+    public RowKeyColumnExpression() {
+        name = null; // Only on client
+    }
+    
+    private RowKeyColumnExpression(PDatum datum, RowKeyValueAccessor accessor, PDataType fromType, String name) {
+        super(datum);
+        this.accessor = accessor;
+        this.fromType = fromType;
+        this.name = name;
+    }
+    
+    public RowKeyColumnExpression(PDatum datum, RowKeyValueAccessor accessor) {
+        this(datum, accessor, datum.getDataType(), datum.toString());
+    }
+    
+    public RowKeyColumnExpression(PDatum datum, RowKeyValueAccessor accessor, String name) {
+        this(datum, accessor, datum.getDataType(), name);
+    }
+    
+    public RowKeyColumnExpression(PDatum datum, RowKeyValueAccessor accessor, PDataType fromType) {
+        this(datum, accessor, fromType, datum.toString());
+    }
+    
+    public int getPosition() {
+        return accessor.getIndex();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + ((accessor == null) ? 0 : accessor.hashCode());
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return name == null ? "PK[" + accessor.getIndex() + "]" : name;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (!super.equals(obj)) return false;
+        if (getClass() != obj.getClass()) return false;
+        RowKeyColumnExpression other = (RowKeyColumnExpression)obj;
+        return accessor.equals(other.accessor);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        tuple.getKey(ptr);
+        int offset = accessor.getOffset(ptr.get(), ptr.getOffset());
+        // Null is represented in the last expression of a multi-part key 
+        // by the bytes not being present.
+        int maxOffset = ptr.getOffset() + ptr.getLength();
+        if (offset < maxOffset) {
+            byte[] buffer = ptr.get();
+            int fixedByteSize = -1;
+            // FIXME: fixedByteSize <= maxByteSize ? fixedByteSize : 0 required because HBase passes bogus keys to filter to position scan (HBASE-6562)
+            if (fromType.isFixedWidth()) {
+                fixedByteSize = getByteSize();
+                fixedByteSize = fixedByteSize <= maxOffset ? fixedByteSize : 0;
+            }
+            int length = fixedByteSize >= 0 ? fixedByteSize  : accessor.getLength(buffer, offset, maxOffset);
+            // In the middle of the key, an empty variable length byte array represents null
+            if (length > 0) {
+                /*
+                if (type == fromType) {
+                    ptr.set(buffer,offset,length);
+                } else {
+                    ptr.set(type.toBytes(type.toObject(buffer, offset, length, fromType)));
+                }
+                */
+                ptr.set(buffer,offset,length);
+                type.coerceBytes(ptr, fromType, getColumnModifier(), getColumnModifier());
+            } else {
+                ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        accessor = new RowKeyValueAccessor();
+        accessor.readFields(input);
+        fromType = type; // fromType only needed on client side
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        accessor.write(output);
+    }
+    
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        return visitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/RowKeyExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/RowKeyExpression.java b/src/main/java/org/apache/phoenix/expression/RowKeyExpression.java
new file mode 100644
index 0000000..c311932
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/RowKeyExpression.java
@@ -0,0 +1,25 @@
+package org.apache.phoenix.expression;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+public class RowKeyExpression extends BaseTerminalExpression {
+    public static final RowKeyExpression INSTANCE = new RowKeyExpression();
+    
+    private RowKeyExpression() {
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        tuple.getKey(ptr);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARBINARY;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/RowValueConstructorExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/RowValueConstructorExpression.java b/src/main/java/org/apache/phoenix/expression/RowValueConstructorExpression.java
new file mode 100644
index 0000000..ba7ec9c
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/RowValueConstructorExpression.java
@@ -0,0 +1,355 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementation for row value constructor (a,b,c) expression.
+ * 
+ * @author samarth.jain
+ * @since 0.1
+ */
+package org.apache.phoenix.expression;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import com.google.common.collect.Lists;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.TypeMismatchException;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.TrustedByteArrayOutputStream;
+
+public class RowValueConstructorExpression extends BaseCompoundExpression {
+    
+    private ImmutableBytesWritable ptrs[];
+    private ImmutableBytesWritable literalExprPtr;
+    private int counter;
+    private int estimatedByteSize;
+    
+    public static interface ExpressionComparabilityWrapper {
+        public Expression wrap(Expression lhs, Expression rhs);
+    }
+    /*
+     * Used to coerce the RHS to the expected type based on the LHS. In some circumstances,
+     * we may need to round the value up or down. For example:
+     * WHERE (a,b) < (2.4, 'foo')
+     * We take the ceiling of 2.4 to make it 3 if a is an INTEGER to prevent needing to coerce
+     * every time during evaluation.
+     */
+    private static ExpressionComparabilityWrapper[] WRAPPERS = new ExpressionComparabilityWrapper[CompareOp.values().length];
+    static {
+        WRAPPERS[CompareOp.LESS.ordinal()] = new ExpressionComparabilityWrapper() {
+
+            @Override
+            public Expression wrap(Expression lhs, Expression rhs) {
+                Expression e = rhs;
+                PDataType rhsType = rhs.getDataType();
+                PDataType lhsType = lhs.getDataType();
+                if (rhsType == PDataType.DECIMAL && lhsType != PDataType.DECIMAL) {
+                    e = new FloorDecimalExpression(rhs);
+                } else if (rhsType == PDataType.TIMESTAMP && lhsType != PDataType.TIMESTAMP) {
+                    e = new FloorTimestampExpression(rhs);
+                }
+                e = new CoerceExpression(e, lhsType, lhs.getColumnModifier(), lhs.getByteSize());
+                return e;
+            }
+            
+        };
+        WRAPPERS[CompareOp.LESS_OR_EQUAL.ordinal()] = WRAPPERS[CompareOp.LESS.ordinal()];
+        
+        WRAPPERS[CompareOp.GREATER.ordinal()] = new ExpressionComparabilityWrapper() {
+
+            @Override
+            public Expression wrap(Expression lhs, Expression rhs) {
+                Expression e = rhs;
+                PDataType rhsType = rhs.getDataType();
+                PDataType lhsType = lhs.getDataType();
+                if (rhsType == PDataType.DECIMAL && lhsType != PDataType.DECIMAL) {
+                    e = new CeilingDecimalExpression(rhs);
+                } else if (rhsType == PDataType.TIMESTAMP && lhsType != PDataType.TIMESTAMP) {
+                    e = new CeilingTimestampExpression(rhs);
+                }
+                e = new CoerceExpression(e, lhsType, lhs.getColumnModifier(), lhs.getByteSize());
+                return e;
+            }
+            
+        };
+        WRAPPERS[CompareOp.GREATER_OR_EQUAL.ordinal()] = WRAPPERS[CompareOp.GREATER.ordinal()];
+    }
+    
+    private static ExpressionComparabilityWrapper getWrapper(CompareOp op) {
+        ExpressionComparabilityWrapper wrapper = WRAPPERS[op.ordinal()];
+        if (wrapper == null) {
+            throw new IllegalStateException("Unexpected compare op of " + op + " for row value constructor");
+        }
+        return wrapper;
+    }
+    
+    /**
+     * Recursively coerce the RHS to match the LHS type, throwing if the types are incompatible. The
+     * recursion occurs when the RHS or LHS is a row value constructor.
+     * TODO: this no longer needs to be recursive, as we flatten out rvc when we normalize the statement.
+     * @param lhs left hand side expression
+     * @param rhs right hand side expression
+     * @param op operator being used to compare the expressions, which can affect rounding we may need to do.
+     * @return new row value constructor expression that has been coerced
+     * @throws SQLException
+     */
+    public static Expression coerce(Expression lhs, Expression rhs, CompareOp op) throws SQLException {
+        return coerce(lhs, rhs, getWrapper(op));
+    }
+        
+    public static Expression coerce(Expression lhs, Expression rhs, ExpressionComparabilityWrapper wrapper) throws SQLException {
+        
+        if (lhs instanceof RowValueConstructorExpression && rhs instanceof RowValueConstructorExpression) {
+            int i = 0;
+            List<Expression> coercedNodes = Lists.newArrayListWithExpectedSize(Math.max(lhs.getChildren().size(), rhs.getChildren().size()));
+            for (; i < Math.min(lhs.getChildren().size(),rhs.getChildren().size()); i++) {
+                coercedNodes.add(coerce(lhs.getChildren().get(i), rhs.getChildren().get(i), wrapper));
+            }
+            for (; i < lhs.getChildren().size(); i++) {
+                coercedNodes.add(coerce(lhs.getChildren().get(i), null, wrapper));
+            }
+            for (; i < rhs.getChildren().size(); i++) {
+                coercedNodes.add(coerce(null, rhs.getChildren().get(i), wrapper));
+            }
+            trimTrailingNulls(coercedNodes);
+            return coercedNodes.equals(rhs.getChildren()) ? rhs : new RowValueConstructorExpression(coercedNodes, rhs.isConstant());
+        } else if (lhs instanceof RowValueConstructorExpression) {
+            List<Expression> coercedNodes = Lists.newArrayListWithExpectedSize(Math.max(rhs.getChildren().size(), lhs.getChildren().size()));
+            coercedNodes.add(coerce(lhs.getChildren().get(0), rhs, wrapper));
+            for (int i = 1; i < lhs.getChildren().size(); i++) {
+                coercedNodes.add(coerce(lhs.getChildren().get(i), null, wrapper));
+            }
+            trimTrailingNulls(coercedNodes);
+            return coercedNodes.equals(rhs.getChildren()) ? rhs : new RowValueConstructorExpression(coercedNodes, rhs.isConstant());
+        } else if (rhs instanceof RowValueConstructorExpression) {
+            List<Expression> coercedNodes = Lists.newArrayListWithExpectedSize(Math.max(rhs.getChildren().size(), lhs.getChildren().size()));
+            coercedNodes.add(coerce(lhs, rhs.getChildren().get(0), wrapper));
+            for (int i = 1; i < rhs.getChildren().size(); i++) {
+                coercedNodes.add(coerce(null, rhs.getChildren().get(i), wrapper));
+            }
+            trimTrailingNulls(coercedNodes);
+            return coercedNodes.equals(rhs.getChildren()) ? rhs : new RowValueConstructorExpression(coercedNodes, rhs.isConstant());
+        } else if (lhs == null && rhs == null) {
+            return LiteralExpression.newConstant(null);
+        } else if (lhs == null) { 
+            return rhs;
+        } else if (rhs == null) {
+            return LiteralExpression.newConstant(null, lhs.getDataType());
+        } else {
+            if (rhs.getDataType() != null && lhs.getDataType() != null && !rhs.getDataType().isCastableTo(lhs.getDataType())) {
+                throw new TypeMismatchException(lhs.getDataType(), rhs.getDataType());
+            }
+            return wrapper.wrap(lhs, rhs);
+        }
+    }
+    
+    private static void trimTrailingNulls(List<Expression> expressions) {
+        for (int i = expressions.size() - 1; i >= 0; i--) {
+            Expression e = expressions.get(i);
+            if (e instanceof LiteralExpression && ((LiteralExpression)e).getValue() == null) {
+                expressions.remove(i);
+            } else {
+                break;
+            }
+        }
+    }
+
+
+    public RowValueConstructorExpression() {
+    }
+    
+    public RowValueConstructorExpression(List<Expression> children, boolean isConstant) {
+        super(children);
+        counter = 0;
+        estimatedByteSize = 0;
+        init(isConstant);
+    }
+
+    public int getEstimatedSize() {
+        return estimatedByteSize;
+    }
+    
+    @Override
+    public boolean isConstant() {
+        return literalExprPtr != null;
+    }
+    
+    @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;
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        init(input.readBoolean());
+    }
+    
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        output.writeBoolean(literalExprPtr != null);
+    }
+    
+    private void init(boolean isConstant) {
+        this.ptrs = new ImmutableBytesWritable[children.size()];
+        if(isConstant) {
+            ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+            this.evaluate(null, ptr);
+            literalExprPtr = ptr;
+        }
+    }
+    
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARBINARY;
+    }
+    
+    @Override
+    public void reset() {
+        counter = 0;
+        estimatedByteSize = 0;
+        Arrays.fill(ptrs, null);
+    }
+    
+    private static int getExpressionByteCount(Expression e) {
+        PDataType childType = e.getDataType();
+        if (childType != null && !childType.isFixedWidth()) {
+            return 1;
+        } else {
+            // Write at least one null byte in the case of the child being null with a childType of null
+            Integer byteSize = e.getByteSize();
+            int bytesToWrite = byteSize == null ? 1 : Math.max(1, byteSize);
+            return bytesToWrite;
+        }
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if(literalExprPtr != null) {
+            // if determined during construction that the row value constructor is just comprised of literal expressions, 
+            // let's just return the ptr we have already computed and be done with evaluation.
+            ptr.set(literalExprPtr.get(), literalExprPtr.getOffset(), literalExprPtr.getLength());
+            return true;
+        }
+        try {
+            int j;
+            int expressionCount = counter;
+            for(j = counter; j < ptrs.length; j++) {
+                final Expression expression = children.get(j);
+                // TODO: handle overflow and underflow
+                if (expression.evaluate(tuple, ptr)) {
+                    if (ptr.getLength() == 0) {
+                        estimatedByteSize += getExpressionByteCount(expression);
+                    } else {
+                        expressionCount = j+1;
+                        ptrs[j] = new ImmutableBytesWritable();
+                        ptrs[j].set(ptr.get(), ptr.getOffset(), ptr.getLength());
+                        estimatedByteSize += ptr.getLength() + (expression.getDataType().isFixedWidth() ? 0 : 1); // 1 extra for the separator byte.
+                    }
+                    counter++;
+                } else if (tuple == null || tuple.isImmutable()) {
+                    estimatedByteSize += getExpressionByteCount(expression);
+                    counter++;
+                } else {
+                    return false;
+                }
+            }
+            
+            if (j == ptrs.length) {
+                if (expressionCount == 0) {
+                    ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+                    return true;
+                }
+                if (expressionCount == 1) {
+                    ptr.set(ptrs[0].get(), ptrs[0].getOffset(), ptrs[0].getLength());
+                    return true;
+                }
+                TrustedByteArrayOutputStream output = new TrustedByteArrayOutputStream(estimatedByteSize);
+                try {
+                    boolean previousCarryOver = false;
+                    for (int i = 0; i< expressionCount; i++) {
+                        Expression child = getChildren().get(i);
+                        PDataType childType = child.getDataType();
+                        ImmutableBytesWritable tempPtr = ptrs[i];
+                        if (tempPtr == null) {
+                            // Since we have a null and have no representation for null,
+                            // we must decrement the value of the current. Otherwise,
+                            // we'd have an ambiguity if this value happened to be the
+                            // min possible value.
+                            previousCarryOver = childType == null || childType.isFixedWidth();
+                            int bytesToWrite = getExpressionByteCount(child);
+                            for (int m = 0; m < bytesToWrite; m++) {
+                                output.write(QueryConstants.SEPARATOR_BYTE);
+                            }
+                        } else {
+                            output.write(tempPtr.get(), tempPtr.getOffset(), tempPtr.getLength());
+                            if (!childType.isFixedWidth()) {
+                                output.write(QueryConstants.SEPARATOR_BYTE);
+                            }
+                            if (previousCarryOver) {
+                                previousCarryOver = !ByteUtil.previousKey(output.getBuffer(), output.size());
+                            }
+                        }
+                    }
+                    int outputSize = output.size();
+                    byte[] outputBytes = output.getBuffer();
+                    for (int k = expressionCount -1 ; 
+                            k >=0 &&  getChildren().get(k).getDataType() != null && !getChildren().get(k).getDataType().isFixedWidth() && outputBytes[outputSize-1] == QueryConstants.SEPARATOR_BYTE ; k--) {
+                        outputSize--;
+                    }
+                    ptr.set(outputBytes, 0, outputSize);
+                    return true;
+                } finally {
+                    output.close();
+                }
+            }  
+            return false;
+        } catch (IOException e) {
+            throw new RuntimeException(e); //Impossible.
+        }
+    }
+    
+    @Override
+    public final String toString() {
+        StringBuilder buf = new StringBuilder("(");
+        for (int i = 0; i < children.size() - 1; i++) {
+            buf.append(children.get(i) + ", ");
+        }
+        buf.append(children.get(children.size()-1) + ")");
+        return buf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/StringConcatExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/StringConcatExpression.java b/src/main/java/org/apache/phoenix/expression/StringConcatExpression.java
new file mode 100644
index 0000000..24e96f7
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/StringConcatExpression.java
@@ -0,0 +1,95 @@
+/*
+ * 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;
+
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+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;
+
+
+/**
+ * 
+ * Implementation for || string concatenation expression.
+ * @author kmahadik
+ * @since 0.1
+ */
+
+public class StringConcatExpression extends BaseCompoundExpression {
+    public StringConcatExpression() {
+    }
+
+    public StringConcatExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder("(");
+        for (int i = 0; i < children.size() - 1; i++) {
+            buf.append(children.get(i) + " || ");
+        }
+        buf.append(children.get(children.size()-1));
+        buf.append(')');
+        return buf.toString();
+    }
+
+    @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;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        byte[] result = ByteUtil.EMPTY_BYTE_ARRAY;
+        for (int i=0; i<children.size(); i++) {
+            if (children.get(i).getDataType() == null || !children.get(i).evaluate(tuple, ptr)) {
+                continue;
+            }
+            PDataType childType = children.get(i).getDataType();
+            ColumnModifier columnModifier = children.get(i).getColumnModifier();
+            // We could potentially not invert the bytes, but we might as well since we're allocating
+            // additional space here anyway.
+            if (childType.isCoercibleTo(PDataType.VARCHAR)) {
+                result = ByteUtil.concat(result, ByteUtil.concat(columnModifier, ptr));
+            } else {
+                result = ByteUtil.concat(result, PDataType.VARCHAR.toBytes(childType.toObject(ptr, columnModifier).toString()));
+            }
+        }
+        ptr.set(result);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/SubtractExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/SubtractExpression.java b/src/main/java/org/apache/phoenix/expression/SubtractExpression.java
new file mode 100644
index 0000000..a9c9c93
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/SubtractExpression.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.query.QueryConstants;
+
+
+/**
+ * 
+ * Subtract expression implementation
+ *
+ * @author kmahadik
+ * @since 0.1
+ */
+public abstract class SubtractExpression extends BaseAddSubtractExpression {
+    protected static final BigDecimal BD_MILLIS_IN_DAY = BigDecimal.valueOf(QueryConstants.MILLIS_IN_DAY);
+
+    public SubtractExpression() {
+    }
+
+    public SubtractExpression(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;
+    }
+    
+    @Override
+    public String getOperatorString() {
+        return " - ";
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/TimestampAddExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/TimestampAddExpression.java b/src/main/java/org/apache/phoenix/expression/TimestampAddExpression.java
new file mode 100644
index 0000000..ae33ad4
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/TimestampAddExpression.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.DateUtil;
+
+/**
+ * 
+ * Class to encapsulate addition arithmetic for {@link PDataType#TIMESTAMP}.
+ *
+ * @author samarth.jain
+ * @since 2.1.3
+ */
+
+public class TimestampAddExpression extends AddExpression {
+
+    public TimestampAddExpression() {
+    }
+
+    public TimestampAddExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        BigDecimal finalResult = BigDecimal.ZERO;
+        
+        for(int i=0; i<children.size(); i++) {
+            if (!children.get(i).evaluate(tuple, ptr)) {
+                return false;
+            }
+            if (ptr.getLength() == 0) {
+                return true;
+            }
+            BigDecimal value;
+            PDataType type = children.get(i).getDataType();
+            ColumnModifier columnModifier = children.get(i).getColumnModifier();
+            if(type == PDataType.TIMESTAMP) {
+                value = (BigDecimal)(PDataType.DECIMAL.toObject(ptr, PDataType.TIMESTAMP, columnModifier));
+            } else if (type.isCoercibleTo(PDataType.DECIMAL)) {
+                value = (((BigDecimal)PDataType.DECIMAL.toObject(ptr, columnModifier)).multiply(QueryConstants.BD_MILLIS_IN_DAY)).setScale(6, RoundingMode.HALF_UP);
+            } else if (type.isCoercibleTo(PDataType.DOUBLE)) {
+                value = ((BigDecimal.valueOf(type.getCodec().decodeDouble(ptr, columnModifier))).multiply(QueryConstants.BD_MILLIS_IN_DAY)).setScale(6, RoundingMode.HALF_UP);
+            } else {
+                value = BigDecimal.valueOf(type.getCodec().decodeLong(ptr, columnModifier));
+            } 
+            finalResult = finalResult.add(value);
+        }
+        Timestamp ts = DateUtil.getTimestamp(finalResult);
+        byte[] resultPtr = new byte[getDataType().getByteSize()];
+        PDataType.TIMESTAMP.toBytes(ts, resultPtr, 0);
+        ptr.set(resultPtr);
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.TIMESTAMP;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/TimestampSubtractExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/TimestampSubtractExpression.java b/src/main/java/org/apache/phoenix/expression/TimestampSubtractExpression.java
new file mode 100644
index 0000000..2841d25
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/TimestampSubtractExpression.java
@@ -0,0 +1,89 @@
+/*
+ * 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;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.DateUtil;
+/**
+ * 
+ * Class to encapsulate subtraction arithmetic for {@link PDataType#TIMESTAMP}.
+ *
+ * @author samarth.jain
+ * @since 2.1.3
+ */
+public class TimestampSubtractExpression extends SubtractExpression {
+
+    public TimestampSubtractExpression() {
+    }
+
+    public TimestampSubtractExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        BigDecimal finalResult = BigDecimal.ZERO;
+        
+        for(int i=0; i<children.size(); i++) {
+            if (!children.get(i).evaluate(tuple, ptr)) {
+                return false;
+            }
+            if (ptr.getLength() == 0) {
+                return true;
+            }
+            BigDecimal value;
+            PDataType type = children.get(i).getDataType();
+            ColumnModifier columnModifier = children.get(i).getColumnModifier();
+            if(type == PDataType.TIMESTAMP) {
+                value = (BigDecimal)(PDataType.DECIMAL.toObject(ptr, PDataType.TIMESTAMP, columnModifier));
+            } else if (type.isCoercibleTo(PDataType.DECIMAL)) {
+                value = (((BigDecimal)PDataType.DECIMAL.toObject(ptr, columnModifier)).multiply(BD_MILLIS_IN_DAY)).setScale(6, RoundingMode.HALF_UP);
+            } else if (type.isCoercibleTo(PDataType.DOUBLE)) {
+                value = ((BigDecimal.valueOf(type.getCodec().decodeDouble(ptr, columnModifier))).multiply(BD_MILLIS_IN_DAY)).setScale(6, RoundingMode.HALF_UP);
+            } else {
+                value = BigDecimal.valueOf(type.getCodec().decodeLong(ptr, columnModifier));
+            }
+            if (i == 0) {
+                finalResult = value;
+            } else {
+                finalResult = finalResult.subtract(value);
+            }
+        }
+        Timestamp ts = DateUtil.getTimestamp(finalResult);
+        byte[] resultPtr = new byte[getDataType().getByteSize()];
+        PDataType.TIMESTAMP.toBytes(ts, resultPtr, 0);
+        ptr.set(resultPtr);
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.TIMESTAMP;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/aggregator/Aggregator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/aggregator/Aggregator.java b/src/main/java/org/apache/phoenix/expression/aggregator/Aggregator.java
new file mode 100644
index 0000000..4067eb4
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/aggregator/Aggregator.java
@@ -0,0 +1,48 @@
+/*
+ * 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.aggregator;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Interface to abstract the incremental calculation of an aggregated value.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public interface Aggregator extends Expression {
+    
+    /**
+     * Incrementally aggregate the value with the current row
+     * @param tuple the result containing all the key values of the row
+     * @param ptr the bytes pointer to the underlying result
+     */
+    public void aggregate(Tuple tuple, ImmutableBytesWritable ptr);
+    
+    /**
+     * Get the size in bytes
+     */
+    public int getSize();
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/aggregator/Aggregators.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/aggregator/Aggregators.java b/src/main/java/org/apache/phoenix/expression/aggregator/Aggregators.java
new file mode 100644
index 0000000..c25f02b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/aggregator/Aggregators.java
@@ -0,0 +1,125 @@
+/*
+ * 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.aggregator;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+import org.apache.phoenix.schema.KeyValueSchema;
+import org.apache.phoenix.schema.KeyValueSchema.KeyValueSchemaBuilder;
+import org.apache.phoenix.schema.ValueBitSet;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.SizedUtil;
+
+
+/**
+ * 
+ * Represents an ordered list of Aggregators
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class Aggregators {
+    protected final int size;
+    protected final KeyValueSchema schema;
+    protected final ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+    protected final ValueBitSet valueSet;
+    protected final Aggregator[] aggregators;
+    protected final SingleAggregateFunction[] functions;
+    
+    public int getSize() {
+        return size;
+    }
+    
+    public Aggregators(SingleAggregateFunction[] functions, Aggregator[] aggregators, int minNullableIndex) {
+        this.functions = functions;
+        this.aggregators = aggregators;
+        this.size = calculateSize(aggregators);
+        this.schema = newValueSchema(aggregators, minNullableIndex);
+        this.valueSet = ValueBitSet.newInstance(schema);
+    }
+    
+    public KeyValueSchema getValueSchema() {
+        return schema;
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(this.getClass().getName() + " [" + functions.length + "]:");
+        for (int i = 0; i < functions.length; i++) {
+            SingleAggregateFunction function = functions[i];
+            buf.append("\t" + i + ") " + function );
+        }
+        return buf.toString();
+    }
+    /**
+     * Aggregate over aggregators
+     * @param result the single row Result from scan iteration
+     */
+    abstract public void aggregate(Aggregator[] aggregators, Tuple result);
+
+    protected static int calculateSize(Aggregator[] aggregators) {
+        
+        int size = SizedUtil.ARRAY_SIZE /*aggregators[]*/  + (SizedUtil.POINTER_SIZE  * aggregators.length);
+        for (Aggregator aggregator : aggregators) {
+            size += aggregator.getSize();
+        }
+        return size;
+    }
+    
+    /**
+     * Get the ValueSchema for the Aggregators
+     */
+    private static KeyValueSchema newValueSchema(Aggregator[] aggregators, int minNullableIndex) {
+        KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(minNullableIndex);
+        for (int i = 0; i < aggregators.length; i++) {
+            Aggregator aggregator = aggregators[i];
+            builder.addField(aggregator);
+        }
+        return builder.build();
+    }
+
+    /**
+     * @return byte representation of the ValueSchema
+     */
+    public byte[] toBytes(Aggregator[] aggregators) {
+        return schema.toBytes(aggregators, valueSet, ptr);
+    }
+    
+    public int getAggregatorCount() {
+        return aggregators.length;
+    }
+
+    public Aggregator[] getAggregators() {
+        return aggregators;
+    }
+    
+    abstract public Aggregator[] newAggregators();
+    
+    public void reset(Aggregator[] aggregators) {
+        for (int i = 0; i < aggregators.length; i++) {
+            aggregators[i].reset();
+        }
+    }
+    
+    protected Aggregator getAggregator(int position) {
+        return aggregators[position];
+    }
+}