You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/01/27 20:23:30 UTC
[29/51] [partial] Initial commit
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java b/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
new file mode 100644
index 0000000..b90fd7c
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ReverseFunction.java
@@ -0,0 +1,70 @@
+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.StringUtil;
+
+@BuiltInFunction(name=ReverseFunction.NAME, args={
+ @Argument(allowedTypes={PDataType.VARCHAR})} )
+public class ReverseFunction extends ScalarFunction {
+ public static final String NAME = "REVERSE";
+
+ public ReverseFunction() {
+ }
+
+ public ReverseFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression arg = getChildren().get(0);
+ if (!arg.evaluate(tuple, ptr)) {
+ return false;
+ }
+
+ int targetOffset = ptr.getLength();
+ if (targetOffset == 0) {
+ return true;
+ }
+
+ byte[] source = ptr.get();
+ byte[] target = new byte[targetOffset];
+ int sourceOffset = ptr.getOffset();
+ int endOffset = sourceOffset + ptr.getLength();
+ ColumnModifier modifier = arg.getColumnModifier();
+ while (sourceOffset < endOffset) {
+ int nBytes = StringUtil.getBytesInChar(source[sourceOffset], modifier);
+ targetOffset -= nBytes;
+ System.arraycopy(source, sourceOffset, target, targetOffset, nBytes);
+ sourceOffset += nBytes;
+ }
+ ptr.set(target);
+ return true;
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return getChildren().get(0).getColumnModifier();
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.VARCHAR;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java b/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
new file mode 100644
index 0000000..23adb62
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/RoundFunction.java
@@ -0,0 +1,238 @@
+/*
+ * 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.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.sql.Date;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PDataType.PDataCodec;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ *
+ * Function used to bucketize date/time values by rounding them to
+ * an even increment. Usage:
+ * ROUND(<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=RoundFunction.NAME, args= {
+ @Argument(allowedTypes={PDataType.DATE}),
+ @Argument(enumeration="TimeUnit"),
+ @Argument(allowedTypes={PDataType.INTEGER}, isConstant=true, defaultValue="1")} )
+public class RoundFunction extends ScalarFunction {
+ public static final String NAME = "ROUND";
+ private long divBy;
+
+ private static final long[] TIME_UNIT_MS = new long[] {
+ 24 * 60 * 60 * 1000,
+ 60 * 60 * 1000,
+ 60 * 1000,
+ 1000,
+ 1
+ };
+
+ public RoundFunction() {
+ }
+
+ public RoundFunction(List<Expression> children) throws SQLException {
+ super(children.subList(0, 1));
+ Object timeUnitValue = ((LiteralExpression)children.get(1)).getValue();
+ Object multiplierValue = ((LiteralExpression)children.get(2)).getValue();
+ if (timeUnitValue != null && multiplierValue != null) {
+ TimeUnit timeUnit = TimeUnit.valueOf(timeUnitValue.toString().toUpperCase());
+ int multiplier = ((Number)multiplierValue).intValue();
+ divBy = multiplier * TIME_UNIT_MS[timeUnit.ordinal()];
+ }
+ }
+
+ protected long getRoundUpAmount() {
+ return divBy/2;
+ }
+
+ private long roundTime(long time) {
+ long value;
+ long halfDivBy = getRoundUpAmount();
+ if (time <= Long.MAX_VALUE - halfDivBy) { // If no overflow, add
+ value = (time + halfDivBy) / divBy;
+ } else { // Else subtract and add one
+ value = (time - halfDivBy) / divBy + 1;
+ }
+ return value * divBy;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ // If divBy is 0 this means <time unit> or <multiplier> was null
+ if (divBy != 0 && children.get(0).evaluate(tuple, ptr)) {
+ long time = getDataType().getCodec().decodeLong(ptr, children.get(0).getColumnModifier());
+ long value = roundTime(time);
+ // TODO: use temporary buffer instead and have way for caller to check if copying is necessary
+ byte[] byteValue = getDataType().toBytes(new Date(value));
+ ptr.set(byteValue);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ long roundUpAmount = this.getRoundUpAmount();
+ result = prime * result + (int)(divBy ^ (divBy >>> 32));
+ result = prime * result + (int)(roundUpAmount ^ (roundUpAmount >>> 32));
+ result = prime * result + children.get(0).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;
+ RoundFunction other = (RoundFunction)obj;
+ if (divBy != other.divBy) return false;
+ if (getRoundUpAmount() != other.getRoundUpAmount()) return false;
+ return children.get(0).equals(other.children.get(0));
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ divBy = WritableUtils.readVLong(input);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeVLong(output, divBy);
+ }
+
+ @Override
+ public final PDataType getDataType() {
+ return PDataType.DATE;
+ }
+
+ @Override
+ public Integer getByteSize() {
+ return children.get(0).getByteSize();
+ }
+
+ @Override
+ public boolean isNullable() {
+ return children.get(0).isNullable() || divBy == 0;
+ }
+
+ @Override
+ public OrderPreserving preservesOrder() {
+ return OrderPreserving.YES;
+ }
+
+ @Override
+ public int getKeyFormationTraversalIndex() {
+ return 0;
+ }
+
+ /**
+ * Form the key range from the key to the key right before or at the
+ * next rounded value.
+ */
+ @Override
+ public KeyPart newKeyPart(final KeyPart childPart) {
+ return new KeyPart() {
+ private final List<Expression> extractNodes = Collections.<Expression>singletonList(RoundFunction.this);
+
+ @Override
+ public PColumn getColumn() {
+ return childPart.getColumn();
+ }
+
+ @Override
+ public List<Expression> getExtractNodes() {
+ return extractNodes;
+ }
+
+ @Override
+ public KeyRange getKeyRange(CompareOp op, Expression rhs) {
+ PDataType type = getColumn().getDataType();
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ rhs.evaluate(null, ptr);
+ byte[] key = ByteUtil.copyKeyBytesIfNecessary(ptr);
+ // No need to take into account column modifier, because ROUND
+ // always forces the value to be in ascending order
+ PDataCodec codec = type.getCodec();
+ int offset = ByteUtil.isInclusive(op) ? 1 : 0;
+ long value = codec.decodeLong(key, 0, null);
+ byte[] nextKey = new byte[type.getByteSize()];
+ switch (op) {
+ case EQUAL:
+ // If the value isn't evenly divisible by the div amount, then it
+ // can't possibly be equal to any rounded value. For example, if you
+ // had ROUND(dateCol,'DAY') = TO_DATE('2013-01-01 23:00:00')
+ // it could never be equal, since date constant isn't at a day
+ // boundary.
+ if (value % divBy != 0) {
+ return KeyRange.EMPTY_RANGE;
+ }
+ codec.encodeLong(value + divBy, nextKey, 0);
+ return type.getKeyRange(key, true, nextKey, false);
+ case GREATER:
+ case GREATER_OR_EQUAL:
+ codec.encodeLong((value + divBy - offset)/divBy*divBy, nextKey, 0);
+ return type.getKeyRange(nextKey, true, KeyRange.UNBOUND, false);
+ case LESS:
+ case LESS_OR_EQUAL:
+ codec.encodeLong((value + divBy - (1 -offset))/divBy*divBy, nextKey, 0);
+ return type.getKeyRange(KeyRange.UNBOUND, false, nextKey, false);
+ default:
+ return childPart.getKeyRange(op, rhs);
+ }
+ }
+ };
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java b/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
new file mode 100644
index 0000000..1d1059b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ScalarFunction.java
@@ -0,0 +1,72 @@
+/*
+ * 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.util.List;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+public abstract class ScalarFunction extends FunctionExpression {
+ public static final int NO_TRAVERSAL = -1;
+
+ public ScalarFunction() {
+ }
+
+ public ScalarFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ public final <T> T accept(ExpressionVisitor<T> visitor) {
+ List<T> l = acceptChildren(visitor, visitor.visitEnter(this));
+ T t = visitor.visitLeave(this, l);
+ if (t == null) {
+ t = visitor.defaultReturn(this, l);
+ }
+ return t;
+ }
+
+ /**
+ * Determines whether or not a function may be used to form
+ * the start/stop key of a scan
+ * @return the zero-based position of the argument to traverse
+ * into to look for a primary key column reference, or
+ * {@value #NO_TRAVERSAL} if the function cannot be used to
+ * form the scan key.
+ */
+ public int getKeyFormationTraversalIndex() {
+ return NO_TRAVERSAL;
+ }
+
+ /**
+ * Manufactures a KeyPart used to construct the KeyRange given
+ * a constant and a comparison operator.
+ * @param childPart the KeyPart formulated for the child expression
+ * at the {@link #getKeyFormationTraversalIndex()} position.
+ * @return the KeyPart for constructing the KeyRange for this
+ * function.
+ */
+ public KeyPart newKeyPart(KeyPart childPart) {
+ return null;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
new file mode 100644
index 0000000..82dcb8b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SingleAggregateFunction.java
@@ -0,0 +1,166 @@
+/*
+ * 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.io.DataInput;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.aggregator.Aggregator;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Base class for aggregate functions that calculate an aggregation
+ * using a single {{@link Aggregator}
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class SingleAggregateFunction extends AggregateFunction {
+ private static final List<Expression> DEFAULT_EXPRESSION_LIST = Arrays.<Expression>asList(LiteralExpression.newConstant(1));
+ protected boolean isConstant;
+ private Aggregator aggregator;
+
+ /**
+ * Sort aggregate functions with nullable fields last. This allows us not to have to store trailing null values.
+ * Within non-nullable/nullable groups, put fixed width values first since we can access those more efficiently
+ * (i.e. we can skip over groups of them in-mass instead of reading the length of each one to skip over as
+ * required by a variable length value).
+ */
+ public static final Comparator<SingleAggregateFunction> SCHEMA_COMPARATOR = new Comparator<SingleAggregateFunction>() {
+
+ @Override
+ public int compare(SingleAggregateFunction o1, SingleAggregateFunction o2) {
+ boolean isNullable1 = o1.isNullable();
+ boolean isNullable2 = o2.isNullable();
+ if (isNullable1 != isNullable2) {
+ return isNullable1 ? 1 : -1;
+ }
+ isNullable1 = o1.getAggregatorExpression().isNullable();
+ isNullable2 = o2.getAggregatorExpression().isNullable();
+ if (isNullable1 != isNullable2) {
+ return isNullable1 ? 1 : -1;
+ }
+ // Ensures COUNT(1) sorts first TODO: unit test for this
+ boolean isConstant1 = o1.isConstantExpression();
+ boolean isConstant2 = o2.isConstantExpression();
+ if (isConstant1 != isConstant2) {
+ return isConstant1 ? 1 : -1;
+ }
+ PDataType r1 = o1.getAggregator().getDataType();
+ PDataType r2 = o2.getAggregator().getDataType();
+ if (r1.isFixedWidth() != r2.isFixedWidth()) {
+ return r1.isFixedWidth() ? -1 : 1;
+ }
+ return r1.compareTo(r2);
+ }
+ };
+
+ protected SingleAggregateFunction() {
+ this(DEFAULT_EXPRESSION_LIST, true);
+ }
+
+ public SingleAggregateFunction(List<Expression> children) {
+ this(children, children.get(0) instanceof LiteralExpression);
+ }
+
+ private SingleAggregateFunction(List<Expression> children, boolean isConstant) {
+ super(children);
+ this.isConstant = children.get(0) instanceof LiteralExpression;
+ this.aggregator = newClientAggregator();
+ }
+
+ public boolean isConstantExpression() {
+ return isConstant;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return children.get(0).getDataType();
+ }
+
+ public Expression getAggregatorExpression() {
+ return children.get(0);
+ }
+
+ public Aggregator getAggregator() {
+ return aggregator;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ return getAggregator().evaluate(tuple, ptr);
+ }
+
+ /**
+ * Create the aggregator to do server-side aggregation.
+ * The data type of the returned Aggregator must match
+ * the data type returned by {@link #newClientAggregator()}
+ * @param conf HBase configuration.
+ * @return the aggregator to use on the server-side
+ */
+ abstract public Aggregator newServerAggregator(Configuration conf);
+ /**
+ * Create the aggregator to do client-side aggregation
+ * based on the results returned from the aggregating
+ * coprocessor. The data type of the returned Aggregator
+ * must match the data type returned by {@link #newServerAggregator(Configuration)}
+ * @return the aggregator to use on the client-side
+ */
+ public Aggregator newClientAggregator() {
+ return newServerAggregator(null);
+ }
+
+ public void readFields(DataInput input, Configuration conf) throws IOException {
+ super.readFields(input);
+ aggregator = newServerAggregator(conf);
+ }
+
+ @Override
+ public boolean isNullable() {
+ return true;
+ }
+
+ protected SingleAggregateFunction getDelegate() {
+ return this;
+ }
+
+ @Override
+ public final <T> T accept(ExpressionVisitor<T> visitor) {
+ SingleAggregateFunction function = getDelegate();
+ List<T> l = acceptChildren(visitor, visitor.visitEnter(function));
+ T t = visitor.visitLeave(function, l);
+ if (t == null) {
+ t = visitor.defaultReturn(function, l);
+ }
+ return t;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java b/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
new file mode 100644
index 0000000..9ffbd90
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SqlTableType.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.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.PDataType;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Function used to get the SQL table type name from the serialized table type.
+ * Usage:
+ * SqlTableType('v') will return 'VIEW' based on
+ * {@link java.sql.DatabaseMetaData#getTableTypes()}
+ *
+ * @author jtaylor
+ * @since 2.2
+ */
+@BuiltInFunction(name=SqlTableType.NAME, args= {
+ @Argument(allowedTypes=PDataType.CHAR)} )
+public class SqlTableType extends ScalarFunction {
+ public static final String NAME = "SqlTableType";
+
+ public SqlTableType() {
+ }
+
+ public SqlTableType(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression child = children.get(0);
+ if (!child.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+ PTableType tableType = PTableType.fromSerializedValue(ptr.get()[ptr.getOffset()]);
+ ptr.set(tableType.getValue().getBytes());
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.VARCHAR;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java b/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.java
new file mode 100644
index 0000000..e0d9807
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SqlTypeNameFunction.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.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.IllegalDataException;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ *
+ * Function used to get the SQL type name from the SQL type integer.
+ * Usage:
+ * SqlTypeName(12)
+ * will return 'VARCHAR' based on {@link java.sql.Types#VARCHAR} being 12
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SqlTypeNameFunction.NAME, args= {
+ @Argument(allowedTypes=PDataType.INTEGER)} )
+public class SqlTypeNameFunction extends ScalarFunction {
+ public static final String NAME = "SqlTypeName";
+
+ public SqlTypeNameFunction() {
+ }
+
+ public SqlTypeNameFunction(List<Expression> children) throws SQLException {
+ super(children);
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression child = children.get(0);
+ if (!child.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (ptr.getLength() == 0) {
+ return true;
+ }
+ int sqlType = child.getDataType().getCodec().decodeInt(ptr, child.getColumnModifier());
+ try {
+ byte[] sqlTypeNameBytes = PDataType.fromSqlType(sqlType).getSqlTypeNameBytes();
+ ptr.set(sqlTypeNameBytes);
+ } catch (IllegalDataException e) {
+ ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ }
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.VARCHAR;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java b/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.java
new file mode 100644
index 0000000..675b34b
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/StddevPopFunction.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.function;
+
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+/**
+ *
+ * Built-in function for STDDEV_POP(<expression>) aggregate function
+ *
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = StddevPopFunction.NAME, args = { @Argument(allowedTypes={PDataType.DECIMAL})})
+public class StddevPopFunction extends SingleAggregateFunction {
+ public static final String NAME = "STDDEV_POP";
+
+ public StddevPopFunction() {
+
+ }
+
+ public StddevPopFunction(List<Expression> childern) {
+ super(childern);
+ }
+
+ @Override
+ public Aggregator newServerAggregator(Configuration conf) {
+ return new DistinctValueWithCountServerAggregator(conf);
+ }
+
+ @Override
+ public Aggregator newClientAggregator() {
+ if (children.get(0).getDataType() == PDataType.DECIMAL) {
+ // Special Aggregators for DECIMAL datatype for more precision than double
+ return new DecimalStddevPopAggregator(children, getAggregatorExpression().getColumnModifier());
+ }
+ return new StddevPopAggregator(children, getAggregatorExpression().getColumnModifier());
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java b/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.java
new file mode 100644
index 0000000..53e9595
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/StddevSampFunction.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.function;
+
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+
+/**
+ *
+ * Built-in function for STDDEV_SAMP(<expression>) aggregate function
+ *
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = StddevSampFunction.NAME, args = { @Argument(allowedTypes={PDataType.DECIMAL})})
+public class StddevSampFunction extends SingleAggregateFunction {
+ public static final String NAME = "STDDEV_SAMP";
+
+ public StddevSampFunction() {
+
+ }
+
+ public StddevSampFunction(List<Expression> childern) {
+ super(childern);
+ }
+
+ @Override
+ public Aggregator newServerAggregator(Configuration conf) {
+ return new DistinctValueWithCountServerAggregator(conf);
+ }
+
+ @Override
+ public Aggregator newClientAggregator() {
+ if (children.get(0).getDataType() == PDataType.DECIMAL) {
+ // Special Aggregators for DECIMAL datatype for more precision than double
+ return new DecimalStddevSampAggregator(children, getAggregatorExpression().getColumnModifier());
+ }
+ return new StddevSampAggregator(children, getAggregatorExpression().getColumnModifier());
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DECIMAL;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java b/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
new file mode 100644
index 0000000..90aa3c8
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SubstrFunction.java
@@ -0,0 +1,217 @@
+/*
+ * 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.io.DataInput;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+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.StringUtil;
+
+
+/**
+ *
+ * Implementation of the SUBSTR(<string>,<offset>[,<length>]) built-in function
+ * where <offset> is the offset from the start of <string>. A positive offset
+ * is treated as 1-based, a zero offset is treated as 0-based, and a negative
+ * offset starts from the end of the string working backwards. The optional
+ * <length> argument is the number of characters to return. In the absence of the
+ * <length> argument, the rest of the string starting from <offset> is returned.
+ * If <length> is less than 1, null is returned.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SubstrFunction.NAME, args={
+ @Argument(allowedTypes={PDataType.VARCHAR}),
+ @Argument(allowedTypes={PDataType.LONG}), // These are LONG because negative numbers end up as longs
+ @Argument(allowedTypes={PDataType.LONG},defaultValue="null")} )
+public class SubstrFunction extends PrefixFunction {
+ public static final String NAME = "SUBSTR";
+ private boolean hasLengthExpression;
+ private boolean isOffsetConstant;
+ private boolean isLengthConstant;
+ private boolean isFixedWidth;
+ private Integer byteSize;
+
+ public SubstrFunction() {
+ }
+
+ public SubstrFunction(List<Expression> children) {
+ super(children);
+ init();
+ }
+
+ private void init() {
+ // TODO: when we have ColumnModifier.REVERSE, we'll need to negate offset,
+ // since the bytes are reverse and we'll want to work from the end.
+ isOffsetConstant = getOffsetExpression() instanceof LiteralExpression;
+ isLengthConstant = getLengthExpression() instanceof LiteralExpression;
+ hasLengthExpression = !isLengthConstant || ((LiteralExpression)getLengthExpression()).getValue() != null;
+ isFixedWidth = getStrExpression().getDataType().isFixedWidth() && ((hasLengthExpression && isLengthConstant) || (!hasLengthExpression && isOffsetConstant));
+ if (hasLengthExpression && isLengthConstant) {
+ Integer maxLength = ((Number)((LiteralExpression)getLengthExpression()).getValue()).intValue();
+ this.byteSize = maxLength >= 0 ? maxLength : 0;
+ } else if (isOffsetConstant) {
+ Number offsetNumber = (Number)((LiteralExpression)getOffsetExpression()).getValue();
+ if (offsetNumber != null) {
+ int offset = offsetNumber.intValue();
+ if (getStrExpression().getDataType().isFixedWidth()) {
+ if (offset >= 0) {
+ byteSize = getStrExpression().getByteSize() - offset + (offset == 0 ? 0 : 1);
+ } else {
+ byteSize = -offset;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression offsetExpression = getOffsetExpression();
+ if (!offsetExpression.evaluate(tuple, ptr)) {
+ return false;
+ }
+ int offset = offsetExpression.getDataType().getCodec().decodeInt(ptr, offsetExpression.getColumnModifier());
+
+ int length = -1;
+ if (hasLengthExpression) {
+ Expression lengthExpression = getLengthExpression();
+ if (!lengthExpression.evaluate(tuple, ptr)) {
+ return false;
+ }
+ length = lengthExpression.getDataType().getCodec().decodeInt(ptr, lengthExpression.getColumnModifier());
+ if (length <= 0) {
+ return false;
+ }
+ }
+
+ if (!getStrExpression().evaluate(tuple, ptr)) {
+ return false;
+ }
+
+ try {
+ boolean isCharType = getStrExpression().getDataType() == PDataType.CHAR;
+ ColumnModifier columnModifier = getStrExpression().getColumnModifier();
+ int strlen = isCharType ? ptr.getLength() : StringUtil.calculateUTF8Length(ptr.get(), ptr.getOffset(), ptr.getLength(), columnModifier);
+
+ // Account for 1 versus 0-based offset
+ offset = offset - (offset <= 0 ? 0 : 1);
+ if (offset < 0) { // Offset < 0 means get from end
+ offset = strlen + offset;
+ }
+ if (offset < 0 || offset >= strlen) {
+ return false;
+ }
+ int maxLength = strlen - offset;
+ length = length == -1 ? maxLength : Math.min(length,maxLength);
+
+ int byteOffset = isCharType ? offset : StringUtil.getByteLengthForUtf8SubStr(ptr.get(), ptr.getOffset(), offset, columnModifier);
+ int byteLength = isCharType ? length : StringUtil.getByteLengthForUtf8SubStr(ptr.get(), ptr.getOffset() + byteOffset, length, columnModifier);
+ ptr.set(ptr.get(), ptr.getOffset() + byteOffset, byteLength);
+ return true;
+ } catch (UnsupportedEncodingException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public PDataType getDataType() {
+ // If fixed width, then return child expression type.
+ // If not fixed width, then we don't know how big this will be across the board
+ return isFixedWidth ? getStrExpression().getDataType() : PDataType.VARCHAR;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return getStrExpression().isNullable() || !isFixedWidth || getOffsetExpression().isNullable();
+ }
+
+ @Override
+ public Integer getByteSize() {
+ return byteSize;
+ }
+
+ // TODO: we shouldn't need both getByteSize() and getMaxLength()
+ @Override
+ public Integer getMaxLength() {
+ return byteSize;
+ }
+
+ @Override
+ public ColumnModifier getColumnModifier() {
+ return getStrExpression().getColumnModifier();
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ init();
+ }
+
+ private Expression getStrExpression() {
+ return children.get(0);
+ }
+
+ private Expression getOffsetExpression() {
+ return children.get(1);
+ }
+
+ private Expression getLengthExpression() {
+ return children.get(2);
+ }
+
+ @Override
+ public OrderPreserving preservesOrder() {
+ if (isOffsetConstant) {
+ LiteralExpression literal = (LiteralExpression) getOffsetExpression();
+ Number offsetNumber = (Number) literal.getValue();
+ if (offsetNumber != null) {
+ int offset = offsetNumber.intValue();
+ if ((offset == 0 || offset == 1) && (!hasLengthExpression || isLengthConstant)) {
+ return OrderPreserving.YES_IF_LAST;
+ }
+ }
+ }
+ return OrderPreserving.NO;
+ }
+
+ @Override
+ protected boolean extractNode() {
+ return true;
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
new file mode 100644
index 0000000..b6143bb
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/SumAggregateFunction.java
@@ -0,0 +1,146 @@
+/*
+ * 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.math.BigDecimal;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.aggregator.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.schema.ColumnModifier;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ *
+ * Built-in function for SUM aggregation function.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=SumAggregateFunction.NAME, nodeClass=SumAggregateParseNode.class, args= {@Argument(allowedTypes={PDataType.DECIMAL})} )
+public class SumAggregateFunction extends DelegateConstantToCountAggregateFunction {
+ public static final String NAME = "SUM";
+
+ public SumAggregateFunction() {
+ }
+
+ // TODO: remove when not required at built-in func register time
+ public SumAggregateFunction(List<Expression> childExpressions){
+ super(childExpressions, null);
+ }
+
+ public SumAggregateFunction(List<Expression> childExpressions, CountAggregateFunction delegate){
+ super(childExpressions, delegate);
+ }
+
+ @Override
+ public Aggregator newServerAggregator(Configuration conf) {
+ final PDataType type = getAggregatorExpression().getDataType();
+ ColumnModifier columnModifier = getAggregatorExpression().getColumnModifier();
+ switch( type ) {
+ case DECIMAL:
+ return new DecimalSumAggregator(columnModifier);
+ case UNSIGNED_DOUBLE:
+ case UNSIGNED_FLOAT:
+ case DOUBLE:
+ case FLOAT:
+ return new DoubleSumAggregator(columnModifier) {
+ @Override
+ protected PDataType getInputDataType() {
+ return type;
+ }
+ };
+ default:
+ return new NumberSumAggregator(columnModifier) {
+ @Override
+ protected PDataType getInputDataType() {
+ return type;
+ }
+ };
+ }
+ }
+
+ @Override
+ public Aggregator newClientAggregator() {
+ switch( getDataType() ) {
+ case DECIMAL:
+ // On the client, we'll always aggregate over non modified column values,
+ // because we always get them back from the server in their non modified
+ // form.
+ return new DecimalSumAggregator(null);
+ case LONG:
+ return new LongSumAggregator(null);
+ case DOUBLE:
+ return new DoubleSumAggregator(null);
+ default:
+ throw new IllegalStateException("Unexpected SUM type: " + getDataType());
+ }
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ if (!super.evaluate(tuple, ptr)) {
+ return false;
+ }
+ if (isConstantExpression()) {
+ PDataType type = getDataType();
+ Object constantValue = ((LiteralExpression)children.get(0)).getValue();
+ if (type == PDataType.DECIMAL) {
+ BigDecimal value = ((BigDecimal)constantValue).multiply((BigDecimal)PDataType.DECIMAL.toObject(ptr, PDataType.LONG));
+ ptr.set(PDataType.DECIMAL.toBytes(value));
+ } else {
+ long constantLongValue = ((Number)constantValue).longValue();
+ long value = constantLongValue * type.getCodec().decodeLong(ptr, null);
+ ptr.set(new byte[type.getByteSize()]);
+ type.getCodec().encodeLong(value, ptr);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ switch(super.getDataType()) {
+ case DECIMAL:
+ return PDataType.DECIMAL;
+ case UNSIGNED_FLOAT:
+ case UNSIGNED_DOUBLE:
+ case FLOAT:
+ case DOUBLE:
+ return PDataType.DOUBLE;
+ default:
+ return PDataType.LONG;
+ }
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java b/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
new file mode 100644
index 0000000..ffe19fe
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/TimeUnit.java
@@ -0,0 +1,22 @@
+/*
+ * 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;
+
+public enum TimeUnit{DAY, HOUR, MINUTE, SECOND, MILLISECOND}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
new file mode 100644
index 0000000..d6cdc99
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ToCharFunction.java
@@ -0,0 +1,135 @@
+/*
+ * 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.io.*;
+import java.sql.SQLException;
+import java.text.Format;
+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 the TO_CHAR(<date>/<number>,[<format-string>] built-in function.
+ * The first argument must be of type DATE or TIME or TIMESTAMP or DECIMAL or INTEGER, and the second argument must be a constant string.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToCharFunction.NAME, nodeClass=ToCharParseNode.class, args={
+ @Argument(allowedTypes={PDataType.TIMESTAMP, PDataType.DECIMAL}),
+ @Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null") } )
+public class ToCharFunction extends ScalarFunction {
+ public static final String NAME = "TO_CHAR";
+ private String formatString;
+ private Format formatter;
+ private FunctionArgumentType type;
+
+ public ToCharFunction() {
+ }
+
+ public ToCharFunction(List<Expression> children, FunctionArgumentType type, String formatString, Format formatter) throws SQLException {
+ super(children.subList(0, 1));
+ Preconditions.checkNotNull(formatString);
+ Preconditions.checkNotNull(formatter);
+ Preconditions.checkNotNull(type);
+ this.type = type;
+ this.formatString = formatString;
+ this.formatter = formatter;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + formatString.hashCode();
+ result = prime * result + getExpression().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;
+ ToCharFunction other = (ToCharFunction)obj;
+ if (!getExpression().equals(other.getExpression())) return false;
+ if (!formatString.equals(other.formatString)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression expression = getExpression();
+ if (!expression.evaluate(tuple, ptr)) {
+ return false;
+ }
+ PDataType type = expression.getDataType();
+ Object value = formatter.format(type.toObject(ptr, expression.getColumnModifier()));
+ byte[] b = getDataType().toBytes(value);
+ ptr.set(b);
+ return true;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.VARCHAR;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return getExpression().isNullable();
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ formatString = WritableUtils.readString(input);
+ type = WritableUtils.readEnum(input, FunctionArgumentType.class);
+ formatter = type.getFormatter(formatString);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeString(output, formatString);
+ WritableUtils.writeEnum(output, type);
+ }
+
+ private Expression getExpression() {
+ return children.get(0);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
new file mode 100644
index 0000000..5ef0034
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/ToDateFunction.java
@@ -0,0 +1,133 @@
+/*
+ * 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.io.*;
+import java.sql.SQLException;
+import java.text.Format;
+import java.text.ParseException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.hadoop.io.WritableUtils;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.parse.*;
+import org.apache.phoenix.parse.FunctionParseNode.Argument;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.DateUtil;
+
+
+/**
+ *
+ * Implementation of the TO_DATE(<string>,[<format-string>]) built-in function.
+ * The second argument is optional and defaults to the phoenix.query.dateFormat value
+ * from the HBase config. If present it must be a constant string.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=ToDateFunction.NAME, nodeClass=ToDateParseNode.class, args= {@Argument(allowedTypes={PDataType.VARCHAR}),@Argument(allowedTypes={PDataType.VARCHAR},isConstant=true,defaultValue="null")} )
+public class ToDateFunction extends ScalarFunction {
+ public static final String NAME = "TO_DATE";
+ private Format dateParser;
+ private String dateFormat;
+
+ public ToDateFunction() {
+ }
+
+ public ToDateFunction(List<Expression> children, String dateFormat, Format dateParser) throws SQLException {
+ super(children.subList(0, 1));
+ this.dateFormat = dateFormat;
+ this.dateParser = dateParser;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + dateFormat.hashCode();
+ result = prime * result + getExpression().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;
+ ToDateFunction other = (ToDateFunction)obj;
+ if (!getExpression().equals(other.getExpression())) return false;
+ if (!dateFormat.equals(other.dateFormat)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+ Expression expression = getExpression();
+ if (!expression.evaluate(tuple, ptr) || ptr.getLength() == 0) {
+ return false;
+ }
+ PDataType type = expression.getDataType();
+ String dateStr = (String)type.toObject(ptr, expression.getColumnModifier());
+ try {
+ Object value = dateParser.parseObject(dateStr);
+ byte[] byteValue = getDataType().toBytes(value);
+ ptr.set(byteValue);
+ return true;
+ } catch (ParseException e) {
+ throw new IllegalStateException("to_date('" + dateStr + ")' did not match expected date format of '" + dateFormat + "'.");
+ }
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.DATE;
+ }
+
+ @Override
+ public boolean isNullable() {
+ return getExpression().isNullable();
+ }
+
+ @Override
+ public void readFields(DataInput input) throws IOException {
+ super.readFields(input);
+ dateFormat = WritableUtils.readString(input);
+ dateParser = DateUtil.getDateParser(dateFormat);
+ }
+
+ @Override
+ public void write(DataOutput output) throws IOException {
+ super.write(output);
+ WritableUtils.writeString(output, dateFormat);
+ }
+
+ private Expression getExpression() {
+ return children.get(0);
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java b/src/main/java/org/apache/phoenix/expression/function/ToNumberFunction.java
new file mode 100644
index 0000000..84cc2b4
--- /dev/null
+++ b/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/c5b80246/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java b/src/main/java/org/apache/phoenix/expression/function/TrimFunction.java
new file mode 100644
index 0000000..b8c06cd
--- /dev/null
+++ b/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/c5b80246/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java b/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
new file mode 100644
index 0000000..59f7e66
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/TruncFunction.java
@@ -0,0 +1,58 @@
+/*
+ * 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.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="TRUNC", args= {
+ @Argument(allowedTypes={PDataType.TIME}),
+ @Argument(enumeration="TimeUnit"),
+ @Argument(allowedTypes={PDataType.INTEGER}, isConstant=true, defaultValue="1")} )
+public class TruncFunction extends RoundFunction {
+ public TruncFunction() {
+ }
+
+ public TruncFunction(List<Expression> node) throws SQLException {
+ super(node);
+ }
+
+ @Override
+ protected long getRoundUpAmount() {
+ return 0;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java b/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.java
new file mode 100644
index 0000000..484430f
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/visitor/BaseExpressionVisitor.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.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.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.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 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;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java b/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
new file mode 100644
index 0000000..951e9f3
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/visitor/ExpressionVisitor.java
@@ -0,0 +1,136 @@
+/*
+ * 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.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.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 E visit(LiteralExpression node);
+ public E visit(RowKeyColumnExpression node);
+ public E visit(KeyValueColumnExpression 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);
+
+}