Repository: phoenix Updated Branches: refs/heads/4.x-HBase-0.98 ffedf5ac0 -> be431e9b1
PHOENIX-2147 Implement STRING_TO_ARRAY built in function (Dumindu Buddhika) Conflicts: phoenix-core/src/main/java/org/apache/phoenix/expression/ExpressionType.java Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/be431e9b Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/be431e9b Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/be431e9b Branch: refs/heads/4.x-HBase-0.98 Commit: be431e9b18f440df5c0db43173677d577bc1e516 Parents: ffedf5a Author: ramkrishna <ramkrishna.s.vasude...@gmail.com> Authored: Tue Jul 28 10:30:00 2015 +0530 Committer: ramkrishna <ramkrishna.s.vasude...@gmail.com> Committed: Tue Jul 28 11:36:44 2015 +0530 ---------------------------------------------------------------------- .../end2end/StringToArrayFunctionIT.java | 423 +++++++++++++++++++ .../phoenix/expression/ExpressionType.java | 6 +- .../function/StringToArrayFunction.java | 91 ++++ .../phoenix/schema/types/PArrayDataType.java | 21 + .../expression/StringToArrayFunctionTest.java | 275 ++++++++++++ 5 files changed, 814 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/be431e9b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StringToArrayFunctionIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StringToArrayFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StringToArrayFunctionIT.java new file mode 100644 index 0000000..6e6ac9f --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StringToArrayFunctionIT.java @@ -0,0 +1,423 @@ +/* + * 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.sql.*; + +import org.apache.phoenix.schema.types.PVarchar; +import org.apache.phoenix.schema.types.PhoenixArray; +import org.junit.Test; + +public class StringToArrayFunctionIT extends BaseHBaseManagedTimeIT { + + private void initTables(Connection conn) throws Exception { + String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY, string1 VARCHAR, string2 CHAR(50), delimiter1 VARCHAR, delimiter2 CHAR(20), nullstring1 VARCHAR, nullstring2 CHAR(20))"; + conn.createStatement().execute(ddl); + String dml = "UPSERT INTO regions(region_name, string1, string2, delimiter1, delimiter2, nullstring1, nullstring2) VALUES('SF Bay Area'," + + "'a,b,c,d'," + + "'1.2.3.4'," + + "','," + + "'.'," + + "'c'," + + "'3'" + + ")"; + PreparedStatement stmt = conn.prepareStatement(dml); + stmt.execute(); + conn.commit(); + } + + @Test + public void testStringToArrayFunction1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string1, delimiter1) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", "c", "d"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string1, delimiter1, nullstring1) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", null, "d"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string1, delimiter1, 'a') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{null, "b", "c", "d"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction4() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string1, delimiter1, 'd') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", "c", null}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction5() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string2, delimiter2) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"1", "2", "3", "4"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction6() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string2, delimiter2, nullstring2) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"1", "2", null, "4"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction7() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string2, delimiter2, '1') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{null, "2", "3", "4"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction8() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(string2, delimiter2, '4') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"1", "2", "3", null}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction9() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(region_name, ' ', '4') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"SF", "Bay", "Area"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction10() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY('hello,hello,hello', delimiter1) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"hello", "hello", "hello"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction11() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY('a,hello,hello,hello,b', ',', 'hello') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", null, null, null, "b"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunction12() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY('b.a.b', delimiter2, 'b') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{null, "a", null}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithNestedFunctions1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT ARRAY_LENGTH(STRING_TO_ARRAY('a, b, c', ', ')) FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + assertEquals(3, rs.getInt(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithNestedFunctions2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(ARRAY_TO_STRING(ARRAY['a', 'b', 'c'], delimiter2), delimiter2, 'b') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", null, "c"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithNestedFunctions3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT STRING_TO_ARRAY(ARRAY_TO_STRING(ARRAY['a', 'b', 'c'], delimiter2), ARRAY_ELEM(ARRAY[',', '.'], 2), 'b') FROM regions WHERE region_name = 'SF Bay Area'"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", null, "c"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithUpsert1() 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', STRING_TO_ARRAY('hello, world, :-)', ', '))"; + 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()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"hello", "world", ":-)"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithUpsert2() 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', STRING_TO_ARRAY('a, b, -, c', ', ', '-'))"; + 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()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", null, "c"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithUpsertSelect1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE source (region_name VARCHAR PRIMARY KEY, varchar VARCHAR)"; + conn.createStatement().execute(ddl); + + ddl = "CREATE TABLE target (region_name VARCHAR PRIMARY KEY, varchars VARCHAR[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO source(region_name, varchar) VALUES('SF Bay Area', 'a,b,c,d')"; + conn.createStatement().execute(dml); + + dml = "UPSERT INTO source(region_name, varchar) VALUES('SF Bay Area2', '1,2,3,4')"; + conn.createStatement().execute(dml); + conn.commit(); + + dml = "UPSERT INTO target(region_name, varchars) SELECT region_name, STRING_TO_ARRAY(varchar, ',') FROM source"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT varchars FROM target"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", "c", "d"}); + + assertEquals(expected, rs.getArray(1)); + assertTrue(rs.next()); + + expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"1", "2", "3", "4"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionWithUpsertSelect2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + + String ddl = "CREATE TABLE source (region_name VARCHAR PRIMARY KEY, varchar VARCHAR)"; + conn.createStatement().execute(ddl); + + ddl = "CREATE TABLE target (region_name VARCHAR PRIMARY KEY, varchars VARCHAR[])"; + conn.createStatement().execute(ddl); + + String dml = "UPSERT INTO source(region_name, varchar) VALUES('SF Bay Area', 'a,b,-,c,d')"; + conn.createStatement().execute(dml); + + dml = "UPSERT INTO source(region_name, varchar) VALUES('SF Bay Area2', '1,2,-,3,4')"; + conn.createStatement().execute(dml); + conn.commit(); + + dml = "UPSERT INTO target(region_name, varchars) SELECT region_name, STRING_TO_ARRAY(varchar, ',', '-') FROM source"; + conn.createStatement().execute(dml); + conn.commit(); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT varchars FROM target"); + assertTrue(rs.next()); + + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"a", "b", null, "c", "d"}); + + assertEquals(expected, rs.getArray(1)); + assertTrue(rs.next()); + + expected = new PhoenixArray(PVarchar.INSTANCE, new Object[]{"1", "2", null, "3", "4"}); + + assertEquals(expected, rs.getArray(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionInWhere1() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY['a', 'b', 'c', 'd']=STRING_TO_ARRAY(string1, delimiter1)"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionInWhere2() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE 'a'=ANY(STRING_TO_ARRAY(string1, delimiter1))"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } + + @Test + public void testStringToArrayFunctionInWhere3() throws Exception { + Connection conn = DriverManager.getConnection(getUrl()); + initTables(conn); + + ResultSet rs; + rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE 'a'=ALL(STRING_TO_ARRAY('a,a,a,', delimiter1))"); + assertTrue(rs.next()); + + assertEquals("SF Bay Area", rs.getString(1)); + assertFalse(rs.next()); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/be431e9b/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 cfc0376..53d77ef 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 @@ -96,6 +96,7 @@ import org.apache.phoenix.expression.function.StddevSampFunction; import org.apache.phoenix.expression.function.StringBasedRegexpReplaceFunction; import org.apache.phoenix.expression.function.StringBasedRegexpSplitFunction; import org.apache.phoenix.expression.function.StringBasedRegexpSubstrFunction; +import org.apache.phoenix.expression.function.StringToArrayFunction; import org.apache.phoenix.expression.function.SubstrFunction; import org.apache.phoenix.expression.function.SumAggregateFunction; import org.apache.phoenix.expression.function.TimezoneOffsetFunction; @@ -250,8 +251,9 @@ public enum ExpressionType { PowerFunction(PowerFunction.class), ArrayConcatFunction(ArrayConcatFunction.class), ArrayFillFunction(ArrayFillFunction.class), - ArrayToStringFunction(ArrayToStringFunction.class); - + ArrayToStringFunction(ArrayToStringFunction.class), + StringToArrayFunction(StringToArrayFunction.class) + ; ExpressionType(Class<? extends Expression> clazz) { this.clazz = clazz; } http://git-wip-us.apache.org/repos/asf/phoenix/blob/be431e9b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringToArrayFunction.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringToArrayFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringToArrayFunction.java new file mode 100644 index 0000000..ffbda01 --- /dev/null +++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringToArrayFunction.java @@ -0,0 +1,91 @@ +/* + * 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.parse.FunctionParseNode; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.schema.tuple.Tuple; +import org.apache.phoenix.schema.types.*; + +@FunctionParseNode.BuiltInFunction(name = StringToArrayFunction.NAME, args = { + @FunctionParseNode.Argument(allowedTypes = {PVarchar.class, PChar.class}), + @FunctionParseNode.Argument(allowedTypes = {PVarchar.class, PChar.class}), + @FunctionParseNode.Argument(allowedTypes = {PVarchar.class, PChar.class}, defaultValue = "null")}) +public class StringToArrayFunction extends ScalarFunction { + public static final String NAME = "STRING_TO_ARRAY"; + + public StringToArrayFunction() { + } + + public StringToArrayFunction(List<Expression> children) { + super(children); + } + + @Override + public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) { + Expression delimiterExpr = children.get(1); + String delimiter; + if (!delimiterExpr.evaluate(tuple, ptr)) { + return false; + } else if (ptr.getLength() == 0) { + delimiter = ""; + } else { + delimiter = (String) delimiterExpr.getDataType().toObject(ptr, delimiterExpr.getSortOrder(), delimiterExpr.getMaxLength(), delimiterExpr.getScale()); + } + + Expression stringExpr = children.get(0); + if (!stringExpr.evaluate(tuple, ptr)) { + return false; + } else if (ptr.getLength() == 0) { + return true; + } + String string = (String) stringExpr.getDataType().toObject(ptr, stringExpr.getSortOrder(), stringExpr.getMaxLength(), stringExpr.getScale()); + + Expression nullExpr = children.get(2); + String nullString = null; + if (nullExpr.evaluate(tuple, ptr) && ptr.getLength() != 0) { + nullString = (String) nullExpr.getDataType().toObject(ptr, nullExpr.getSortOrder(), nullExpr.getMaxLength(), nullExpr.getScale()); + } + + return PArrayDataType.stringToArray(ptr, string, delimiter, nullString, getSortOrder()); + } + + @Override + public String getName() { + return NAME; + } + + @Override + public Integer getMaxLength() { + return null; + } + + @Override + public PDataType getDataType() { + return PVarcharArray.INSTANCE; + } + + @Override + public SortOrder getSortOrder() { + return children.get(0).getSortOrder(); + } +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/be431e9b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PArrayDataType.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PArrayDataType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PArrayDataType.java index 28144fd..a1759a4 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PArrayDataType.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/types/PArrayDataType.java @@ -24,6 +24,7 @@ import java.sql.Types; import java.text.Format; import java.util.LinkedList; import java.util.List; +import java.util.regex.Pattern; import org.apache.hadoop.hbase.io.ImmutableBytesWritable; import org.apache.hadoop.hbase.util.Bytes; @@ -990,6 +991,26 @@ public abstract class PArrayDataType<T> extends PDataType<T> { return true; } + public static boolean stringToArray(ImmutableBytesWritable ptr, String string, String delimiter, String nullString, SortOrder sortOrder) { + Pattern pattern = Pattern.compile(Pattern.quote(delimiter)); + String[] array; + if (delimiter.length() != 0) { + array = pattern.split(string); + if (nullString != null) { + for (int i = 0; i < array.length; i++) { + if (array[i].equals(nullString)) { + array[i] = null; + } + } + } + } else { + array = string.split("(?!^)"); + } + PhoenixArray phoenixArray = new PhoenixArray(PVarchar.INSTANCE, array); + ptr.set(PVarcharArray.INSTANCE.toBytes(phoenixArray, PVarchar.INSTANCE, sortOrder)); + return true; + } + public static int serailizeOffsetArrayIntoStream(DataOutputStream oStream, TrustedByteArrayOutputStream byteStream, int noOfElements, int maxOffset, int[] offsetPos) throws IOException { int offsetPosition = (byteStream.size()); http://git-wip-us.apache.org/repos/asf/phoenix/blob/be431e9b/phoenix-core/src/test/java/org/apache/phoenix/expression/StringToArrayFunctionTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/StringToArrayFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/StringToArrayFunctionTest.java new file mode 100644 index 0000000..6e8e532 --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/StringToArrayFunctionTest.java @@ -0,0 +1,275 @@ +/* + * 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.sql.SQLException; +import java.util.List; + +import org.apache.hadoop.hbase.io.ImmutableBytesWritable; +import org.apache.phoenix.expression.function.StringToArrayFunction; +import org.apache.phoenix.schema.SortOrder; +import org.apache.phoenix.schema.types.*; +import org.junit.Test; + +import com.google.common.collect.Lists; + +public class StringToArrayFunctionTest { + + private static void testExpression(LiteralExpression array, LiteralExpression delimiter, LiteralExpression nullString, PhoenixArray expected) + throws SQLException { + List<Expression> expressions = Lists.newArrayList((Expression) array); + expressions.add(delimiter); + expressions.add(nullString); + + Expression stringToArrayFunction = new StringToArrayFunction(expressions); + ImmutableBytesWritable ptr = new ImmutableBytesWritable(); + stringToArrayFunction.evaluate(null, ptr); + PhoenixArray result = (PhoenixArray) stringToArrayFunction.getDataType().toObject(ptr, stringToArrayFunction.getSortOrder(), stringToArrayFunction.getMaxLength(), stringToArrayFunction.getScale()); + assertEquals(expected, result); + } + + private static void test(String string, String delimiter, String nullString, PhoenixArray expected, SortOrder stringSortOrder, SortOrder delimiterSortOrder, SortOrder nullStringSortOrder, PDataType stringType, PDataType delimiterType, PDataType nullStringType) throws SQLException { + LiteralExpression arrayLiteral, delimiterLiteral, nullStringLiteral; + arrayLiteral = LiteralExpression.newConstant(string, stringType, null, null, stringSortOrder, Determinism.ALWAYS); + delimiterLiteral = LiteralExpression.newConstant(delimiter, delimiterType, null, null, delimiterSortOrder, Determinism.ALWAYS); + nullStringLiteral = LiteralExpression.newConstant(nullString, nullStringType, null, null, nullStringSortOrder, Determinism.ALWAYS); + testExpression(arrayLiteral, delimiterLiteral, nullStringLiteral, expected); + } + + @Test + public void testStringToArrayFunction1() throws SQLException { + String string = "1,2,3,4,5"; + Object[] o1 = new Object[]{"1", "2", "3", "4", "5"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ","; + String nullString = "*"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction2() throws SQLException { + String string = "1,2,3,4,5"; + Object[] o1 = new Object[]{"1", "2", "3", "4", "5"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ","; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction3() throws SQLException { + String string = "1234"; + Object[] o1 = new Object[]{"1", "2", "3", "4"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = null; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction4() throws SQLException { + String string = "1"; + Object[] o1 = new Object[]{"1"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ","; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction5() throws SQLException { + String string = "hello, hello, hello"; + Object[] o1 = new Object[]{"hello", "hello", "hello"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ", "; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction6() throws SQLException { + String string = "1.2...2.3...5.6"; + Object[] o1 = new Object[]{"1.2", "2.3", "5.6"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = "..."; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction7() throws SQLException { + String string = "a\\b\\c\\d\\e\\f"; + Object[] o1 = new Object[]{"a", "b", "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = "\\"; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction8() throws SQLException { + String string = "a-b-c-d-e-f-"; + Object[] o1 = new Object[]{"a", "b", "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = "-"; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction9() throws SQLException { + String string = "a b c d e f"; + Object[] o1 = new Object[]{"a", "b", "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction10() throws SQLException { + String string = "axbxcxdxexf"; + Object[] o1 = new Object[]{"a", "b", "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = "x"; + String nullString = ""; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction11() throws SQLException { + String string = "axbxcxdxexfx*"; + Object[] o1 = new Object[]{"a", "b", "c", "d", "e", "f", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = "x"; + String nullString = "*"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction12() throws SQLException { + String string = "* a b c d e f"; + Object[] o1 = new Object[]{null, "a", "b", "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = "*"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction13() throws SQLException { + String string = "a * b * c d e f"; + Object[] o1 = new Object[]{"a", null, "b", null, "c", "d", "e", "f"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = "*"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction14() throws SQLException { + String string = "null a null"; + Object[] o1 = new Object[]{null, "a", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction16() throws SQLException { + String string = "null a null"; + Object[] o1 = new Object[]{null, "a", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction17() throws SQLException { + String string = "null a null"; + Object[] o1 = new Object[]{null, "a", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = " "; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction18() throws SQLException { + String string = "null,a,null"; + Object[] o1 = new Object[]{null, "a", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ","; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PVarchar.INSTANCE); + } + + @Test + public void testStringToArrayFunction19() throws SQLException { + String string = "null,a,null"; + Object[] o1 = new Object[]{null, "a", null}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = ","; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PChar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PChar.INSTANCE); + } + + @Test + public void testStringToArrayFunction20() throws SQLException { + String string = "abc"; + Object[] o1 = new Object[]{"a", "b", "c"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = null; + String nullString = "null"; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PChar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PChar.INSTANCE, PChar.INSTANCE, PChar.INSTANCE); + } + + @Test + public void testStringToArrayFunction21() throws SQLException { + String string = "(?!^)"; + Object[] o1 = new Object[]{"(", "?", "!", "^", ")"}; + PhoenixArray expected = new PhoenixArray(PVarchar.INSTANCE, o1); + String delimiter = null; + String nullString = null; + test(string, delimiter, nullString, expected, SortOrder.ASC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + test(string, delimiter, nullString, expected, SortOrder.DESC, SortOrder.ASC, SortOrder.ASC, PVarchar.INSTANCE, PVarchar.INSTANCE, PVarchar.INSTANCE); + } +}