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:49 UTC
[33/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/AndExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
new file mode 100644
index 0000000..c35eca5
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
@@ -0,0 +1,79 @@
+/*
+ * 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;
+
+
+/**
+ *
+ * AND expression implementation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class AndExpression extends AndOrExpression {
+ private static final String AND = "AND";
+
+ public static String combine(String expression1, String expression2) {
+ if (expression1 == null) {
+ return expression2;
+ }
+ if (expression2 == null) {
+ return expression1;
+ }
+ return "(" + expression1 + ") " + AND + " (" + expression2 + ")";
+ }
+
+ public AndExpression() {
+ }
+
+ public AndExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected boolean getStopValue() {
+ return Boolean.FALSE;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder("(");
+ for (int i = 0; i < children.size() - 1; i++) {
+ buf.append(children.get(i) + " " + AND + " ");
+ }
+ 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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
new file mode 100644
index 0000000..aebd63a
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndOrExpression.java
@@ -0,0 +1,99 @@
+/*
+ * 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.BitSet;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Abstract expression implementation for compound AND and OR expressions
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class AndOrExpression extends BaseCompoundExpression {
+ // Remember evaluation of child expression for partial evaluation
+ private BitSet partialEvalState;
+
+ public AndOrExpression() {
+ }
+
+ public AndOrExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public int hashCode() {
+ return 31 * super.hashCode() + Boolean.valueOf(this.getStopValue()).hashCode();
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.BOOLEAN;
+ }
+
+ @Override
+ public void reset() {
+ if (partialEvalState == null) {
+ partialEvalState = new BitSet(children.size());
+ } else {
+ partialEvalState.clear();
+ }
+ super.reset();
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ boolean isNull = false;
+ boolean stopValue = getStopValue();
+ for (int i = 0; i < children.size(); i++) {
+ Expression child = children.get(i);
+ // If partial state is available, then use that to know we've already evaluated this
+ // child expression and do not need to do so again.
+ if (partialEvalState == null || !partialEvalState.get(i)) {
+ // Call through to child evaluate method matching parent call to allow child to optimize
+ // evaluate versus getValue code path.
+ if (child.evaluate(tuple, ptr)) {
+ // Short circuit if we see our stop value
+ if (Boolean.valueOf(stopValue).equals(PDataType.BOOLEAN.toObject(ptr, child.getDataType()))) {
+ return true;
+ } else if (partialEvalState != null) {
+ partialEvalState.set(i);
+ }
+ } else {
+ isNull = true;
+ }
+ }
+ }
+ if (isNull) {
+ return false;
+ }
+ return true;
+ }
+
+ protected abstract boolean getStopValue();
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/ArithmeticExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ArithmeticExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ArithmeticExpression.java
new file mode 100644
index 0000000..622d709
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ArithmeticExpression.java
@@ -0,0 +1,45 @@
+/*
+ * 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;
+
+public abstract class ArithmeticExpression extends BaseCompoundExpression {
+
+ public ArithmeticExpression() {
+ }
+
+ public ArithmeticExpression(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) + getOperatorString());
+ }
+ buf.append(children.get(children.size()-1));
+ buf.append(')');
+ return buf.toString();
+ }
+
+ abstract protected String getOperatorString();
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/ArrayConstructorExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ArrayConstructorExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ArrayConstructorExpression.java
new file mode 100644
index 0000000..6dbf865
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ArrayConstructorExpression.java
@@ -0,0 +1,101 @@
+/*
+ * 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.Types;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.schema.PArrayDataType;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PhoenixArray;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+/**
+ * Creates an expression for Upsert with Values/Select using ARRAY
+ */
+public class ArrayConstructorExpression extends BaseCompoundExpression {
+ private PDataType baseType;
+ private int position = -1;
+ private Object[] elements;
+
+
+ public ArrayConstructorExpression(List<Expression> children, PDataType baseType) {
+ super(children);
+ init(baseType);
+ }
+
+ private void init(PDataType baseType) {
+ this.baseType = baseType;
+ elements = new Object[getChildren().size()];
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.fromTypeId(baseType.getSqlType() + Types.ARRAY);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ position = 0;
+ Arrays.fill(elements, null);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ for (int i = position >= 0 ? position : 0; i < elements.length; i++) {
+ Expression child = children.get(i);
+ if (!child.evaluate(tuple, ptr)) {
+ if (tuple != null && !tuple.isImmutable()) {
+ if (position >= 0) position = i;
+ return false;
+ }
+ } else {
+ elements[i] = baseType.toObject(ptr, child.getDataType(), child.getColumnModifier());
+ }
+ }
+ if (position >= 0) position = elements.length;
+ PhoenixArray array = PArrayDataType.instantiatePhoenixArray(baseType, elements);
+ // FIXME: Need to see if this creation of an array and again back to byte[] can be avoided
+ ptr.set(getDataType().toBytes(array));
+ return true;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ int baseTypeOrdinal = WritableUtils.readVInt(input);
+ init(PDataType.values()[baseTypeOrdinal]);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeVInt(output, baseType.ordinal());
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseAddSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseAddSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseAddSubtractExpression.java
new file mode 100644
index 0000000..1b9e4e5
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseAddSubtractExpression.java
@@ -0,0 +1,53 @@
+/*
+ * 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.schema.PDataType;
+
+
+abstract public class BaseAddSubtractExpression extends ArithmeticExpression {
+ public BaseAddSubtractExpression() {
+ }
+
+ public BaseAddSubtractExpression(List<Expression> children) {
+ super(children);
+ }
+
+ protected static Integer getPrecision(Integer lp, Integer rp, Integer ls, Integer rs) {
+ if (ls == null || rs == null) {
+ return PDataType.MAX_PRECISION;
+ }
+ int val = getScale(lp, rp, ls, rs) + Math.max(lp - ls, rp - rs) + 1;
+ return Math.min(PDataType.MAX_PRECISION, val);
+ }
+
+ protected 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 = Math.max(ls, rs);
+ return Math.min(PDataType.MAX_PRECISION, val);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java
new file mode 100644
index 0000000..82a130d
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseCompoundExpression.java
@@ -0,0 +1,145 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+public abstract class BaseCompoundExpression extends BaseExpression {
+ protected List<Expression> children;
+ private boolean isNullable;
+ private boolean isStateless;
+ private boolean isDeterministic;
+
+ public BaseCompoundExpression() {
+ }
+
+ public BaseCompoundExpression(List<Expression> children) {
+ init(children);
+ }
+
+ private void init(List<Expression> children) {
+ this.children = ImmutableList.copyOf(children);
+ boolean isStateless = true;
+ boolean isDeterministic = true;
+ boolean isNullable = false;
+ for (int i = 0; i < children.size(); i++) {
+ Expression child = children.get(i);
+ isNullable |= child.isNullable();
+ isStateless &= child.isStateless();
+ isDeterministic &= child.isDeterministic();
+ }
+ this.isStateless = isStateless;
+ this.isDeterministic = isDeterministic;
+ this.isNullable = isNullable;
+ }
+
+ @Override
+ public List<Expression> getChildren() {
+ return children;
+ }
+
+
+ @Override
+ public boolean isDeterministic() {
+ return isDeterministic;
+ }
+
+ @Override
+ public boolean isStateless() {
+ return isStateless;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return isNullable;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + children.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;
+ BaseCompoundExpression other = (BaseCompoundExpression)obj;
+ if (!children.equals(other.children)) return false;
+ return true;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ int len = WritableUtils.readVInt(input);
+ List<Expression>children = new ArrayList<Expression>(len);
+ for (int i = 0; i < len; i++) {
+ Expression child = ExpressionType.values()[WritableUtils.readVInt(input)].newInstance();
+ child.readFields(input);
+ children.add(child);
+ }
+ init(children);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ WritableUtils.writeVInt(output, children.size());
+ for (int i = 0; i < children.size(); i++) {
+ Expression child = children.get(i);
+ WritableUtils.writeVInt(output, ExpressionType.valueOf(child).ordinal());
+ child.write(output);
+ }
+ }
+
+ @Override
+ public void reset() {
+ for (int i = 0; i < children.size(); i++) {
+ children.get(i).reset();
+ }
+ }
+
+ @Override
+ public <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() {
+ return this.getClass().getName() + " [children=" + children + "]";
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseDecimalAddSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseDecimalAddSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseDecimalAddSubtractExpression.java
new file mode 100644
index 0000000..4f641fe
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseDecimalAddSubtractExpression.java
@@ -0,0 +1,5 @@
+package org.apache.phoenix.expression;
+
+public class BaseDecimalAddSubtractExpression {
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java
new file mode 100644
index 0000000..9bd5581
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseExpression.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.ColumnModifier;
+
+
+
+/**
+ *
+ * Base class for Expression hierarchy that provides common
+ * default implementations for most methods
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class BaseExpression implements Expression {
+ @Override
+ public boolean isNullable() {
+ return false;
+ }
+
+ @Override
+ public Integer getByteSize() {
+ return getDataType().isFixedWidth() ? getDataType().getByteSize() : null;
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return null;
+ }
+
+ @Override
+ public Integer getScale() {
+ return null;
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return null;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ }
+
+ @Override
+ public void reset() {
+ }
+
+ protected final <T> List<T> acceptChildren(ExpressionVisitor<T> visitor, Iterator<Expression> iterator) {
+ if (iterator == null) {
+ iterator = visitor.defaultIterator(this);
+ }
+ List<T> l = Collections.emptyList();
+ while (iterator.hasNext()) {
+ Expression child = iterator.next();
+ T t = child.accept(visitor);
+ if (t != null) {
+ if (l.isEmpty()) {
+ l = new ArrayList<T>(getChildren().size());
+ }
+ l.add(t);
+ }
+ }
+ return l;
+ }
+
+ @Override
+ public boolean isDeterministic() {
+ return true;
+ }
+
+ @Override
+ public boolean isStateless() {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseSingleExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseSingleExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseSingleExpression.java
new file mode 100644
index 0000000..1758438
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseSingleExpression.java
@@ -0,0 +1,91 @@
+/*
+ * 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.List;
+
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+/**
+ *
+ * Base class for expressions which have a single child expression
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class BaseSingleExpression extends BaseExpression {
+
+ protected List<Expression> children;
+
+ public BaseSingleExpression() {
+ }
+
+ public BaseSingleExpression(Expression expression) {
+ this.children = ImmutableList.of(expression);
+ }
+
+ @Override
+ public List<Expression> getChildren() {
+ return children;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ Expression expression = ExpressionType.values()[WritableUtils.readVInt(input)].newInstance();
+ expression.readFields(input);
+ children = ImmutableList.of(expression);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ WritableUtils.writeVInt(output, ExpressionType.valueOf(children.get(0)).ordinal());
+ children.get(0).write(output);
+ }
+
+ @Override
+ public boolean isNullable() {
+ return children.get(0).isNullable();
+ }
+
+ @Override
+ public void reset() {
+ children.get(0).reset();
+ }
+
+ @Override
+ public <T> T accept(ExpressionVisitor<T> visitor) {
+ List<T> l = acceptChildren(visitor, null);
+ if (l.isEmpty()) {
+ return visitor.defaultReturn(this, l);
+ }
+ return l.get(0);
+ }
+
+ public Expression getChild() {
+ return children.get(0);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseTerminalExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseTerminalExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseTerminalExpression.java
new file mode 100644
index 0000000..aaa4371
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/BaseTerminalExpression.java
@@ -0,0 +1,47 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+
+/**
+ *
+ * Grouping class for expression that have no expression children
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class BaseTerminalExpression extends BaseExpression {
+ @Override
+ public List<Expression> getChildren() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public <T> T accept(ExpressionVisitor<T> visitor) {
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/CaseExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/CaseExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/CaseExpression.java
new file mode 100644
index 0000000..f9a524a
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/CaseExpression.java
@@ -0,0 +1,234 @@
+/*
+ * 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.ArrayList;
+import java.util.List;
+
+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.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * CASE/WHEN expression implementation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class CaseExpression extends BaseCompoundExpression {
+ private static final int FULLY_EVALUATE = -1;
+
+ private short evalIndex = FULLY_EVALUATE;
+ private boolean foundIndex;
+ private PDataType returnType;
+
+ public CaseExpression() {
+ }
+
+ private static List<Expression> coerceIfNecessary(List<Expression> children) throws SQLException {
+ boolean isChildTypeUnknown = false;
+ PDataType returnType = children.get(0).getDataType();
+ for (int i = 2; i < children.size(); i+=2) {
+ Expression child = children.get(i);
+ PDataType childType = child.getDataType();
+ if (childType == null) {
+ isChildTypeUnknown = true;
+ } else if (returnType == null) {
+ returnType = childType;
+ isChildTypeUnknown = true;
+ } else if (returnType == childType || childType.isCoercibleTo(returnType)) {
+ continue;
+ } else if (returnType.isCoercibleTo(childType)) {
+ returnType = childType;
+ } else {
+ throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CONVERT_TYPE)
+ .setMessage("Case expressions must have common type: " + returnType + " cannot be coerced to " + childType)
+ .build().buildException();
+ }
+ }
+ // If we found an "unknown" child type and the return type is a number
+ // make the return type be the most general number type of DECIMAL.
+ if (isChildTypeUnknown && returnType != null && returnType.isCoercibleTo(PDataType.DECIMAL)) {
+ returnType = PDataType.DECIMAL;
+ }
+ List<Expression> newChildren = children;
+ for (int i = 0; i < children.size(); i+=2) {
+ Expression child = children.get(i);
+ PDataType childType = child.getDataType();
+ if (childType != returnType) {
+ if (newChildren == children) {
+ newChildren = new ArrayList<Expression>(children);
+ }
+ newChildren.set(i, CoerceExpression.create(child, returnType));
+ }
+ }
+ return newChildren;
+ }
+ /**
+ * Construct CASE/WHEN expression
+ * @param expressions list of expressions in the form of:
+ * ((<result expression>, <boolean expression>)+, [<optional else result expression>])
+ * @throws SQLException if return type of case expressions do not match and cannot
+ * be coerced to a common type
+ */
+ public CaseExpression(List<Expression> expressions) throws SQLException {
+ super(coerceIfNecessary(expressions));
+ returnType = children.get(0).getDataType();
+ }
+
+ private boolean isPartiallyEvaluating() {
+ return evalIndex != FULLY_EVALUATE;
+ }
+
+ public boolean hasElse() {
+ return children.size() % 2 != 0;
+ }
+
+ @Override
+ public boolean isNullable() {
+ // If any expression is nullable or there's no else clause
+ // return true since null may be returned.
+ if (super.isNullable() || !hasElse()) {
+ return true;
+ }
+ return children.get(children.size()-1).isNullable();
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return returnType;
+ }
+
+ @Override
+ public void reset() {
+ foundIndex = false;
+ evalIndex = 0;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ this.returnType = PDataType.values()[WritableUtils.readVInt(input)];
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeVInt(output, this.returnType.ordinal());
+ }
+
+ public int evaluateIndexOf(Tuple tuple, ImmutableBytesWritable ptr) {
+ if (foundIndex) {
+ return evalIndex;
+ }
+ int size = children.size();
+ // If we're doing partial evaluation, start where we left off
+ for (int i = isPartiallyEvaluating() ? evalIndex : 0; i < size; i+=2) {
+ // Short circuit if we see our stop value
+ if (i+1 == size) {
+ return i;
+ }
+ // If we get null, we have to re-evaluate from that point (special case this in filter, like is null)
+ // We may only run this when we're done/have all values
+ boolean evaluated = children.get(i+1).evaluate(tuple, ptr);
+ if (evaluated && Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(ptr))) {
+ if (isPartiallyEvaluating()) {
+ foundIndex = true;
+ }
+ return i;
+ }
+ if (isPartiallyEvaluating()) {
+ if (evaluated || tuple.isImmutable()) {
+ evalIndex+=2;
+ } else {
+ /*
+ * Return early here if incrementally evaluating and we don't
+ * have all the key values yet. We can't continue because we'd
+ * potentially be bypassing cases which we could later evaluate
+ * once we have more column values.
+ */
+ return -1;
+ }
+ }
+ }
+ // No conditions matched, return size to indicate that we were able
+ // to evaluate all cases, but didn't find any matches.
+ return size;
+ }
+
+ /**
+ * Only expression that currently uses the isPartial flag. The IS NULL
+ * expression will use it too. TODO: We could alternatively have a non interface
+ * method, like setIsPartial in which we set to false prior to calling
+ * evaluate.
+ */
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ int index = evaluateIndexOf(tuple, ptr);
+ if (index < 0) {
+ return false;
+ } else if (index == children.size()) {
+ ptr.set(PDataType.NULL_BYTES);
+ return true;
+ }
+ if (children.get(index).evaluate(tuple, ptr)) {
+ return true;
+ }
+ return false;
+ }
+
+ @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("CASE ");
+ for (int i = 0; i < children.size() - 1; i+=2) {
+ buf.append("WHEN ");
+ buf.append(children.get(i+1));
+ buf.append(" THEN ");
+ buf.append(children.get(i));
+ }
+ if (hasElse()) {
+ buf.append(" ELSE " + children.get(children.size()-1));
+ }
+ buf.append(" END");
+ return buf.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/CoerceExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/CoerceExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/CoerceExpression.java
new file mode 100644
index 0000000..827d70e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/CoerceExpression.java
@@ -0,0 +1,153 @@
+/*
+ * 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.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+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;
+
+
+public class CoerceExpression extends BaseSingleExpression {
+ private PDataType toType;
+ private ColumnModifier toMod;
+ private Integer byteSize;
+
+ public CoerceExpression() {
+ }
+
+ public static Expression create(Expression expression, PDataType toType) throws SQLException {
+ if (toType == expression.getDataType()) {
+ return expression;
+ }
+ return new CoerceExpression(expression, toType);
+ }
+
+ //Package protected for tests
+ CoerceExpression(Expression expression, PDataType toType) {
+ this(expression, toType, null, null);
+ }
+
+ CoerceExpression(Expression expression, PDataType toType, ColumnModifier toMod, Integer byteSize) {
+ super(expression);
+ this.toType = toType;
+ this.toMod = toMod;
+ this.byteSize = byteSize;
+ }
+
+ @Override
+ public Integer getByteSize() {
+ return byteSize;
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return byteSize;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((byteSize == null) ? 0 : byteSize.hashCode());
+ result = prime * result + ((toMod == null) ? 0 : toMod.hashCode());
+ result = prime * result + ((toType == null) ? 0 : toType.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;
+ CoerceExpression other = (CoerceExpression)obj;
+ if (byteSize == null) {
+ if (other.byteSize != null) return false;
+ } else if (!byteSize.equals(other.byteSize)) return false;
+ if (toMod != other.toMod) return false;
+ if (toType != other.toType) return false;
+ return true;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ toType = PDataType.values()[WritableUtils.readVInt(input)];
+ toMod = ColumnModifier.fromSystemValue(WritableUtils.readVInt(input));
+ int byteSize = WritableUtils.readVInt(input);
+ this.byteSize = byteSize == -1 ? null : byteSize;
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeVInt(output, toType.ordinal());
+ WritableUtils.writeVInt(output, ColumnModifier.toSystemValue(toMod));
+ WritableUtils.writeVInt(output, byteSize == null ? -1 : byteSize);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ if (getChild().evaluate(tuple, ptr)) {
+ getDataType().coerceBytes(ptr, getChild().getDataType(), getChild().getColumnModifier(), getColumnModifier());
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return toType;
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return toMod;
+ }
+
+ @Override
+ public <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("TO_" + toType.toString() + "(");
+ 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/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/ColumnExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ColumnExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ColumnExpression.java
new file mode 100644
index 0000000..bfb0d70
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ColumnExpression.java
@@ -0,0 +1,154 @@
+/*
+ * 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.io.WritableUtils;
+
+import com.google.common.base.Objects;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PDatum;
+
+/**
+ *
+ * Common base class for column value accessors
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class ColumnExpression extends BaseTerminalExpression {
+ protected PDataType type;
+ private Integer byteSize;
+ private boolean isNullable;
+ private Integer maxLength;
+ private Integer scale;
+ private ColumnModifier columnModifier;
+
+ public ColumnExpression() {
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (isNullable() ? 1231 : 1237);
+ Integer maxLength = this.getByteSize();
+ result = prime * result + ((maxLength == null) ? 0 : maxLength.hashCode());
+ PDataType type = this.getDataType();
+ result = prime * result + ((type == null) ? 0 : type.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;
+ ColumnExpression other = (ColumnExpression)obj;
+ if (this.isNullable() != other.isNullable()) return false;
+ if (!Objects.equal(this.getByteSize(),other.getByteSize())) return false;
+ if (this.getDataType() != other.getDataType()) return false;
+ return true;
+ }
+
+ public ColumnExpression(PDatum datum) {
+ this.type = datum.getDataType();
+ this.isNullable = datum.isNullable();
+ if (type.isFixedWidth() && type.getByteSize() == null) {
+ this.byteSize = datum.getByteSize();
+ }
+ this.maxLength = datum.getMaxLength();
+ this.scale = datum.getScale();
+ this.columnModifier = datum.getColumnModifier();
+ }
+
+ @Override
+ public boolean isNullable() {
+ return isNullable;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return type;
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return columnModifier;
+ }
+
+ @Override
+ public Integer getByteSize() {
+ if (byteSize != null) {
+ return byteSize;
+ }
+ return super.getByteSize();
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return maxLength;
+ }
+
+ @Override
+ public Integer getScale() {
+ return scale;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ // read/write type ordinal, maxLength presence, scale presence and isNullable bit together to save space
+ int typeAndFlag = WritableUtils.readVInt(input);
+ isNullable = (typeAndFlag & 0x01) != 0;
+ if ((typeAndFlag & 0x02) != 0) {
+ scale = WritableUtils.readVInt(input);
+ }
+ if ((typeAndFlag & 0x04) != 0) {
+ maxLength = WritableUtils.readVInt(input);
+ }
+ type = PDataType.values()[typeAndFlag >>> 3];
+ if (type.isFixedWidth() && type.getByteSize() == null) {
+ byteSize = WritableUtils.readVInt(input);
+ }
+ columnModifier = ColumnModifier.fromSystemValue(WritableUtils.readVInt(input));
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ // read/write type ordinal, maxLength presence, scale presence and isNullable bit together to save space
+ int typeAndFlag = (isNullable ? 1 : 0) | ((scale != null ? 1 : 0) << 1) | ((maxLength != null ? 1 : 0) << 2)
+ | (type.ordinal() << 3);
+ WritableUtils.writeVInt(output,typeAndFlag);
+ if (scale != null) {
+ WritableUtils.writeVInt(output, scale);
+ }
+ if (maxLength != null) {
+ WritableUtils.writeVInt(output, maxLength);
+ }
+ if (type.isFixedWidth() && type.getByteSize() == null) {
+ WritableUtils.writeVInt(output, byteSize);
+ }
+ WritableUtils.writeVInt(output, ColumnModifier.toSystemValue(columnModifier));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
new file mode 100644
index 0000000..5d3af1b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
@@ -0,0 +1,159 @@
+/*
+ * 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.List;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.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;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ *
+ * Implementation for <,<=,>,>=,=,!= comparison expressions
+ * @author jtaylor
+ * @since 0.1
+ */
+public class ComparisonExpression extends BaseCompoundExpression {
+ private CompareOp op;
+ private static final String[] CompareOpString = new String[CompareOp.values().length];
+ static {
+ CompareOpString[CompareOp.EQUAL.ordinal()] = " = ";
+ CompareOpString[CompareOp.NOT_EQUAL.ordinal()] = " != ";
+ CompareOpString[CompareOp.GREATER.ordinal()] = " > ";
+ CompareOpString[CompareOp.LESS.ordinal()] = " < ";
+ CompareOpString[CompareOp.GREATER_OR_EQUAL.ordinal()] = " >= ";
+ CompareOpString[CompareOp.LESS_OR_EQUAL.ordinal()] = " <= ";
+ }
+
+ public ComparisonExpression() {
+ }
+
+ public ComparisonExpression(CompareOp op, List<Expression> children) {
+ super(children);
+ if (op == null) {
+ throw new NullPointerException();
+ }
+ this.op = op;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + op.hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ ComparisonExpression other = (ComparisonExpression)obj;
+ if (op != other.op) return false;
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.BOOLEAN;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ if (!children.get(0).evaluate(tuple, ptr)) {
+ return false;
+ }
+ byte[] lhsBytes = ptr.get();
+ int lhsOffset = ptr.getOffset();
+ int lhsLength = ptr.getLength();
+ PDataType lhsDataType = children.get(0).getDataType();
+ ColumnModifier lhsColumnModifier = children.get(0).getColumnModifier();
+
+ if (!children.get(1).evaluate(tuple, ptr)) {
+ return false;
+ }
+
+ byte[] rhsBytes = ptr.get();
+ int rhsOffset = ptr.getOffset();
+ int rhsLength = ptr.getLength();
+ PDataType rhsDataType = children.get(1).getDataType();
+ ColumnModifier rhsColumnModifier = children.get(1).getColumnModifier();
+ if (rhsDataType == PDataType.CHAR) {
+ rhsLength = StringUtil.getUnpaddedCharLength(rhsBytes, rhsOffset, rhsLength, rhsColumnModifier);
+ }
+ if (lhsDataType == PDataType.CHAR) {
+ lhsLength = StringUtil.getUnpaddedCharLength(lhsBytes, lhsOffset, lhsLength, lhsColumnModifier);
+ }
+
+
+ int comparisonResult = lhsDataType.compareTo(lhsBytes, lhsOffset, lhsLength, lhsColumnModifier,
+ rhsBytes, rhsOffset, rhsLength, rhsColumnModifier, rhsDataType);
+ ptr.set(ByteUtil.compare(op, comparisonResult) ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
+ return true;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ op = CompareOp.values()[WritableUtils.readVInt(input)];
+ super.readFields(input);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ WritableUtils.writeVInt(output, op.ordinal());
+ super.write(output);
+ }
+
+ @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 CompareOp getFilterOp() {
+ return op;
+ }
+
+ public static String toString(CompareOp op, List<Expression> children) {
+ return (children.get(0) + CompareOpString[op.ordinal()] + children.get(1));
+ }
+
+ @Override
+ public String toString() {
+ return toString(getFilterOp(), children);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java
new file mode 100644
index 0000000..b221c1c
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/CurrentDateTimeFunction.java
@@ -0,0 +1,44 @@
+/*
+ * 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.function.ScalarFunction;
+
+public abstract class CurrentDateTimeFunction extends ScalarFunction {
+
+ public CurrentDateTimeFunction() {
+ }
+
+ public CurrentDateTimeFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public boolean isStateless() {
+ return true;
+ }
+
+ @Override
+ public boolean isDeterministic() {
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DateAddExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DateAddExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DateAddExpression.java
new file mode 100644
index 0000000..a36bb48
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DateAddExpression.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression;
+
+import java.math.BigDecimal;
+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;
+
+
+public class DateAddExpression extends AddExpression {
+ static private final BigDecimal BD_MILLIS_IN_DAY = BigDecimal.valueOf(QueryConstants.MILLIS_IN_DAY);
+
+ public DateAddExpression() {
+ }
+
+ public DateAddExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ long finalResult=0;
+
+ for(int i=0;i<children.size();i++) {
+ if (!children.get(i).evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+ long value;
+ PDataType type = children.get(i).getDataType();
+ ColumnModifier columnModifier = children.get(i).getColumnModifier();
+ if (type == PDataType.DECIMAL) {
+ BigDecimal bd = (BigDecimal)PDataType.DECIMAL.toObject(ptr, columnModifier);
+ value = bd.multiply(BD_MILLIS_IN_DAY).longValue();
+ } else if (type.isCoercibleTo(PDataType.LONG)) {
+ value = type.getCodec().decodeLong(ptr, columnModifier) * QueryConstants.MILLIS_IN_DAY;
+ } else if (type.isCoercibleTo(PDataType.DOUBLE)) {
+ value = (long)(type.getCodec().decodeDouble(ptr, columnModifier) * QueryConstants.MILLIS_IN_DAY);
+ } else {
+ value = type.getCodec().decodeLong(ptr, columnModifier);
+ }
+ finalResult += value;
+ }
+ byte[] resultPtr = new byte[getDataType().getByteSize()];
+ ptr.set(resultPtr);
+ getDataType().getCodec().encodeLong(finalResult, ptr);
+ return true;
+ }
+
+ @Override
+ public final PDataType getDataType() {
+ return PDataType.DATE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DateSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DateSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DateSubtractExpression.java
new file mode 100644
index 0000000..7329aff
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DateSubtractExpression.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression;
+
+import java.math.BigDecimal;
+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;
+
+
+public class DateSubtractExpression extends SubtractExpression {
+
+ public DateSubtractExpression() {
+ }
+
+ public DateSubtractExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ long finalResult=0;
+
+ for(int i=0;i<children.size();i++) {
+ if (!children.get(i).evaluate(tuple, ptr) || ptr.getLength() == 0) {
+ return false;
+ }
+ long value;
+ PDataType type = children.get(i).getDataType();
+ ColumnModifier columnModifier = children.get(i).getColumnModifier();
+ if (type == PDataType.DECIMAL) {
+ BigDecimal bd = (BigDecimal)PDataType.DECIMAL.toObject(ptr, columnModifier);
+ value = bd.multiply(BD_MILLIS_IN_DAY).longValue();
+ } else if (type.isCoercibleTo(PDataType.LONG)) {
+ value = type.getCodec().decodeLong(ptr, columnModifier) * QueryConstants.MILLIS_IN_DAY;
+ } else if (type.isCoercibleTo(PDataType.DOUBLE)) {
+ value = (long)(type.getCodec().decodeDouble(ptr, columnModifier) * QueryConstants.MILLIS_IN_DAY);
+ } else {
+ value = type.getCodec().decodeLong(ptr, columnModifier);
+ }
+ if (i == 0) {
+ finalResult = value;
+ } else {
+ finalResult -= value;
+ }
+ }
+ byte[] resultPtr=new byte[getDataType().getByteSize()];
+ ptr.set(resultPtr);
+ getDataType().getCodec().encodeLong(finalResult, ptr);
+ return true;
+ }
+
+ @Override
+ public final PDataType getDataType() {
+ return PDataType.DATE;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalAddExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalAddExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalAddExpression.java
new file mode 100644
index 0000000..24444a6
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalAddExpression.java
@@ -0,0 +1,101 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.exception.ValueTypeIncompatibleException;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.NumberUtil;
+
+
+public class DecimalAddExpression extends AddExpression {
+ private Integer maxLength;
+ private Integer scale;
+
+ public DecimalAddExpression() {
+ }
+
+ public DecimalAddExpression(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 boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ BigDecimal result = null;
+ for (int i=0; i<children.size(); i++) {
+ Expression childExpr = children.get(i);
+ if (!childExpr.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ PDataType childType = childExpr.getDataType();
+ ColumnModifier childColumnModifier = childExpr.getColumnModifier();
+ BigDecimal bd = (BigDecimal)PDataType.DECIMAL.toObject(ptr, childType, childColumnModifier);
+
+ if (result == null) {
+ result = bd;
+ } else {
+ result = result.add(bd);
+ }
+ }
+ if (maxLength != null && scale != null) {
+ result = NumberUtil.setDecimalWidthAndScale(result, maxLength, scale);
+ }
+ if (result == null) {
+ throw new ValueTypeIncompatibleException(PDataType.DECIMAL, maxLength, scale);
+ }
+ ptr.set(PDataType.DECIMAL.toBytes(result));
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+
+ @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/DecimalDivideExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalDivideExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalDivideExpression.java
new file mode 100644
index 0000000..a1e3b34
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalDivideExpression.java
@@ -0,0 +1,79 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.exception.ValueTypeIncompatibleException;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.NumberUtil;
+
+
+public class DecimalDivideExpression extends DivideExpression {
+
+ public DecimalDivideExpression() {
+ }
+
+ public DecimalDivideExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ BigDecimal result = null;
+ for (int i=0; i<children.size(); i++) {
+ Expression childExpr = children.get(i);
+ if (!childExpr.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ PDataType childType = childExpr.getDataType();
+ ColumnModifier childColumnModifier = childExpr.getColumnModifier();
+ BigDecimal bd= (BigDecimal)PDataType.DECIMAL.toObject(ptr, childType, childColumnModifier);
+
+ if (result == null) {
+ result = bd;
+ } else {
+ result = result.divide(bd, PDataType.DEFAULT_MATH_CONTEXT);
+ }
+ }
+ if (getMaxLength() != null && getScale() != null) {
+ result = NumberUtil.setDecimalWidthAndScale(result, getMaxLength(), getScale());
+ }
+ if (result == null) {
+ throw new ValueTypeIncompatibleException(PDataType.DECIMAL, getMaxLength(), getScale());
+ }
+ ptr.set(PDataType.DECIMAL.toBytes(result));
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalMultiplyExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalMultiplyExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalMultiplyExpression.java
new file mode 100644
index 0000000..8b5ffae
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalMultiplyExpression.java
@@ -0,0 +1,79 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.exception.ValueTypeIncompatibleException;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.NumberUtil;
+
+
+public class DecimalMultiplyExpression extends MultiplyExpression {
+
+ public DecimalMultiplyExpression() {
+ }
+
+ public DecimalMultiplyExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ BigDecimal result = null;
+ for (int i=0; i<children.size(); i++) {
+ Expression childExpr = children.get(i);
+ if (!childExpr.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ PDataType childType = children.get(i).getDataType();
+ ColumnModifier childColumnModifier = children.get(i).getColumnModifier();
+ BigDecimal bd = (BigDecimal)PDataType.DECIMAL.toObject(ptr, childType, childColumnModifier);
+
+ if (result == null) {
+ result = bd;
+ } else {
+ result = result.multiply(bd);
+ }
+ }
+ if (getMaxLength() != null && getScale() != null) {
+ result = NumberUtil.setDecimalWidthAndScale(result, getMaxLength(), getScale());
+ }
+ if (result == null) {
+ throw new ValueTypeIncompatibleException(PDataType.DECIMAL, getMaxLength(), getScale());
+ }
+ ptr.set(PDataType.DECIMAL.toBytes(result));
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalSubtractExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalSubtractExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalSubtractExpression.java
new file mode 100644
index 0000000..a572cf2
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DecimalSubtractExpression.java
@@ -0,0 +1,118 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.exception.ValueTypeIncompatibleException;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.NumberUtil;
+
+
+/**
+ *
+ * Subtract expression implementation
+ *
+ * @author kmahadik
+ * @since 0.1
+ */
+public class DecimalSubtractExpression extends SubtractExpression {
+ private Integer maxLength;
+ private Integer scale;
+
+ public DecimalSubtractExpression() {
+ }
+
+ public DecimalSubtractExpression(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 boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ BigDecimal result = null;
+ for (int i=0; i<children.size(); i++) {
+ Expression childExpr = children.get(i);
+ if (!childExpr.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ PDataType childType = childExpr.getDataType();
+ boolean isDate = childType.isCoercibleTo(PDataType.DATE);
+ ColumnModifier childColumnModifier = childExpr.getColumnModifier();
+ BigDecimal bd = isDate ?
+ BigDecimal.valueOf(childType.getCodec().decodeLong(ptr, childColumnModifier)) :
+ (BigDecimal)PDataType.DECIMAL.toObject(ptr, childType, childColumnModifier);
+
+ if (result == null) {
+ result = bd;
+ } else {
+ result = result.subtract(bd);
+ /*
+ * 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) {
+ result = result.divide(BD_MILLIS_IN_DAY, PDataType.DEFAULT_MATH_CONTEXT);
+ }
+ }
+ }
+ if (maxLength != null && scale != null) {
+ result = NumberUtil.setDecimalWidthAndScale(result, maxLength, scale);
+ }
+ if (result == null) {
+ throw new ValueTypeIncompatibleException(PDataType.DECIMAL, maxLength, scale);
+ }
+ ptr.set(PDataType.DECIMAL.toBytes(result));
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+
+ @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/DivideExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DivideExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DivideExpression.java
new file mode 100644
index 0000000..ab9d0d7
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DivideExpression.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;
+
+
+/**
+ *
+ * Divide expression implementation
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class DivideExpression extends ArithmeticExpression {
+ private Integer maxLength;
+ private Integer scale;
+
+ public DivideExpression() {
+ }
+
+ public DivideExpression(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 = getScale(lp, rp, ls, rs) + lp - ls + 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 = Math.max(PDataType.MAX_PRECISION - lp + ls - rs, 0);
+ 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/DoubleAddExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleAddExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleAddExpression.java
new file mode 100644
index 0000000..96fc9fa
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/DoubleAddExpression.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 DoubleAddExpression extends AddExpression {
+
+ public DoubleAddExpression() {
+ }
+
+ public DoubleAddExpression(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) {
+ 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;
+ }
+
+}