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;
+ }
+}