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 23:15:48 UTC

[32/51] [partial] Initial commit of master branch from github

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleDivideExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleDivideExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleDivideExpression.java
new file mode 100644
index 0000000..561cf90
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleDivideExpression.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;
+
+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 DoubleDivideExpression extends DivideExpression {
+
+    public DoubleDivideExpression() {
+    }
+
+    public DoubleDivideExpression(List<Expression> children) {
+        super(children);
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        double result = 0.0;
+        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 true;
+            }
+            double childvalue = child.getDataType().getCodec()
+                    .decodeDouble(ptr, child.getColumnModifier());
+            if (!Double.isNaN(childvalue)
+                    && childvalue != Double.NEGATIVE_INFINITY
+                    && childvalue != Double.POSITIVE_INFINITY) {
+                if (i == 0) {
+                    result = childvalue;
+                } else {
+                    result /= childvalue;
+                }
+            } else {
+                return false;
+            }
+        }
+        byte[] resultPtr = new byte[getDataType().getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeDouble(result, ptr);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DOUBLE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleMultiplyExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleMultiplyExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleMultiplyExpression.java
new file mode 100644
index 0000000..b9e8165
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleMultiplyExpression.java
@@ -0,0 +1,70 @@
+/*
+ * 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 DoubleMultiplyExpression extends MultiplyExpression {
+
+    public DoubleMultiplyExpression() {
+    }
+
+    public DoubleMultiplyExpression(List<Expression> children) {
+        super(children);
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        double result = 1.0;
+        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 true;
+            }
+            double childvalue = child.getDataType().getCodec()
+                    .decodeDouble(ptr, child.getColumnModifier());
+            if (!Double.isNaN(childvalue)
+                    && childvalue != Double.NEGATIVE_INFINITY
+                    && childvalue != Double.POSITIVE_INFINITY) {
+                result *= childvalue;
+            } else {
+                return false;
+            }
+        }
+        byte[] resultPtr = new byte[getDataType().getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeDouble(result, ptr);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DOUBLE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleSubtractExpression.java
new file mode 100644
index 0000000..8752c15
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleSubtractExpression.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;
+
+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 DoubleSubtractExpression extends SubtractExpression {
+
+    public DoubleSubtractExpression() {
+    }
+
+    public DoubleSubtractExpression(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        double result = 0.0;
+        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 true;
+            }
+            double childvalue = child.getDataType().getCodec()
+                    .decodeDouble(ptr, child.getColumnModifier());
+            if (!Double.isNaN(childvalue)
+                    && childvalue != Double.NEGATIVE_INFINITY
+                    && childvalue != Double.POSITIVE_INFINITY) {
+                if (i == 0) {
+                    result = childvalue;
+                } else {
+                    result -= childvalue;
+                }
+            } else {
+                return false;
+            }
+        }
+        byte[] resultPtr = new byte[getDataType().getByteSize()];
+        ptr.set(resultPtr);
+        getDataType().getCodec().encodeDouble(result, ptr);
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DOUBLE;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java
new file mode 100644
index 0000000..ddced6a
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/Expression.java
@@ -0,0 +1,82 @@
+/*
+ * 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.hadoop.io.Writable;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDatum;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Interface for general expression evaluation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public interface Expression extends PDatum, Writable {
+    /**
+     * Access the value by setting a pointer to it (as opposed to making
+     * a copy of it which can be expensive)
+     * @param tuple Single row result during scan iteration
+     * @param ptr Pointer to byte value being accessed
+     * @return true if the expression could be evaluated (i.e. ptr was set)
+     * and false otherwise
+     */
+    boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr);
+    
+    /**
+     * Means of traversing expression tree through visitor.
+     * @param visitor
+     */
+    <T> T accept(ExpressionVisitor<T> visitor);
+    
+    /**
+     * @return the child expressions
+     */
+    List<Expression> getChildren();
+    
+    /**
+     * Resets the state of a expression back to its initial state and
+     * enables the expession to be evaluated incrementally (which
+     * occurs during filter evaluation where we see one key value at
+     * a time; it's possible to evaluate immediately rather than
+     * wait until all key values have been seen). Note that when
+     * evaluating incrementally, you must call this method before
+     * processing a new row.
+     */
+    void reset();
+    
+    /**
+     * @return true if the expression can be evaluated without
+     * requiring a row Tuple and false otherwise.
+     */
+    boolean isStateless();
+    /**
+     * @return true if the expression returns the same output every
+     * time given the same input.
+     */
+    boolean isDeterministic();
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
new file mode 100644
index 0000000..c462878
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java
@@ -0,0 +1,192 @@
+/*
+ * 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.Map;
+
+import org.apache.phoenix.expression.function.ArrayIndexFunction;
+import org.apache.phoenix.expression.function.ArrayLengthFunction;
+import org.apache.phoenix.expression.function.CeilDateExpression;
+import org.apache.phoenix.expression.function.CeilDecimalExpression;
+import org.apache.phoenix.expression.function.CeilFunction;
+import org.apache.phoenix.expression.function.CeilTimestampExpression;
+import org.apache.phoenix.expression.function.CoalesceFunction;
+import org.apache.phoenix.expression.function.CountAggregateFunction;
+import org.apache.phoenix.expression.function.DistinctCountAggregateFunction;
+import org.apache.phoenix.expression.function.FloorDateExpression;
+import org.apache.phoenix.expression.function.FloorDecimalExpression;
+import org.apache.phoenix.expression.function.FloorFunction;
+import org.apache.phoenix.expression.function.IndexStateNameFunction;
+import org.apache.phoenix.expression.function.InvertFunction;
+import org.apache.phoenix.expression.function.LTrimFunction;
+import org.apache.phoenix.expression.function.LengthFunction;
+import org.apache.phoenix.expression.function.MaxAggregateFunction;
+import org.apache.phoenix.expression.function.MinAggregateFunction;
+import org.apache.phoenix.expression.function.PercentRankAggregateFunction;
+import org.apache.phoenix.expression.function.PercentileContAggregateFunction;
+import org.apache.phoenix.expression.function.PercentileDiscAggregateFunction;
+import org.apache.phoenix.expression.function.RTrimFunction;
+import org.apache.phoenix.expression.function.RegexpReplaceFunction;
+import org.apache.phoenix.expression.function.RegexpSubstrFunction;
+import org.apache.phoenix.expression.function.ReverseFunction;
+import org.apache.phoenix.expression.function.RoundDateExpression;
+import org.apache.phoenix.expression.function.RoundDecimalExpression;
+import org.apache.phoenix.expression.function.RoundFunction;
+import org.apache.phoenix.expression.function.RoundTimestampExpression;
+import org.apache.phoenix.expression.function.SQLTableTypeFunction;
+import org.apache.phoenix.expression.function.SQLViewTypeFunction;
+import org.apache.phoenix.expression.function.SqlTypeNameFunction;
+import org.apache.phoenix.expression.function.StddevPopFunction;
+import org.apache.phoenix.expression.function.StddevSampFunction;
+import org.apache.phoenix.expression.function.SubstrFunction;
+import org.apache.phoenix.expression.function.SumAggregateFunction;
+import org.apache.phoenix.expression.function.ToCharFunction;
+import org.apache.phoenix.expression.function.ToDateFunction;
+import org.apache.phoenix.expression.function.ToNumberFunction;
+import org.apache.phoenix.expression.function.TrimFunction;
+import org.apache.phoenix.expression.function.TruncFunction;
+
+import com.google.common.collect.Maps;
+
+/**
+ * 
+ * Enumeration of all Expression types that may be evaluated on the server-side.
+ * Used during serialization and deserialization to pass Expression between client
+ * and server.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public enum ExpressionType {
+    ReverseFunction(ReverseFunction.class),
+    RowKey(RowKeyColumnExpression.class),
+    KeyValue(KeyValueColumnExpression.class),
+    LiteralValue(LiteralExpression.class),
+    RoundFunction(RoundFunction.class),
+    FloorFunction(FloorFunction.class),
+    CeilFunction(CeilFunction.class),
+    RoundDateExpression(RoundDateExpression.class),
+    FloorDateExpression(FloorDateExpression.class),
+    CeilDateExpression(CeilDateExpression.class),
+    RoundTimestampExpression(RoundTimestampExpression.class),
+    CeilTimestampExpression(CeilTimestampExpression.class),
+    RoundDecimalExpression(RoundDecimalExpression.class),
+    FloorDecimalExpression(FloorDecimalExpression.class),
+    CeilDecimalExpression(CeilDecimalExpression.class),
+    TruncFunction(TruncFunction.class),
+    ToDateFunction(ToDateFunction.class),
+    ToCharFunction(ToCharFunction.class),
+    ToNumberFunction(ToNumberFunction.class),
+    CoerceFunction(CoerceExpression.class),
+    SubstrFunction(SubstrFunction.class),
+    AndExpression(AndExpression.class),
+    OrExpression(OrExpression.class),
+    ComparisonExpression(ComparisonExpression.class),
+    CountAggregateFunction(CountAggregateFunction.class),
+    SumAggregateFunction(SumAggregateFunction.class),
+    MinAggregateFunction(MinAggregateFunction.class),
+    MaxAggregateFunction(MaxAggregateFunction.class),
+    LikeExpression(LikeExpression.class),
+    NotExpression(NotExpression.class),
+    CaseExpression(CaseExpression.class),
+    InListExpression(InListExpression.class),
+    IsNullExpression(IsNullExpression.class),
+    LongSubtractExpression(LongSubtractExpression.class),
+    DateSubtractExpression(DateSubtractExpression.class),
+    DecimalSubtractExpression(DecimalSubtractExpression.class),
+    LongAddExpression(LongAddExpression.class),
+    DecimalAddExpression(DecimalAddExpression.class),
+    DateAddExpression(DateAddExpression.class),
+    LongMultiplyExpression(LongMultiplyExpression.class),
+    DecimalMultiplyExpression(DecimalMultiplyExpression.class),
+    LongDivideExpression(LongDivideExpression.class),
+    DecimalDivideExpression(DecimalDivideExpression.class),
+    CoalesceFunction(CoalesceFunction.class),
+    RegexpReplaceFunction(RegexpReplaceFunction.class),
+    SQLTypeNameFunction(SqlTypeNameFunction.class),
+    RegexpSubstrFunction(RegexpSubstrFunction.class),
+    StringConcatExpression(StringConcatExpression.class),
+    LengthFunction(LengthFunction.class),
+    LTrimFunction(LTrimFunction.class),
+    RTrimFunction(RTrimFunction.class),
+    TrimFunction(TrimFunction.class),
+    DistinctCountAggregateFunction(DistinctCountAggregateFunction.class),
+    PercentileContAggregateFunction(PercentileContAggregateFunction.class),
+    PercentRankAggregateFunction(PercentRankAggregateFunction.class),
+    StddevPopFunction(StddevPopFunction.class),
+    StddevSampFunction(StddevSampFunction.class),
+    PercentileDiscAggregateFunction(PercentileDiscAggregateFunction.class),
+    DoubleAddExpression(DoubleAddExpression.class),
+    DoubleSubtractExpression(DoubleSubtractExpression.class),
+    DoubleMultiplyExpression(DoubleMultiplyExpression.class),
+    DoubleDivideExpression(DoubleDivideExpression.class),
+    RowValueConstructorExpression(RowValueConstructorExpression.class),
+    SQLTableTypeFunction(SQLTableTypeFunction.class),
+    IndexKeyValue(IndexKeyValueColumnExpression.class),
+    IndexStateName(IndexStateNameFunction.class),
+    InvertFunction(InvertFunction.class),
+    ProjectedColumnExpression(ProjectedColumnExpression.class),
+    TimestampAddExpression(TimestampAddExpression.class),
+    TimestampSubtractExpression(TimestampSubtractExpression.class),
+    ArrayIndexFunction(ArrayIndexFunction.class),
+    ArrayLengthFunction(ArrayLengthFunction.class),
+    ArrayConstructorExpression(ArrayConstructorExpression.class),
+    SQLViewTypeFunction(SQLViewTypeFunction.class);
+    ExpressionType(Class<? extends Expression> clazz) {
+        this.clazz = clazz;
+    }
+
+    public Class<? extends Expression> getExpressionClass() {
+        return clazz;
+    }
+
+    private final Class<? extends Expression> clazz;
+
+    private static final Map<Class<? extends Expression>,ExpressionType> classToEnumMap = Maps.newHashMapWithExpectedSize(3);
+    static {
+        for (ExpressionType type : ExpressionType.values()) {
+            classToEnumMap.put(type.clazz, type);
+        }
+    }
+
+    /**
+     * Return the ExpressionType for a given Expression instance
+     */
+    public static ExpressionType valueOf(Expression expression) {
+        ExpressionType type = classToEnumMap.get(expression.getClass());
+        if (type == null) { // FIXME: this exception gets swallowed and retries happen
+            throw new IllegalArgumentException("No ExpressionType for " + expression.getClass());
+        }
+        return type;
+    }
+
+    /**
+     * Instantiates a DataAccessor based on its DataAccessorType
+     */
+    public Expression newInstance() {
+        try {
+            return clazz.newInstance();
+        } catch (InstantiationException e) {
+            throw new RuntimeException(e);
+        } catch (IllegalAccessException e) {
+            throw new RuntimeException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
new file mode 100644
index 0000000..f6a397d
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/InListExpression.java
@@ -0,0 +1,291 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.hadoop.hbase.index.util.ImmutableBytesPtr;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.ConstraintViolationException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+/*
+ * Implementation of a SQL foo IN (a,b,c) expression. Other than the first
+ * expression, child expressions must be constants.
+ *
+ */
+public class InListExpression extends BaseSingleExpression {
+    private LinkedHashSet<ImmutableBytesPtr> values;
+    private ImmutableBytesPtr minValue;
+    private ImmutableBytesPtr maxValue;
+    private int valuesByteLength;
+    private boolean containsNull;
+    private int fixedWidth = -1;
+    private ImmutableBytesPtr value = new ImmutableBytesPtr();
+    private List<Expression> keyExpressions; // client side only
+
+    public static Expression create (List<Expression> children, ImmutableBytesWritable ptr) throws SQLException {
+        Expression firstChild = children.get(0);
+        PDataType firstChildType = firstChild.getDataType();
+        
+        boolean addedNull = false;
+        List<Expression> keys = Lists.newArrayListWithExpectedSize(children.size());
+        List<Expression> coercedKeyExpressions = Lists.newArrayListWithExpectedSize(children.size());
+        keys.add(firstChild);
+        coercedKeyExpressions.add(firstChild);
+        for (int i = 1; i < children.size(); i++) {
+            Expression rhs = children.get(i);
+            if (rhs.evaluate(null, ptr)) {
+                if (ptr.getLength() == 0) {
+                    if (!addedNull) {
+                        addedNull = true;
+                        keys.add(LiteralExpression.newConstant(null, PDataType.VARBINARY, true));
+                        coercedKeyExpressions.add(LiteralExpression.newConstant(null, firstChildType, true));
+                    }
+                } else {
+                    // Don't specify the firstChild column modifier here, as we specify it in the LiteralExpression creation below
+                    try {
+                        firstChildType.coerceBytes(ptr, rhs.getDataType(), rhs.getColumnModifier(), null);
+                        keys.add(LiteralExpression.newConstant(ByteUtil.copyKeyBytesIfNecessary(ptr), PDataType.VARBINARY, firstChild.getColumnModifier(), true));
+                        if(rhs.getDataType() == firstChildType) {
+                            coercedKeyExpressions.add(rhs);
+                        } else {
+                            coercedKeyExpressions.add(CoerceExpression.create(rhs, firstChildType));    
+                        }
+                    } catch (ConstraintViolationException e) { // Ignore and continue
+                    }
+                }
+            }
+            
+        }
+        if (keys.size() == 1) {
+            return LiteralExpression.newConstant(false, PDataType.BOOLEAN, true);
+        }
+        if (keys.size() == 2 && addedNull) {
+            return LiteralExpression.newConstant(null, PDataType.BOOLEAN, true);
+        }
+        Expression expression;
+        // TODO: if inChildren.isEmpty() then Oracle throws a type mismatch exception. This means
+        // that none of the list elements match in type and there's no null element. We'd return
+        // false in this case. Should we throw?
+        if (keys.size() == 2) {
+            expression = new ComparisonExpression(CompareOp.EQUAL, keys);
+        } else {
+            expression = new InListExpression(keys, coercedKeyExpressions);
+        }
+        return expression;
+    }    
+    public InListExpression() {
+    }
+
+    private InListExpression(List<Expression> keys, List<Expression> keyExpressions) throws SQLException {
+        super(keyExpressions.get(0));
+        this.keyExpressions = keyExpressions.subList(1, keyExpressions.size());
+        Set<ImmutableBytesPtr> values = Sets.newHashSetWithExpectedSize(keys.size()-1);
+        int fixedWidth = -1;
+        boolean isFixedLength = true;
+        for (int i = 1; i < keys.size(); i++) {
+            ImmutableBytesPtr ptr = new ImmutableBytesPtr();
+            Expression child = keys.get(i);
+            assert(child.getDataType() == PDataType.VARBINARY);
+            child.evaluate(null, ptr);
+            if (ptr.getLength() == 0) {
+                containsNull = true;
+            } else {
+                if (values.add(ptr)) {
+                    int length = ptr.getLength();
+                    if (fixedWidth == -1) {
+                        fixedWidth = length;
+                    } else {
+                        isFixedLength &= fixedWidth == length;
+                    }
+                    
+                    valuesByteLength += ptr.getLength();
+                }
+            }
+        }
+        this.fixedWidth = isFixedLength ? fixedWidth : -1;
+        // Sort values by byte value so we can get min/max easily
+        ImmutableBytesPtr[] valuesArray = values.toArray(new ImmutableBytesPtr[values.size()]);
+        Arrays.sort(valuesArray, ByteUtil.BYTES_PTR_COMPARATOR);
+        this.minValue = valuesArray[0];
+        this.maxValue = valuesArray[valuesArray.length-1];
+        this.values = new LinkedHashSet<ImmutableBytesPtr>(Arrays.asList(valuesArray));
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!getChild().evaluate(tuple, ptr)) {
+            return false;
+        }
+        value.set(ptr);
+        if (values.contains(value)) {
+            ptr.set(PDataType.TRUE_BYTES);
+            return true;
+        }
+        if (containsNull) { // If any null value and value not found
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        ptr.set(PDataType.FALSE_BYTES);
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (containsNull ? 1231 : 1237);
+        result = prime * result + values.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;
+        InListExpression other = (InListExpression)obj;
+        if (containsNull != other.containsNull) return false;
+        if (!values.equals(other.values)) return false;
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.BOOLEAN;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return super.isNullable() || containsNull;
+    }
+
+    private int readValue(DataInput input, byte[] valuesBytes, int offset, ImmutableBytesPtr ptr) throws IOException {
+        int valueLen = fixedWidth == -1 ? WritableUtils.readVInt(input) : fixedWidth;
+        values.add(new ImmutableBytesPtr(valuesBytes,offset,valueLen));
+        return offset + valueLen;
+    }
+    
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        containsNull = input.readBoolean();
+        fixedWidth = WritableUtils.readVInt(input);
+        byte[] valuesBytes = Bytes.readByteArray(input);
+        valuesByteLength = valuesBytes.length;
+        int len = fixedWidth == -1 ? WritableUtils.readVInt(input) : valuesByteLength / fixedWidth;
+        values = Sets.newLinkedHashSetWithExpectedSize(len);
+        int offset = 0;
+        int i  = 0;
+        if (i < len) {
+            offset = readValue(input, valuesBytes, offset, minValue = new ImmutableBytesPtr());
+            while (++i < len-1) {
+                offset = readValue(input, valuesBytes, offset, new ImmutableBytesPtr());
+            }
+            if (i < len) {
+                offset = readValue(input, valuesBytes, offset, maxValue = new ImmutableBytesPtr());
+            } else {
+                maxValue = minValue;
+            }
+        } else {
+            minValue = maxValue = new ImmutableBytesPtr(ByteUtil.EMPTY_BYTE_ARRAY);
+        }
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        output.writeBoolean(containsNull);
+        WritableUtils.writeVInt(output, fixedWidth);
+        WritableUtils.writeVInt(output, valuesByteLength);
+        for (ImmutableBytesPtr ptr : values) {
+            output.write(ptr.get(), ptr.getOffset(), ptr.getLength());
+        }
+        if (fixedWidth == -1) {
+            WritableUtils.writeVInt(output, values.size());
+            for (ImmutableBytesPtr ptr : values) {
+                WritableUtils.writeVInt(output, ptr.getLength());
+            }
+        }
+    }
+
+    @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 List<Expression> getKeyExpressions() {
+        return keyExpressions;
+    }
+
+    public ImmutableBytesWritable getMinKey() {
+        return minValue;
+    }
+
+    public ImmutableBytesWritable getMaxKey() {
+        return maxValue;
+    }
+
+    @Override
+    public String toString() {
+        int maxToStringLen = 200;
+        Expression firstChild = children.get(0);
+        PDataType type = firstChild.getDataType();
+        StringBuilder buf = new StringBuilder(firstChild + " IN (");
+        if (containsNull) {
+            buf.append("null,");
+        }
+        for (ImmutableBytesPtr value : values) {
+            if (firstChild.getColumnModifier() != null) {
+                type.coerceBytes(value, type, firstChild.getColumnModifier(), null);
+            }
+            buf.append(type.toStringLiteral(value, null));
+            buf.append(',');
+            if (buf.length() >= maxToStringLen) {
+                buf.append("... ");
+                break;
+            }
+        }
+        buf.setCharAt(buf.length()-1,')');
+        return buf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/IndexKeyValueColumnExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/IndexKeyValueColumnExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/IndexKeyValueColumnExpression.java
new file mode 100644
index 0000000..fb066c1
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/IndexKeyValueColumnExpression.java
@@ -0,0 +1,26 @@
+package org.apache.phoenix.expression;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.util.IndexUtil;
+import org.apache.phoenix.util.SchemaUtil;
+
+public class IndexKeyValueColumnExpression extends KeyValueColumnExpression {
+    public IndexKeyValueColumnExpression() {
+    }
+
+    public IndexKeyValueColumnExpression(PColumn column) {
+        super(column);
+    }
+    
+    @Override
+    public String toString() {
+        // Translate to the data table column name
+        String indexColumnName = Bytes.toString(this.getColumnName());
+        String dataFamilyName = IndexUtil.getDataColumnFamilyName(indexColumnName);
+        String dataColumnName = IndexUtil.getDataColumnName(indexColumnName);
+        return SchemaUtil.getColumnDisplayName(dataFamilyName, dataColumnName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java
new file mode 100644
index 0000000..e6ef621
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/IsNullExpression.java
@@ -0,0 +1,106 @@
+/*
+ * 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.*;
+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 IS NULL and IS NOT NULL expression
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class IsNullExpression extends BaseSingleExpression {
+    private boolean isNegate;
+
+    public IsNullExpression() {
+    }
+    
+    public IsNullExpression(Expression expression, boolean negate) {
+        super(expression);
+        this.isNegate = negate;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        boolean evaluated = getChild().evaluate(tuple, ptr);
+        if (evaluated) {
+            ptr.set(isNegate ^ ptr.getLength() == 0 ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
+            return true;
+        }
+        if (tuple.isImmutable()) {
+            ptr.set(isNegate ? PDataType.FALSE_BYTES : PDataType.TRUE_BYTES);
+            return true;
+        }
+        
+        return false;
+    }
+
+    public boolean isNegate() {
+        return isNegate;
+    }
+    
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        isNegate = input.readBoolean();
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        output.writeBoolean(isNegate);
+    }
+
+    @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(children.get(0).toString());
+        if (isNegate) {
+            buf.append(" IS NOT NULL");
+        } else {
+            buf.append(" IS NULL");
+        }
+        return buf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/KeyValueColumnExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/KeyValueColumnExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/KeyValueColumnExpression.java
new file mode 100644
index 0000000..b082aba
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/KeyValueColumnExpression.java
@@ -0,0 +1,113 @@
+/*
+ * 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.util.Arrays;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.SchemaUtil;
+
+
+/**
+ * 
+ * Class to access a column value stored in a KeyValue
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class KeyValueColumnExpression extends ColumnExpression {
+    private byte[] cf;
+    private byte[] cq;
+
+    public KeyValueColumnExpression() {
+    }
+
+    public KeyValueColumnExpression(PColumn column) {
+        super(column);
+        this.cf = column.getFamilyName().getBytes();
+        this.cq = column.getName().getBytes();
+    }
+
+    public byte[] getColumnFamily() {
+        return cf;
+    }
+
+    public byte[] getColumnName() {
+        return cq;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + Arrays.hashCode(cf);
+        result = prime * result + Arrays.hashCode(cq);
+        return result;
+    }
+
+    // TODO: assumes single table
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        KeyValueColumnExpression other = (KeyValueColumnExpression)obj;
+        if (!Arrays.equals(cf, other.cf)) return false;
+        if (!Arrays.equals(cq, other.cq)) return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return SchemaUtil.getColumnDisplayName(cf, cq);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        return tuple.getValue(cf, cq, ptr);
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        cf = Bytes.readByteArray(input);
+        cq = Bytes.readByteArray(input);
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        super.write(output);
+        Bytes.writeByteArray(output, cf);
+        Bytes.writeByteArray(output, cq);
+    }
+
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        return visitor.visit(this);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
new file mode 100644
index 0000000..038f705
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
new file mode 100644
index 0000000..202bcb0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
@@ -0,0 +1,316 @@
+/*
+ * 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.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, false);
+    private static final LiteralExpression ND_NULL_EXPRESSION = new LiteralExpression(null, true);
+    private static final LiteralExpression[] TYPED_NULL_EXPRESSIONS = new LiteralExpression[PDataType.values().length * 2];
+    static {
+        for (int i = 0; i < PDataType.values().length; i++) {
+            TYPED_NULL_EXPRESSIONS[i] = new LiteralExpression(PDataType.values()[i], true);
+        }
+        for (int i = 0; i < PDataType.values().length; i++) {
+            TYPED_NULL_EXPRESSIONS[i+PDataType.values().length] = new LiteralExpression(PDataType.values()[i], false);
+        }
+    }
+    private static final LiteralExpression FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), true);
+    private static final LiteralExpression TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), true);
+    private static final LiteralExpression ND_FALSE_EXPRESSION = new LiteralExpression(Boolean.FALSE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.FALSE), false);
+    private static final LiteralExpression ND_TRUE_EXPRESSION = new LiteralExpression(Boolean.TRUE, PDataType.BOOLEAN, PDataType.BOOLEAN.toBytes(Boolean.TRUE), false);
+
+    private Object value;
+    private PDataType type;
+    private boolean isDeterministic;
+    private byte[] byteValue;
+    private Integer byteSize;
+    private Integer maxLength;
+    private Integer scale;
+    private ColumnModifier columnModifier;
+
+
+    public static boolean isFalse(Expression child) {
+        return child == FALSE_EXPRESSION || child == ND_FALSE_EXPRESSION;
+    }
+    
+    public static boolean isTrue(Expression child) {
+        return child == TRUE_EXPRESSION || child == ND_TRUE_EXPRESSION;
+    }
+    
+    public static LiteralExpression newConstant(Object value) {
+        return newConstant(value, true);
+    }
+    
+    // TODO: cache?
+    public static LiteralExpression newConstant(Object value, boolean isDeterministic) {
+        if (Boolean.FALSE.equals(value)) {
+            return isDeterministic ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION;
+        }
+        if (Boolean.TRUE.equals(value)) {
+            return isDeterministic ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION;
+        }
+        if (value == null) {
+            return isDeterministic ? NULL_EXPRESSION : ND_NULL_EXPRESSION;
+        }
+        PDataType type = PDataType.fromLiteral(value);
+        byte[] b = type.toBytes(value);
+        if (b.length == 0) {
+            return TYPED_NULL_EXPRESSIONS[type.ordinal() + ( isDeterministic ? 0 : TYPED_NULL_EXPRESSIONS.length/2)];
+        }
+        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, isDeterministic);
+    }
+
+    public static LiteralExpression newConstant(Object value, PDataType type) throws SQLException {
+        return newConstant(value, type, true);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, boolean isDeterministic) throws SQLException {
+        return newConstant(value, type, null, isDeterministic);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, ColumnModifier columnModifier) throws SQLException {
+        return newConstant(value, type, null, null, columnModifier, true);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, ColumnModifier columnModifier, boolean isDeterministic) throws SQLException {
+        return newConstant(value, type, null, null, columnModifier, isDeterministic);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale) throws SQLException {
+        return newConstant(value, type, maxLength, scale, null, true);
+    }
+    
+    public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, boolean isDeterministic) throws SQLException { // remove?
+        return newConstant(value, type, maxLength, scale, null, isDeterministic);
+    }
+
+    // TODO: cache?
+    public static LiteralExpression newConstant(Object value, PDataType type, Integer maxLength, Integer scale, ColumnModifier columnModifier, boolean isDeterministic)
+            throws SQLException {
+        if (value == null) {
+            if (type == null) {
+                return NULL_EXPRESSION;
+            }
+            return TYPED_NULL_EXPRESSIONS[type.ordinal()];
+        }
+        if (Boolean.FALSE.equals(value)) {
+            return isDeterministic ? FALSE_EXPRESSION : ND_FALSE_EXPRESSION;
+        }
+        if (Boolean.TRUE.equals(value)) {
+            return isDeterministic ? TRUE_EXPRESSION : ND_TRUE_EXPRESSION;
+        }
+        PDataType actualType = PDataType.fromLiteral(value);
+        // For array we should check individual element in it?
+        // It would be costly though!!!!!
+        if (!actualType.isCoercibleTo(type, value)) {
+            throw TypeMismatchException.newException(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, isDeterministic);
+        } catch (IllegalDataException e) {
+            throw new SQLExceptionInfo.Builder(SQLExceptionCode.ILLEGAL_DATA).setRootCause(e).build().buildException();
+        }
+    }
+
+    public LiteralExpression() {
+    }
+
+    private LiteralExpression(PDataType type, boolean isDeterministic) {
+        this(null, type, ByteUtil.EMPTY_BYTE_ARRAY, isDeterministic);
+    }
+
+    private LiteralExpression(Object value, PDataType type, byte[] byteValue, boolean isDeterministic) {
+        this(value, type, byteValue, type == null? null : type.getMaxLength(value), type == null? null : type.getScale(value), null, isDeterministic);
+    }
+
+    private LiteralExpression(Object value, PDataType type, byte[] byteValue,
+            Integer maxLength, Integer scale, ColumnModifier columnModifier, boolean isDeterministic) {
+        this.value = value;
+        this.type = type;
+        this.byteValue = byteValue;
+        this.byteSize = byteValue.length;
+        this.maxLength = maxLength;
+        this.scale = scale;
+        this.columnModifier = columnModifier;
+        this.isDeterministic = isDeterministic;
+    }
+
+    @Override
+    public boolean isDeterministic() {
+        return isDeterministic;
+    }
+    
+    @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 {
+        int encodedByteLengthAndBool = WritableUtils.readVInt(input);
+        this.isDeterministic = encodedByteLengthAndBool > 0;
+        int byteLength = Math.abs(encodedByteLengthAndBool)-1;
+        this.byteValue = new byte[byteLength];
+        input.readFully(byteValue, 0, byteLength);
+        columnModifier = ColumnModifier.fromSystemValue(WritableUtils.readVInt(input));
+        int typeOrdinal = WritableUtils.readVInt(input);
+        if (typeOrdinal < 0) {
+            this.type = null;
+        } else {
+            this.type = PDataType.values()[typeOrdinal];
+        }
+        if (this.byteValue.length == 0) {
+            this.value = null;
+        } else {
+            this.value = this.type.toObject(byteValue, 0, byteValue.length, this.type, columnModifier);
+        }
+        // Only to prevent continual reallocations of Integer
+        this.byteSize = this.byteValue.length;
+    }
+
+    @Override
+    public void write(DataOutput output) throws IOException {
+        WritableUtils.writeVInt(output, (byteValue.length + 1) * (this.isDeterministic ? 1 : -1));
+        output.write(byteValue);
+        WritableUtils.writeVInt(output, ColumnModifier.toSystemValue(columnModifier));
+        WritableUtils.writeVInt(output, type == null ? -1 : 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 isStateless() {
+        return true;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LongAddExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LongAddExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LongAddExpression.java
new file mode 100644
index 0000000..a14286d
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LongDivideExpression.java
new file mode 100644
index 0000000..68560a6
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LongMultiplyExpression.java
new file mode 100644
index 0000000..508d33c
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LongSubtractExpression.java
new file mode 100644
index 0000000..56317d6
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/MultiplyExpression.java
new file mode 100644
index 0000000..fa815a2
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/NotExpression.java
new file mode 100644
index 0000000..c3a07c9
--- /dev/null
+++ b/phoenix-core/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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/OrExpression.java
new file mode 100644
index 0000000..7339852
--- /dev/null
+++ b/phoenix-core/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;
+    }
+}