Return-Path: X-Original-To: apmail-phoenix-commits-archive@minotaur.apache.org Delivered-To: apmail-phoenix-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1C8A610DDD for ; Mon, 27 Jan 2014 19:25:07 +0000 (UTC) Received: (qmail 30438 invoked by uid 500); 27 Jan 2014 19:24:34 -0000 Delivered-To: apmail-phoenix-commits-archive@phoenix.apache.org Received: (qmail 29344 invoked by uid 500); 27 Jan 2014 19:24:02 -0000 Mailing-List: contact commits-help@phoenix.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@phoenix.incubator.apache.org Delivered-To: mailing list commits@phoenix.incubator.apache.org Received: (qmail 29228 invoked by uid 99); 27 Jan 2014 19:23:59 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 27 Jan 2014 19:23:59 +0000 X-ASF-Spam-Status: No, hits=-2000.5 required=5.0 tests=ALL_TRUSTED,RP_MATCHES_RCVD X-Spam-Check-By: apache.org Received: from [140.211.11.3] (HELO mail.apache.org) (140.211.11.3) by apache.org (qpsmtpd/0.29) with SMTP; Mon, 27 Jan 2014 19:23:34 +0000 Received: (qmail 27696 invoked by uid 99); 27 Jan 2014 19:23:04 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 27 Jan 2014 19:23:04 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 631169166E5; Mon, 27 Jan 2014 19:23:03 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: jamestaylor@apache.org To: commits@phoenix.incubator.apache.org Date: Mon, 27 Jan 2014 19:23:31 -0000 Message-Id: <4869c031c1294514b3a32f71e1f52650@git.apache.org> In-Reply-To: <5b6d8b961d204abab5cda9588a1b3c82@git.apache.org> References: <5b6d8b961d204abab5cda9588a1b3c82@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [30/51] [partial] Initial commit X-Virus-Checked: Checked by ClamAV on apache.org 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 children) { + super(children); + this.countFunc = null; + this.sumFunc = null; + setScale(children); + } + + public AvgAggregateFunction(List children, CountAggregateFunction countFunc, SumAggregateFunction sumFunc) { + super(children); + this.countFunc = countFunc; + this.sumFunc = sumFunc; + setScale(children); + } + + private void setScale(List 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 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 children) { + super(children); + } + + @Override + public final T accept(ExpressionVisitor 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() 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 STAR = Arrays.asList(LiteralExpression.newConstant(1)); + public static final String NORMALIZED_NAME = SchemaUtil.normalizeIdentifier(NAME); + + public CountAggregateFunction() { + } + + public CountAggregateFunction(List 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 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 ) 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 childExpressions) { + this(childExpressions, null); + } + + public DistinctCountAggregateFunction(List 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 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 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 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 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() build-in function. It removes from the left end of + * 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 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() build-in function. is the string + * of characters we want to find the length of. If 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 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 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 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([,]) WITHIN GROUP (ORDER BY [,] 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 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() WITHIN GROUP (ORDER BY 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 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() WITHIN GROUP (ORDER BY 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 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 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 extractNodes = extractNode() ? Collections.singletonList(PrefixFunction.this) : Collections.emptyList(); + + @Override + public PColumn getColumn() { + return childPart.getColumn(); + } + + @Override + public List 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() build-in function. It removes from the right end of + * 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 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 getExtractNodes() { + return Collections.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 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 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(, , ) built-in function, + * where is the offset from the start of . 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 is the pattern we would like to search for in the string. + * The function returns the first occurrence of any substring in the string that matches + * the 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 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; + } + +}