phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject [30/51] [partial] Initial commit
Date Mon, 27 Jan 2014 19:23:31 GMT
http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/AvgAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/AvgAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/AvgAggregateFunction.java
new file mode 100644
index 0000000..62bb565
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/AvgAggregateFunction.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.math.BigDecimal;
+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.*;
+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;
+
+
+@BuiltInFunction(name=AvgAggregateFunction.NAME, nodeClass=AvgAggregateParseNode.class, args= {@Argument(allowedTypes={PDataType.DECIMAL})} )
+public class AvgAggregateFunction extends CompositeAggregateFunction {
+    public static final String NAME = "AVG";
+    private final CountAggregateFunction countFunc;
+    private final SumAggregateFunction sumFunc;
+    private Integer scale;
+
+    // TODO: remove when not required at built-in func register time
+    public AvgAggregateFunction(List<Expression> children) {
+        super(children);
+        this.countFunc = null;
+        this.sumFunc = null;
+        setScale(children);
+    }
+
+    public AvgAggregateFunction(List<Expression> children, CountAggregateFunction countFunc, SumAggregateFunction sumFunc) {
+        super(children);
+        this.countFunc = countFunc;
+        this.sumFunc = sumFunc;
+        setScale(children);
+    }
+
+    private void setScale(List<Expression> children) {
+        scale = PDataType.MIN_DECIMAL_AVG_SCALE; // At least 4;
+        for (Expression child: children) {
+            if (child.getScale() != null) {
+                scale = Math.max(scale, child.getScale());
+            }
+        }
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.DECIMAL;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!countFunc.evaluate(tuple, ptr)) {
+            return false;
+        }
+        long count = countFunc.getDataType().getCodec().decodeLong(ptr, null);
+        if (count == 0) {
+            return false;
+        }
+        
+        // Normal case where a column reference was used as the argument to AVG
+        if (!countFunc.isConstantExpression()) {
+            sumFunc.evaluate(tuple, ptr);
+            BigDecimal sum = (BigDecimal)PDataType.DECIMAL.toObject(ptr, sumFunc.getDataType());
+            // For the final column projection, we divide the sum by the count, both coerced to BigDecimal.
+            // TODO: base the precision on column metadata instead of constant
+            BigDecimal avg = sum.divide(BigDecimal.valueOf(count), PDataType.DEFAULT_MATH_CONTEXT);
+            avg = avg.setScale(scale, BigDecimal.ROUND_DOWN);
+            ptr.set(PDataType.DECIMAL.toBytes(avg));
+            return true;
+        }
+        BigDecimal value = (BigDecimal) ((LiteralExpression)countFunc.getChildren().get(0)).getValue();
+        value = value.setScale(scale, BigDecimal.ROUND_DOWN);
+        ptr.set(PDataType.DECIMAL.toBytes(value));
+        return true;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return sumFunc != null && sumFunc.isNullable();
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    @Override
+    public Integer getScale() {
+        return scale;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java b/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java
new file mode 100644
index 0000000..05f6bd8
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/CoalesceFunction.java
@@ -0,0 +1,100 @@
+/*
+ * 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.exception.SQLExceptionCode;
+import org.apache.phoenix.exception.SQLExceptionInfo;
+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.tuple.Tuple;
+
+
+/**
+ * 
+ * Function used to provide an alternative value when the first argument is null.
+ * Usage:
+ * COALESCE(expr1,expr2)
+ * If expr1 is not null, then it is returned, otherwise expr2 is returned. 
+ *
+ * TODO: better bind parameter type matching, since arg2 must be coercible
+ * to arg1. consider allowing a common base type?
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=CoalesceFunction.NAME, args= {
+    @Argument(),
+    @Argument()} )
+public class CoalesceFunction extends ScalarFunction {
+    public static final String NAME = "COALESCE";
+
+    public CoalesceFunction() {
+    }
+
+    public CoalesceFunction(List<Expression> children) throws SQLException {
+        super(children);
+        if (!children.get(1).getDataType().isCoercibleTo(children.get(0).getDataType())) {
+            throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CONVERT_TYPE)
+                .setMessage(getName() + " expected " + children.get(0).getDataType() + ", but got " + children.get(1).getDataType())
+                .build().buildException();
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (children.get(0).evaluate(tuple, ptr)) {
+            return true;
+        }
+        return children.get(1).evaluate(tuple, ptr);
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return children.get(0).getDataType();
+    }
+
+    @Override
+    public Integer getByteSize() {
+        Integer maxByteSize1 = children.get(0).getByteSize();
+        if (maxByteSize1 != null) {
+            Integer maxByteSize2 = children.get(1).getByteSize();
+            if (maxByteSize2 != null) {
+                return maxByteSize1 > maxByteSize2 ? maxByteSize1 : maxByteSize2;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isNullable() {
+        return children.get(0).isNullable() && children.get(1).isNullable();
+    }
+
+    @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/CompositeAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/CompositeAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/CompositeAggregateFunction.java
new file mode 100644
index 0000000..2c8da08
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/CompositeAggregateFunction.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.util.List;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.visitor.ExpressionVisitor;
+
+
+/**
+ * 
+ * Base class for aggregation functions which are composed of other
+ * aggregation functions (for example, AVG is modeled as a SUM aggregate
+ * function and a COUNT aggregate function).
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class CompositeAggregateFunction extends AggregateFunction {
+
+    public CompositeAggregateFunction(List<Expression> children) {
+        super(children);
+    }
+    
+    @Override
+    public final <T> T accept(ExpressionVisitor<T> visitor) {
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java
new file mode 100644
index 0000000..acca15a
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/CountAggregateFunction.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.expression.function;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+
+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.schema.PDataType;
+import org.apache.phoenix.util.SchemaUtil;
+
+
+/**
+ * 
+ * Built-in function for COUNT(<expression>) aggregate function,
+ * for example COUNT(foo), COUNT(1), COUNT(*)
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=CountAggregateFunction.NAME, args= {@Argument()} )
+public class CountAggregateFunction extends SingleAggregateFunction {
+    public static final String NAME = "COUNT";
+    public static final List<Expression> STAR = Arrays.<Expression>asList(LiteralExpression.newConstant(1));
+    public static final String NORMALIZED_NAME = SchemaUtil.normalizeIdentifier(NAME);
+    
+    public CountAggregateFunction() {
+    }
+    
+    public CountAggregateFunction(List<Expression> childExpressions) {
+        super(childExpressions);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        CountAggregateFunction other = (CountAggregateFunction)obj;
+        return (isConstantExpression() && other.isConstantExpression()) || children.equals(other.getChildren());
+    }
+
+    @Override
+    public int hashCode() {
+        return isConstantExpression() ? 0 : super.hashCode();
+    }
+
+    /**
+     * The COUNT function never returns null
+     */
+    @Override
+    public boolean isNullable() {
+        return false;
+    }
+    
+    @Override
+    public PDataType getDataType() {
+        return PDataType.LONG;
+    }
+
+    @Override 
+    public Aggregator newClientAggregator() {
+        // Since COUNT can never be null, ensure the aggregator is not nullable.
+        // This allows COUNT(*) to return 0 with the initial state of ClientAggregators
+        // when no rows are returned. 
+        return new LongSumAggregator(null) {
+            @Override
+            public boolean isNullable() {
+                return false;
+            }
+        };
+    }
+    
+    @Override 
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new CountAggregator();
+    }
+    
+    @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/CurrentDateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/CurrentDateFunction.java b/src/main/java/org/apache/phoenix/expression/function/CurrentDateFunction.java
new file mode 100644
index 0000000..7442594
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/CurrentDateFunction.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.parse.CurrentDateParseNode;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Function that returns the current date accurate to the millisecond. Note that this
+ * function is never evaluated on the server-side, instead the server side date is
+ * retrieved (piggy-backed on the call to check that the metadata is up-to-date) and
+ * passed into this function at create time.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=CurrentDateFunction.NAME, nodeClass=CurrentDateParseNode.class, args= {} )
+public class CurrentDateFunction extends ScalarFunction {
+    public static final String NAME = "CURRENT_DATE";
+    private final ImmutableBytesWritable currentDate = new ImmutableBytesWritable(new byte[PDataType.DATE.getByteSize()]);
+    
+    public CurrentDateFunction() {
+        this(System.currentTimeMillis());
+    }
+
+    public CurrentDateFunction(long timeStamp) {
+        getDataType().getCodec().encodeLong(timeStamp, currentDate);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        ptr.set(currentDate.get(), 0, PDataType.DATE.getByteSize());
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.DATE;
+    }
+
+    @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/CurrentTimeFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/CurrentTimeFunction.java b/src/main/java/org/apache/phoenix/expression/function/CurrentTimeFunction.java
new file mode 100644
index 0000000..68b5be2
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/CurrentTimeFunction.java
@@ -0,0 +1,68 @@
+/*
+ * 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 org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.parse.CurrentTimeParseNode;
+import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Function that returns the current date accurate to the millisecond. Note that this
+ * function is never evaluated on the server-side, instead the server side date is
+ * retrieved (piggy-backed on the call to check that the metadata is up-to-date) and
+ * passed into this function at create time.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+@BuiltInFunction(name=CurrentTimeFunction.NAME, nodeClass=CurrentTimeParseNode.class, args={} )
+public class CurrentTimeFunction extends ScalarFunction {
+    public static final String NAME = "CURRENT_TIME";
+    private final ImmutableBytesWritable currentDate = new ImmutableBytesWritable(new byte[PDataType.TIME.getByteSize()]);
+    
+    public CurrentTimeFunction() {
+        this(System.currentTimeMillis());
+    }
+
+    public CurrentTimeFunction(long timeStamp) {
+        getDataType().getCodec().encodeLong(timeStamp, currentDate);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        ptr.set(currentDate.get(), 0, PDataType.TIME.getByteSize());
+        return true;
+    }
+
+    @Override
+    public final PDataType getDataType() {
+        return PDataType.TIME;
+    }
+
+    @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/DelegateConstantToCountAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/DelegateConstantToCountAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/DelegateConstantToCountAggregateFunction.java
new file mode 100644
index 0000000..744e5bb
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/DelegateConstantToCountAggregateFunction.java
@@ -0,0 +1,75 @@
+/*
+ * 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.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Base class for non composite aggregation functions that optimize aggregation by
+ * delegating to {@link CountAggregateFunction} when the child expression is a 
+ * constant.
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+abstract public class DelegateConstantToCountAggregateFunction extends SingleAggregateFunction {
+    private static final ImmutableBytesWritable ZERO = new ImmutableBytesWritable(PDataType.LONG.toBytes(0L));
+    private CountAggregateFunction delegate;
+    
+    public DelegateConstantToCountAggregateFunction() {
+    }
+    
+    public DelegateConstantToCountAggregateFunction(List<Expression> childExpressions, CountAggregateFunction delegate) {
+        super(childExpressions);
+        // Using a delegate here causes us to optimize the number of aggregators
+        // by sharing the CountAggregator across functions. On the server side,
+        // this will always be null, since if it had not been null on the client,
+        // the function would not have been transfered over (the delegate would
+        // have instead).
+        this.delegate = delegate;
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (delegate == null) {
+            return super.evaluate(tuple, ptr);
+        }
+        delegate.evaluate(tuple, ptr);
+        if (PDataType.LONG.compareTo(ptr,ZERO) == 0) {
+            return false;
+        }
+        return true;
+    }
+
+
+    @Override
+    protected SingleAggregateFunction getDelegate() {
+        return delegate != null ? delegate : super.getDelegate();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java
new file mode 100644
index 0000000..7af9584
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/DistinctCountAggregateFunction.java
@@ -0,0 +1,115 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+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;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.SchemaUtil;
+
+
+/**
+ * 
+ * Built-in function for COUNT(distinct <expression>) aggregate function,
+ *
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name=DistinctCountAggregateFunction.NAME, args= {@Argument()} )
+public class DistinctCountAggregateFunction extends DelegateConstantToCountAggregateFunction {
+    public static final String NAME = "DISTINCT_COUNT";
+    public static final String NORMALIZED_NAME = SchemaUtil.normalizeIdentifier(NAME);
+    public final static byte[] ZERO = PDataType.LONG.toBytes(0L);
+    public final static byte[] ONE = PDataType.LONG.toBytes(1L);
+    
+    public DistinctCountAggregateFunction() {
+    }
+
+    public DistinctCountAggregateFunction(List<Expression> childExpressions) {
+        this(childExpressions, null);
+    }
+
+    public DistinctCountAggregateFunction(List<Expression> childExpressions,
+            CountAggregateFunction delegate) {
+        super(childExpressions, delegate);
+        assert childExpressions.size() == 1;
+    }
+    
+    @Override
+    public int hashCode() {
+        return isConstantExpression() ? 0 : super.hashCode();
+    }
+
+    /**
+     * The COUNT function never returns null
+     */
+    @Override
+    public boolean isNullable() {
+        return false;
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        DistinctCountAggregateFunction other = (DistinctCountAggregateFunction)obj;
+        return (isConstantExpression() && other.isConstantExpression()) || children.equals(other.getChildren());
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.LONG;
+    }
+
+    @Override 
+    public Aggregator newClientAggregator() {
+        return new DistinctCountClientAggregator(getAggregatorExpression().getColumnModifier());
+    }
+    
+    @Override 
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new DistinctValueWithCountServerAggregator(conf);
+    }
+    
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        // TODO: optimize query plan of this to run scan serially for a limit of one row
+        if (!super.evaluate(tuple, ptr)) {
+            ptr.set(ZERO); // If evaluate returns false, then no rows were found, so result is 0
+        } else if (isConstantExpression()) {
+            ptr.set(ONE); // Otherwise, we found one or more rows, so a distinct on a constant is 1
+        }
+        return true; // Always evaluates to a LONG value
+    }
+    
+    @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/FunctionArgumentType.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/FunctionArgumentType.java b/src/main/java/org/apache/phoenix/expression/function/FunctionArgumentType.java
new file mode 100644
index 0000000..0284caf
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/FunctionArgumentType.java
@@ -0,0 +1,35 @@
+package org.apache.phoenix.expression.function;
+
+import java.text.DecimalFormat;
+import java.text.Format;
+
+import org.apache.phoenix.util.DateUtil;
+
+public enum FunctionArgumentType {
+    TEMPORAL {
+        @Override
+        public Format getFormatter(String format) {
+            return DateUtil.getDateFormatter(format);
+        }
+    }, 
+    NUMERIC {
+        @Override
+        public Format getFormatter(String format) {
+            return new DecimalFormat(format);
+        }
+    },
+    CHAR {
+        @Override
+        public Format getFormatter(String format) {
+            return getDecimalFormat(format);
+        }
+    };        
+
+    public abstract Format getFormatter(String format);
+    
+    private static DecimalFormat getDecimalFormat(String formatString) {
+        DecimalFormat result = new DecimalFormat(formatString);
+        result.setParseBigDecimal(true);
+        return result;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/FunctionExpression.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/FunctionExpression.java b/src/main/java/org/apache/phoenix/expression/function/FunctionExpression.java
new file mode 100644
index 0000000..db305d3
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/FunctionExpression.java
@@ -0,0 +1,71 @@
+/*
+ * 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.expression.BaseCompoundExpression;
+import org.apache.phoenix.expression.Expression;
+
+/**
+ * 
+ * Compiled representation of a built-in function
+ *
+ * @author jtaylor
+ * @since 0.1
+ */
+public abstract class FunctionExpression extends BaseCompoundExpression {
+    public enum OrderPreserving {NO, YES_IF_LAST, YES};
+    public FunctionExpression() {
+    }
+    
+    public FunctionExpression(List<Expression> children) {
+        super(children);
+    }
+    
+    /**
+     * Determines whether or not the result of the function invocation
+     * will be ordered in the same way as the input to the function.
+     * Returning YES enables an optimization to occur when a
+     * GROUP BY contains function invocations using the leading PK
+     * column(s).
+     * @return YES if the function invocation will always preserve order for
+     * the inputs versus the outputs and false otherwise, YES_IF_LAST if the
+     * function preserves order, but any further column reference would not
+     * continue to preserve order, and NO if the function does not preserve
+     * order.
+     */
+    public OrderPreserving preservesOrder() {
+        return OrderPreserving.NO;
+    }
+
+    abstract public String getName();
+    
+    @Override
+    public final String toString() {
+        StringBuilder buf = new StringBuilder(getName() + "(");
+        for (int i = 0; i < children.size() - 1; i++) {
+            buf.append(children.get(i) + ", ");
+        }
+        buf.append(children.get(children.size()-1) + ")");
+        return buf.toString();
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/IndexStateNameFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/IndexStateNameFunction.java b/src/main/java/org/apache/phoenix/expression/function/IndexStateNameFunction.java
new file mode 100644
index 0000000..41890bc
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/IndexStateNameFunction.java
@@ -0,0 +1,81 @@
+/*
+ * 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.PIndexState;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Function used to get the index state name from the serialized byte value
+ * Usage:
+ * IndexStateName('a')
+ * will return 'ACTIVE'
+ * 
+ * @author jtaylor
+ * @since 2.1
+ */
+@BuiltInFunction(name=IndexStateNameFunction.NAME, args= {
+    @Argument(allowedTypes=PDataType.CHAR)} )
+public class IndexStateNameFunction extends ScalarFunction {
+    public static final String NAME = "IndexStateName";
+
+    public IndexStateNameFunction() {
+    }
+    
+    public IndexStateNameFunction(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;
+        }
+        byte serializedByte = ptr.get()[ptr.getOffset()];
+        PIndexState indexState = PIndexState.fromSerializedValue(serializedByte);
+        ptr.set(indexState.toBytes());
+        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/InvertFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java b/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java
new file mode 100644
index 0000000..72ac31a
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/InvertFunction.java
@@ -0,0 +1,129 @@
+/*
+ * 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.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+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.ColumnModifier;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+@BuiltInFunction(name = InvertFunction.NAME, args = { @Argument() })
+public class InvertFunction extends ScalarFunction {
+    public static final String NAME = "INVERT";
+
+    public InvertFunction() throws SQLException {}
+
+    public InvertFunction(List<Expression> children) throws SQLException {
+        super(children);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (!getChildExpression().evaluate(tuple, ptr)) { return false; }
+        if (ptr.getLength() == 0) { return true; }
+        byte[] buf = new byte[ptr.getLength()];
+        ColumnModifier.SORT_DESC.apply(ptr.get(), ptr.getOffset(), buf, 0, ptr.getLength());
+        ptr.set(buf);
+        return true;
+    }
+
+    @Override
+    public ColumnModifier getColumnModifier() {
+        return getChildExpression().getColumnModifier() == null ? ColumnModifier.SORT_DESC : null;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return getChildExpression().getDataType();
+    }
+
+    @Override
+    public Integer getMaxLength() {
+        return getChildExpression().getMaxLength();
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return getChildExpression().getByteSize();
+    }
+
+    @Override
+    public boolean isNullable() {
+        return getChildExpression().isNullable();
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+    /**
+     * INVERT may be optimized through
+     */
+    @Override
+    public int getKeyFormationTraversalIndex() {
+        return 0;
+    }
+
+    /**
+     * Invert the childPart key range
+     */
+    @Override
+    public KeyPart newKeyPart(final KeyPart childPart) {
+        return new KeyPart() {
+
+            @Override
+            public KeyRange getKeyRange(CompareOp op, Expression rhs) {
+                KeyRange range = childPart.getKeyRange(op, rhs);
+                return range.invert();
+            }
+
+            @Override
+            public List<Expression> getExtractNodes() {
+                return childPart.getExtractNodes();
+            }
+
+            @Override
+            public PColumn getColumn() {
+                return childPart.getColumn();
+            }
+        };
+    }
+    
+    @Override
+    public OrderPreserving preservesOrder() {
+        return OrderPreserving.YES;
+    }
+
+    private Expression getChildExpression() {
+        return children.get(0);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/LTrimFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/LTrimFunction.java b/src/main/java/org/apache/phoenix/expression/function/LTrimFunction.java
new file mode 100644
index 0000000..1622f55
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/LTrimFunction.java
@@ -0,0 +1,115 @@
+/*
+ * 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 LTrim(<string>) build-in function. It removes from the left end of
+ * <string> space character and other function bytes in single byte utf8 characters 
+ * set.
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=LTrimFunction.NAME, args={
+    @Argument(allowedTypes={PDataType.VARCHAR})})
+public class LTrimFunction extends ScalarFunction {
+    public static final String NAME = "LTRIM";
+
+    private Integer byteSize;
+
+    public LTrimFunction() { }
+
+    public LTrimFunction(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) {
+        // Starting from the front of the byte, look for all single bytes at the end of the string
+        // that is below SPACE_UTF8 (space and control characters) or 0x7f (control chars).
+        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 = getStringExpression().getColumnModifier();
+        // TODO: when we have ColumnModifier.REVERSE, we'll need to trim from the end instead of
+        // the beginning (just delegate to RTrimFunction or replace from ExpressionCompiler instead?)
+        int i = StringUtil.getFirstNonBlankCharIdxFromStart(string, offset, length, columnModifier);
+        if (i == offset + length) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        
+        ptr.set(string, i, offset + length - i);
+        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/LengthFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/LengthFunction.java b/src/main/java/org/apache/phoenix/expression/function/LengthFunction.java
new file mode 100644
index 0000000..770f77a
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/LengthFunction.java
@@ -0,0 +1,96 @@
+/*
+ * 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.UnsupportedEncodingException;
+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.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.StringUtil;
+
+
+/**
+ * 
+ * Implementation of the LENGTH(<string>) build-in function. <string> is the string
+ * of characters we want to find the length of. If <string> is NULL or empty, null
+ * is returned.
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=LengthFunction.NAME, args={
+    @Argument(allowedTypes={PDataType.VARCHAR})} )
+public class LengthFunction extends ScalarFunction {
+    public static final String NAME = "LENGTH";
+
+    public LengthFunction() { }
+
+    public LengthFunction(List<Expression> children) throws SQLException {
+        super(children);
+    }
+
+    private Expression getStringExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        Expression child = getStringExpression();
+        if (!child.evaluate(tuple, ptr)) {
+            return false;
+        }
+        if (ptr.getLength() == 0) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        int len;
+        if (child.getDataType() == PDataType.CHAR) {
+            // Only single-byte characters allowed in CHAR
+            len = ptr.getLength();
+        } else {
+            try {
+                len = StringUtil.calculateUTF8Length(ptr.get(), ptr.getOffset(), ptr.getLength(), child.getColumnModifier());
+            } catch (UnsupportedEncodingException e) {
+                return false;
+            }
+        }
+        ptr.set(PDataType.INTEGER.toBytes(len));
+        return true;
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.INTEGER;
+    }
+
+    @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/MaxAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/MaxAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/MaxAggregateFunction.java
new file mode 100644
index 0000000..c37a61a
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/MaxAggregateFunction.java
@@ -0,0 +1,75 @@
+/*
+ * 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.Aggregator;
+import org.apache.phoenix.expression.aggregator.MaxAggregator;
+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;
+
+
+
+/**
+ * Built-in function for finding MAX.
+ * 
+ * @author syyang
+ * @since 0.1
+ */
+@BuiltInFunction(name=MaxAggregateFunction.NAME, nodeClass=MaxAggregateParseNode.class, args= {@Argument()} )
+public class MaxAggregateFunction extends MinAggregateFunction {
+    public static final String NAME = "MAX";
+
+    public MaxAggregateFunction() {
+    }
+    
+    public MaxAggregateFunction(List<Expression> childExpressions, CountAggregateFunction delegate) {
+        super(childExpressions, delegate);
+    }
+
+    @Override 
+    public Aggregator newServerAggregator(Configuration conf) {
+        final PDataType type = getAggregatorExpression().getDataType();
+        ColumnModifier columnModifier = getAggregatorExpression().getColumnModifier();
+        return new MaxAggregator(columnModifier) {
+            @Override
+            public PDataType getDataType() {
+                return type;
+            }
+        };
+    }
+    
+    @Override
+    public String getName() {
+        return NAME;
+    }
+    
+    @Override
+    public ColumnModifier getColumnModifier() {
+       return getAggregatorExpression().getColumnModifier(); 
+    }    
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/MinAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/MinAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/MinAggregateFunction.java
new file mode 100644
index 0000000..6caa915
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/MinAggregateFunction.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.aggregator.Aggregator;
+import org.apache.phoenix.expression.aggregator.MinAggregator;
+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 finding MIN.
+ * 
+ * @author syyang
+ * @since 0.1
+ */
+@BuiltInFunction(name=MinAggregateFunction.NAME, nodeClass=MinAggregateParseNode.class, args= {@Argument()} )
+public class MinAggregateFunction extends DelegateConstantToCountAggregateFunction {
+    public static final String NAME = "MIN";
+
+    public MinAggregateFunction() {
+    }
+    
+    public MinAggregateFunction(List<Expression> childExpressions, CountAggregateFunction delegate) {
+        super(childExpressions, delegate);
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        boolean wasEvaluated = super.evaluate(tuple, ptr);
+        if (!wasEvaluated) {
+            return false;
+        }
+        if (isConstantExpression()) {
+            getAggregatorExpression().evaluate(tuple, ptr);
+        }
+        return true;
+    }
+
+    @Override 
+    public Aggregator newServerAggregator(Configuration conf) {
+        final PDataType type = getAggregatorExpression().getDataType();
+        ColumnModifier columnModifier = getAggregatorExpression().getColumnModifier();
+        return new MinAggregator(columnModifier) {
+            @Override
+            public PDataType getDataType() {
+                return type;
+            }
+        };
+    }
+    
+    @Override
+    public ColumnModifier getColumnModifier() {
+       return getAggregatorExpression().getColumnModifier(); 
+    }
+    
+    @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/PercentRankAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/PercentRankAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/PercentRankAggregateFunction.java
new file mode 100644
index 0000000..6e9cffb
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/PercentRankAggregateFunction.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+/**
+ * 
+ * PERCENT_RANK(<expression>[,<expression>]) WITHIN GROUP (ORDER BY <expression>[,<expression>] ASC/DESC) aggregate function
+ *
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = PercentRankAggregateFunction.NAME, args = { @Argument(),
+        @Argument(allowedTypes = { PDataType.BOOLEAN }, isConstant = true), @Argument(isConstant = true) })
+public class PercentRankAggregateFunction extends SingleAggregateFunction {
+    public static final String NAME = "PERCENT_RANK";
+
+    public PercentRankAggregateFunction() {
+
+    }
+
+    public PercentRankAggregateFunction(List<Expression> childern) {
+        super(childern);
+    }
+
+    @Override
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new DistinctValueWithCountServerAggregator(conf);
+    }
+
+    @Override
+    public Aggregator newClientAggregator() {
+        return new PercentRankClientAggregator(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/PercentileContAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/PercentileContAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/PercentileContAggregateFunction.java
new file mode 100644
index 0000000..cbbc90f
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/PercentileContAggregateFunction.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.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 PERCENTILE_CONT(<expression>) WITHIN GROUP (ORDER BY <expression> ASC/DESC) aggregate function
+ *
+ * @author anoopsjohn
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = PercentileContAggregateFunction.NAME, args = { @Argument(allowedTypes = { PDataType.DECIMAL }),
+        @Argument(allowedTypes = { PDataType.BOOLEAN }, isConstant = true),
+        @Argument(allowedTypes = { PDataType.DECIMAL }, isConstant = true, minValue = "0", maxValue = "1") })
+public class PercentileContAggregateFunction extends SingleAggregateFunction {
+    public static final String NAME = "PERCENTILE_CONT";
+
+    public PercentileContAggregateFunction() {
+        
+    }
+    
+    public PercentileContAggregateFunction(List<Expression> childern) {
+        super(childern);
+    }
+
+    @Override
+    public Aggregator newServerAggregator(Configuration conf) {
+        return new DistinctValueWithCountServerAggregator(conf);
+    }
+
+    @Override
+    public Aggregator newClientAggregator() {
+        return new PercentileClientAggregator(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/PercentileDiscAggregateFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/PercentileDiscAggregateFunction.java b/src/main/java/org/apache/phoenix/expression/function/PercentileDiscAggregateFunction.java
new file mode 100644
index 0000000..25e3642
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/PercentileDiscAggregateFunction.java
@@ -0,0 +1,69 @@
+/*
+ * 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 PERCENTILE_DISC(<expression>) WITHIN GROUP (ORDER BY <expression> ASC/DESC) aggregate function
+ *
+ * @author ramkrishna
+ * @since 1.2.1
+ */
+@BuiltInFunction(name = PercentileDiscAggregateFunction.NAME, args = { @Argument(allowedTypes = { PDataType.DECIMAL }),
+        @Argument(allowedTypes = { PDataType.BOOLEAN }, isConstant = true),
+        @Argument(allowedTypes = { PDataType.DECIMAL }, isConstant = true, minValue = "0", maxValue = "1") })
+public class PercentileDiscAggregateFunction extends SingleAggregateFunction {
+
+	public static final String NAME = "PERCENTILE_DISC";
+
+	public PercentileDiscAggregateFunction() {
+	}
+
+	public PercentileDiscAggregateFunction(List<Expression> childern) {
+		super(childern);
+	}
+	
+	@Override
+	public Aggregator newServerAggregator(Configuration conf) {
+		return new DistinctValueWithCountServerAggregator(conf);
+	}
+	
+	@Override
+	public Aggregator newClientAggregator() {
+		return new PercentileDiscClientAggregator(children, getAggregatorExpression().getColumnModifier());
+	}
+
+	@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/PrefixFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java b/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java
new file mode 100644
index 0000000..2612d74
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/PrefixFunction.java
@@ -0,0 +1,83 @@
+package org.apache.phoenix.expression.function;
+
+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.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.query.KeyRange;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.util.ByteUtil;
+
+abstract public class PrefixFunction extends ScalarFunction {
+    public PrefixFunction() {
+    }
+
+    public PrefixFunction(List<Expression> children) {
+        super(children);
+    }
+
+    @Override
+    public int getKeyFormationTraversalIndex() {
+        return preservesOrder() == OrderPreserving.NO ? NO_TRAVERSAL : 0;
+    }
+    
+    protected boolean extractNode() {
+        return false;
+    }
+
+    private static byte[] evaluateExpression(Expression rhs) {
+        ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+        rhs.evaluate(null, ptr);
+        byte[] key = ByteUtil.copyKeyBytesIfNecessary(ptr);
+        return key;
+    }
+    
+    @Override
+    public KeyPart newKeyPart(final KeyPart childPart) {
+        return new KeyPart() {
+            private final List<Expression> extractNodes = extractNode() ? Collections.<Expression>singletonList(PrefixFunction.this) : Collections.<Expression>emptyList();
+
+            @Override
+            public PColumn getColumn() {
+                return childPart.getColumn();
+            }
+
+            @Override
+            public List<Expression> getExtractNodes() {
+                return extractNodes;
+            }
+
+            @Override
+            public KeyRange getKeyRange(CompareOp op, Expression rhs) {
+                byte[] key;
+                KeyRange range;
+                PDataType type = getColumn().getDataType();
+                switch (op) {
+                case EQUAL:
+                    key = evaluateExpression(rhs);
+                    range = type.getKeyRange(key, true, ByteUtil.nextKey(key), false);
+                    break;
+                case GREATER:
+                    key = evaluateExpression(rhs);
+                    range = type.getKeyRange(ByteUtil.nextKey(key), true, KeyRange.UNBOUND, false);
+                    break;
+                case LESS_OR_EQUAL:
+                    key = evaluateExpression(rhs);
+                    range = type.getKeyRange(KeyRange.UNBOUND, false, ByteUtil.nextKey(key), false);
+                    break;
+                default:
+                    return childPart.getKeyRange(op, rhs);
+                }
+                Integer length = getColumn().getByteSize();
+                return length == null ? range : range.fill(length);
+            }
+        };
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c5b80246/src/main/java/org/apache/phoenix/expression/function/RTrimFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/RTrimFunction.java b/src/main/java/org/apache/phoenix/expression/function/RTrimFunction.java
new file mode 100644
index 0000000..d7702a5
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/RTrimFunction.java
@@ -0,0 +1,161 @@
+/*
+ * 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.Collections;
+import java.util.List;
+
+import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+import org.apache.phoenix.compile.KeyPart;
+import org.apache.phoenix.expression.Expression;
+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.ColumnModifier;
+import org.apache.phoenix.schema.PColumn;
+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 RTrim(<string>) build-in function. It removes from the right end of
+ * <string> space character and other function bytes in single byte utf8 characters set 
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=RTrimFunction.NAME, args={
+    @Argument(allowedTypes={PDataType.VARCHAR})})
+public class RTrimFunction extends ScalarFunction {
+    public static final String NAME = "RTRIM";
+
+    private Integer byteSize;
+
+    public RTrimFunction() { }
+
+    public RTrimFunction(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) {
+        // Starting from the end of the byte, look for all single bytes at the end of the string
+        // that is below SPACE_UTF8 (space and control characters) or above (control chars).
+        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 = getStringExpression().getColumnModifier();
+        int i = StringUtil.getFirstNonBlankCharIdxFromEnd(string, offset, length, columnModifier);
+        if (i == offset - 1) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+            }
+        ptr.set(string, offset, i - offset + 1);
+        return true;
+    }
+
+    @Override
+    public OrderPreserving preservesOrder() {
+        return OrderPreserving.YES_IF_LAST;
+    }
+
+    @Override
+    public int getKeyFormationTraversalIndex() {
+        return 0;
+    }
+
+    @Override
+    public KeyPart newKeyPart(final KeyPart childPart) {
+        return new KeyPart() {
+            @Override
+            public KeyRange getKeyRange(CompareOp op, Expression rhs) {
+                ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+                rhs.evaluate(null, ptr);
+                byte[] key = ByteUtil.copyKeyBytesIfNecessary(ptr);
+                PDataType type = getColumn().getDataType();
+                KeyRange range;
+                switch (op) {
+                case EQUAL:
+                    range = type.getKeyRange(key, true, ByteUtil.nextKey(ByteUtil.concat(key, new byte[] {StringUtil.SPACE_UTF8})), false);
+                    break;
+                case LESS_OR_EQUAL:
+                    range = type.getKeyRange(KeyRange.UNBOUND, false, ByteUtil.nextKey(ByteUtil.concat(key, new byte[] {StringUtil.SPACE_UTF8})), false);
+                    break;
+                default:
+                    range = childPart.getKeyRange(op, rhs);
+                    break;
+                }
+                Integer length = getColumn().getByteSize();
+                return length == null ? range : range.fill(length);
+            }
+
+            @Override
+            public List<Expression> getExtractNodes() {
+                return Collections.<Expression>emptyList();
+            }
+
+            @Override
+            public PColumn getColumn() {
+                return childPart.getColumn();
+            }
+        };
+    }
+
+    @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/RegexpReplaceFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java b/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
new file mode 100644
index 0000000..1f0e28e
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
@@ -0,0 +1,130 @@
+/*
+ * 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.List;
+import java.util.regex.Pattern;
+
+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.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+
+/**
+ * 
+ * Function similar to the regexp_replace function in Postgres, which is used to pattern
+ * match a segment of the string. Usage:
+ * REGEXP_REPLACE(<source_char>,<pattern>,<replace_string>)
+ * source_char is the string in which we want to perform string replacement. pattern is a
+ * Java compatible regular expression string, and we replace all the matching part with 
+ * replace_string. The first 2 arguments are required and are {@link org.apache.phoenix.schema.PDataType#VARCHAR},
+ * the replace_string is default to empty string.
+ * 
+ * The function returns a {@link org.apache.phoenix.schema.PDataType#VARCHAR}
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=RegexpReplaceFunction.NAME, args= {
+    @Argument(allowedTypes={PDataType.VARCHAR}),
+    @Argument(allowedTypes={PDataType.VARCHAR}),
+    @Argument(allowedTypes={PDataType.VARCHAR},defaultValue="null")} )
+public class RegexpReplaceFunction extends ScalarFunction {
+    public static final String NAME = "REGEXP_REPLACE";
+
+    private boolean hasReplaceStr;
+    private Pattern pattern;
+    
+    public RegexpReplaceFunction() { }
+
+    // Expect 1 arguments, the pattern. 
+    public RegexpReplaceFunction(List<Expression> children) {
+        super(children);
+        init();
+    }
+
+    private void init() {
+        hasReplaceStr = ((LiteralExpression)getReplaceStrExpression()).getValue() != null;
+        Object patternString = ((LiteralExpression)children.get(1)).getValue();
+        if (patternString != null) {
+            pattern = Pattern.compile((String)patternString);
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        // Can't parse if there is no replacement pattern.
+        if (pattern == null) {
+            return false;
+        }
+        Expression sourceStrExpression = getSourceStrExpression();
+        if (!sourceStrExpression.evaluate(tuple, ptr)) {
+            return false;
+        }
+        String sourceStr = (String)PDataType.VARCHAR.toObject(ptr, sourceStrExpression.getColumnModifier());
+        if (sourceStr == null) {
+            return false;
+        }
+        String replaceStr;
+        if (hasReplaceStr) {
+            Expression replaceStrExpression = this.getReplaceStrExpression();
+            if (!replaceStrExpression.evaluate(tuple, ptr)) {
+                return false;
+            }
+            replaceStr = (String)PDataType.VARCHAR.toObject(ptr, replaceStrExpression.getColumnModifier());
+        } else {
+            replaceStr = "";
+        }
+        String replacedStr = pattern.matcher(sourceStr).replaceAll(replaceStr);
+        ptr.set(PDataType.VARCHAR.toBytes(replacedStr));
+        return true;
+    }
+
+    private Expression getSourceStrExpression() {
+        return children.get(0);
+    }
+
+    private Expression getReplaceStrExpression() {
+        return children.get(2);
+    }
+
+    @Override
+    public PDataType getDataType() {
+        return PDataType.VARCHAR;
+    }
+
+    @Override
+    public void readFields(DataInput input) throws IOException {
+        super.readFields(input);
+        init();
+    }
+
+    @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/RegexpSubstrFunction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java b/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
new file mode 100644
index 0000000..2308581
--- /dev/null
+++ b/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
@@ -0,0 +1,175 @@
+/*
+ * 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 java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+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.PDataType;
+import org.apache.phoenix.schema.tuple.Tuple;
+import org.apache.phoenix.util.ByteUtil;
+
+
+/**
+ * 
+ * Implementation of REGEXP_SUBSTR(<source>, <pattern>, <offset>) built-in function,
+ * where <offset> is the offset from the start of <string>. 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 <pattern> is the pattern we would like to search for in the <source> string.
+ * The function returns the first occurrence of any substring in the <source> string that matches
+ * the <pattern> input as a VARCHAR. 
+ * 
+ * @author zhuang
+ * @since 0.1
+ */
+@BuiltInFunction(name=RegexpSubstrFunction.NAME, args={
+    @Argument(allowedTypes={PDataType.VARCHAR}),
+    @Argument(allowedTypes={PDataType.VARCHAR}),
+    @Argument(allowedTypes={PDataType.LONG}, defaultValue="1")} )
+public class RegexpSubstrFunction extends PrefixFunction {
+    public static final String NAME = "REGEXP_SUBSTR";
+
+    private Pattern pattern;
+    private boolean isOffsetConstant;
+    private Integer byteSize;
+
+    public RegexpSubstrFunction() { }
+
+    public RegexpSubstrFunction(List<Expression> children) {
+        super(children);
+        init();
+    }
+
+    private void init() {
+        Object patternString = ((LiteralExpression)children.get(1)).getValue();
+        if (patternString != null) {
+            pattern = Pattern.compile((String)patternString);
+        }
+        // If the source string has a fixed width, then the max length would be the length 
+        // of the source string minus the offset, or the absolute value of the offset if 
+        // it's negative. Offset number is a required argument. However, if the source string
+        // is not fixed width, the maxLength would be null.
+        isOffsetConstant = getOffsetExpression() instanceof LiteralExpression;
+        Number offsetNumber = (Number)((LiteralExpression)getOffsetExpression()).getValue();
+        if (offsetNumber != null) {
+            int offset = offsetNumber.intValue();
+            if (getSourceStrExpression().getDataType().isFixedWidth()) {
+                if (offset >= 0) {
+                    byteSize = getSourceStrExpression().getByteSize() - offset - (offset == 0 ? 0 : 1);
+                } else {
+                    byteSize = -offset;
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+        if (pattern == null) {
+            return false;
+        }
+        if (!getSourceStrExpression().evaluate(tuple, ptr)) {
+            return false;
+        }
+        String sourceStr = (String)PDataType.VARCHAR.toObject(ptr, getSourceStrExpression().getColumnModifier());
+        if (sourceStr == null) {
+            return false;
+        }
+
+        Expression offsetExpression = getOffsetExpression();
+        if (!offsetExpression.evaluate(tuple, ptr)) {
+            return false;
+        }
+        int offset = offsetExpression.getDataType().getCodec().decodeInt(ptr, offsetExpression.getColumnModifier());
+
+        int strlen = sourceStr.length();
+        // 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;
+        }
+
+        Matcher matcher = pattern.matcher(sourceStr);
+        boolean hasSubString = matcher.find(offset);
+        if (!hasSubString) {
+            ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+            return true;
+        }
+        String subString = matcher.group();
+        ptr.set(PDataType.VARCHAR.toBytes(subString));
+        return true;
+    }
+
+    @Override
+    public Integer getByteSize() {
+        return byteSize;
+    }
+
+    @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) {
+                    return OrderPreserving.YES_IF_LAST;
+                }
+            }
+        }
+        return OrderPreserving.NO;
+    }
+
+    @Override
+    public int getKeyFormationTraversalIndex() {
+        return preservesOrder() == OrderPreserving.NO ? NO_TRAVERSAL : 0;
+    }
+
+    private Expression getOffsetExpression() {
+        return children.get(2);
+    }
+
+    private Expression getSourceStrExpression() {
+        return children.get(0);
+    }
+
+    @Override
+    public PDataType getDataType() {
+        // ALways VARCHAR since we do not know in advanced how long the 
+        // matched string will be.
+        return PDataType.VARCHAR;
+    }
+
+    @Override
+    public String getName() {
+        return NAME;
+    }
+
+}


Mime
View raw message