Repository: phoenix Updated Branches: refs/heads/4.x-HBase-1.0 b2527520a -> 329363f7d
PHOENIX-2060 - Implement ARRAY_FILL built in function (Dumindu Buddhika) Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/329363f7 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/329363f7 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/329363f7 Branch: refs/heads/4.x-HBase-1.0 Commit: 329363f7d85ceec4b4b0701dff8f1e0ca91535ef Parents: b252752 Author: ramkrishna <ramkrishna.s.vasude...@gmail.com> Authored: Thu Jul 2 11:14:55 2015 +0530 Committer: ramkrishna <ramkrishna.s.vasude...@gmail.com> Committed: Thu Jul 2 11:14:55 2015 +0530 ---------------------------------------------------------------------- .../phoenix/end2end/ArrayFillFunctionIT.java | 531 +++++++++++++++++++ .../phoenix/expression/ExpressionType.java | 5 +- .../expression/function/ArrayFillFunction.java | 79 +++ .../expression/ArrayFillFunctionTest.java | 221 ++++++++ 4 files changed, 835 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/329363f7/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayFillFunctionIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayFillFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayFillFunctionIT.java new file mode 100644 index 0000000..f9ce88d --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayFillFunctionIT.java @@ -0,0 +1,531 @@ +/* + * 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.end2end; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.math.BigDecimal; +import java.sql.*; + +import org.junit.Test; + +public class ArrayFillFunctionIT extends BaseHBaseManagedTimeIT { + + private void initTables(Connection conn) throws Exception { + String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY,length1 INTEGER, length2 INTEGER,date DATE,time TIME,timestamp TIMESTAMP,varchar VARCHAR,integer INTEGER,double DOUBLE,bigint BIGINT,char CHAR(15),double1 DOUBLE,char1 CHAR(17),nullcheck INTEGER,chars2 CHAR(15)[], varchars2 VARCHAR[])"; + conn.createStatement().execute(ddl); + String dml = "UPSERT INTO regions(region_name,length1,length2,date,time,timestamp,varchar,integer,double,bigint,char,double1,char1,nullcheck,chars2,varchars2) VALUES('SF Bay Area'," + + "0," + + "-3," + + "to_date('2015-05-20 06:12:14.184')," + + "to_time('2015-05-20 06:12:14.184')," + + "to_timestamp('2015-05-20 06:12:14.184')," + + "'foo'," + + "34," + + "23.45," + + "34567," + + "'foo'," + + "23.45," + + "'wert'," + + "NULL," + + "ARRAY['hello','hello','hello']," + + "ARRAY['hello','hello','hello']" + + ")"; + PreparedStatement stmt = conn.prepareStatement(dml); + stmt.execute(); + conn.commit(); + } + + @Test + public void testArrayFillFunctionVarchar() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(varchar,5) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + String[] strings = new String[]{"foo", "foo", "foo", "foo", "foo"}; + + Array array = conn.createArrayOf("VARCHAR", strings); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInteger() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(integer,4) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{34, 34, 34, 34}; + + Array array = conn.createArrayOf("INTEGER", objects); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionDouble() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(double,4) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{23.45, 23.45, 23.45, 23.45}; + + Array array = conn.createArrayOf("DOUBLE", objects); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionBigint() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(bigint,4) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{34567l, 34567l, 34567l, 34567l}; + + Array array = conn.createArrayOf("BIGINT", objects); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionChar() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(char,4) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{"foo", "foo", "foo", "foo"}; + + Array array = conn.createArrayOf("CHAR", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionVarChar() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(varchar,4) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{"foo", "foo", "foo", "foo"}; + + Array array = conn.createArrayOf("VARCHAR", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionDate() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(date,3) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{new Date(1432102334184l), new Date(1432102334184l), new Date(1432102334184l)}; + + Array array = conn.createArrayOf("DATE", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionTime() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(time,3) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{new Time(1432102334184l), new Time(1432102334184l), new Time(1432102334184l)}; + + Array array = conn.createArrayOf("TIME", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionTimestamp() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(timestamp,3) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{new Timestamp(1432102334184l), new Timestamp(1432102334184l), new Timestamp(1432102334184l)}; + + Array array = conn.createArrayOf("TIMESTAMP", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test(expected = IllegalArgumentException.class) + public void testArrayFillFunctionInvalidLength1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(timestamp,length2) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{new Timestamp(1432102334184l), new Timestamp(1432102334184l), new Timestamp(1432102334184l)}; + + Array array = conn.createArrayOf("TIMESTAMP", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test(expected = IllegalArgumentException.class) + public void testArrayFillFunctionInvalidLength2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(timestamp,length1) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{new Timestamp(1432102334184l), new Timestamp(1432102334184l), new Timestamp(1432102334184l)}; + + Array array = conn.createArrayOf("TIMESTAMP", objects); + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithNestedFunctions1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(ARRAY_ELEM(ARRAY[23,45],1),3) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Integer[] integers = new Integer[]{23, 23, 23}; + + Array array = conn.createArrayOf("INTEGER", integers); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithNestedFunctions2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL('hello', ARRAY_LENGTH(ARRAY[34, 45])) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{"hello", "hello"}; + + Array array = conn.createArrayOf("VARCHAR", objects); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithNestedFunctions3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_FILL(3.4, ARRAY_LENGTH(ARRAY[34, 45])) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Object[] objects = new Object[]{BigDecimal.valueOf(3.4), BigDecimal.valueOf(3.4)}; + + Array array = conn.createArrayOf("DECIMAL", objects); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithUpsert1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY,varchars VARCHAR[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO regions(region_name,varchars) VALUES('SF Bay Area',ARRAY_FILL('hello',3))"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT varchars FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + String[] strings = new String[]{"hello", "hello", "hello"}; + + Array array = conn.createArrayOf("VARCHAR", strings); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithUpsert2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY,integers INTEGER[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO regions(region_name,integers) VALUES('SF Bay Area',ARRAY_FILL(3456,3))"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT integers FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Integer[] integers = new Integer[]{3456, 3456, 3456}; + + Array array = conn.createArrayOf("INTEGER", integers); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithUpsert3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY,doubles DOUBLE[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO regions(region_name,doubles) VALUES('SF Bay Area',ARRAY_FILL(2.5,3))"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT doubles FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + Double[] doubles = new Double[]{2.5, 2.5, 2.5}; + + Array array = conn.createArrayOf("DOUBLE", doubles); + + assertEquals(array, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithUpsertSelect1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE source (region_name VARCHAR PRIMARY KEY,doubles DOUBLE[])"; + conn.createStatement().execute(ddl); + + ddl = "CREATE TABLE target (region_name VARCHAR PRIMARY KEY,doubles DOUBLE[],doubles2 DOUBLE[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO source(region_name,doubles) VALUES('SF Bay Area',ARRAY_FILL(3.4,3))"; + conn.createStatement().execute(dml); + + dml = "UPSERT INTO source(region_name,doubles) VALUES('SF Bay Area2',ARRAY_FILL(2.3,3))"; + conn.createStatement().execute(dml); + conn.commit(); + + dml = "UPSERT INTO target(region_name, doubles, doubles2) SELECT region_name, doubles,ARRAY_FILL(4.5,5) FROM source"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT doubles, doubles2 FROM target"); + assertTrue(rs.next()); + + Double[] doubles = new Double[]{3.4, 3.4, 3.4}; + Double[] doubles2 = new Double[]{4.5, 4.5, 4.5, 4.5, 4.5}; + Array array = conn.createArrayOf("DOUBLE", doubles); + Array array2 = conn.createArrayOf("DOUBLE", doubles2); + + assertEquals(array, rs.getArray(1)); + assertEquals(array2, rs.getArray(2)); + assertTrue(rs.next()); + + doubles = new Double[]{2.3, 2.3, 2.3}; + array = conn.createArrayOf("DOUBLE", doubles); + + assertEquals(array, rs.getArray(1)); + assertEquals(array2, rs.getArray(2)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionWithUpsertSelect2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE source (region_name VARCHAR PRIMARY KEY,varchars VARCHAR[])"; + conn.createStatement().execute(ddl); + + ddl = "CREATE TABLE target (region_name VARCHAR PRIMARY KEY,varchars VARCHAR[],varchars2 VARCHAR[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO source(region_name,varchars) VALUES('SF Bay Area',ARRAY_FILL('foo',3))"; + conn.createStatement().execute(dml); + + dml = "UPSERT INTO source(region_name,varchars) VALUES('SF Bay Area2',ARRAY_FILL('hello',3))"; + conn.createStatement().execute(dml); + conn.commit(); + + dml = "UPSERT INTO target(region_name, varchars, varchars2) SELECT region_name, varchars,ARRAY_FILL(':-)',5) FROM source"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT varchars, varchars2 FROM target"); + assertTrue(rs.next()); + + String[] strings = new String[]{"foo", "foo", "foo"}; + String[] strings2 = new String[]{":-)", ":-)", ":-)", ":-)", ":-)"}; + Array array = conn.createArrayOf("VARCHAR", strings); + Array array2 = conn.createArrayOf("VARCHAR", strings2); + + assertEquals(array, rs.getArray(1)); + assertEquals(array2, rs.getArray(2)); + assertTrue(rs.next()); + + strings = new String[]{"hello", "hello", "hello"}; + array = conn.createArrayOf("VARCHAR", strings); + + assertEquals(array, rs.getArray(1)); + assertEquals(array2, rs.getArray(2)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[12, 12, 12, 12]=ARRAY_FILL(12,4)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE varchar=ANY(ARRAY_FILL('foo',3))"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY['2345', '2345', '2345', '2345']=ARRAY_FILL('2345', 4)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere4() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[23.45, 23.45, 23.45]=ARRAY_FILL(23.45, 3)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere5() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY['foo','foo','foo','foo','foo']=ARRAY_FILL(varchar,5)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere6() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE varchars2=ARRAY_FILL('hello',3)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testArrayFillFunctionInWhere7() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[2,2,2,2]=ARRAY_FILL(2,4)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/329363f7/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java index 51f4089..1390d3d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java @@ -25,6 +25,7 @@ import org.apache.phoenix.expression.function.ArrayAnyComparisonExpression; import org.apache.phoenix.expression.function.ArrayAppendFunction; import org.apache.phoenix.expression.function.ArrayConcatFunction; import org.apache.phoenix.expression.function.ArrayElemRefExpression; +import org.apache.phoenix.expression.function.ArrayFillFunction; import org.apache.phoenix.expression.function.ArrayIndexFunction; import org.apache.phoenix.expression.function.ArrayLengthFunction; import org.apache.phoenix.expression.function.ArrayPrependFunction; @@ -247,7 +248,9 @@ public enum ExpressionType { LogFunction(LogFunction.class), ExpFunction(ExpFunction.class), PowerFunction(PowerFunction.class), - ArrayConcatFunction(ArrayConcatFunction.class) + ArrayConcatFunction(ArrayConcatFunction.class), + ArrayFillFunction(ArrayFillFunction.class), + ; ExpressionType(Class<? extends Expression> clazz) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/329363f7/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayFillFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayFillFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayFillFunction.java new file mode 100644 index 0000000..5c3a2e5 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayFillFunction.java @@ -0,0 +1,79 @@ +package org.apache.phoenix.expression.function; + +import java.util.Arrays; +import java.util.List; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.Expression; +import org.apache.phoenix.parse.FunctionParseNode; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.schema.TypeMismatchException; +import org.apache.phoenix.schema.tuple.Tuple; +import org.apache.phoenix.schema.types.*; + +@FunctionParseNode.BuiltInFunction(name = ArrayFillFunction.NAME, args = { + @FunctionParseNode.Argument(allowedTypes = {PVarbinary.class}), + @FunctionParseNode.Argument(allowedTypes = {PInteger.class})}) +public class ArrayFillFunction extends ScalarFunction { + + public static final String NAME = "ARRAY_FILL"; + + public ArrayFillFunction() { + } + + public ArrayFillFunction(List<Expression> children) throws TypeMismatchException { + super(children); + } + + @Override + public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { + if (!getElementExpr().evaluate(tuple, ptr)) { + return false; + } + Object element = getElementExpr().getDataType().toObject(ptr, getElementExpr().getSortOrder(), getElementExpr().getMaxLength(), getElementExpr().getScale()); + if (!getLengthExpr().evaluate(tuple, ptr) || ptr.getLength() == 0) { + return false; + } + int length = (Integer) getLengthExpr().getDataType().toObject(ptr, getLengthExpr().getSortOrder(), getLengthExpr().getMaxLength(), getLengthExpr().getScale()); + if (length <= 0) { + throw new IllegalArgumentException("Array length should be greater than 0"); + } + Object[] elements = new Object[length]; + Arrays.fill(elements, element); + PhoenixArray array = PDataType.instantiatePhoenixArray(getElementExpr().getDataType(), elements); + //When max length of a char array is not the max length of the element passed in + if (getElementExpr().getDataType().isFixedWidth() && getMaxLength() != null && getMaxLength() != array.getMaxLength()) { + array = new PhoenixArray(array, getMaxLength()); + } + ptr.set(((PArrayDataType) getDataType()).toBytes(array, getElementExpr().getDataType(), getElementExpr().getSortOrder())); + return true; + } + + @Override + public String getName() { + return NAME; + } + + @Override + public PDataType getDataType() { + return PArrayDataType.fromTypeId(PDataType.ARRAY_TYPE_BASE + getElementExpr().getDataType().getSqlType()); + } + + @Override + public Integer getMaxLength() { + return getElementExpr().getDataType().getByteSize() == null ? getElementExpr().getMaxLength() : null; + } + + @Override + public SortOrder getSortOrder() { + return children.get(0).getSortOrder(); + } + + public Expression getElementExpr() { + return children.get(0); + } + + public Expression getLengthExpr() { + return children.get(1); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/329363f7/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayFillFunctionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayFillFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayFillFunctionTest.java new file mode 100644 index 0000000..be8cc6f --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayFillFunctionTest.java @@ -0,0 +1,221 @@ +/* + * 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; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.sql.Date; +import java.sql.SQLException; +import java.sql.Time; +import java.util.List; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.function.ArrayFillFunction; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.schema.types.*; +import org.junit.Test; + +import com.google.common.collect.Lists; + +public class ArrayFillFunctionTest { + + private static void testExpression(LiteralExpression element, LiteralExpression length, PhoenixArray expected) + throws SQLException { + List<Expression> expressions = Lists.newArrayList((Expression) element); + expressions.add(length); + + Expression arrayFillFunction = new ArrayFillFunction(expressions); + ImmutableBytesWritable ptr = new ImmutableBytesWritable(); + arrayFillFunction.evaluate(null, ptr); + PhoenixArray result = (PhoenixArray) arrayFillFunction.getDataType().toObject(ptr, arrayFillFunction.getSortOrder(), arrayFillFunction.getMaxLength(), arrayFillFunction.getScale()); + assertEquals(expected, result); + } + + private static void test(Object element, Object length, PDataType elementDataType, Integer elementMaxLen, Integer elementScale, PDataType lengthDataType, Integer lengthMaxlen, Integer lengthScale, PhoenixArray expected, SortOrder elementSortOrder, SortOrder lengthSortOrder) throws SQLException { + LiteralExpression elementLiteral, lengthLiteral; + elementLiteral = LiteralExpression.newConstant(element, elementDataType, elementMaxLen, elementScale, elementSortOrder, Determinism.ALWAYS); + lengthLiteral = LiteralExpression.newConstant(length, lengthDataType, lengthMaxlen, lengthScale, lengthSortOrder, Determinism.ALWAYS); + testExpression(elementLiteral, lengthLiteral, expected); + } + + @Test + public void testForInt() throws SQLException { + Object element = 5; + Object length = 3; + PDataType baseType = PInteger.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, new Object[]{5, 5, 5}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForBoolean() throws SQLException { + Object element = false; + Object length = 3; + PDataType baseType = PBoolean.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveBooleanPhoenixArray(baseType, new Object[]{false, false, false}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForVarchar() throws SQLException { + Object element = "foo"; + Object length = 3; + PDataType baseType = PVarchar.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{"foo", "foo", "foo"}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForChar() throws SQLException { + Object element = "foo"; + Object length = 3; + PDataType baseType = PChar.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{"foo", "foo", "foo"}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForDouble() throws SQLException { + Object element = 34.67; + Object length = 3; + PDataType baseType = PDouble.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveDoublePhoenixArray(baseType, new Object[]{34.67, 34.67, 34.67}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + } + + @Test + public void testForFloat() throws SQLException { + Object element = 5.6; + Object length = 3; + PDataType baseType = PFloat.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveFloatPhoenixArray(baseType, new Object[]{(float) 5.6, (float) 5.6, (float) 5.6}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + } + + @Test + public void testForSmallint() throws SQLException { + Object element = 5; + Object length = 3; + PDataType baseType = PSmallint.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveShortPhoenixArray(baseType, new Object[]{(short) 5, (short) 5, (short) 5}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForTinyint() throws SQLException { + Object element = 6; + Object length = 3; + PDataType baseType = PTinyint.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveBytePhoenixArray(baseType, new Object[]{(byte) 6, (byte) 6, (byte) 6}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForLong() throws SQLException { + Object element = 34567l; + Object length = 3; + PDataType baseType = PLong.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveLongPhoenixArray(baseType, new Object[]{34567l, 34567l, 34567l}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForDecimal() throws SQLException { + Object element = BigDecimal.valueOf(345.67); + Object length = 3; + PDataType baseType = PDecimal.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{BigDecimal.valueOf(345.67), BigDecimal.valueOf(345.67), BigDecimal.valueOf(345.67)}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForDate() throws SQLException { + Object element = new Date(23); + Object length = 3; + PDataType baseType = PDate.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{new Date(23), new Date(23), new Date(23)}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForTime() throws SQLException { + Object element = new Time(23); + Object length = 3; + PDataType baseType = PTime.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{new Time(23), new Time(23), new Time(23)}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForNulls1() throws SQLException { + Object element = null; + Object length = 3; + PDataType baseType = PInteger.INSTANCE; + PhoenixArray e = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, new Object[]{0, 0, 0}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } + + @Test + public void testForNulls2() throws SQLException { + Object element = null; + Object length = 3; + PDataType baseType = PVarchar.INSTANCE; + PhoenixArray e = new PhoenixArray(baseType, new Object[]{null, null, null}); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.ASC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.ASC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.DESC); + test(element, length, baseType, null, null, PInteger.INSTANCE, null, null, e, SortOrder.DESC, SortOrder.ASC); + } +}