[
https://issues.apache.org/jira/browse/PHOENIX-1978?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Rajeshbabu Chintaguntla updated PHOENIX-1978:
---------------------------------------------
Attachment: PHOENIX-1908.patch
[~alexdl] Thanks for testing and reporting the bug.
The function argument parsing creating the problem. When one of the argument is
array type then remaining arguments are considering as array types because once
we parse array type argument then ar or lsq variable become not null and they
are not setting back to null before parsing the other arguments. Patch fixes
the issue. Also added the example used by [~alexdl] as test case.
> UDF ArgumentTypeMismatchException
> ---------------------------------
>
> Key: PHOENIX-1978
> URL: https://issues.apache.org/jira/browse/PHOENIX-1978
> Project: Phoenix
> Issue Type: Bug
> Reporter: alex kamil
> Assignee: Rajeshbabu Chintaguntla
> Fix For: 4.4.1
>
> Attachments: PHOENIX-1908.patch
>
>
> I created a sample UDF with Phoenix 4.4 by copying ARRAY_ELEM function
> (https://github.com/apache/phoenix/blob/master/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayIndexFunction.java)
> and removing the BuiltInFunction annotation
> after deploying to the server and running the following queries it throws an
> exception below
> create function UDF_ARRAY_ELEM(VARCHAR ARRAY, INTEGER) returns "VARCHAR" as
> 'com.test.ArrayIndexFunction' using jar '/tmp/udf.jar'
> CREATE TABLE TESTTABLE10(ID VARCHAR NOT NULL, NAME VARCHAR ARRAY, CITY
> VARCHAR ARRAY CONSTRAINT pk PRIMARY KEY (ID) )
> UPSERT INTO TESTTABLE10(ID,NAME,CITY) VALUES('111',
> ARRAY['JOHN','MIKE','BOB'], ARRAY['NYC','LA','SF'])
> UPSERT INTO TESTTABLE10(ID,NAME,CITY) VALUES('112',
> ARRAY['CHEN','CARL','ALICE'], ARRAY['BOSTON','WASHINGTON','PALO ALTO'])
> SELECT ID, UDF_ARRAY_ELEM(NAME, 2) FROM TESTTABLE10
> org.apache.phoenix.schema.ArgumentTypeMismatchException: ERROR 203 (22005):
> Type mismatch. expected: [INTEGER ARRAY] but was: INTEGER at UDF_ARRAY_ELEM
> argument 2
> at
> org.apache.phoenix.parse.FunctionParseNode.validate(FunctionParseNode.java:195)
> at
> org.apache.phoenix.compile.ExpressionCompiler.visitLeave(ExpressionCompiler.java:326)
> at
> org.apache.phoenix.compile.ProjectionCompiler$SelectClauseVisitor.visitLeave(ProjectionCompiler.java:637)
> at
> org.apache.phoenix.compile.ProjectionCompiler$SelectClauseVisitor.visitLeave(ProjectionCompiler.java:538)
> at
> org.apache.phoenix.parse.FunctionParseNode.accept(FunctionParseNode.java:85)Hbase>
> at
> org.apache.phoenix.compile.ProjectionCompiler.compile(ProjectionCompiler.java:396)
> at
> org.apache.phoenix.compile.QueryCompiler.compileSingleFlatQuery(QueryCompiler.java:537)
> at
> org.apache.phoenix.compile.QueryCompiler.compileSingleQuery(QueryCompiler.java:488)
> at
> org.apache.phoenix.compile.QueryCompiler.compileSelect(QueryCompiler.java:200)
> at
> org.apache.phoenix.compile.QueryCompiler.compile(QueryCompiler.java:157)
> at
> org.apache.phoenix.jdbc.PhoenixStatement$ExecutableSelectStatement.compilePlan(PhoenixStatement.java:361)
> at
> org.apache.phoenix.jdbc.PhoenixStatement$ExecutableSelectStatement.compilePlan(PhoenixStatement.java:335)
> at
> org.apache.phoenix.jdbc.PhoenixStatement$1.call(PhoenixStatement.java:243)
> at
> org.apache.phoenix.jdbc.PhoenixStatement$1.call(PhoenixStatement.java:238)
> at org.apache.phoenix.call.CallRunner.run(CallRunner.java:53)
> at
> org.apache.phoenix.jdbc.PhoenixStatement.executeQuery(PhoenixStatement.java:237)
> at
> org.apache.phoenix.jdbc.PhoenixPreparedStatement.executeQuery(PhoenixPreparedStatement.java:187)
> at CustomSQL.openTerminal(CustomSQL.java:45)
> at CustomSQL.main(CustomSQL.java:19)
> udf function:
> package com.test;
> import java.util.List;
> import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
> import org.apache.phoenix.expression.Expression;
> import org.apache.phoenix.expression.function.ScalarFunction;
> import org.apache.phoenix.parse.FunctionParseNode.Argument;
> import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
> import org.apache.phoenix.parse.ParseException;
> import org.apache.phoenix.schema.types.PBinaryArray;
> import org.apache.phoenix.schema.types.PInteger;
> import org.apache.phoenix.schema.types.PArrayDataType;
> import org.apache.phoenix.schema.types.PDataType;
> import org.apache.phoenix.schema.types.PVarbinaryArray;
> import org.apache.phoenix.schema.SortOrder;
> import org.apache.phoenix.schema.tuple.Tuple;
> /*@BuiltInFunction(name = ArrayIndexFunction.NAME, args = {
> @Argument(allowedTypes = { PBinaryArray.class,
> PVarbinaryArray.class }),
> @Argument(allowedTypes = { PInteger.class }) })
> */
> public class ArrayIndexFunction extends ScalarFunction {
> public static final String NAME = "UDF_ARRAY_ELEM";
> public ArrayIndexFunction() {
> }
> public ArrayIndexFunction(List<Expression> children) {
> super(children);
> }
> @Override
> public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
> Expression indexExpr = children.get(1);
> if (!indexExpr.evaluate(tuple, ptr)) {
> return false;
> } else if (ptr.getLength() == 0) {
> return true;
> }
> // Use Codec to prevent Integer object allocation
> int index = PInteger.INSTANCE.getCodec().decodeInt(ptr,
> indexExpr.getSortOrder());
> if(index < 0) {
> throw new ParseException("Index cannot be negative :" +
> index);
> }
> Expression arrayExpr = children.get(0);
> return PArrayDataType.positionAtArrayElement(tuple, ptr, index,
> arrayExpr, getDataType(), getMaxLength());
> }
> @Override
> public PDataType getDataType() {
> return
> PDataType.fromTypeId(children.get(0).getDataType().getSqlType() -
> PDataType.ARRAY_TYPE_BASE);
> }
>
> @Override
> public Integer getMaxLength() {
> return this.children.get(0).getMaxLength();
> }
> @Override
> public String getName() {
> return NAME;
> }
>
> @Override
> public SortOrder getSortOrder() {
> return this.children.get(0).getSortOrder();
> }
> }
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)