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:43 UTC
[27/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/function/ToNumberFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
new file mode 100644
index 0000000..84cc2b4
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import static org.apache.phoenix.util.ByteUtil.EMPTY_BYTE_ARRAY;
+
+import java.io.*;
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.text.*;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import com.google.common.base.Preconditions;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+/**
+ *
+ * Implementation of TO_NUMBER(<string>/<date>/<timestamp>, [<pattern-string>]) built-in function. The format for the optional
+ * <code>pattern_string</code> param is specified in {@link DecimalFormat}.
+ *
+ * @author elevine
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToNumberFunction.NAME, nodeClass=ToNumberParseNode.class, args= {
+ @Argument(allowedTypes={PDataType.VARCHAR, PDataType.TIMESTAMP}),
+ @Argument(allowedTypes={PDataType.VARCHAR}, isConstant=true, defaultValue="null")} )
+public class ToNumberFunction extends ScalarFunction {
+ public static final String NAME = "TO_NUMBER";
+
+ private String formatString = null;
+ private Format format = null;
+ private FunctionArgumentType type;
+
+ public ToNumberFunction() {}
+
+ public ToNumberFunction(List<Expression> children, FunctionArgumentType type, String formatString, Format formatter) throws SQLException {
+ super(children.subList(0, 1));
+ Preconditions.checkNotNull(type);
+ this.type = type;
+ this.formatString = formatString;
+ this.format = formatter;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression expression = getExpression();
+ if (!expression.evaluate(tuple, ptr)) {
+ return false;
+ } else if (ptr.getLength() == 0) {
+ return true;
+ }
+
+ PDataType type = expression.getDataType();
+ if (type.isCoercibleTo(PDataType.TIMESTAMP)) {
+ Date date = (Date) type.toObject(ptr, expression.getColumnModifier());
+ BigDecimal time = new BigDecimal(date.getTime());
+ byte[] byteValue = getDataType().toBytes(time);
+ ptr.set(byteValue);
+ return true;
+ }
+
+ String stringValue = (String)type.toObject(ptr, expression.getColumnModifier());
+ if (stringValue == null) {
+ ptr.set(EMPTY_BYTE_ARRAY);
+ return true;
+ }
+ stringValue = stringValue.trim();
+ BigDecimal decimalValue;
+ if (format == null) {
+ decimalValue = (BigDecimal) getDataType().toObject(stringValue);
+ } else {
+ ParsePosition parsePosition = new ParsePosition(0);
+ Number number = ((DecimalFormat) format).parse(stringValue, parsePosition);
+ if (parsePosition.getErrorIndex() > -1) {
+ ptr.set(EMPTY_BYTE_ARRAY);
+ return true;
+ }
+
+ if (number instanceof BigDecimal) {
+ // since we set DecimalFormat.setParseBigDecimal(true) we are guaranteeing result to be
+ // of type BigDecimal in most cases. see java.text.DecimalFormat.parse() JavaDoc.
+ decimalValue = (BigDecimal)number;
+ } else {
+ ptr.set(EMPTY_BYTE_ARRAY);
+ return true;
+ }
+ }
+ byte[] byteValue = getDataType().toBytes(decimalValue);
+ ptr.set(byteValue);
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return getExpression().isNullable();
+ }
+
+ private Expression getExpression() {
+ return children.get(0);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ formatString = WritableUtils.readString(input);
+ type = WritableUtils.readEnum(input, FunctionArgumentType.class);
+ if (formatString != null) {
+ format = type.getFormatter(formatString);
+ }
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeString(output, formatString);
+ WritableUtils.writeEnum(output, type);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((formatString == null) ? 0 : formatString.hashCode());
+ result = prime * result + getExpression().hashCode();
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (!super.equals(obj)) return false;
+ if (getClass() != obj.getClass()) return false;
+ ToNumberFunction other = (ToNumberFunction)obj;
+ if (formatString == null) {
+ if (other.formatString != null) return false;
+ } else if (!formatString.equals(other.formatString)) return false;
+ if (!getExpression().equals(other.getExpression())) return false;
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
new file mode 100644
index 0000000..b8c06cd
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * Implementation of the Trim(<string>) build-in function. It removes from both end of <string>
+ * space character and other function bytes in single byte utf8 characters set.
+ *
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=TrimFunction.NAME, args={
+ @Argument(allowedTypes={PDataType.VARCHAR})} )
+public class TrimFunction extends ScalarFunction {
+ public static final String NAME = "TRIM";
+
+ private Integer byteSize;
+
+ public TrimFunction() { }
+
+ public TrimFunction(List<Expression> children) throws SQLException {
+ super(children);
+ if (getStringExpression().getDataType().isFixedWidth()) {
+ byteSize = getStringExpression().getByteSize();
+ }
+ }
+
+ private Expression getStringExpression() {
+ return children.get(0);
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return children.get(0).getColumnModifier();
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ if (!getStringExpression().evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ return true;
+ }
+ byte[] string = ptr.get();
+ int offset = ptr.getOffset();
+ int length = ptr.getLength();
+
+ ColumnModifier columnModifier = getColumnModifier();
+ int end = StringUtil.getFirstNonBlankCharIdxFromEnd(string, offset, length, columnModifier);
+ if (end == offset - 1) {
+ ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ return true;
+ }
+ int head = StringUtil.getFirstNonBlankCharIdxFromStart(string, offset, length, columnModifier);
+ ptr.set(string, head, end - head + 1);
+ return true;
+ }
+
+ @Override
+ public Integer getByteSize() {
+ return byteSize;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.VARCHAR;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
new file mode 100644
index 0000000..26a75ee
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/TruncFunction.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.function;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.FloorParseNode;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+
+/**
+ *
+ * Function used to bucketize date/time values by truncating them to
+ * an even increment. Usage:
+ * TRUNC(<date/time col ref>,<'day'|'hour'|'minute'|'second'|'millisecond'>,[<optional integer multiplier>])
+ * The integer multiplier is optional and is used to do rollups to a partial time unit (i.e. 10 minute rollup)
+ * The function returns a {@link org.apache.phoenix.schema.PDataType#DATE}
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name = TruncFunction.NAME,
+nodeClass = FloorParseNode.class,
+args = {
+ @Argument(allowedTypes={PDataType.TIMESTAMP, PDataType.DECIMAL}),
+ @Argument(allowedTypes={PDataType.VARCHAR, PDataType.INTEGER}, defaultValue = "null", isConstant=true),
+ @Argument(allowedTypes={PDataType.INTEGER}, defaultValue="1", isConstant=true)
+ }
+)
+public abstract class TruncFunction extends ScalarFunction {
+
+ public static final String NAME = "TRUNC";
+
+ public TruncFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
new file mode 100644
index 0000000..a524617
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.phoenix.expression.AddExpression;
+import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.ArrayConstructorExpression;
+import org.apache.phoenix.expression.CaseExpression;
+import org.apache.phoenix.expression.CoerceExpression;
+import org.apache.phoenix.expression.ComparisonExpression;
+import org.apache.phoenix.expression.DivideExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.InListExpression;
+import org.apache.phoenix.expression.IsNullExpression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LikeExpression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.MultiplyExpression;
+import org.apache.phoenix.expression.NotExpression;
+import org.apache.phoenix.expression.OrExpression;
+import org.apache.phoenix.expression.ProjectedColumnExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.StringConcatExpression;
+import org.apache.phoenix.expression.SubtractExpression;
+import org.apache.phoenix.expression.function.ScalarFunction;
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+
+
+public abstract class BaseExpressionVisitor<E> implements ExpressionVisitor<E> {
+ @Override
+ public E visit(Expression node) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(Expression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(Expression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public E defaultReturn(Expression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(AndExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(AndExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(OrExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(OrExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(ScalarFunction node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(ScalarFunction node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(ComparisonExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(ComparisonExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(LikeExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(LikeExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(SingleAggregateFunction node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(SingleAggregateFunction node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(CaseExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(CaseExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(NotExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(NotExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(IsNullExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(IsNullExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(InListExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(InListExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public E visit(LiteralExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visit(RowKeyColumnExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visit(KeyValueColumnExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visit(ProjectedColumnExpression node) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(SubtractExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(SubtractExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(AddExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(AddExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(MultiplyExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(MultiplyExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(DivideExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(DivideExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(StringConcatExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(StringConcatExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(RowValueConstructorExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(RowValueConstructorExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(CoerceExpression node) {
+ return null;
+ }
+
+ @Override
+ public E visitLeave(CoerceExpression node, List<E> l) {
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(ArrayConstructorExpression node) {
+ return null;
+ }
+ @Override
+ public E visitLeave(ArrayConstructorExpression node, List<E> l) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
new file mode 100644
index 0000000..efde2a4
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.phoenix.expression.AddExpression;
+import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.ArrayConstructorExpression;
+import org.apache.phoenix.expression.CaseExpression;
+import org.apache.phoenix.expression.CoerceExpression;
+import org.apache.phoenix.expression.ComparisonExpression;
+import org.apache.phoenix.expression.DivideExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.InListExpression;
+import org.apache.phoenix.expression.IsNullExpression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LikeExpression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.MultiplyExpression;
+import org.apache.phoenix.expression.NotExpression;
+import org.apache.phoenix.expression.OrExpression;
+import org.apache.phoenix.expression.ProjectedColumnExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.StringConcatExpression;
+import org.apache.phoenix.expression.SubtractExpression;
+import org.apache.phoenix.expression.function.ScalarFunction;
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+
+
+/**
+ *
+ * Visitor for an expression (which may contain other nested expressions)
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public interface ExpressionVisitor<E> {
+ /**
+ * Default visit method when an expression subclass doesn't
+ * define an accept method of its own. This will end up calling
+ * the {@link #defaultIterator(Expression)} to iterate over the
+ * children calling accept on them
+ */
+ public E visit(Expression node);
+ /**
+ * Default visitEnter method when an expression subclass doesn't
+ * define an accept method of its own. This will end up calling
+ * the {@link #defaultIterator(Expression)} to iterate over the
+ * children calling accept on them
+ */
+ public Iterator<Expression> visitEnter(Expression node);
+ /**
+ * Default visitLeave method when an expression subclass doesn't
+ * define an accept method of its own. This will end up calling
+ * the {@link #defaultReturn(Expression, List)} with the list from
+ * the iteration over the children.
+ */
+ public E visitLeave(Expression node, List<E> l);
+
+ public E defaultReturn(Expression node, List<E> l);
+ public Iterator<Expression> defaultIterator(Expression node);
+
+ public Iterator<Expression> visitEnter(AndExpression node);
+ public E visitLeave(AndExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(OrExpression node);
+ public E visitLeave(OrExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(ScalarFunction node);
+ public E visitLeave(ScalarFunction node, List<E> l);
+
+ public Iterator<Expression> visitEnter(ComparisonExpression node);
+ public E visitLeave(ComparisonExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(LikeExpression node);
+ public E visitLeave(LikeExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(SingleAggregateFunction node);
+ public E visitLeave(SingleAggregateFunction node, List<E> l);
+
+ public Iterator<Expression> visitEnter(CaseExpression node);
+ public E visitLeave(CaseExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(NotExpression node);
+ public E visitLeave(NotExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(InListExpression node);
+ public E visitLeave(InListExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(IsNullExpression node);
+ public E visitLeave(IsNullExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(SubtractExpression node);
+ public E visitLeave(SubtractExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(MultiplyExpression node);
+ public E visitLeave(MultiplyExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(AddExpression node);
+ public E visitLeave(AddExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(DivideExpression node);
+ public E visitLeave(DivideExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(CoerceExpression node);
+ public E visitLeave(CoerceExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(ArrayConstructorExpression node);
+ public E visitLeave(ArrayConstructorExpression node, List<E> l);
+
+ public E visit(LiteralExpression node);
+ public E visit(RowKeyColumnExpression node);
+ public E visit(KeyValueColumnExpression node);
+ public E visit(ProjectedColumnExpression node);
+
+ public Iterator<Expression> visitEnter(StringConcatExpression node);
+ public E visitLeave(StringConcatExpression node, List<E> l);
+
+ public Iterator<Expression> visitEnter(RowValueConstructorExpression node);
+ public E visitLeave(RowValueConstructorExpression node, List<E> l);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/KeyValueExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/KeyValueExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/KeyValueExpressionVisitor.java
new file mode 100644
index 0000000..838bb0b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/KeyValueExpressionVisitor.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+
+
+
+
+/**
+ *
+ * Implementation of ExpressionVisitor where only KeyValueDataAccessor
+ * is being visited
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class KeyValueExpressionVisitor extends TraverseAllExpressionVisitor<Void> {
+ @Override
+ abstract public Void visit(KeyValueColumnExpression node);
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/SingleAggregateFunctionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/SingleAggregateFunctionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/SingleAggregateFunctionVisitor.java
new file mode 100644
index 0000000..63313a7
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/SingleAggregateFunctionVisitor.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import java.util.Iterator;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.SingleAggregateFunction;
+
+
+
+/**
+ *
+ * Implementation of ExpressionVisitor where only SingleAggregateFunction
+ * instances are visited
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class SingleAggregateFunctionVisitor extends TraverseAllExpressionVisitor<Void> {
+ @Override
+ abstract public Iterator<Expression> visitEnter(SingleAggregateFunction node);
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseAllExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseAllExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseAllExpressionVisitor.java
new file mode 100644
index 0000000..39e7a3d
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseAllExpressionVisitor.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import java.util.*;
+
+import org.apache.phoenix.expression.Expression;
+
+
+
+
+public class TraverseAllExpressionVisitor<E> extends BaseExpressionVisitor<E> {
+
+ @Override
+ public Iterator<Expression> defaultIterator(Expression node) {
+ final List<Expression> children = node.getChildren();
+ return new Iterator<Expression>() {
+ private int position;
+
+ @Override
+ public final boolean hasNext() {
+ return position < children.size();
+ }
+
+ @Override
+ public final Expression next() {
+ if (!hasNext()) {
+ throw new NoSuchElementException();
+ }
+ return children.get(position++);
+ }
+
+ @Override
+ public final void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseNoExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseNoExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseNoExpressionVisitor.java
new file mode 100644
index 0000000..fe1d1f5
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/TraverseNoExpressionVisitor.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.visitor;
+
+import java.util.Iterator;
+
+
+import com.google.common.collect.Iterators;
+import org.apache.phoenix.expression.Expression;
+
+public class TraverseNoExpressionVisitor<E> extends BaseExpressionVisitor<E> {
+
+ @Override
+ public Iterator<Expression> defaultIterator(Expression node) {
+ return Iterators.emptyIterator();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java
new file mode 100644
index 0000000..d7b2243
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/BooleanExpressionFilter.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.filter;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.filter.FilterBase;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.ExpressionType;
+import org.apache.phoenix.schema.IllegalDataException;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ServerUtil;
+
+
+/**
+ *
+ * Base class for filter that evaluates a WHERE clause expression.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class BooleanExpressionFilter extends FilterBase {
+
+ protected Expression expression;
+ protected boolean evaluateOnCompletion;
+ private ImmutableBytesWritable tempPtr = new ImmutableBytesWritable();
+
+ public BooleanExpressionFilter() {
+ }
+
+ public BooleanExpressionFilter(Expression expression) {
+ this.expression = expression;
+ }
+
+ protected void setEvaluateOnCompletion(boolean evaluateOnCompletion) {
+ this.evaluateOnCompletion = evaluateOnCompletion;
+ }
+
+ protected boolean evaluateOnCompletion() {
+ return evaluateOnCompletion;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + expression.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;
+ BooleanExpressionFilter other = (BooleanExpressionFilter)obj;
+ if (!expression.equals(other.expression)) return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return expression.toString();
+ }
+
+ @edu.umd.cs.findbugs.annotations.SuppressWarnings(
+ value="NP_BOOLEAN_RETURN_NULL",
+ justification="Returns null by design.")
+ protected Boolean evaluate(Tuple input) {
+ try {
+ if (!expression.evaluate(input, tempPtr)) {
+ return null;
+ }
+ } catch (IllegalDataException e) {
+ return Boolean.FALSE;
+ }
+ return (Boolean)expression.getDataType().toObject(tempPtr);
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ try {
+ expression = ExpressionType.values()[WritableUtils.readVInt(input)].newInstance();
+ expression.readFields(input);
+ } catch (Throwable t) { // Catches incompatibilities during reading/writing and doesn't retry
+ ServerUtil.throwIOException("BooleanExpressionFilter failed during reading", t);
+ }
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ try {
+ WritableUtils.writeVInt(output, ExpressionType.valueOf(expression).ordinal());
+ expression.write(output);
+ } catch (Throwable t) { // Catches incompatibilities during reading/writing and doesn't retry
+ ServerUtil.throwIOException("BooleanExpressionFilter failed during writing", t);
+ }
+ }
+
+ @Override
+ public void reset() {
+ expression.reset();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/EvaluateOnCompletionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/EvaluateOnCompletionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/EvaluateOnCompletionVisitor.java
new file mode 100644
index 0000000..7dcc954
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/EvaluateOnCompletionVisitor.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.filter;
+
+import java.util.Iterator;
+
+import org.apache.phoenix.expression.ArrayConstructorExpression;
+import org.apache.phoenix.expression.CaseExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.IsNullExpression;
+import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.visitor.TraverseAllExpressionVisitor;
+
+
+/**
+ *
+ * Implementation of ExpressionVisitor for the expression used by the
+ * BooleanExpressionFilter that looks for expressions that need to be
+ * evaluated upon completion. Examples include:
+ * - CaseExpression with an else clause, since upon completion, the
+ * else clause would apply if the when clauses could not be evaluated
+ * due to the absense of a value.
+ * - IsNullExpression that's not negated, since upon completion, we
+ * know definitively that a column value was not found.
+ * - row key columns are used, since we may never have encountered a
+ * key value column of interest, but the expression may evaluate to true
+ * just based on the row key columns.
+ * @author jtaylor
+ * @since 0.1
+ */
+public class EvaluateOnCompletionVisitor extends TraverseAllExpressionVisitor<Void> {
+ private boolean evaluateOnCompletion = false;
+
+ public boolean evaluateOnCompletion() {
+ return evaluateOnCompletion;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(IsNullExpression node) {
+ evaluateOnCompletion |= !node.isNegate();
+ return null;
+ }
+ @Override
+ public Iterator<Expression> visitEnter(CaseExpression node) {
+ evaluateOnCompletion |= node.hasElse();
+ return null;
+ }
+ @Override
+ public Void visit(RowKeyColumnExpression node) {
+ evaluateOnCompletion = true;
+ return null;
+ }
+ @Override
+ public Iterator<Expression> visitEnter(RowValueConstructorExpression node) {
+ evaluateOnCompletion = true;
+ return null;
+ }
+
+ @Override
+ public Iterator<Expression> visitEnter(ArrayConstructorExpression node) {
+ evaluateOnCompletion = true;
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCFCQKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCFCQKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCFCQKeyValueComparisonFilter.java
new file mode 100644
index 0000000..27a356b
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCFCQKeyValueComparisonFilter.java
@@ -0,0 +1,134 @@
+/*
+ * 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.filter;
+
+import java.util.TreeSet;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.Expression;
+
+
+/**
+ *
+ * Filter that evaluates WHERE clause expression, used in the case where there
+ * are references to multiple column qualifiers over multiple column families.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class MultiCFCQKeyValueComparisonFilter extends MultiKeyValueComparisonFilter {
+ private final ImmutablePairBytesPtr ptr = new ImmutablePairBytesPtr();
+ private TreeSet<byte[]> cfSet;
+
+ public MultiCFCQKeyValueComparisonFilter() {
+ }
+
+ public MultiCFCQKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ }
+
+ @Override
+ protected void init() {
+ cfSet = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
+ super.init();
+ }
+
+ @Override
+ protected Object setColumnKey(byte[] cf, int cfOffset, int cfLength,
+ byte[] cq, int cqOffset, int cqLength) {
+ ptr.set(cf, cfOffset, cfLength, cq, cqOffset, cqLength);
+ return ptr;
+ }
+
+ @Override
+ protected Object newColumnKey(byte[] cf, int cfOffset, int cfLength,
+ byte[] cq, int cqOffset, int cqLength) {
+
+ byte[] cfKey;
+ if (cfOffset == 0 && cf.length == cfLength) {
+ cfKey = cf;
+ } else {
+ // Copy bytes here, but figure cf names are typically a few bytes at most,
+ // so this will be better than creating an ImmutableBytesPtr
+ cfKey = new byte[cfLength];
+ System.arraycopy(cf, cfOffset, cfKey, 0, cfLength);
+ }
+ cfSet.add(cfKey);
+ return new ImmutablePairBytesPtr(cf, cfOffset, cfLength, cq, cqOffset, cqLength);
+ }
+
+ private static class ImmutablePairBytesPtr {
+ private byte[] bytes1;
+ private int offset1;
+ private int length1;
+ private byte[] bytes2;
+ private int offset2;
+ private int length2;
+ private int hashCode;
+
+ private ImmutablePairBytesPtr() {
+ }
+
+ private ImmutablePairBytesPtr(byte[] bytes1, int offset1, int length1, byte[] bytes2, int offset2, int length2) {
+ set(bytes1, offset1, length1, bytes2, offset2, length2);
+ }
+
+ @Override
+ public int hashCode() {
+ return hashCode;
+ }
+
+ public void set(byte[] bytes1, int offset1, int length1, byte[] bytes2, int offset2, int length2) {
+ this.bytes1 = bytes1;
+ this.offset1 = offset1;
+ this.length1 = length1;
+ this.bytes2 = bytes2;
+ this.offset2 = offset2;
+ this.length2 = length2;
+ int hash = 1;
+ for (int i = offset1; i < offset1 + length1; i++)
+ hash = (31 * hash) + bytes1[i];
+ for (int i = offset2; i < offset2 + length2; i++)
+ hash = (31 * hash) + bytes2[i];
+ hashCode = hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+ ImmutablePairBytesPtr that = (ImmutablePairBytesPtr)obj;
+ if (this.hashCode != that.hashCode) return false;
+ if (Bytes.compareTo(this.bytes2, this.offset2, this.length2, that.bytes2, that.offset2, that.length2) != 0) return false;
+ if (Bytes.compareTo(this.bytes1, this.offset1, this.length1, that.bytes1, that.offset1, that.length1) != 0) return false;
+ return true;
+ }
+ }
+
+
+ @SuppressWarnings("all") // suppressing missing @Override since this doesn't exist for HBase 0.94.4
+ public boolean isFamilyEssential(byte[] name) {
+ // Only the column families involved in the expression are essential.
+ // The others are for columns projected in the select expression.
+ return cfSet.contains(name);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCQKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCQKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCQKeyValueComparisonFilter.java
new file mode 100644
index 0000000..c66b788
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiCQKeyValueComparisonFilter.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.filter;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.hadoop.hbase.index.util.ImmutableBytesPtr;
+import org.apache.phoenix.expression.Expression;
+
+/**
+ *
+ * Filter that evaluates WHERE clause expression, used in the case where there
+ * are references to multiple column qualifiers over a single column family.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class MultiCQKeyValueComparisonFilter extends MultiKeyValueComparisonFilter {
+ private ImmutableBytesPtr ptr = new ImmutableBytesPtr();
+ private byte[] cf;
+
+ public MultiCQKeyValueComparisonFilter() {
+ }
+
+ public MultiCQKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ }
+
+ @Override
+ protected Object setColumnKey(byte[] cf, int cfOffset, int cfLength, byte[] cq, int cqOffset,
+ int cqLength) {
+ ptr.set(cq, cqOffset, cqLength);
+ return ptr;
+ }
+
+ @Override
+ protected Object newColumnKey(byte[] cf, int cfOffset, int cfLength, byte[] cq, int cqOffset,
+ int cqLength) {
+ if (cfOffset == 0 && cf.length == cfLength) {
+ this.cf = cf;
+ } else {
+ this.cf = new byte[cfLength];
+ System.arraycopy(cf, cfOffset, this.cf, 0, cfLength);
+ }
+ return new ImmutableBytesPtr(cq, cqOffset, cqLength);
+ }
+
+
+ @SuppressWarnings("all") // suppressing missing @Override since this doesn't exist for HBase 0.94.4
+ public boolean isFamilyEssential(byte[] name) {
+ return Bytes.compareTo(cf, name) == 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java
new file mode 100644
index 0000000..ab8e1c0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/MultiKeyValueComparisonFilter.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.filter;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Modeled after {@link org.apache.hadoop.hbase.filter.SingleColumnValueFilter},
+ * but for general expression evaluation in the case where multiple KeyValue
+ * columns are referenced in the expression.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class MultiKeyValueComparisonFilter extends BooleanExpressionFilter {
+ private static final byte[] UNITIALIZED_KEY_BUFFER = new byte[0];
+
+ private Boolean matchedColumn;
+ protected final IncrementalResultTuple inputTuple = new IncrementalResultTuple();
+
+ public MultiKeyValueComparisonFilter() {
+ }
+
+ public MultiKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ init();
+ }
+
+ private static final class KeyValueRef {
+ public KeyValue keyValue;
+
+ @Override
+ public String toString() {
+ if(keyValue != null) {
+ return keyValue.toString() + " value = " + Bytes.toStringBinary(keyValue.getValue());
+ } else {
+ return super.toString();
+ }
+ }
+ }
+
+ protected abstract Object setColumnKey(byte[] cf, int cfOffset, int cfLength, byte[] cq, int cqOffset, int cqLength);
+ protected abstract Object newColumnKey(byte[] cf, int cfOffset, int cfLength, byte[] cq, int cqOffset, int cqLength);
+
+ private final class IncrementalResultTuple implements Tuple {
+ private int refCount;
+ private final ImmutableBytesWritable keyPtr = new ImmutableBytesWritable(UNITIALIZED_KEY_BUFFER);
+ private final Map<Object,KeyValueRef> foundColumns = new HashMap<Object,KeyValueRef>(5);
+
+ public void reset() {
+ refCount = 0;
+ keyPtr.set(UNITIALIZED_KEY_BUFFER);
+ for (KeyValueRef ref : foundColumns.values()) {
+ ref.keyValue = null;
+ }
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return refCount == foundColumns.size();
+ }
+
+ public void setImmutable() {
+ refCount = foundColumns.size();
+ }
+
+ public ReturnCode resolveColumn(KeyValue value) {
+ // Always set key, in case we never find a key value column of interest,
+ // and our expression uses row key columns.
+ setKey(value);
+ byte[] buf = value.getBuffer();
+ Object ptr = setColumnKey(buf, value.getFamilyOffset(), value.getFamilyLength(), buf, value.getQualifierOffset(), value.getQualifierLength());
+ KeyValueRef ref = foundColumns.get(ptr);
+ if (ref == null) {
+ // Return INCLUDE here. Although this filter doesn't need this KV
+ // it should still be projected into the Result
+ return ReturnCode.INCLUDE;
+ }
+ // Since we only look at the latest key value for a given column,
+ // we are not interested in older versions
+ // TODO: test with older versions to confirm this doesn't get tripped
+ // This shouldn't be necessary, because a scan only looks at the latest
+ // version
+ if (ref.keyValue != null) {
+ // Can't do NEXT_ROW, because then we don't match the other columns
+ // SKIP, INCLUDE, and NEXT_COL seem to all act the same
+ return ReturnCode.NEXT_COL;
+ }
+ ref.keyValue = value;
+ refCount++;
+ return null;
+ }
+
+ public void addColumn(byte[] cf, byte[] cq) {
+ Object ptr = MultiKeyValueComparisonFilter.this.newColumnKey(cf, 0, cf.length, cq, 0, cq.length);
+ foundColumns.put(ptr, new KeyValueRef());
+ }
+
+ public void setKey(KeyValue value) {
+ keyPtr.set(value.getBuffer(), value.getRowOffset(), value.getRowLength());
+ }
+
+ @Override
+ public void getKey(ImmutableBytesWritable ptr) {
+ ptr.set(keyPtr.get(),keyPtr.getOffset(),keyPtr.getLength());
+ }
+
+ @Override
+ public KeyValue getValue(byte[] cf, byte[] cq) {
+ Object ptr = setColumnKey(cf, 0, cf.length, cq, 0, cq.length);
+ KeyValueRef ref = foundColumns.get(ptr);
+ return ref == null ? null : ref.keyValue;
+ }
+
+ @Override
+ public String toString() {
+ return foundColumns.toString();
+ }
+
+ @Override
+ public int size() {
+ return refCount;
+ }
+
+ @Override
+ public KeyValue getValue(int index) {
+ // This won't perform very well, but it's not
+ // currently used anyway
+ for (KeyValueRef ref : foundColumns.values()) {
+ if (ref.keyValue == null) {
+ continue;
+ }
+ if (index == 0) {
+ return ref.keyValue;
+ }
+ index--;
+ }
+ throw new IndexOutOfBoundsException(Integer.toString(index));
+ }
+
+ @Override
+ public boolean getValue(byte[] family, byte[] qualifier,
+ ImmutableBytesWritable ptr) {
+ KeyValue kv = getValue(family, qualifier);
+ if (kv == null)
+ return false;
+ ptr.set(kv.getBuffer(), kv.getValueOffset(), kv.getValueLength());
+ return true;
+ }
+ }
+
+ protected void init() {
+ EvaluateOnCompletionVisitor visitor = new EvaluateOnCompletionVisitor() {
+ @Override
+ public Void visit(KeyValueColumnExpression expression) {
+ inputTuple.addColumn(expression.getColumnFamily(), expression.getColumnName());
+ return null;
+ }
+ };
+ expression.accept(visitor);
+ this.evaluateOnCompletion = visitor.evaluateOnCompletion();
+ expression.reset();
+ }
+
+ @Override
+ public ReturnCode filterKeyValue(KeyValue keyValue) {
+ if (Boolean.TRUE.equals(this.matchedColumn)) {
+ // We already found and matched the single column, all keys now pass
+ return ReturnCode.INCLUDE;
+ }
+ if (Boolean.FALSE.equals(this.matchedColumn)) {
+ // We found all the columns, but did not match the expression, so skip to next row
+ return ReturnCode.NEXT_ROW;
+ }
+ // This is a key value we're not interested in (TODO: why INCLUDE here instead of NEXT_COL?)
+ ReturnCode code = inputTuple.resolveColumn(keyValue);
+ if (code != null) {
+ return code;
+ }
+
+ // We found a new column, so we can re-evaluate
+ // TODO: if we have row key columns in our expression, should
+ // we always evaluate or just wait until the end?
+ this.matchedColumn = this.evaluate(inputTuple);
+ if (this.matchedColumn == null) {
+ if (inputTuple.isImmutable()) {
+ this.matchedColumn = Boolean.FALSE;
+ } else {
+ return ReturnCode.INCLUDE;
+ }
+ }
+ return this.matchedColumn ? ReturnCode.INCLUDE : ReturnCode.NEXT_ROW;
+ }
+
+ @Override
+ public boolean filterRow() {
+ if (this.matchedColumn == null && !inputTuple.isImmutable() && evaluateOnCompletion()) {
+ inputTuple.setImmutable();
+ this.matchedColumn = this.evaluate(inputTuple);
+ }
+
+ return ! (Boolean.TRUE.equals(this.matchedColumn));
+ }
+
+ @Override
+ public void reset() {
+ matchedColumn = null;
+ inputTuple.reset();
+ super.reset();
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ init();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/RowKeyComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/RowKeyComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/RowKeyComparisonFilter.java
new file mode 100644
index 0000000..bd47a8c
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/RowKeyComparisonFilter.java
@@ -0,0 +1,156 @@
+/*
+ * 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.filter;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.hadoop.io.WritableUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Filter for use when expressions only reference row key columns
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class RowKeyComparisonFilter extends BooleanExpressionFilter {
+ private static final Logger logger = LoggerFactory.getLogger(RowKeyComparisonFilter.class);
+
+ private boolean evaluate = true;
+ private boolean keepRow = false;
+ private RowKeyTuple inputTuple = new RowKeyTuple();
+ private byte[] essentialCF;
+
+ public RowKeyComparisonFilter() {
+ }
+
+ public RowKeyComparisonFilter(Expression expression, byte[] essentialCF) {
+ super(expression);
+ this.essentialCF = essentialCF;
+ }
+
+ @Override
+ public void reset() {
+ this.keepRow = false;
+ this.evaluate = true;
+ super.reset();
+ }
+
+ /**
+ * Evaluate in filterKeyValue instead of filterRowKey, because HBASE-6562 causes filterRowKey
+ * to be called with deleted or partial row keys.
+ */
+ @Override
+ public ReturnCode filterKeyValue(KeyValue v) {
+ if (evaluate) {
+ inputTuple.setKey(v.getBuffer(), v.getRowOffset(), v.getRowLength());
+ this.keepRow = Boolean.TRUE.equals(evaluate(inputTuple));
+ if (logger.isDebugEnabled()) {
+ logger.debug("RowKeyComparisonFilter: " + (this.keepRow ? "KEEP" : "FILTER") + " row " + inputTuple);
+ }
+ evaluate = false;
+ }
+ return keepRow ? ReturnCode.INCLUDE : ReturnCode.NEXT_ROW;
+ }
+
+ private final class RowKeyTuple implements Tuple {
+ private byte[] buf;
+ private int offset;
+ private int length;
+
+ public void setKey(byte[] buf, int offset, int length) {
+ this.buf = buf;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Override
+ public void getKey(ImmutableBytesWritable ptr) {
+ ptr.set(buf, offset, length);
+ }
+
+ @Override
+ public KeyValue getValue(byte[] cf, byte[] cq) {
+ return null;
+ }
+
+ @Override
+ public boolean isImmutable() {
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return Bytes.toStringBinary(buf, offset, length);
+ }
+
+ @Override
+ public int size() {
+ return 0;
+ }
+
+ @Override
+ public KeyValue getValue(int index) {
+ throw new IndexOutOfBoundsException(Integer.toString(index));
+ }
+
+ @Override
+ public boolean getValue(byte[] family, byte[] qualifier,
+ ImmutableBytesWritable ptr) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean filterRow() {
+ return !this.keepRow;
+ }
+
+ @SuppressWarnings("all") // suppressing missing @Override since this doesn't exist for HBase 0.94.4
+ public boolean isFamilyEssential(byte[] name) {
+ // We only need our "guaranteed to have a key value" column family,
+ // which we pass in and serialize through. In the case of a VIEW where
+ // we don't have this, we have to say that all families are essential.
+ return this.essentialCF.length == 0 ? true : Bytes.compareTo(this.essentialCF, name) == 0;
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ this.essentialCF = WritableUtils.readCompressedByteArray(input);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeCompressedByteArray(output, this.essentialCF);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCFCQKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCFCQKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCFCQKeyValueComparisonFilter.java
new file mode 100644
index 0000000..5b8a5f0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCFCQKeyValueComparisonFilter.java
@@ -0,0 +1,51 @@
+/*
+ * 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.filter;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.Expression;
+
+
+/**
+ *
+ * SingleKeyValueComparisonFilter that needs to compare both the column family and
+ * column qualifier parts of the key value to disambiguate with another similarly
+ * named column qualifier in a different column family.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class SingleCFCQKeyValueComparisonFilter extends SingleKeyValueComparisonFilter {
+ public SingleCFCQKeyValueComparisonFilter() {
+ }
+
+ public SingleCFCQKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ }
+
+ @Override
+ protected final int compare(byte[] cfBuf, int cfOffset, int cfLength, byte[] cqBuf, int cqOffset, int cqLength) {
+ int c = Bytes.compareTo(cf, 0, cf.length, cfBuf, cfOffset, cfLength);
+ if (c != 0) return c;
+ return Bytes.compareTo(cq, 0, cq.length, cqBuf, cqOffset, cqLength);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCQKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCQKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCQKeyValueComparisonFilter.java
new file mode 100644
index 0000000..425839a
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleCQKeyValueComparisonFilter.java
@@ -0,0 +1,49 @@
+/*
+ * 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.filter;
+
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.Expression;
+
+
+/**
+ *
+ * SingleKeyValueComparisonFilter that needs to only compare the column qualifier
+ * part of the key value since the column qualifier is unique across all column
+ * families.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public class SingleCQKeyValueComparisonFilter extends SingleKeyValueComparisonFilter {
+ public SingleCQKeyValueComparisonFilter() {
+ }
+
+ public SingleCQKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ }
+
+ @Override
+ protected final int compare(byte[] cfBuf, int cfOffset, int cfLength, byte[] cqBuf, int cqOffset, int cqLength) {
+ return Bytes.compareTo(cq, 0, cq.length, cqBuf, cqOffset, cqLength);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/50d523f6/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleKeyValueComparisonFilter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleKeyValueComparisonFilter.java b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleKeyValueComparisonFilter.java
new file mode 100644
index 0000000..1caa332
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/filter/SingleKeyValueComparisonFilter.java
@@ -0,0 +1,147 @@
+/*
+ * 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.filter;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.hadoop.hbase.KeyValue;
+import org.apache.hadoop.hbase.util.Bytes;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.schema.tuple.SingleKeyValueTuple;
+
+
+
+/**
+ *
+ * Modeled after {@link org.apache.hadoop.hbase.filter.SingleColumnValueFilter},
+ * but for general expression evaluation in the case where only a single KeyValue
+ * column is referenced in the expression.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class SingleKeyValueComparisonFilter extends BooleanExpressionFilter {
+ private final SingleKeyValueTuple inputTuple = new SingleKeyValueTuple();
+ private boolean matchedColumn;
+ protected byte[] cf;
+ protected byte[] cq;
+
+ public SingleKeyValueComparisonFilter() {
+ }
+
+ public SingleKeyValueComparisonFilter(Expression expression) {
+ super(expression);
+ init();
+ }
+
+ protected abstract int compare(byte[] cfBuf, int cfOffset, int cfLength, byte[] cqBuf, int cqOffset, int cqLength);
+
+ private void init() {
+ EvaluateOnCompletionVisitor visitor = new EvaluateOnCompletionVisitor() {
+ @Override
+ public Void visit(KeyValueColumnExpression expression) {
+ cf = expression.getColumnFamily();
+ cq = expression.getColumnName();
+ return null;
+ }
+ };
+ expression.accept(visitor);
+ this.evaluateOnCompletion = visitor.evaluateOnCompletion();
+ }
+
+ private boolean foundColumn() {
+ return inputTuple.size() > 0;
+ }
+
+ @Override
+ public ReturnCode filterKeyValue(KeyValue keyValue) {
+ if (this.matchedColumn) {
+ // We already found and matched the single column, all keys now pass
+ // TODO: why won't this cause earlier versions of a kv to be included?
+ return ReturnCode.INCLUDE;
+ }
+ if (this.foundColumn()) {
+ // We found all the columns, but did not match the expression, so skip to next row
+ return ReturnCode.NEXT_ROW;
+ }
+ byte[] buf = keyValue.getBuffer();
+ if (compare(buf, keyValue.getFamilyOffset(), keyValue.getFamilyLength(), buf, keyValue.getQualifierOffset(), keyValue.getQualifierLength()) != 0) {
+ // Remember the key in case this is the only key value we see.
+ // We'll need it if we have row key columns too.
+ inputTuple.setKey(keyValue);
+ // This is a key value we're not interested in
+ // TODO: use NEXT_COL when bug fix comes through that includes the row still
+ return ReturnCode.INCLUDE;
+ }
+ inputTuple.setKeyValue(keyValue);
+
+ // We have the columns, so evaluate here
+ if (!Boolean.TRUE.equals(evaluate(inputTuple))) {
+ return ReturnCode.NEXT_ROW;
+ }
+ this.matchedColumn = true;
+ return ReturnCode.INCLUDE;
+ }
+
+ @Override
+ public boolean filterRow() {
+ // If column was found, return false if it was matched, true if it was not.
+ if (foundColumn()) {
+ return !this.matchedColumn;
+ }
+ // If column was not found, evaluate the expression here upon completion.
+ // This is required with certain expressions, for example, with IS NULL
+ // expressions where they'll evaluate to TRUE when the column being
+ // tested wasn't found.
+ // Since the filter is called also to position the scan initially, we have
+ // to guard against this by checking whether or not we've filtered in
+ // the key value (i.e. filterKeyValue was called and we found the keyValue
+ // for which we're looking).
+ if (inputTuple.hasKey() && evaluateOnCompletion()) {
+ return !Boolean.TRUE.equals(evaluate(inputTuple));
+ }
+ // Finally, if we have no values, and we're not required to re-evaluate it
+ // just filter the row
+ return true;
+ }
+
+ @Override
+ public void reset() {
+ inputTuple.reset();
+ matchedColumn = false;
+ super.reset();
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ init();
+ }
+
+ @SuppressWarnings("all") // suppressing missing @Override since this doesn't exist for HBase 0.94.4
+ public boolean isFamilyEssential(byte[] name) {
+ // Only the column families involved in the expression are essential.
+ // The others are for columns projected in the select expression
+ return Bytes.compareTo(cf, name) == 0;
+ }
+}