You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2015/04/14 21:09:38 UTC
[1/3] phoenix git commit: PHOENIX-1705 implement ARRAY_APPEND built
in function (Dumindu Buddhika)
Repository: phoenix
Updated Branches:
refs/heads/master 986080f3f -> 3f6b25947
PHOENIX-1705 implement ARRAY_APPEND 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/7ef17181
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/7ef17181
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/7ef17181
Branch: refs/heads/master
Commit: 7ef1718127ffaa99adbc4c25ec3715d9472464f9
Parents: 986080f
Author: James Taylor <jt...@salesforce.com>
Authored: Tue Apr 14 12:07:29 2015 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Tue Apr 14 12:07:29 2015 -0700
----------------------------------------------------------------------
.../phoenix/end2end/ArrayAppendFunctionIT.java | 667 +++++++++++++++++++
.../function/ArrayAppendFunction.java | 127 ++++
.../expression/ArrayAppendFunctionTest.java | 345 ++++++++++
3 files changed, 1139 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/7ef17181/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayAppendFunctionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayAppendFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayAppendFunctionIT.java
new file mode 100644
index 0000000..1957b3a
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayAppendFunctionIT.java
@@ -0,0 +1,667 @@
+/*
+ * 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.assertFalse;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.*;
+
+import org.apache.phoenix.schema.TypeMismatchException;
+import org.junit.Test;
+
+public class ArrayAppendFunctionIT extends BaseHBaseManagedTimeIT {
+ private void initTables(Connection conn) throws Exception {
+ String ddl = "CREATE TABLE regions (region_name VARCHAR PRIMARY KEY,varchars VARCHAR[],integers INTEGER[],doubles DOUBLE[],bigints BIGINT[],chars CHAR(15)[],double1 DOUBLE,char1 CHAR(17),nullcheck INTEGER,chars2 CHAR(15)[])";
+ conn.createStatement().execute(ddl);
+ String dml = "UPSERT INTO regions(region_name,varchars,integers,doubles,bigints,chars,double1,char1,nullcheck,chars2) VALUES('SF Bay Area'," +
+ "ARRAY['2345','46345','23234']," +
+ "ARRAY[2345,46345,23234,456]," +
+ "ARRAY[23.45,46.345,23.234,45.6,5.78]," +
+ "ARRAY[12,34,56,78,910]," +
+ "ARRAY['a','bbbb','c','ddd','e']," +
+ "23.45," +
+ "'wert'," +
+ "NULL," +
+ "ARRAY['a','bbbb','c','ddd','e','foo']" +
+ ")";
+ PreparedStatement stmt = conn.prepareStatement(dml);
+ stmt.execute();
+ conn.commit();
+ }
+
+ private void initTablesDesc(Connection conn, String type, String val) throws Exception {
+ String ddl = "CREATE TABLE regions (pk " + type + " PRIMARY KEY DESC,varchars VARCHAR[],integers INTEGER[],doubles DOUBLE[],bigints BIGINT[],chars CHAR(15)[],chars2 CHAR(15)[], bools BOOLEAN[])";
+ conn.createStatement().execute(ddl);
+ String dml = "UPSERT INTO regions(pk,varchars,integers,doubles,bigints,chars,chars2,bools) VALUES(" + val + "," +
+ "ARRAY['2345','46345','23234']," +
+ "ARRAY[2345,46345,23234,456]," +
+ "ARRAY[23.45,46.345,23.234,45.6,5.78]," +
+ "ARRAY[12,34,56,78,910]," +
+ "ARRAY['a','bbbb','c','ddd','e']," +
+ "ARRAY['a','bbbb','c','ddd','e','foo']," +
+ "ARRAY[true,false]" +
+ ")";
+ PreparedStatement stmt = conn.prepareStatement(dml);
+ stmt.execute();
+ conn.commit();
+ }
+
+ @Test
+ public void testArrayAppendFunctionVarchar() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(varchars,'34567') FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"2345", "46345", "23234", "34567"};
+
+ Array array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInteger() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(integers,1234) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{2345, 46345, 23234, 456, 1234};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionDouble() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(doubles,double1) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{23.45, 46.345, 23.234, 45.6, 5.78, 23.45};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionDouble2() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(doubles,23) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{23.45, 46.345, 23.234, 45.6, 5.78, new Double(23)};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionBigint() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(bigints,1112) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Long[] longs = new Long[]{12l, 34l, 56l, 78l, 910l, 1112l};
+
+ Array array = conn.createArrayOf("BIGINT", longs);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionChar() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(chars,'fac') FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"a", "bbbb", "c", "ddd", "e", "fac"};
+
+ Array array = conn.createArrayOf("CHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test(expected = TypeMismatchException.class)
+ public void testArrayAppendFunctionIntToCharArray() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(varchars,234) FROM regions WHERE region_name = 'SF Bay Area'");
+ }
+
+ @Test(expected = TypeMismatchException.class)
+ public void testArrayAppendFunctionVarcharToIntegerArray() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(integers,'234') FROM regions WHERE region_name = 'SF Bay Area'");
+
+ }
+
+ @Test(expected = SQLException.class)
+ public void testArrayAppendFunctionChar2() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(chars,'facfacfacfacfacfacfac') FROM regions WHERE region_name = 'SF Bay Area'");
+ rs.next();
+ rs.getArray(1);
+ }
+
+ @Test
+ public void testArrayAppendFunctionIntegerToDoubleArray() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(doubles,45) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{23.45, 46.345, 23.234, 45.6, 5.78, 45.0};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithNestedFunctions1() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(ARRAY[23,45],integers[1]) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{23, 45, 2345};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithNestedFunctions2() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(integers,ARRAY_ELEM(ARRAY[2,4],1)) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{2345, 46345, 23234, 456, 2};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithNestedFunctions3() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(doubles,ARRAY_ELEM(doubles,2)) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{23.45, 46.345, 23.234, 45.6, 5.78, 46.345};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithUpsert1() 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_APPEND(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());
+
+ String[] strings = new String[]{"hello", "world", ":-)"};
+
+ Array array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithUpsert2() 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_APPEND(ARRAY[4,5],6))";
+ 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[]{4, 5, 6};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithUpsert3() 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_APPEND(ARRAY[5.67,7.87],9.0))";
+ 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[]{5.67, 7.87, new Double(9)};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithUpsertSelect1() 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[])";
+ conn.createStatement().execute(ddl);
+
+ String dml = "UPSERT INTO source(region_name,doubles) VALUES('SF Bay Area',ARRAY_APPEND(ARRAY[5.67,7.87],9.0))";
+ conn.createStatement().execute(dml);
+
+ dml = "UPSERT INTO source(region_name,doubles) VALUES('SF Bay Area2',ARRAY_APPEND(ARRAY[56.7,7.87],9.2))";
+ conn.createStatement().execute(dml);
+ conn.commit();
+
+ dml = "UPSERT INTO target(region_name, doubles) SELECT region_name, ARRAY_APPEND(doubles,5) FROM source";
+ conn.createStatement().execute(dml);
+ conn.commit();
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT doubles FROM target");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{5.67, 7.87, new Double(9), new Double(5)};
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertTrue(rs.next());
+
+ doubles = new Double[]{56.7, 7.87, new Double(9.2), new Double(5)};
+ array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithUpsertSelect2() 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[])";
+ conn.createStatement().execute(ddl);
+
+ String dml = "UPSERT INTO source(region_name,varchars) VALUES('SF Bay Area',ARRAY_APPEND(ARRAY['abcd','b'],'c'))";
+ conn.createStatement().execute(dml);
+
+ dml = "UPSERT INTO source(region_name,varchars) VALUES('SF Bay Area2',ARRAY_APPEND(ARRAY['d','fgh'],'something'))";
+ conn.createStatement().execute(dml);
+ conn.commit();
+
+ dml = "UPSERT INTO target(region_name, varchars) SELECT region_name, ARRAY_APPEND(varchars,'stu') FROM source";
+ conn.createStatement().execute(dml);
+ conn.commit();
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT varchars FROM target");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"abcd", "b", "c", "stu"};
+ Array array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertTrue(rs.next());
+
+ strings = new String[]{"d", "fgh", "something", "stu"};
+ array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere1() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[2345,46345,23234,456,123]=ARRAY_APPEND(integers,123)");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere2() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE varchars[1]=ANY(ARRAY_APPEND(ARRAY['2345','46345','23234'],'1234'))");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere3() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY['2345','46345','23234','1234']=ARRAY_APPEND(ARRAY['2345','46345','23234'],'1234')");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere4() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[23.45,4634.5,2.3234,123.4]=ARRAY_APPEND(ARRAY[23.45,4634.5,2.3234],123.4)");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere5() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY['2345','46345','23234','foo']=ARRAY_APPEND(varchars,'foo')");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere6() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE chars2=ARRAY_APPEND(chars,'foo')");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionInWhere7() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT region_name FROM regions WHERE ARRAY[2,3,4]=ARRAY_APPEND(ARRAY[2,3],4)");
+ assertTrue(rs.next());
+
+ assertEquals("SF Bay Area", rs.getString(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionIntegerWithNull() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(NULL,NULL) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{2345, 46345, 23234, 456};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(null, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionVarcharWithNull() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(varchars,NULL) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"2345", "46345", "23234"};
+
+ Array array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionDoublesWithNull() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(doubles,NULL) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Double[] doubles = new Double[]{23.45, 46.345, 23.234, 45.6, 5.78};
+
+ Array array = conn.createArrayOf("DOUBLE", doubles);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionCharsWithNull() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(chars,NULL) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"a", "bbbb", "c", "ddd", "e"};
+
+ Array array = conn.createArrayOf("CHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionWithNull() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(integers,nullcheck) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{2345, 46345, 23234, 456};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test(expected = SQLException.class)
+ public void testArrayAppendFunctionCharLimitCheck() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTables(conn);
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(chars,char1) FROM regions WHERE region_name = 'SF Bay Area'");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"a", "bbbb", "c", "ddd", "e", "wert"};
+
+ Array array = conn.createArrayOf("CHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionIntegerDesc() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTablesDesc(conn, "INTEGER", "23");
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(integers,pk) FROM regions");
+ assertTrue(rs.next());
+
+ Integer[] integers = new Integer[]{2345, 46345, 23234, 456, 23};
+
+ Array array = conn.createArrayOf("INTEGER", integers);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+
+ }
+
+ @Test
+ public void testArrayAppendFunctionVarcharDesc() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTablesDesc(conn, "VARCHAR", "'e'");
+
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(varchars,pk) FROM regions");
+ assertTrue(rs.next());
+
+ String[] strings = new String[]{"2345", "46345", "23234", "e"};
+
+ Array array = conn.createArrayOf("VARCHAR", strings);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionBigIntDesc() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTablesDesc(conn, "BIGINT", "1112");
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(bigints,pk) FROM regions");
+ assertTrue(rs.next());
+
+ Long[] longs = new Long[]{12l, 34l, 56l, 78l, 910l, 1112l};
+
+ Array array = conn.createArrayOf("BIGINT", longs);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+
+ @Test
+ public void testArrayAppendFunctionBooleanDesc() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ initTablesDesc(conn, "BOOLEAN", "false");
+ ResultSet rs;
+ rs = conn.createStatement().executeQuery("SELECT ARRAY_APPEND(bools,pk) FROM regions");
+ assertTrue(rs.next());
+
+ Boolean[] booleans = new Boolean[]{true, false, false};
+
+ Array array = conn.createArrayOf("BOOLEAN", booleans);
+
+ assertEquals(array, rs.getArray(1));
+ assertFalse(rs.next());
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/7ef17181/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayAppendFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayAppendFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayAppendFunction.java
new file mode 100644
index 0000000..db92d61
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ArrayAppendFunction.java
@@ -0,0 +1,127 @@
+/*
+ * 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.exception.DataExceedsCapacityException;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.parse.FunctionParseNode;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.TypeMismatchException;
+import org.apache.phoenix.schema.types.*;
+import org.apache.phoenix.schema.tuple.Tuple;
+
+@FunctionParseNode.BuiltInFunction(name = ArrayAppendFunction.NAME, args = {
+ @FunctionParseNode.Argument(allowedTypes = {PBinaryArray.class,
+ PVarbinaryArray.class}),
+ @FunctionParseNode.Argument(allowedTypes = {PVarbinary.class}, defaultValue = "null")})
+public class ArrayAppendFunction extends ScalarFunction {
+
+ public static final String NAME = "ARRAY_APPEND";
+
+ public ArrayAppendFunction() {
+ }
+
+ public ArrayAppendFunction(List<Expression> children) throws TypeMismatchException {
+ super(children);
+
+ if (getDataType() != null && !(getElementExpr() instanceof LiteralExpression && getElementExpr().isNullable()) && !getElementDataType().isCoercibleTo(getBaseType())) {
+ throw TypeMismatchException.newException(getBaseType(), getElementDataType());
+ }
+
+ // If the base type of an element is fixed width, make sure the element being appended will fit
+ if (getDataType() != null && getElementExpr().getDataType().getByteSize() == null && getElementDataType() != null && getBaseType().isFixedWidth() && getElementDataType().isFixedWidth() && getArrayExpr().getMaxLength() != null &&
+ getElementExpr().getMaxLength() != null && getElementExpr().getMaxLength() > getArrayExpr().getMaxLength()) {
+ throw new DataExceedsCapacityException("");
+ }
+ // If the base type has a scale, make sure the element being appended has a scale less than or equal to it
+ if (getDataType() != null && getArrayExpr().getScale() != null && getElementExpr().getScale() != null &&
+ getElementExpr().getScale() > getArrayExpr().getScale()) {
+ throw new DataExceedsCapacityException(getBaseType(), getArrayExpr().getMaxLength(), getArrayExpr().getScale());
+ }
+ }
+
+ @Override
+ public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
+
+ if (!getArrayExpr().evaluate(tuple, ptr)) {
+ return false;
+ } else if (ptr.getLength() == 0) {
+ return true;
+ }
+ int arrayLength = PArrayDataType.getArrayLength(ptr, getBaseType(), getArrayExpr().getMaxLength());
+
+ int length = ptr.getLength();
+ int offset = ptr.getOffset();
+ byte[] arrayBytes = ptr.get();
+
+ if (!getElementExpr().evaluate(tuple, ptr) || ptr.getLength() == 0) {
+ ptr.set(arrayBytes, offset, length);
+ return true;
+ }
+
+ if (!getBaseType().isSizeCompatible(ptr, null, getElementDataType(), getElementExpr().getMaxLength(), getElementExpr().getScale(), getArrayExpr().getMaxLength(), getArrayExpr().getScale())) {
+ throw new DataExceedsCapacityException("");
+ }
+
+ getBaseType().coerceBytes(ptr, null, getElementDataType(), getElementExpr().getMaxLength(), getElementExpr().getScale(), getElementExpr().getSortOrder(), getArrayExpr().getMaxLength(), getArrayExpr().getScale(), getArrayExpr().getSortOrder());
+
+ return PArrayDataType.appendItemToArray(ptr, length, offset, arrayBytes, getBaseType(), arrayLength, getMaxLength(), getArrayExpr().getSortOrder());
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return children.get(0).getDataType();
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return this.children.get(0).getMaxLength();
+ }
+
+ @Override
+ public SortOrder getSortOrder() {
+ return getChildren().get(0).getSortOrder();
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ public Expression getArrayExpr() {
+ return getChildren().get(0);
+ }
+
+ public Expression getElementExpr() {
+ return getChildren().get(1);
+ }
+
+ public PDataType getBaseType() {
+ return PDataType.arrayBaseType(getArrayExpr().getDataType());
+ }
+
+ public PDataType getElementDataType() {
+ return getElementExpr().getDataType();
+ }
+
+
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/7ef17181/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayAppendFunctionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayAppendFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayAppendFunctionTest.java
new file mode 100644
index 0000000..2b4cb84
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/ArrayAppendFunctionTest.java
@@ -0,0 +1,345 @@
+/*
+ * 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.assertTrue;
+
+import java.math.BigDecimal;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.ArrayAppendFunction;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.*;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class ArrayAppendFunctionTest {
+
+ private static void testExpression(LiteralExpression array, LiteralExpression element, PhoenixArray expected)
+ throws SQLException {
+ List<Expression> expressions = Lists.newArrayList((Expression) array);
+ expressions.add(element);
+
+ Expression arrayAppendFunction = new ArrayAppendFunction(expressions);
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ arrayAppendFunction.evaluate(null, ptr);
+ PhoenixArray result = (PhoenixArray) arrayAppendFunction.getDataType().toObject(ptr, expressions.get(0).getSortOrder(), array.getMaxLength(), array.getScale());
+ assertTrue(result.equals(expected));
+ }
+
+ private static void test(PhoenixArray array, Object element, PDataType arrayDataType, Integer arrMaxLen, Integer arrScale, PDataType elementDataType, Integer elemMaxLen, Integer elemScale, PhoenixArray expected, SortOrder arraySortOrder, SortOrder elementSortOrder) throws SQLException {
+ LiteralExpression arrayLiteral, elementLiteral;
+ arrayLiteral = LiteralExpression.newConstant(array, arrayDataType, arrMaxLen, arrScale, arraySortOrder, Determinism.ALWAYS);
+ elementLiteral = LiteralExpression.newConstant(element, elementDataType, elemMaxLen, elemScale, elementSortOrder, Determinism.ALWAYS);
+ testExpression(arrayLiteral, elementLiteral, expected);
+ }
+
+ @Test
+ public void testArrayAppendFunction1() throws Exception {
+ Object[] o = new Object[]{1, 2, -3, 4};
+ Object[] o2 = new Object[]{1, 2, -3, 4, 5};
+ Object element = 5;
+ PDataType baseType = PInteger.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction2() throws Exception {
+ Object[] o = new Object[]{"1", "2", "3", "4"};
+ Object[] o2 = new Object[]{"1", "2", "3", "4", "56"};
+ Object element = "56";
+ PDataType baseType = PVarchar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction3() throws Exception {
+ //offset array short to int transition
+ Object[] o = new Object[Short.MAX_VALUE + 1];
+ for (int i = 0; i < o.length; i++) {
+ o[i] = "a";
+ }
+ Object[] o2 = new Object[Short.MAX_VALUE + 2];
+ for (int i = 0; i < o2.length - 1; i++) {
+ o2[i] = "a";
+ }
+ Object element = "b";
+ o2[o2.length - 1] = element;
+ PDataType baseType = PVarchar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction4() throws Exception {
+ //offset array int
+ Object[] o = new Object[Short.MAX_VALUE + 7];
+ for (int i = 0; i < o.length; i++) {
+ o[i] = "a";
+ }
+ Object[] o2 = new Object[Short.MAX_VALUE + 8];
+ for (int i = 0; i < o2.length - 1; i++) {
+ o2[i] = "a";
+ }
+ Object element = "b";
+ o2[o2.length - 1] = element;
+ PDataType baseType = PVarchar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction5() throws Exception {
+ Boolean[] o = new Boolean[]{true, false, false, true};
+ Boolean[] o2 = new Boolean[]{true, false, false, true, false};
+ Boolean element = false;
+ PDataType baseType = PBoolean.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction6() throws Exception {
+ Object[] o = new Object[]{new Float(2.3), new Float(7.9), new Float(-9.6), new Float(2.3)};
+ Object[] o2 = new Object[]{new Float(2.3), new Float(7.9), new Float(-9.6), new Float(2.3), new Float(8.9)};
+ Object element = 8.9;
+ PDataType baseType = PFloat.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveFloatPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveFloatPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction7() throws Exception {
+ Object[] o = new Object[]{4.78, 9.54, 2.34, -9.675, Double.MAX_VALUE};
+ Object[] o2 = new Object[]{4.78, 9.54, 2.34, -9.675, Double.MAX_VALUE, 12.67};
+ Object element = 12.67;
+ PDataType baseType = PDouble.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveDoublePhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveDoublePhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction8() throws Exception {
+ Object[] o = new Object[]{123l, 677l, 98789l, -78989l, 66787l};
+ Object[] o2 = new Object[]{123l, 677l, 98789l, -78989l, 66787l, 543l};
+ Object element = 543l;
+ PDataType baseType = PLong.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveLongPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveLongPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction9() throws Exception {
+ Object[] o = new Object[]{(short) 34, (short) -23, (short) -89, (short) 999, (short) 34};
+ Object[] o2 = new Object[]{(short) 34, (short) -23, (short) -89, (short) 999, (short) 34, (short) 7};
+ Object element = (short) 7;
+ PDataType baseType = PSmallint.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveShortPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveShortPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction10() throws Exception {
+ Object[] o = new Object[]{(byte) 4, (byte) 8, (byte) 9};
+ Object[] o2 = new Object[]{(byte) 4, (byte) 8, (byte) 9, (byte) 6};
+ Object element = (byte) 6;
+ PDataType baseType = PTinyint.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveBytePhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveBytePhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction11() throws Exception {
+ Object[] o = new Object[]{BigDecimal.valueOf(2345), BigDecimal.valueOf(-23.45), BigDecimal.valueOf(785)};
+ Object[] o2 = new Object[]{BigDecimal.valueOf(2345), BigDecimal.valueOf(-23.45), BigDecimal.valueOf(785), BigDecimal.valueOf(-19)};
+ Object element = BigDecimal.valueOf(-19);
+ PDataType baseType = PDecimal.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction12() throws Exception {
+ Calendar calendar = Calendar.getInstance();
+ java.util.Date currentDate = calendar.getTime();
+ java.sql.Date date = new java.sql.Date(currentDate.getTime());
+
+ Object[] o = new Object[]{date, date, date};
+ Object[] o2 = new Object[]{date, date, date, date};
+ PDataType baseType = PDate.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, date, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction13() throws Exception {
+ Calendar calendar = Calendar.getInstance();
+ java.util.Date currentDate = calendar.getTime();
+ java.sql.Time time = new java.sql.Time(currentDate.getTime());
+
+ Object[] o = new Object[]{time, time, time};
+ Object[] o2 = new Object[]{time, time, time, time};
+ PDataType baseType = PTime.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, time, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction14() throws Exception {
+ Calendar calendar = Calendar.getInstance();
+ java.util.Date currentDate = calendar.getTime();
+ java.sql.Timestamp timestamp = new java.sql.Timestamp(currentDate.getTime());
+
+ Object[] o = new Object[]{timestamp, timestamp, timestamp};
+ Object[] o2 = new Object[]{timestamp, timestamp, timestamp, timestamp};
+ PDataType baseType = PTimestamp.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, timestamp, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction15() throws Exception {
+ Object[] o = new Object[]{1, 2, -3, 4};
+ Object[] o2 = new Object[]{1, 2, -3, 4, 5};
+ Object element = 5;
+ PDataType baseType = PInteger.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.DESC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction16() throws Exception {
+ Object[] o = new Object[]{1, 2, -3, 4};
+ Object[] o2 = new Object[]{1, 2, -3, 4, 5};
+ Object element = 5;
+ PDataType baseType = PInteger.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.DESC, SortOrder.DESC);
+ }
+
+ @Test
+ public void testArrayAppendFunction17() throws Exception {
+ Object[] o = new Object[]{1, 2, -3, 4};
+ Object[] o2 = new Object[]{1, 2, -3, 4, 5};
+ Object element = 5;
+ PDataType baseType = PInteger.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveIntPhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.DESC);
+ }
+
+ @Test
+ public void testArrayAppendFunction18() throws Exception {
+ Object[] o = new Object[]{"1 ", "2 ", "3 ", "4 "};
+ Object[] o2 = new Object[]{"1", "2", "3", "4", "5"};
+ Object element = "5";
+ PDataType baseType = PChar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), 4, null, baseType, 1, null, expected, SortOrder.ASC, SortOrder.DESC);
+ }
+
+ @Test
+ public void testArrayAppendFunction19() throws Exception {
+ Object[] o = new Object[]{"1 ", "2 ", "3 ", "4 "};
+ Object[] o2 = new Object[]{"1", "2", "3", "4", "5"};
+ Object element = "5";
+ PDataType baseType = PChar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), 4, null, baseType, 1, null, expected, SortOrder.DESC, SortOrder.ASC);
+ }
+
+ @Test
+ public void testArrayAppendFunction20() throws Exception {
+ Object[] o = new Object[]{"1 ", "2 ", "3 ", "4 "};
+ Object[] o2 = new Object[]{"1", "2", "3", "4", "5"};
+ Object element = "5";
+ PDataType baseType = PChar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), 4, null, baseType, 1, null, expected, SortOrder.DESC, SortOrder.DESC);
+ }
+
+ @Test
+ public void testArrayAppendFunction21() throws Exception {
+ Object[] o = new Object[]{4.78, 9.54, 2.34, -9.675, Double.MAX_VALUE};
+ Object[] o2 = new Object[]{4.78, 9.54, 2.34, -9.675, Double.MAX_VALUE, 12.67};
+ Object element = 12.67;
+ PDataType baseType = PDouble.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray.PrimitiveDoublePhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray.PrimitiveDoublePhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), null, null, baseType, null, null, expected, SortOrder.ASC, SortOrder.DESC);
+ }
+
+ @Test
+ public void testArrayAppendFunction22() throws Exception {
+ Object[] o = new Object[]{"1 ", "2 ", "3 ", "4 "};
+ Object[] o2 = new Object[]{"1", "2", "3", "4"};
+ Object element = null;
+ PDataType baseType = PChar.INSTANCE;
+
+ PhoenixArray arr = new PhoenixArray(baseType, o);
+ PhoenixArray expected = new PhoenixArray(baseType, o2);
+ test(arr, element, PDataType.fromTypeId(baseType.getSqlType() + PDataType.ARRAY_TYPE_BASE), 4, null, baseType, 1, null, expected, SortOrder.ASC, SortOrder.DESC);
+ }
+
+}
[2/3] phoenix git commit: PHOENIX-1287 Use the joni byte[] regex
engine in place of j.u.regex (Shuxiong Ye)
Posted by ja...@apache.org.
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSubstrParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSubstrParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSubstrParseNode.java
new file mode 100644
index 0000000..a975550
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSubstrParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * 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.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSubstrFunction;
+import org.apache.phoenix.expression.function.RegexpSubstrFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpSubstrFunction;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+
+/**
+ * Parse node corresponding to {@link RegexpSubstrFunction}. It also acts as a factory for creating
+ * the right kind of RegexpSubstrFunction according to setting in
+ * QueryServices.USE_BYTE_BASED_REGEX_ATTRIB
+ */
+public class RegexpSubstrParseNode extends FunctionParseNode {
+
+ RegexpSubstrParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+ super(name, children, info);
+ }
+
+ @Override
+ public Expression create(List<Expression> children, StatementContext context)
+ throws SQLException {
+ QueryServices services = context.getConnection().getQueryServices();
+ boolean useByteBasedRegex =
+ services.getProps().getBoolean(QueryServices.USE_BYTE_BASED_REGEX_ATTRIB,
+ QueryServicesOptions.DEFAULT_USE_BYTE_BASED_REGEX);
+ if (useByteBasedRegex) {
+ return new ByteBasedRegexpSubstrFunction(children);
+ } else {
+ return new StringBasedRegexpSubstrFunction(children);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
index adf146d..3c6a6c1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java
@@ -50,6 +50,8 @@ public interface QueryServices extends SQLCloseable {
public static final String AUTO_COMMIT_ATTRIB = "phoenix.connection.autoCommit";
// consistency configuration setting
public static final String CONSISTENCY_ATTRIB = "phoenix.connection.consistency";
+ // joni byte regex engine setting
+ public static final String USE_BYTE_BASED_REGEX_ATTRIB = "phoenix.regex.byteBased";
/**
* max size to spool the the result into
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
index 884b820..5cc4fa7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java
@@ -61,6 +61,7 @@ import static org.apache.phoenix.query.QueryServices.STATS_UPDATE_FREQ_MS_ATTRIB
import static org.apache.phoenix.query.QueryServices.STATS_USE_CURRENT_TIME_ATTRIB;
import static org.apache.phoenix.query.QueryServices.THREAD_POOL_SIZE_ATTRIB;
import static org.apache.phoenix.query.QueryServices.THREAD_TIMEOUT_MS_ATTRIB;
+import static org.apache.phoenix.query.QueryServices.USE_BYTE_BASED_REGEX_ATTRIB;
import static org.apache.phoenix.query.QueryServices.USE_INDEXES_ATTRIB;
import java.util.Map.Entry;
@@ -68,10 +69,8 @@ import java.util.Map.Entry;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Coprocessor;
import org.apache.hadoop.hbase.client.Consistency;
-import org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory;
import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
import org.apache.hadoop.hbase.ipc.controller.ClientRpcControllerFactory;
-import org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory;
import org.apache.hadoop.hbase.regionserver.wal.WALCellCodec;
import org.apache.phoenix.schema.SaltingUtil;
import org.apache.phoenix.trace.util.Tracing;
@@ -194,6 +193,8 @@ public class QueryServicesOptions {
public static final String DEFAULT_CONSISTENCY_LEVEL = Consistency.STRONG.toString();
+ public static final boolean DEFAULT_USE_BYTE_BASED_REGEX = true;
+
private final Configuration config;
private QueryServicesOptions(Configuration config) {
@@ -247,6 +248,7 @@ public class QueryServicesOptions {
.setIfUnset(DELAY_FOR_SCHEMA_UPDATE_CHECK, DEFAULT_DELAY_FOR_SCHEMA_UPDATE_CHECK)
.setIfUnset(METRICS_ENABLED, DEFAULT_IS_METRICS_ENABLED)
.setIfUnset(RpcControllerFactory.CUSTOM_CONTROLLER_CONF_KEY, DEFAULT_CLIENT_RPC_CONTROLLER_FACTORY)
+ .setIfUnset(USE_BYTE_BASED_REGEX_ATTRIB, DEFAULT_USE_BYTE_BASED_REGEX)
;
// HBase sets this to 1, so we reset it to something more appropriate.
// Hopefully HBase will change this, because we can't know if a user set
@@ -450,6 +452,10 @@ public class QueryServicesOptions {
return config.getBoolean(METRICS_ENABLED, DEFAULT_IS_METRICS_ENABLED);
}
+ public boolean isUseByteBasedRegex() {
+ return config.getBoolean(USE_BYTE_BASED_REGEX_ATTRIB, DEFAULT_USE_BYTE_BASED_REGEX);
+ }
+
public QueryServicesOptions setMaxServerCacheTTLMs(int ttl) {
return set(MAX_SERVER_CACHE_TIME_TO_LIVE_MS_ATTRIB, ttl);
}
@@ -524,4 +530,8 @@ public class QueryServicesOptions {
return this;
}
+ public QueryServicesOptions setUseByteBasedRegex(boolean flag) {
+ config.setBoolean(USE_BYTE_BASED_REGEX_ATTRIB, flag);
+ return this;
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/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 b6dce34..c6861f7 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
@@ -21,6 +21,8 @@ import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.Format;
+import java.util.LinkedList;
+import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
@@ -755,4 +757,93 @@ public abstract class PArrayDataType<T> extends PDataType<T> {
buf.append(']');
return buf.toString();
}
+
+ static public class PArrayDataTypeBytesArrayBuilder<T> {
+ static private final int BYTE_ARRAY_DEFAULT_SIZE = 128;
+
+ private PDataType baseType;
+ private SortOrder sortOrder;
+ private List<Integer> offsetPos;
+ private TrustedByteArrayOutputStream byteStream;
+ private DataOutputStream oStream;
+ private int nulls;
+
+ public PArrayDataTypeBytesArrayBuilder(PDataType baseType, SortOrder sortOrder) {
+ this.baseType = baseType;
+ this.sortOrder = sortOrder;
+ offsetPos = new LinkedList<Integer>();
+ byteStream = new TrustedByteArrayOutputStream(BYTE_ARRAY_DEFAULT_SIZE);
+ oStream = new DataOutputStream(byteStream);
+ nulls = 0;
+ }
+
+ private void close() {
+ try {
+ if (byteStream != null) byteStream.close();
+ if (oStream != null) oStream.close();
+ byteStream = null;
+ oStream = null;
+ } catch (IOException ioe) {
+ }
+ }
+
+ public boolean appendElem(byte[] bytes) {
+ return appendElem(bytes, 0, bytes.length);
+ }
+
+ public boolean appendElem(byte[] bytes, int offset, int len) {
+ if (oStream == null || byteStream == null) return false;
+ try {
+ if (!baseType.isFixedWidth()) {
+ if (len == 0) {
+ offsetPos.add(byteStream.size());
+ nulls++;
+ } else {
+ nulls = serializeNulls(oStream, nulls);
+ offsetPos.add(byteStream.size());
+ if (sortOrder == SortOrder.DESC) {
+ SortOrder.invert(bytes, offset, bytes, offset, len);
+ }
+ oStream.write(bytes, offset, len);
+ oStream.write(QueryConstants.SEPARATOR_BYTE);
+ }
+ } else {
+ if (sortOrder == SortOrder.DESC) {
+ SortOrder.invert(bytes, offset, bytes, offset, len);
+ }
+ oStream.write(bytes, offset, len);
+ }
+ return true;
+ } catch (IOException e) {
+ }
+ return false;
+ }
+
+ public byte[] getBytesAndClose() {
+ try {
+ if (!baseType.isFixedWidth()) {
+ int noOfElements = offsetPos.size();
+ int[] offsetPosArray = new int[noOfElements];
+ int index = 0;
+ for (Integer i : offsetPos) {
+ offsetPosArray[index] = i;
+ ++index;
+ }
+ PArrayDataType.writeEndSeperatorForVarLengthArray(oStream);
+ noOfElements =
+ PArrayDataType.serailizeOffsetArrayIntoStream(oStream, byteStream,
+ noOfElements, offsetPosArray[offsetPosArray.length - 1],
+ offsetPosArray);
+ serializeHeaderInfoIntoStream(oStream, noOfElements);
+ }
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ ptr.set(byteStream.getBuffer(), 0, byteStream.size());
+ return ByteUtil.copyKeyBytesIfNecessary(ptr);
+ } catch (IOException e) {
+ } finally {
+ close();
+ }
+ return null;
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/util/StringUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/StringUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/StringUtil.java
index 4a7ae38..89ae43b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/StringUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/StringUtil.java
@@ -115,7 +115,13 @@ public class StringUtil {
}
public static int getBytesInChar(byte b, SortOrder sortOrder) {
- Preconditions.checkNotNull(sortOrder);
+ int ret = getBytesInCharNoException(b, sortOrder);
+ if (ret == -1) throw new UndecodableByteException(b);
+ return ret;
+ }
+
+ private static int getBytesInCharNoException(byte b, SortOrder sortOrder) {
+ Preconditions.checkNotNull(sortOrder);
if (sortOrder == SortOrder.DESC) {
b = SortOrder.invert(b);
}
@@ -128,8 +134,7 @@ public class StringUtil {
return 3;
if ((c & BYTES_4_MASK) == 0xF0)
return 4;
- // Any thing else in the first byte is invalid
- throw new UndecodableByteException(b);
+ return -1;
}
public static int calculateUTF8Length(byte[] bytes, int offset, int length, SortOrder sortOrder) {
@@ -143,6 +148,63 @@ public class StringUtil {
return length;
}
+ // given an array of bytes containing utf-8 encoded strings, starting from curPos, ending before
+ // range, and return the next character offset, -1 if no next character available or
+ // UndecodableByteException
+ private static int calculateNextCharOffset(byte[] bytes, int curPos, int range,
+ SortOrder sortOrder) {
+ int ret = getBytesInCharNoException(bytes[curPos], sortOrder);
+ if (ret == -1) return -1;
+ ret += curPos;
+ if (ret >= range) return -1;
+ return ret;
+ }
+
+ // given an array of bytes containing utf-8 encoded strings, starting from offset, and return
+ // the previous character offset , -1 if UndecodableByteException. curPos points to current
+ // character starting offset.
+ private static int calculatePreCharOffset(byte[] bytes, int curPos, int offset,
+ SortOrder sortOrder) {
+ --curPos;
+ for (int i = 1, pos = curPos - i + 1; i <= 4 && offset <= pos; ++i, --pos) {
+ int ret = getBytesInCharNoException(bytes[pos], sortOrder);
+ if (ret == i) return pos;
+ }
+ return -1;
+ }
+
+ // return actural offsetInBytes corresponding to offsetInStr in utf-8 encoded strings bytes
+ // containing
+ // @param bytes an array of bytes containing utf-8 encoded strings
+ // @param offset
+ // @param length
+ // @param sortOrder
+ // @param offsetInStr offset for utf-8 encoded strings bytes array containing. Can be negative
+ // meaning counting from the end of encoded strings
+ // @return actural offsetInBytes corresponding to offsetInStr. -1 if offsetInStr is out of index
+ public static int calculateUTF8Offset(byte[] bytes, int offset, int length,
+ SortOrder sortOrder, int offsetInStr) {
+ if (offsetInStr == 0) return offset;
+ int ret, range = offset + length;
+ if (offsetInStr > 0) {
+ ret = offset;
+ while (offsetInStr > 0) {
+ ret = calculateNextCharOffset(bytes, ret, range, sortOrder);
+ if (ret == -1) return -1;
+ --offsetInStr;
+ }
+ } else {
+ ret = offset + length;
+ while (offsetInStr < 0) {
+ ret = calculatePreCharOffset(bytes, ret, offset, sortOrder);
+ // if calculateCurCharOffset returns -1, ret must be smaller than offset
+ if (ret < offset) return -1;
+ ++offsetInStr;
+ }
+ }
+ return ret;
+ }
+
// Given an array of bytes containing encoding utf-8 encoded strings, the offset and a length
// parameter, return the actual index into the byte array which would represent a substring
// of <length> starting from the character at <offset>. We assume the <offset> is the start
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
index 94b25d0..f40afc3 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/WhereOptimizerTest.java
@@ -731,7 +731,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(like(
ENTITY_ID,
- likeArg)),
+ likeArg,
+ context)),
filter);
byte[] startRow = ByteUtil.concat(
@@ -757,7 +758,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(like(
ENTITY_ID,
- likeArg)),
+ likeArg,
+ context)),
filter);
byte[] startRow = ByteUtil.concat(
@@ -783,7 +785,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(like(
substr(ENTITY_ID,1,10),
- likeArg)),
+ likeArg,
+ context)),
filter);
byte[] startRow = ByteUtil.concat(
@@ -809,7 +812,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(like(
substr(ENTITY_ID,4,10),
- likeArg)),
+ likeArg,
+ context)),
filter);
byte[] startRow = PVarchar.INSTANCE.toBytes(tenantId);
@@ -832,7 +836,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(like(
ENTITY_ID,
- likeArg)),
+ likeArg,
+ context)),
filter);
byte[] startRow = PVarchar.INSTANCE.toBytes(tenantId);
@@ -855,7 +860,8 @@ public class WhereOptimizerTest extends BaseConnectionlessQueryTest {
assertEquals(
rowKeyFilter(not(like(
ENTITY_ID,
- likeArg))),
+ likeArg,
+ context))),
filter);
byte[] startRow = PVarchar.INSTANCE.toBytes(tenantId);
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/ILikeExpressionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/ILikeExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/ILikeExpressionTest.java
index 3033edf..e66ad13 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/expression/ILikeExpressionTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/ILikeExpressionTest.java
@@ -20,24 +20,40 @@ package org.apache.phoenix.expression;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.phoenix.parse.LikeParseNode.LikeType;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PVarchar;
import org.junit.Test;
public class ILikeExpressionTest {
- public boolean testExpression (String value, String expression) {
- LiteralExpression v = LiteralExpression.newConstant(value);
- LiteralExpression p = LiteralExpression.newConstant(expression);
+ private boolean testExpression (String value, String expression, SortOrder sortorder)
+ throws SQLException {
+ LiteralExpression v = LiteralExpression.newConstant(value, PVarchar.INSTANCE, sortorder);
+ LiteralExpression p = LiteralExpression.newConstant(expression, PVarchar.INSTANCE, sortorder);
List<Expression> children = Arrays.<Expression>asList(v,p);
- LikeExpression e = LikeExpression.create(children, LikeType.CASE_INSENSITIVE);
+ LikeExpression e1 = ByteBasedLikeExpression.create(children, LikeType.CASE_INSENSITIVE);
+ LikeExpression e2 = StringBasedLikeExpression.create(children, LikeType.CASE_INSENSITIVE);
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
- boolean evaluated = e.evaluate(null, ptr);
- Boolean result = (Boolean)e.getDataType().toObject(ptr);
- assertTrue(evaluated);
- return result;
+ boolean evaluated1 = e1.evaluate(null, ptr);
+ Boolean result1 = (Boolean)e1.getDataType().toObject(ptr);
+ assertTrue(evaluated1);
+ boolean evaluated2 = e2.evaluate(null, ptr);
+ Boolean result2 = (Boolean)e2.getDataType().toObject(ptr);
+ assertTrue(evaluated2);
+ assertEquals(result1, result2);
+ return result1;
+ }
+
+ private boolean testExpression(String value, String expression) throws SQLException {
+ boolean result1 = testExpression(value, expression, SortOrder.ASC);
+ boolean result2 = testExpression(value, expression, SortOrder.DESC);
+ assertEquals(result1, result2);
+ return result1;
}
@Test
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/LikeExpressionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/LikeExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/LikeExpressionTest.java
index 27e6547..0bf8b06 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/expression/LikeExpressionTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/LikeExpressionTest.java
@@ -20,25 +20,42 @@ package org.apache.phoenix.expression;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.phoenix.parse.LikeParseNode.LikeType;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PVarchar;
import org.junit.Test;
public class LikeExpressionTest {
- public boolean testExpression (String value, String expression) {
- LiteralExpression v = LiteralExpression.newConstant(value);
- LiteralExpression p = LiteralExpression.newConstant(expression);
+ private boolean testExpression(String value, String expression, SortOrder sortorder)
+ throws SQLException {
+ LiteralExpression v = LiteralExpression.newConstant(value, PVarchar.INSTANCE, sortorder);
+ LiteralExpression p = LiteralExpression.newConstant(expression, PVarchar.INSTANCE, sortorder);
List<Expression> children = Arrays.<Expression>asList(v,p);
- LikeExpression e = LikeExpression.create(children, LikeType.CASE_SENSITIVE);
+ LikeExpression e1 = ByteBasedLikeExpression.create(children, LikeType.CASE_SENSITIVE);
+ LikeExpression e2 = StringBasedLikeExpression.create(children, LikeType.CASE_SENSITIVE);
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
- boolean evaluated = e.evaluate(null, ptr);
- Boolean result = (Boolean)e.getDataType().toObject(ptr);
- assertTrue(evaluated);
- return result;
+ boolean evaluated1 = e1.evaluate(null, ptr);
+ Boolean result1 = (Boolean)e1.getDataType().toObject(ptr);
+ assertTrue(evaluated1);
+ boolean evaluated2 = e2.evaluate(null, ptr);
+ Boolean result2 = (Boolean)e2.getDataType().toObject(ptr);
+ assertTrue(evaluated2);
+ assertEquals(result1, result2);
+ return result1;
}
+
+ private boolean testExpression(String value, String expression) throws SQLException {
+ boolean result1 = testExpression(value, expression, SortOrder.ASC);
+ boolean result2 = testExpression(value, expression, SortOrder.DESC);
+ assertEquals(result1, result2);
+ return result1;
+ }
+
@Test
public void testStartWildcard() throws Exception {
assertEquals(Boolean.FALSE, testExpression ("149na7-app1-2-", "%-w"));
@@ -58,4 +75,10 @@ public class LikeExpressionTest {
assertEquals(Boolean.TRUE, testExpression ("test", "%s%"));
assertEquals(Boolean.FALSE, testExpression ("test", "%S%"));
}
+
+ @Test
+ public void testEmptySourceStr() throws Exception {
+ assertEquals(Boolean.TRUE, testExpression ("", "%"));
+ assertEquals(Boolean.FALSE, testExpression ("", "_"));
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpReplaceFunctionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpReplaceFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpReplaceFunctionTest.java
new file mode 100644
index 0000000..ad11c1b
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpReplaceFunctionTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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 static org.junit.Assert.assertTrue;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.ByteBasedRegexpReplaceFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpReplaceFunction;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class RegexpReplaceFunctionTest {
+ private final static PVarchar TYPE = PVarchar.INSTANCE;
+
+ private String evalExp(Expression exp) {
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ boolean eval = exp.evaluate(null, ptr);
+ assertTrue(eval);
+ String res = (String) exp.getDataType().toObject(ptr);
+ return res;
+ }
+
+ private String testExpression(String srcStr, String patternStr, String replaceStr,
+ SortOrder sortOrder) throws SQLException {
+ Expression srcExp, patternExp, replaceExp;
+ srcExp = LiteralExpression.newConstant(srcStr, TYPE, sortOrder);
+ patternExp = LiteralExpression.newConstant(patternStr, TYPE, sortOrder);
+ replaceExp = LiteralExpression.newConstant(replaceStr, TYPE, sortOrder);
+ List<Expression> expressions = Lists.newArrayList(srcExp, patternExp, replaceExp);
+ String res1, res2;
+ res1 = evalExp(new ByteBasedRegexpReplaceFunction(expressions));
+ res2 = evalExp(new StringBasedRegexpReplaceFunction(expressions));
+ assertEquals(res1, res2);
+ return res1;
+ }
+
+ private String testExpression(String srcStr, String patternStr, String replaceStr)
+ throws SQLException {
+ String result1 = testExpression(srcStr, patternStr, replaceStr, SortOrder.ASC);
+ String result2 = testExpression(srcStr, patternStr, replaceStr, SortOrder.DESC);
+ assertEquals(result1, result2);
+ return result1;
+ }
+
+ private void testExpression(String srcStr, String patternStr, String replaceStr,
+ String expectedStr) throws SQLException {
+ String result = testExpression(srcStr, patternStr, replaceStr);
+ assertEquals(expectedStr, result);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testExpression("aa11bb22cc33dd44ee", "[0-9]+", "*", "aa*bb*cc*dd*ee");
+ testExpression("aa11bb22cc33dd44ee", "[0-9]+", "", "aabbccddee");
+ testExpression("aa11bb22cc33dd44ee", "[a-z][0-9]", "", "a1b2c3d4ee");
+ testExpression("aa11bb22cc33dd44ee", "[a-z0-9]+", "", (String) null);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSplitFunctionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSplitFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSplitFunctionTest.java
new file mode 100644
index 0000000..6157ce0
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSplitFunctionTest.java
@@ -0,0 +1,94 @@
+/*
+ * 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 static org.junit.Assert.assertTrue;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSplitFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpSplitFunction;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.schema.types.PhoenixArray;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class RegexpSplitFunctionTest {
+ private final static PVarchar TYPE = PVarchar.INSTANCE;
+
+ private String[] evalExp(Expression exp) throws SQLException {
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ boolean eval = exp.evaluate(null, ptr);
+ assertTrue(eval);
+ PhoenixArray evalRes = (PhoenixArray) exp.getDataType().toObject(ptr);
+ String[] res = (String[]) evalRes.getArray();
+ return res;
+ }
+
+ private String[] testExpression(String srcStr, String patternStr, SortOrder sortOrder)
+ throws SQLException {
+ Expression srcExp, patternExp;
+ srcExp = LiteralExpression.newConstant(srcStr, TYPE, sortOrder);
+ patternExp = LiteralExpression.newConstant(patternStr, TYPE, sortOrder);
+ List<Expression> expressions = Lists.newArrayList(srcExp, patternExp);
+ String[] res1, res2;
+ res1 = evalExp(new ByteBasedRegexpSplitFunction(expressions));
+ res2 = evalExp(new StringBasedRegexpSplitFunction(expressions));
+ testEqual(res2, res1);
+ return res1;
+ }
+
+ private String[] testExpression(String srcStr, String patternStr) throws SQLException {
+ String[] result1 = testExpression(srcStr, patternStr, SortOrder.ASC);
+ String[] result2 = testExpression(srcStr, patternStr, SortOrder.DESC);
+ testEqual(result1, result2);
+ return result1;
+ }
+
+ private void testEqual(String[] expectedStr, String[] result) {
+ if (result == null ^ expectedStr == null) return;
+ if (expectedStr == null) return;
+ assertEquals(expectedStr.length, result.length);
+ for (int i = 0; i < expectedStr.length; ++i)
+ assertEquals(expectedStr[i], result[i]);
+ }
+
+ private void testExpression(String srcStr, String patternStr, String[] expectedStr)
+ throws SQLException {
+ String[] result = testExpression(srcStr, patternStr);
+ testEqual(expectedStr, result);
+ }
+
+ @Test
+ public void test() throws Exception {
+ String[] res = new String[] { "ONE", "TWO", "THREE" };
+ testExpression("ONE:TWO:THREE", ":", res);
+ testExpression("ONE,TWO,THREE", ",", res);
+ testExpression("12ONE34TWO56THREE78", "[0-9]+", new String[] { null, "ONE", "TWO", "THREE",
+ null });
+ testExpression("ONE34TWO56THREE78", "[0-9]+", new String[] { "ONE", "TWO", "THREE", null });
+ testExpression("123ONE34TWO56THREE", "[0-9]+", new String[] { null, "ONE", "TWO", "THREE" });
+ testExpression("123", "[0-9]+", new String[] { null, null });
+ testExpression("ONE", "[0-9]+", new String[] { "ONE" });
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSubstrFunctionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSubstrFunctionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSubstrFunctionTest.java
new file mode 100644
index 0000000..c2889b3
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/RegexpSubstrFunctionTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 static org.junit.Assert.assertTrue;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSubstrFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpSubstrFunction;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PInteger;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class RegexpSubstrFunctionTest {
+ private final static PVarchar TYPE = PVarchar.INSTANCE;
+
+ private String evalExp(Expression exp) {
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ boolean eval = exp.evaluate(null, ptr);
+ assertTrue(eval);
+ String res = (String) exp.getDataType().toObject(ptr);
+ return res;
+ }
+
+ private String testExpression(String srcStr, String patternStr, int offset, SortOrder sortOrder) throws SQLException {
+ Expression srcExp, patternExp, offsetExp;
+ srcExp = LiteralExpression.newConstant(srcStr, TYPE, sortOrder);
+ patternExp = LiteralExpression.newConstant(patternStr, TYPE, sortOrder);
+ offsetExp = LiteralExpression.newConstant(offset, PInteger.INSTANCE, sortOrder);
+ List<Expression> expressions = Lists.newArrayList(srcExp, patternExp, offsetExp);
+ String res1, res2;
+ res1 = evalExp(new ByteBasedRegexpSubstrFunction(expressions));
+ res2 = evalExp(new StringBasedRegexpSubstrFunction(expressions));
+ assertEquals(res1, res2);
+ return res1;
+ }
+
+ private String testExpression(String srcStr, String patternStr, int offset) throws SQLException {
+ String result1 = testExpression(srcStr, patternStr, offset, SortOrder.ASC);
+ String result2 = testExpression(srcStr, patternStr, offset, SortOrder.DESC);
+ assertEquals(result1, result2);
+ return result1;
+ }
+
+ private void testExpression(String srcStr, String patternStr, int offset, String expectedStr)
+ throws SQLException {
+ String result = testExpression(srcStr, patternStr, offset);
+ assertEquals(expectedStr, result);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testExpression("Report1?1", "[^\\\\?]+", 1, "Report1");
+ testExpression("Report1?2", "[^\\\\?]+", 1, "Report1");
+ testExpression("Report2?1", "[^\\\\?]+", 1, "Report2");
+ testExpression("Report3?2", "[^\\\\?]+", 1, "Report3");
+ testExpression("Report3?2", "[4-9]+", 0, (String) null);
+ testExpression("Report3?2", "[^\\\\?]+", 2, "eport3");
+ testExpression("Report3?2", "[^\\\\?]+", -5, "rt3");
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java
index 8fb1a6c..b9ee0eb 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/SortOrderExpressionTest.java
@@ -30,16 +30,18 @@ import java.util.TimeZone;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.expression.function.ByteBasedRegexpReplaceFunction;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSubstrFunction;
import org.apache.phoenix.expression.function.FunctionArgumentType;
import org.apache.phoenix.expression.function.LTrimFunction;
import org.apache.phoenix.expression.function.LengthFunction;
import org.apache.phoenix.expression.function.LowerFunction;
import org.apache.phoenix.expression.function.LpadFunction;
import org.apache.phoenix.expression.function.RTrimFunction;
-import org.apache.phoenix.expression.function.RegexpReplaceFunction;
-import org.apache.phoenix.expression.function.RegexpSubstrFunction;
import org.apache.phoenix.expression.function.RoundDateExpression;
import org.apache.phoenix.expression.function.SqlTypeNameFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpReplaceFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpSubstrFunction;
import org.apache.phoenix.expression.function.SubstrFunction;
import org.apache.phoenix.expression.function.ToCharFunction;
import org.apache.phoenix.expression.function.ToDateFunction;
@@ -80,13 +82,15 @@ public class SortOrderExpressionTest {
@Test
public void regexpSubstr() throws Exception {
List<Expression> args = Lists.newArrayList(getInvertedLiteral("blah", PChar.INSTANCE), getLiteral("l.h"), getLiteral(2));
- evaluateAndAssertResult(new RegexpSubstrFunction(args), "lah");
+ evaluateAndAssertResult(new StringBasedRegexpSubstrFunction(args), "lah");
+ evaluateAndAssertResult(new ByteBasedRegexpSubstrFunction(args), "lah");
}
@Test
public void regexpReplace() throws Exception {
List<Expression> args = Lists.newArrayList(getInvertedLiteral("blah", PChar.INSTANCE), getLiteral("l.h"), getLiteral("foo"));
- evaluateAndAssertResult(new RegexpReplaceFunction(args), "bfoo");
+ evaluateAndAssertResult(new ByteBasedRegexpReplaceFunction(args), "bfoo");
+ evaluateAndAssertResult(new StringBasedRegexpReplaceFunction(args), "bfoo");
}
@Test
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/expression/util/regex/PatternPerformanceTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/expression/util/regex/PatternPerformanceTest.java b/phoenix-core/src/test/java/org/apache/phoenix/expression/util/regex/PatternPerformanceTest.java
new file mode 100644
index 0000000..908c662
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/expression/util/regex/PatternPerformanceTest.java
@@ -0,0 +1,144 @@
+/*
+ * 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.util.regex;
+
+import static org.junit.Assert.assertTrue;
+
+import java.sql.SQLException;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.schema.types.PBoolean;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.schema.types.PVarcharArray;
+import org.apache.phoenix.schema.types.PhoenixArray;
+import org.junit.Test;
+
+public class PatternPerformanceTest {
+
+ static private class Timer {
+ private long startTimeStamp;
+
+ public void reset() {
+ startTimeStamp = System.currentTimeMillis();
+ }
+
+ public double currentTime() {
+ return (System.currentTimeMillis() - startTimeStamp) / 1000.0;
+ }
+
+ public void printTime(String hint) {
+ System.out.println(hint + " Time=" + currentTime());
+ }
+ }
+
+ private String[] data = new String[] { "ONE:TWO:THREE", "ABC:DEF", "PKU:THU:FDU" };
+ private ImmutableBytesWritable[] dataPtr = new ImmutableBytesWritable[] { getPtr(data[0]),
+ getPtr(data[1]), getPtr(data[2]) };
+ private String patternString;
+ private ImmutableBytesWritable resultPtr = new ImmutableBytesWritable();
+ private int maxTimes = 10000000;
+ private Timer timer = new Timer();
+ private final boolean ENABLE_ASSERT = false;
+
+ private static ImmutableBytesWritable getPtr(String str) {
+ return new ImmutableBytesWritable(PVarchar.INSTANCE.toBytes(str));
+ }
+
+ private void testReplaceAll(ImmutableBytesWritable replacePtr, AbstractBasePattern pattern,
+ String name) {
+ timer.reset();
+ for (int i = 0; i < maxTimes; ++i) {
+ pattern.replaceAll(dataPtr[i % 3], replacePtr, resultPtr);
+ if (ENABLE_ASSERT) {
+ String result = (String) PVarchar.INSTANCE.toObject(resultPtr);
+ assertTrue((i % 3 == 1 && ":".equals(result))
+ || (i % 3 != 1 && "::".equals(result)));
+ }
+ }
+ timer.printTime(name);
+ }
+
+ public void testReplaceAll() {
+ patternString = "[A-Z]+";
+ ImmutableBytesWritable replacePtr = getPtr("");
+ testReplaceAll(replacePtr, new JavaPattern(patternString), "Java replaceAll");
+ testReplaceAll(replacePtr, new JONIPattern(patternString), "JONI replaceAll");
+ }
+
+ private void testLike(AbstractBasePattern pattern, String name) {
+ timer.reset();
+ for (int i = 0; i < maxTimes; ++i) {
+ pattern.matches(dataPtr[i % 3], resultPtr);
+ if (ENABLE_ASSERT) {
+ Boolean b = (Boolean) PBoolean.INSTANCE.toObject(resultPtr);
+ assertTrue(i % 3 != 2 || b.booleanValue());
+ }
+ }
+ timer.printTime(name);
+ }
+
+ public void testLike() {
+ patternString = "\\Q\\E.*\\QU\\E.*\\QU\\E.*\\QU\\E.*\\Q\\E";
+ testLike(new JavaPattern(patternString), "Java Like");
+ testLike(new JONIPattern(patternString), "JONI Like");
+ }
+
+ private void testSubstr(AbstractBasePattern pattern, String name) {
+ timer.reset();
+ for (int i = 0; i < maxTimes; ++i) {
+ boolean ret = pattern.substr(dataPtr[i % 3], 0, resultPtr);
+ if (ENABLE_ASSERT) {
+ assertTrue(ret
+ && (i % 3 != 2 || ":THU".equals(PVarchar.INSTANCE.toObject(resultPtr))));
+ }
+ }
+ timer.printTime(name);
+ }
+
+ public void testSubstr() {
+ patternString = "\\:[A-Z]+";
+ testSubstr(new JavaPattern(patternString), "Java Substr");
+ testSubstr(new JONIPattern(patternString), "JONI Substr");
+ }
+
+ private void testSplit(AbstractBaseSplitter pattern, String name) throws SQLException {
+ timer.reset();
+ for (int i = 0; i < maxTimes; ++i) {
+ boolean ret = pattern.split(dataPtr[i % 3], resultPtr);
+ if (ENABLE_ASSERT) {
+ PhoenixArray array = (PhoenixArray) PVarcharArray.INSTANCE.toObject(resultPtr);
+ assertTrue(ret && (i % 3 != 1 || ((String[]) array.getArray()).length == 2));
+ }
+ }
+ timer.printTime(name);
+ }
+
+ public void testSplit() throws SQLException {
+ patternString = "\\:";
+ testSplit(new GuavaSplitter(patternString), "GuavaSplit");
+ testSplit(new JONIPattern(patternString), "JONI Split");
+ }
+
+ @Test
+ public void test() throws Exception {
+ // testLike();
+ // testReplaceAll();
+ // testSubstr();
+ // testSplit();
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/util/StringUtilTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/StringUtilTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/StringUtilTest.java
index 9c218fb..6d00562 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/StringUtilTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/StringUtilTest.java
@@ -17,7 +17,9 @@
package org.apache.phoenix.util;
import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import org.apache.phoenix.schema.SortOrder;
import org.junit.Test;
public class StringUtilTest {
@@ -48,5 +50,33 @@ public class StringUtilTest {
public void testLpadZeroPadding() throws Exception {
testLpad("ABCD", 4, "1234", "ABCD");
}
-
+
+ @Test
+ public void testCalculateUTF8Offset() throws Exception {
+ String tmp, padding = "padding", data = "零一二三四五六七八九", trailing = "trailing";
+ byte[] bytes = (padding + data + trailing).getBytes();
+ int ret, offset = padding.getBytes().length, length = data.getBytes().length;
+
+ tmp = padding;
+ for (int i = 0; i < data.length(); ++i) {
+ ret = StringUtil.calculateUTF8Offset(bytes, offset, length, SortOrder.ASC, i);
+ assertEquals(tmp.getBytes().length, ret);
+ tmp = tmp + data.charAt(i);
+ }
+ for (int i = data.length(); i < data.length() + 10; ++i) {
+ ret = StringUtil.calculateUTF8Offset(bytes, offset, length, SortOrder.ASC, i);
+ assertEquals(-1, ret);
+ }
+
+ for (int i = -data.length() - 10; i < -data.length(); ++i) {
+ ret = StringUtil.calculateUTF8Offset(bytes, offset, length, SortOrder.ASC, i);
+ assertEquals(-1, ret);
+ }
+ tmp = padding;
+ for (int i = -data.length(); i <= -1; ++i) {
+ ret = StringUtil.calculateUTF8Offset(bytes, offset, length, SortOrder.ASC, i);
+ assertEquals("i=" + i, tmp.getBytes().length, ret);
+ tmp = tmp + data.charAt(i + data.length());
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
index 872c318..66695f8 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/TestUtil.java
@@ -56,15 +56,16 @@ import org.apache.phoenix.coprocessor.generated.MetaDataProtos.ClearCacheRequest
import org.apache.phoenix.coprocessor.generated.MetaDataProtos.ClearCacheResponse;
import org.apache.phoenix.coprocessor.generated.MetaDataProtos.MetaDataService;
import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.ByteBasedLikeExpression;
import org.apache.phoenix.expression.ComparisonExpression;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.expression.InListExpression;
import org.apache.phoenix.expression.KeyValueColumnExpression;
-import org.apache.phoenix.expression.LikeExpression;
import org.apache.phoenix.expression.LiteralExpression;
import org.apache.phoenix.expression.NotExpression;
import org.apache.phoenix.expression.OrExpression;
import org.apache.phoenix.expression.RowKeyColumnExpression;
+import org.apache.phoenix.expression.StringBasedLikeExpression;
import org.apache.phoenix.expression.function.SubstrFunction;
import org.apache.phoenix.filter.MultiCQKeyValueComparisonFilter;
import org.apache.phoenix.filter.MultiKeyValueComparisonFilter;
@@ -77,6 +78,8 @@ import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
import org.apache.phoenix.parse.LikeParseNode.LikeType;
import org.apache.phoenix.query.KeyRange;
import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.RowKeyValueAccessor;
import org.apache.phoenix.schema.TableRef;
@@ -264,13 +267,26 @@ public class TestUtil {
return new ComparisonExpression(Arrays.asList(e, LiteralExpression.newConstant(o)), op);
}
- public static Expression like(Expression e, Object o) {
- return LikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_SENSITIVE);
+ private static boolean useByteBasedRegex(StatementContext context) {
+ return context
+ .getConnection()
+ .getQueryServices()
+ .getProps()
+ .getBoolean(QueryServices.USE_BYTE_BASED_REGEX_ATTRIB,
+ QueryServicesOptions.DEFAULT_USE_BYTE_BASED_REGEX);
}
- public static Expression ilike(Expression e, Object o) {
- return LikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_INSENSITIVE);
- }
+ public static Expression like(Expression e, Object o, StatementContext context) {
+ return useByteBasedRegex(context)?
+ ByteBasedLikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_SENSITIVE):
+ StringBasedLikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_SENSITIVE);
+ }
+
+ public static Expression ilike(Expression e, Object o, StatementContext context) {
+ return useByteBasedRegex(context)?
+ ByteBasedLikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_INSENSITIVE):
+ StringBasedLikeExpression.create(Arrays.asList(e, LiteralExpression.newConstant(o)), LikeType.CASE_INSENSITIVE);
+ }
public static Expression substr(Expression e, Object offset, Object length) {
return new SubstrFunction(Arrays.asList(e, LiteralExpression.newConstant(offset), LiteralExpression.newConstant(length)));
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 4793cf2..c2ff589 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,6 +105,7 @@
<htrace.version>3.1.0-incubating</htrace.version>
<collections.version>3.2.1</collections.version>
<jodatime.version>2.7</jodatime.version>
+ <joni.version>2.1.2</joni.version>
<!-- Test Dependencies -->
<mockito-all.version>1.8.5</mockito-all.version>
[3/3] phoenix git commit: PHOENIX-1287 Use the joni byte[] regex
engine in place of j.u.regex (Shuxiong Ye)
Posted by ja...@apache.org.
PHOENIX-1287 Use the joni byte[] regex engine in place of j.u.regex (Shuxiong Ye)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/3f6b2594
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/3f6b2594
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/3f6b2594
Branch: refs/heads/master
Commit: 3f6b25947d07ea0d7756556dd80e951f12ceda69
Parents: 7ef1718
Author: James Taylor <jt...@salesforce.com>
Authored: Tue Apr 14 12:09:17 2015 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Tue Apr 14 12:09:17 2015 -0700
----------------------------------------------------------------------
.../src/build/components-major-client.xml | 2 +
phoenix-core/pom.xml | 5 +
.../phoenix/end2end/LikeExpressionIT.java | 88 ++++++++
.../end2end/RegexpReplaceFunctionIT.java | 100 +++++++++
.../phoenix/end2end/RegexpSubstrFunctionIT.java | 43 ++--
.../phoenix/compile/ExpressionCompiler.java | 15 +-
.../expression/ByteBasedLikeExpression.java | 48 +++++
.../phoenix/expression/ExpressionType.java | 16 +-
.../phoenix/expression/LikeExpression.java | 64 +++---
.../expression/StringBasedLikeExpression.java | 48 +++++
.../ByteBasedRegexpReplaceFunction.java | 40 ++++
.../function/ByteBasedRegexpSplitFunction.java | 38 ++++
.../function/ByteBasedRegexpSubstrFunction.java | 38 ++++
.../function/RegexpReplaceFunction.java | 38 ++--
.../function/RegexpSplitFunction.java | 54 +++--
.../function/RegexpSubstrFunction.java | 48 ++---
.../StringBasedRegexpReplaceFunction.java | 40 ++++
.../StringBasedRegexpSplitFunction.java | 38 ++++
.../StringBasedRegexpSubstrFunction.java | 38 ++++
.../util/regex/AbstractBasePattern.java | 33 +++
.../util/regex/AbstractBaseSplitter.java | 24 +++
.../expression/util/regex/GuavaSplitter.java | 54 +++++
.../expression/util/regex/JONIPattern.java | 201 +++++++++++++++++++
.../expression/util/regex/JavaPattern.java | 93 +++++++++
.../visitor/CloneExpressionVisitor.java | 3 +-
.../phoenix/parse/RegexpReplaceParseNode.java | 55 +++++
.../phoenix/parse/RegexpSplitParseNode.java | 55 +++++
.../phoenix/parse/RegexpSubstrParseNode.java | 55 +++++
.../org/apache/phoenix/query/QueryServices.java | 2 +
.../phoenix/query/QueryServicesOptions.java | 14 +-
.../phoenix/schema/types/PArrayDataType.java | 91 +++++++++
.../org/apache/phoenix/util/StringUtil.java | 68 ++++++-
.../phoenix/compile/WhereOptimizerTest.java | 18 +-
.../phoenix/expression/ILikeExpressionTest.java | 32 ++-
.../phoenix/expression/LikeExpressionTest.java | 39 +++-
.../expression/RegexpReplaceFunctionTest.java | 81 ++++++++
.../expression/RegexpSplitFunctionTest.java | 94 +++++++++
.../expression/RegexpSubstrFunctionTest.java | 83 ++++++++
.../expression/SortOrderExpressionTest.java | 12 +-
.../util/regex/PatternPerformanceTest.java | 144 +++++++++++++
.../org/apache/phoenix/util/StringUtilTest.java | 32 ++-
.../java/org/apache/phoenix/util/TestUtil.java | 28 ++-
pom.xml | 1 +
43 files changed, 1952 insertions(+), 161 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-assembly/src/build/components-major-client.xml
----------------------------------------------------------------------
diff --git a/phoenix-assembly/src/build/components-major-client.xml b/phoenix-assembly/src/build/components-major-client.xml
index 768cac0..7a2909b 100644
--- a/phoenix-assembly/src/build/components-major-client.xml
+++ b/phoenix-assembly/src/build/components-major-client.xml
@@ -49,6 +49,8 @@
<include>org.codehaus.jackson:jackson-core-asl</include>
<include>commons-collections:commons-collections</include>
<include>joda-time:joda-time</include>
+ <include>org.jruby.joni:joni</include>
+ <include>org.jruby.jcodings:jcodings</include>
</includes>
</dependencySet>
</dependencySets>
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/pom.xml
----------------------------------------------------------------------
diff --git a/phoenix-core/pom.xml b/phoenix-core/pom.xml
index 5e0aff7..45b8d73 100644
--- a/phoenix-core/pom.xml
+++ b/phoenix-core/pom.xml
@@ -417,5 +417,10 @@
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-minicluster</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.jruby.joni</groupId>
+ <artifactId>joni</artifactId>
+ <version>${joni.version}</version>
+ </dependency>
</dependencies>
</project>
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/it/java/org/apache/phoenix/end2end/LikeExpressionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/LikeExpressionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/LikeExpressionIT.java
new file mode 100644
index 0000000..1ee0669
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/LikeExpressionIT.java
@@ -0,0 +1,88 @@
+/*
+ * 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.apache.phoenix.util.TestUtil.closeStmtAndConn;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class LikeExpressionIT extends BaseHBaseManagedTimeIT {
+ @Before
+ public void doBeforeTestSetup() throws Exception {
+ Connection conn = null;
+ PreparedStatement stmt = null;
+ try {
+ conn = DriverManager.getConnection(getUrl());
+ String ddl;
+ ddl = "CREATE TABLE testTable (k VARCHAR NOT NULL PRIMARY KEY, i INTEGER)";
+ conn.createStatement().execute(ddl);
+ conn.commit();
+ } finally {
+ closeStmtAndConn(stmt, conn);
+ }
+ insertRow(conn, "123n7-app-2-", 1);
+ insertRow(conn, "132n7-App-2-", 2);
+ insertRow(conn, "213n7-app-2-", 4);
+ insertRow(conn, "231n7-App-2-", 8);
+ insertRow(conn, "312n7-app-2-", 16);
+ insertRow(conn, "321n7-App-2-", 32);
+ }
+
+ private void insertRow(Connection conn, String k, int i) throws SQLException {
+ PreparedStatement stmt = conn.prepareStatement("UPSERT INTO testTable VALUES (?, ?)");
+ stmt.setString(1, k);
+ stmt.setInt(2, i);
+ stmt.executeUpdate();
+ conn.commit();
+ }
+
+ private void testLikeExpression(Connection conn, String likeStr, int numResult, int expectedSum)
+ throws Exception {
+ String cmd = "select k, i from testTable where k like '" + likeStr + "'";
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery(cmd);
+ int sum = 0;
+ for (int i = 0; i < numResult; ++i) {
+ assertTrue(rs.next());
+ sum += rs.getInt("i");
+ }
+ assertFalse(rs.next());
+ assertEquals(sum, expectedSum);
+ }
+
+ @Test
+ public void testLikeExpression() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ // wildcard
+ testLikeExpression(conn, "%1%3%7%2%", 3, 7);
+ // CaseSensitive
+ testLikeExpression(conn, "%A%", 3, 42);
+ conn.close();
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpReplaceFunctionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpReplaceFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpReplaceFunctionIT.java
new file mode 100644
index 0000000..dcc20ff
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpReplaceFunctionIT.java
@@ -0,0 +1,100 @@
+/*
+ * 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.apache.phoenix.util.TestUtil.GROUPBYTEST_NAME;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import org.junit.Before;
+import org.junit.Test;
+
+
+public class RegexpReplaceFunctionIT extends BaseHBaseManagedTimeIT {
+
+ private int id;
+
+ @Before
+ public void doBeforeTestSetup() throws Exception {
+ ensureTableCreated(getUrl(), GROUPBYTEST_NAME);
+ Connection conn = DriverManager.getConnection(getUrl());
+ insertRow(conn, "Report11", 10);
+ insertRow(conn, "Report11", 10);
+ insertRow(conn, "Report22", 30);
+ insertRow(conn, "Report33", 30);
+ conn.commit();
+ conn.close();
+ }
+
+ private void insertRow(Connection conn, String uri, int appcpu) throws SQLException {
+ PreparedStatement statement = conn.prepareStatement("UPSERT INTO " + GROUPBYTEST_NAME + "(id, uri, appcpu) values (?,?,?)");
+ statement.setString(1, "id" + id);
+ statement.setString(2, uri);
+ statement.setInt(3, appcpu);
+ statement.executeUpdate();
+ id++;
+ }
+
+ @Test
+ public void testGroupByScanWithRegexpReplace() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ Statement stmt = conn.createStatement();
+ ResultSet rs = stmt.executeQuery("select REGEXP_REPLACE(uri, '[1-3]+', '*') suburi, sum(appcpu) sumcpu from " + GROUPBYTEST_NAME + " group by suburi");
+ assertTrue(rs.next());
+ assertEquals(rs.getString("suburi"), "Report*");
+ assertEquals(rs.getInt("sumcpu"), 80);
+ assertFalse(rs.next());
+
+ stmt = conn.createStatement();
+ rs = stmt.executeQuery("select REGEXP_REPLACE(uri, '[1-3]+') suburi, sum(appcpu) sumcpu from " + GROUPBYTEST_NAME + " group by suburi");
+ assertTrue(rs.next());
+ assertEquals(rs.getString("suburi"), "Report");
+ assertEquals(rs.getInt("sumcpu"), 80);
+ assertFalse(rs.next());
+
+ conn.close();
+ }
+
+ @Test
+ public void testFilterWithRegexReplace() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ ResultSet rs = conn.createStatement().executeQuery("select id from " + GROUPBYTEST_NAME + " where REGEXP_REPLACE(uri, '[2-3]+', '*') = 'Report*'");
+ assertTrue(rs.next());
+ assertEquals("id2", rs.getString(1));
+ assertTrue(rs.next());
+ assertEquals("id3", rs.getString(1));
+ assertFalse(rs.next());
+
+ rs = conn.createStatement().executeQuery("select id from " + GROUPBYTEST_NAME + " where REGEXP_REPLACE(uri, '[2-3]+') = 'Report'");
+ assertTrue(rs.next());
+ assertEquals("id2", rs.getString(1));
+ assertTrue(rs.next());
+ assertEquals("id3", rs.getString(1));
+ assertFalse(rs.next());
+ conn.close();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpSubstrFunctionIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpSubstrFunctionIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpSubstrFunctionIT.java
index ff4b95e..938fd5d 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpSubstrFunctionIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RegexpSubstrFunctionIT.java
@@ -58,30 +58,37 @@ public class RegexpSubstrFunctionIT extends BaseHBaseManagedTimeIT {
id++;
}
- @Test
- public void testGroupByScanWithRegexpSubstr() throws Exception {
- Connection conn = DriverManager.getConnection(getUrl());
+ private void testGroupByScanWithRegexpSubstr(Connection conn, Integer offset, String exceptedSubstr) throws Exception {
+ String cmd = "select REGEXP_SUBSTR(uri, '[^\\\\?]+'" + ((offset == null) ? "" : ", " + offset.intValue()) +") suburi, sum(appcpu) sumcpu from " + GROUPBYTEST_NAME + " group by suburi";
Statement stmt = conn.createStatement();
- ResultSet rs = stmt.executeQuery("select REGEXP_SUBSTR(uri, '[^\\\\?]+') suburi, sum(appcpu) sumcpu from " + GROUPBYTEST_NAME
- + " group by suburi");
+ ResultSet rs = stmt.executeQuery(cmd);
assertTrue(rs.next());
- assertEquals(rs.getString("suburi"), "Report1");
+ assertEquals(rs.getString("suburi"), exceptedSubstr + "1");
assertEquals(rs.getInt("sumcpu"), 20);
assertTrue(rs.next());
- assertEquals(rs.getString("suburi"), "Report2");
+ assertEquals(rs.getString("suburi"), exceptedSubstr + "2");
assertEquals(rs.getInt("sumcpu"), 30);
assertTrue(rs.next());
- assertEquals(rs.getString("suburi"), "Report3");
+ assertEquals(rs.getString("suburi"), exceptedSubstr + "3");
assertEquals(rs.getInt("sumcpu"), 30);
assertFalse(rs.next());
- conn.close();
}
@Test
- public void testFilterWithRegexSubstr() throws Exception {
+ public void testGroupByScanWithRegexpSubstr() throws Exception {
Connection conn = DriverManager.getConnection(getUrl());
- ResultSet rs = conn.createStatement().executeQuery(
- "select id from " + GROUPBYTEST_NAME + " where REGEXP_SUBSTR(uri, '[^\\\\?]+') = 'Report1'");
+ // Default offset
+ testGroupByScanWithRegexpSubstr(conn, null, "Report");
+ // Positive offset
+ testGroupByScanWithRegexpSubstr(conn, Integer.valueOf(2), "eport");
+ // Negative offset
+ testGroupByScanWithRegexpSubstr(conn, Integer.valueOf(-5), "rt");
+ conn.close();
+ }
+
+ private void testFilterWithRegexSubstr(Connection conn, Integer offset, String exceptedSubstr) throws Exception {
+ String cmd = "select id from " + GROUPBYTEST_NAME + " where REGEXP_SUBSTR(uri, '[^\\\\?]+'"+ ((offset == null) ? "" : ", " + offset.intValue()) +") = '" + exceptedSubstr + "1'";
+ ResultSet rs = conn.createStatement().executeQuery(cmd);
assertTrue(rs.next());
assertEquals("id0", rs.getString(1));
assertTrue(rs.next());
@@ -89,4 +96,16 @@ public class RegexpSubstrFunctionIT extends BaseHBaseManagedTimeIT {
assertFalse(rs.next());
}
+ @Test
+ public void testFilterWithRegexSubstr() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ // Default offset
+ testFilterWithRegexSubstr(conn, null, "Report");
+ // Positive offset
+ testFilterWithRegexSubstr(conn, Integer.valueOf(2), "eport");
+ // Negative offset
+ testFilterWithRegexSubstr(conn, Integer.valueOf(-5), "rt");
+ conn.close();
+ }
+
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
index 52c67f1..ce95850 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
@@ -32,6 +32,7 @@ import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.expression.AndExpression;
import org.apache.phoenix.expression.ArrayConstructorExpression;
+import org.apache.phoenix.expression.ByteBasedLikeExpression;
import org.apache.phoenix.expression.CaseExpression;
import org.apache.phoenix.expression.CoerceExpression;
import org.apache.phoenix.expression.ComparisonExpression;
@@ -60,6 +61,7 @@ import org.apache.phoenix.expression.NotExpression;
import org.apache.phoenix.expression.OrExpression;
import org.apache.phoenix.expression.RowKeyColumnExpression;
import org.apache.phoenix.expression.RowValueConstructorExpression;
+import org.apache.phoenix.expression.StringBasedLikeExpression;
import org.apache.phoenix.expression.StringConcatExpression;
import org.apache.phoenix.expression.TimestampAddExpression;
import org.apache.phoenix.expression.TimestampSubtractExpression;
@@ -100,6 +102,8 @@ import org.apache.phoenix.parse.StringConcatParseNode;
import org.apache.phoenix.parse.SubqueryParseNode;
import org.apache.phoenix.parse.SubtractParseNode;
import org.apache.phoenix.parse.UnsupportedAllParseNodeVisitor;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.schema.ColumnFamilyNotFoundException;
import org.apache.phoenix.schema.ColumnNotFoundException;
import org.apache.phoenix.schema.ColumnRef;
@@ -497,7 +501,16 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio
}
}
}
- Expression expression = LikeExpression.create(children, node.getLikeType());
+ QueryServices services = context.getConnection().getQueryServices();
+ boolean useByteBasedRegex =
+ services.getProps().getBoolean(QueryServices.USE_BYTE_BASED_REGEX_ATTRIB,
+ QueryServicesOptions.DEFAULT_USE_BYTE_BASED_REGEX);
+ Expression expression;
+ if (useByteBasedRegex) {
+ expression = ByteBasedLikeExpression.create(children, node.getLikeType());
+ } else {
+ expression = StringBasedLikeExpression.create(children, node.getLikeType());
+ }
if (ExpressionUtil.isConstant(expression)) {
ImmutableBytesWritable ptr = context.getTempPtr();
if (!expression.evaluate(null, ptr)) {
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/ByteBasedLikeExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/ByteBasedLikeExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/ByteBasedLikeExpression.java
new file mode 100644
index 0000000..4dd4f70
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/ByteBasedLikeExpression.java
@@ -0,0 +1,48 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.phoenix.expression.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JONIPattern;
+import org.apache.phoenix.parse.LikeParseNode.LikeType;
+
+public class ByteBasedLikeExpression extends LikeExpression {
+
+ public ByteBasedLikeExpression() {
+ }
+
+ public ByteBasedLikeExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JONIPattern(value);
+ }
+
+ public static LikeExpression create(List<Expression> children, LikeType likeType) {
+ return new ByteBasedLikeExpression(addLikeTypeChild(children, likeType));
+ }
+
+ @Override
+ public LikeExpression clone(List<Expression> children) {
+ return new ByteBasedLikeExpression(children);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/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 22778ce..5f598b9 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,9 @@ import org.apache.phoenix.expression.function.ArrayAppendFunction;
import org.apache.phoenix.expression.function.ArrayElemRefExpression;
import org.apache.phoenix.expression.function.ArrayIndexFunction;
import org.apache.phoenix.expression.function.ArrayLengthFunction;
+import org.apache.phoenix.expression.function.ByteBasedRegexpReplaceFunction;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSplitFunction;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSubstrFunction;
import org.apache.phoenix.expression.function.CeilDateExpression;
import org.apache.phoenix.expression.function.CeilDecimalExpression;
import org.apache.phoenix.expression.function.CeilFunction;
@@ -79,6 +82,9 @@ import org.apache.phoenix.expression.function.SignFunction;
import org.apache.phoenix.expression.function.SqlTypeNameFunction;
import org.apache.phoenix.expression.function.StddevPopFunction;
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.SubstrFunction;
import org.apache.phoenix.expression.function.SumAggregateFunction;
import org.apache.phoenix.expression.function.TimezoneOffsetFunction;
@@ -137,6 +143,8 @@ public enum ExpressionType {
MinAggregateFunction(MinAggregateFunction.class),
MaxAggregateFunction(MaxAggregateFunction.class),
LikeExpression(LikeExpression.class),
+ ByteBasedLikeExpression(ByteBasedLikeExpression.class),
+ StringBasedLikeExpression(StringBasedLikeExpression.class),
NotExpression(NotExpression.class),
CaseExpression(CaseExpression.class),
InListExpression(InListExpression.class),
@@ -153,8 +161,12 @@ public enum ExpressionType {
DecimalDivideExpression(DecimalDivideExpression.class),
CoalesceFunction(CoalesceFunction.class),
RegexpReplaceFunction(RegexpReplaceFunction.class),
+ ByteBasedRegexpReplaceFunction(ByteBasedRegexpReplaceFunction.class),
+ StringBasedRegexpReplaceFunction(StringBasedRegexpReplaceFunction.class),
SQLTypeNameFunction(SqlTypeNameFunction.class),
RegexpSubstrFunction(RegexpSubstrFunction.class),
+ ByteBasedRegexpSubstrFunction(ByteBasedRegexpSubstrFunction.class),
+ StringBasedRegexpSubstrFunction(StringBasedRegexpSubstrFunction.class),
StringConcatExpression(StringConcatExpression.class),
LengthFunction(LengthFunction.class),
LTrimFunction(LTrimFunction.class),
@@ -199,7 +211,9 @@ public enum ExpressionType {
SQLIndexTypeFunction(SQLIndexTypeFunction.class),
ModulusExpression(ModulusExpression.class),
DistinctValueAggregateFunction(DistinctValueAggregateFunction.class),
- RegexpSplitFunctiond(RegexpSplitFunction.class),
+ RegexpSplitFunction(RegexpSplitFunction.class),
+ ByteBasedRegexpSplitFunction(ByteBasedRegexpSplitFunction.class),
+ StringBasedRegexpSplitFunction(StringBasedRegexpSplitFunction.class),
RandomFunction(RandomFunction.class),
ToTimeFunction(ToTimeFunction.class),
ToTimestampFunction(ToTimestampFunction.class),
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
index 730cffb..52ac969 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/LikeExpression.java
@@ -21,11 +21,12 @@ import java.io.DataInput;
import java.io.DataOutput;
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.util.regex.AbstractBasePattern;
import org.apache.phoenix.expression.visitor.ExpressionVisitor;
import org.apache.phoenix.parse.LikeParseNode.LikeType;
+import org.apache.phoenix.schema.SortOrder;
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PBoolean;
import org.apache.phoenix.schema.types.PDataType;
@@ -49,7 +50,7 @@ import com.google.common.collect.Lists;
*
* @since 0.1
*/
-public class LikeExpression extends BaseCompoundExpression {
+public abstract class LikeExpression extends BaseCompoundExpression {
private static final Logger logger = LoggerFactory.getLogger(LikeExpression.class);
private static final String ZERO_OR_MORE = "\\E.*\\Q";
@@ -195,10 +196,6 @@ public class LikeExpression extends BaseCompoundExpression {
// return sb.toString();
// }
- public static LikeExpression create(List<Expression> children, LikeType likeType) {
- return new LikeExpression(addLikeTypeChild(children,likeType));
- }
-
private static final int LIKE_TYPE_INDEX = 2;
private static final LiteralExpression[] LIKE_TYPE_LITERAL = new LiteralExpression[LikeType.values().length];
static {
@@ -206,12 +203,12 @@ public class LikeExpression extends BaseCompoundExpression {
LIKE_TYPE_LITERAL[likeType.ordinal()] = LiteralExpression.newConstant(likeType.name());
}
}
- private Pattern pattern;
+ private AbstractBasePattern pattern;
public LikeExpression() {
}
- private static List<Expression> addLikeTypeChild(List<Expression> children, LikeType likeType) {
+ protected static List<Expression> addLikeTypeChild(List<Expression> children, LikeType likeType) {
List<Expression> newChildren = Lists.newArrayListWithExpectedSize(children.size()+1);
newChildren.addAll(children);
newChildren.add(LIKE_TYPE_LITERAL[likeType.ordinal()]);
@@ -247,11 +244,14 @@ public class LikeExpression extends BaseCompoundExpression {
}
}
- protected Pattern compilePattern (String value) {
- if (likeType == LikeType.CASE_SENSITIVE)
- return Pattern.compile(toPattern(value));
- else
- return Pattern.compile("(?i)" + toPattern(value));
+ protected abstract AbstractBasePattern compilePatternSpec(String value);
+
+ protected AbstractBasePattern compilePattern(String value) {
+ if (likeType == LikeType.CASE_SENSITIVE) {
+ return compilePatternSpec(toPattern(value));
+ } else {
+ return compilePatternSpec("(?i)" + toPattern(value));
+ }
}
private Expression getStrExpression() {
@@ -264,36 +264,40 @@ public class LikeExpression extends BaseCompoundExpression {
@Override
public boolean evaluate(Tuple tuple, ImmutableBytesWritable ptr) {
- Pattern pattern = this.pattern;
+ AbstractBasePattern pattern = this.pattern;
if (pattern == null) { // TODO: don't allow? this is going to be slooowwww
if (!getPatternExpression().evaluate(tuple, ptr)) {
- if (logger.isDebugEnabled()) {
- logger.debug("LIKE is FALSE: pattern is null");
+ if (logger.isTraceEnabled()) {
+ logger.trace("LIKE is FALSE: pattern is null");
}
return false;
}
String value = (String) PVarchar.INSTANCE.toObject(ptr, getPatternExpression().getSortOrder());
pattern = compilePattern(value);
- if (logger.isDebugEnabled()) {
- logger.debug("LIKE pattern is expression: " + pattern.pattern());
+ if (logger.isTraceEnabled()) {
+ logger.trace("LIKE pattern is expression: " + pattern.pattern());
}
}
- if (!getStrExpression().evaluate(tuple, ptr)) {
- if (logger.isDebugEnabled()) {
- logger.debug("LIKE is FALSE: child expression is null");
+ Expression strExpression = getStrExpression();
+ SortOrder strSortOrder = strExpression.getSortOrder();
+ PVarchar strDataType = PVarchar.INSTANCE;
+ if (!strExpression.evaluate(tuple, ptr)) {
+ if (logger.isTraceEnabled()) {
+ logger.trace("LIKE is FALSE: child expression is null");
}
return false;
}
- if (ptr.getLength() == 0) {
- return true;
- }
- String value = (String) PVarchar.INSTANCE.toObject(ptr, getStrExpression().getSortOrder());
- boolean matched = pattern.matcher(value).matches();
- ptr.set(matched ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
- if (logger.isDebugEnabled()) {
- logger.debug("LIKE(value='" + value + "'pattern='" + pattern.pattern() + "' is " + matched);
+ String value = null;
+ if (logger.isTraceEnabled()) {
+ value = (String) strDataType.toObject(ptr, strSortOrder);
+ }
+ strDataType.coerceBytes(ptr, strDataType, strSortOrder, SortOrder.ASC);
+ pattern.matches(ptr, ptr);
+ if (logger.isTraceEnabled()) {
+ boolean matched = ((Boolean) PBoolean.INSTANCE.toObject(ptr)).booleanValue();
+ logger.trace("LIKE(value='" + value + "'pattern='" + pattern.pattern() + "' is " + matched);
}
return true;
}
@@ -348,4 +352,6 @@ public class LikeExpression extends BaseCompoundExpression {
public String toString() {
return (children.get(0) + " LIKE " + children.get(1));
}
+
+ abstract public LikeExpression clone(List<Expression> children);
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/StringBasedLikeExpression.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/StringBasedLikeExpression.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/StringBasedLikeExpression.java
new file mode 100644
index 0000000..e2afea2
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/StringBasedLikeExpression.java
@@ -0,0 +1,48 @@
+/*
+ * 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 java.util.List;
+
+import org.apache.phoenix.expression.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JavaPattern;
+import org.apache.phoenix.parse.LikeParseNode.LikeType;
+
+public class StringBasedLikeExpression extends LikeExpression {
+
+ public StringBasedLikeExpression() {
+ }
+
+ public StringBasedLikeExpression(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JavaPattern(value);
+ }
+
+ public static LikeExpression create(List<Expression> children, LikeType likeType) {
+ return new StringBasedLikeExpression(addLikeTypeChild(children, likeType));
+ }
+
+ @Override
+ public LikeExpression clone(List<Expression> children) {
+ return new StringBasedLikeExpression(children);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpReplaceFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpReplaceFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpReplaceFunction.java
new file mode 100644
index 0000000..0d6543c
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpReplaceFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JONIPattern;
+
+public class ByteBasedRegexpReplaceFunction extends RegexpReplaceFunction {
+
+ public ByteBasedRegexpReplaceFunction() {
+ }
+
+ public ByteBasedRegexpReplaceFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JONIPattern(value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSplitFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSplitFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSplitFunction.java
new file mode 100644
index 0000000..062713e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSplitFunction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.regex.AbstractBaseSplitter;
+import org.apache.phoenix.expression.util.regex.JONIPattern;
+
+public class ByteBasedRegexpSplitFunction extends RegexpSplitFunction {
+ public ByteBasedRegexpSplitFunction() {
+ }
+
+ public ByteBasedRegexpSplitFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBaseSplitter compilePatternSpec(String value) {
+ return new JONIPattern(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSubstrFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSubstrFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSubstrFunction.java
new file mode 100644
index 0000000..7ee99bf
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/ByteBasedRegexpSubstrFunction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JONIPattern;
+
+public class ByteBasedRegexpSubstrFunction extends RegexpSubstrFunction {
+ public ByteBasedRegexpSubstrFunction() {
+ }
+
+ public ByteBasedRegexpSubstrFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JONIPattern(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
index 3f470a9..f22c978 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpReplaceFunction.java
@@ -20,17 +20,18 @@ 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.expression.util.regex.AbstractBasePattern;
import org.apache.phoenix.parse.FunctionParseNode.Argument;
import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
+import org.apache.phoenix.parse.RegexpReplaceParseNode;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PVarchar;
-import org.apache.phoenix.schema.tuple.Tuple;
/**
@@ -48,15 +49,16 @@ import org.apache.phoenix.schema.tuple.Tuple;
*
* @since 0.1
*/
-@BuiltInFunction(name=RegexpReplaceFunction.NAME, args= {
+@BuiltInFunction(name=RegexpReplaceFunction.NAME,
+ nodeClass = RegexpReplaceParseNode.class, args= {
@Argument(allowedTypes={PVarchar.class}),
@Argument(allowedTypes={PVarchar.class}),
@Argument(allowedTypes={PVarchar.class},defaultValue="null")} )
-public class RegexpReplaceFunction extends ScalarFunction {
+public abstract class RegexpReplaceFunction extends ScalarFunction {
public static final String NAME = "REGEXP_REPLACE";
private boolean hasReplaceStr;
- private Pattern pattern;
+ private AbstractBasePattern pattern;
public RegexpReplaceFunction() { }
@@ -66,11 +68,13 @@ public class RegexpReplaceFunction extends ScalarFunction {
init();
}
+ protected abstract AbstractBasePattern compilePatternSpec(String value);
+
private void init() {
hasReplaceStr = ((LiteralExpression)getReplaceStrExpression()).getValue() != null;
Object patternString = ((LiteralExpression)children.get(1)).getValue();
if (patternString != null) {
- pattern = Pattern.compile((String)patternString);
+ pattern = compilePatternSpec((String) patternString);
}
}
@@ -84,22 +88,20 @@ public class RegexpReplaceFunction extends ScalarFunction {
if (!sourceStrExpression.evaluate(tuple, ptr)) {
return false;
}
- String sourceStr = (String) PVarchar.INSTANCE.toObject(ptr, sourceStrExpression.getSortOrder());
- if (sourceStr == null) {
- return false;
- }
- String replaceStr;
+ if (ptr == null) return false;
+ PVarchar type = PVarchar.INSTANCE;
+ type.coerceBytes(ptr, type, sourceStrExpression.getSortOrder(), SortOrder.ASC);
+ ImmutableBytesWritable replacePtr = new ImmutableBytesWritable();
if (hasReplaceStr) {
- Expression replaceStrExpression = this.getReplaceStrExpression();
- if (!replaceStrExpression.evaluate(tuple, ptr)) {
+ Expression replaceStrExpression = getReplaceStrExpression();
+ if (!replaceStrExpression.evaluate(tuple, replacePtr)) {
return false;
}
- replaceStr = (String) PVarchar.INSTANCE.toObject(ptr, replaceStrExpression.getSortOrder());
+ type.coerceBytes(replacePtr, type, replaceStrExpression.getSortOrder(), SortOrder.ASC);
} else {
- replaceStr = "";
+ replacePtr.set(type.toBytes(""));
}
- String replacedStr = pattern.matcher(sourceStr).replaceAll(replaceStr);
- ptr.set(PVarchar.INSTANCE.toBytes(replacedStr));
+ pattern.replaceAll(ptr, replacePtr, ptr);
return true;
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSplitFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSplitFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSplitFunction.java
index 89c7c9e..b43dec9 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSplitFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSplitFunction.java
@@ -24,17 +24,16 @@ 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.expression.util.regex.AbstractBaseSplitter;
import org.apache.phoenix.parse.FunctionParseNode;
+import org.apache.phoenix.parse.RegexpSplitParseNode;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.schema.types.PVarcharArray;
-import org.apache.phoenix.schema.types.PhoenixArray;
-import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.util.ByteUtil;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
-
/**
* Function to split a string value into a {@code VARCHAR_ARRAY}.
* <p>
@@ -46,14 +45,15 @@ import com.google.common.collect.Lists;
*
* The function returns a {@link org.apache.phoenix.schema.types.PVarcharArray}
*/
- @FunctionParseNode.BuiltInFunction(name=RegexpSplitFunction.NAME, args= {
+ @FunctionParseNode.BuiltInFunction(name=RegexpSplitFunction.NAME,
+ nodeClass = RegexpSplitParseNode.class, args= {
@FunctionParseNode.Argument(allowedTypes={PVarchar.class}),
@FunctionParseNode.Argument(allowedTypes={PVarchar.class})})
-public class RegexpSplitFunction extends ScalarFunction {
+public abstract class RegexpSplitFunction extends ScalarFunction {
public static final String NAME = "REGEXP_SPLIT";
- private Splitter initializedSplitter = null;
+ private AbstractBaseSplitter initializedSplitter = null;
public RegexpSplitFunction() {}
@@ -67,11 +67,13 @@ public class RegexpSplitFunction extends ScalarFunction {
if (patternExpression instanceof LiteralExpression) {
Object patternValue = ((LiteralExpression) patternExpression).getValue();
if (patternValue != null) {
- initializedSplitter = Splitter.onPattern(patternValue.toString());
+ initializedSplitter = compilePatternSpec(patternValue.toString());
}
}
}
+ protected abstract AbstractBaseSplitter compilePatternSpec(String value);
+
@Override
public void readFields(DataInput input) throws IOException {
super.readFields(input);
@@ -90,38 +92,28 @@ public class RegexpSplitFunction extends ScalarFunction {
}
Expression sourceStrExpression = children.get(0);
- String sourceStr = (String) PVarchar.INSTANCE.toObject(ptr, sourceStrExpression.getSortOrder());
- if (sourceStr == null) { // sourceStr evaluated to null
- ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
- return true;
- }
+ PVarchar type = PVarchar.INSTANCE;
+ type.coerceBytes(ptr, type, sourceStrExpression.getSortOrder(), SortOrder.ASC);
- return split(tuple, ptr, sourceStr);
- }
-
- private boolean split(Tuple tuple, ImmutableBytesWritable ptr, String sourceStr) {
- Splitter splitter = initializedSplitter;
+ AbstractBaseSplitter splitter = initializedSplitter;
if (splitter == null) {
+ ImmutableBytesWritable tmpPtr = new ImmutableBytesWritable();
Expression patternExpression = children.get(1);
- if (!patternExpression.evaluate(tuple, ptr)) {
+ if (!patternExpression.evaluate(tuple, tmpPtr)) {
return false;
}
- if (ptr.getLength() == 0) {
- return true; // ptr is already set to null
+ if (tmpPtr.getLength() == 0) {
+ ptr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ return true; // set ptr to null
}
-
- String patternStr = (String) PVarchar.INSTANCE.toObject(
- ptr, patternExpression.getSortOrder());
- splitter = Splitter.onPattern(patternStr);
+ String patternStr =
+ (String) PVarchar.INSTANCE.toObject(tmpPtr, patternExpression.getSortOrder());
+ splitter = compilePatternSpec(patternStr);
}
- List<String> splitStrings = Lists.newArrayList(splitter.split(sourceStr));
- PhoenixArray splitArray = new PhoenixArray(PVarchar.INSTANCE, splitStrings.toArray());
- ptr.set(PVarcharArray.INSTANCE.toBytes(splitArray));
- return true;
+ return splitter.split(ptr, ptr);
}
-
@Override
public PDataType getDataType() {
return PVarcharArray.INSTANCE;
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
index 93d8706..430b444 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/RegexpSubstrFunction.java
@@ -20,19 +20,19 @@ package org.apache.phoenix.expression.function;
import java.io.DataInput;
import java.io.IOException;
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.expression.util.regex.AbstractBasePattern;
import org.apache.phoenix.parse.FunctionParseNode.Argument;
import org.apache.phoenix.parse.FunctionParseNode.BuiltInFunction;
-import org.apache.phoenix.schema.types.PLong;
+import org.apache.phoenix.parse.RegexpSubstrParseNode;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PLong;
import org.apache.phoenix.schema.types.PVarchar;
-import org.apache.phoenix.schema.tuple.Tuple;
-import org.apache.phoenix.util.ByteUtil;
/**
@@ -47,17 +47,20 @@ import org.apache.phoenix.util.ByteUtil;
*
* @since 0.1
*/
-@BuiltInFunction(name=RegexpSubstrFunction.NAME, args={
+@BuiltInFunction(name=RegexpSubstrFunction.NAME,
+ nodeClass = RegexpSubstrParseNode.class, args={
@Argument(allowedTypes={PVarchar.class}),
@Argument(allowedTypes={PVarchar.class}),
@Argument(allowedTypes={PLong.class}, defaultValue="1")} )
-public class RegexpSubstrFunction extends PrefixFunction {
+public abstract class RegexpSubstrFunction extends PrefixFunction {
public static final String NAME = "REGEXP_SUBSTR";
- private Pattern pattern;
+ private AbstractBasePattern pattern;
private boolean isOffsetConstant;
private Integer maxLength;
+ private static final PDataType TYPE = PVarchar.INSTANCE;
+
public RegexpSubstrFunction() { }
public RegexpSubstrFunction(List<Expression> children) {
@@ -65,10 +68,12 @@ public class RegexpSubstrFunction extends PrefixFunction {
init();
}
+ protected abstract AbstractBasePattern compilePatternSpec(String value);
+
private void init() {
Object patternString = ((LiteralExpression)children.get(1)).getValue();
if (patternString != null) {
- pattern = Pattern.compile((String)patternString);
+ pattern = compilePatternSpec((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
@@ -95,13 +100,11 @@ public class RegexpSubstrFunction extends PrefixFunction {
if (pattern == null) {
return false;
}
- if (!getSourceStrExpression().evaluate(tuple, ptr)) {
- return false;
- }
- String sourceStr = (String) PVarchar.INSTANCE.toObject(ptr, getSourceStrExpression().getSortOrder());
- if (sourceStr == null) {
+ ImmutableBytesWritable srcPtr = new ImmutableBytesWritable();
+ if (!getSourceStrExpression().evaluate(tuple, srcPtr)) {
return false;
}
+ TYPE.coerceBytes(srcPtr, TYPE, getSourceStrExpression().getSortOrder(), SortOrder.ASC);
Expression offsetExpression = getOffsetExpression();
if (!offsetExpression.evaluate(tuple, ptr)) {
@@ -109,25 +112,10 @@ public class RegexpSubstrFunction extends PrefixFunction {
}
int offset = offsetExpression.getDataType().getCodec().decodeInt(ptr, offsetExpression.getSortOrder());
- 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(PVarchar.INSTANCE.toBytes(subString));
- return true;
+ return pattern.substr(srcPtr, offset, ptr);
}
@Override
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpReplaceFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpReplaceFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpReplaceFunction.java
new file mode 100644
index 0000000..9aaec70
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpReplaceFunction.java
@@ -0,0 +1,40 @@
+/*
+ * 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.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JavaPattern;
+
+public class StringBasedRegexpReplaceFunction extends RegexpReplaceFunction {
+
+ public StringBasedRegexpReplaceFunction() {
+ }
+
+ public StringBasedRegexpReplaceFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JavaPattern(value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSplitFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSplitFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSplitFunction.java
new file mode 100644
index 0000000..77321c2
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSplitFunction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.regex.AbstractBaseSplitter;
+import org.apache.phoenix.expression.util.regex.GuavaSplitter;
+
+public class StringBasedRegexpSplitFunction extends RegexpSplitFunction {
+ public StringBasedRegexpSplitFunction() {
+ }
+
+ public StringBasedRegexpSplitFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBaseSplitter compilePatternSpec(String value) {
+ return new GuavaSplitter(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSubstrFunction.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSubstrFunction.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSubstrFunction.java
new file mode 100644
index 0000000..253db36
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/function/StringBasedRegexpSubstrFunction.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.regex.AbstractBasePattern;
+import org.apache.phoenix.expression.util.regex.JavaPattern;
+
+public class StringBasedRegexpSubstrFunction extends RegexpSubstrFunction {
+ public StringBasedRegexpSubstrFunction() {
+ }
+
+ public StringBasedRegexpSubstrFunction(List<Expression> children) {
+ super(children);
+ }
+
+ @Override
+ protected AbstractBasePattern compilePatternSpec(String value) {
+ return new JavaPattern(value);
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBasePattern.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBasePattern.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBasePattern.java
new file mode 100644
index 0000000..27b47a0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBasePattern.java
@@ -0,0 +1,33 @@
+/*
+ * 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.util.regex;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+public abstract class AbstractBasePattern {
+
+ public abstract void matches(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr);
+
+ public abstract void replaceAll(ImmutableBytesWritable srcPtr,
+ ImmutableBytesWritable replacePtr, ImmutableBytesWritable outPtr);
+
+ public abstract boolean substr(ImmutableBytesWritable srcPtr, int offsetInStr,
+ ImmutableBytesWritable outPtr);
+
+ public abstract String pattern();
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBaseSplitter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBaseSplitter.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBaseSplitter.java
new file mode 100644
index 0000000..323eed0
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/AbstractBaseSplitter.java
@@ -0,0 +1,24 @@
+/*
+ * 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.util.regex;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+
+public abstract interface AbstractBaseSplitter {
+ public abstract boolean split(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr);
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/GuavaSplitter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/GuavaSplitter.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/GuavaSplitter.java
new file mode 100644
index 0000000..325919e
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/GuavaSplitter.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util.regex;
+
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.schema.types.PVarcharArray;
+import org.apache.phoenix.schema.types.PhoenixArray;
+import org.apache.phoenix.util.ByteUtil;
+
+import com.google.common.base.Splitter;
+import com.google.common.collect.Lists;
+
+public class GuavaSplitter implements AbstractBaseSplitter {
+ private final Splitter splitter;
+
+ public GuavaSplitter(String patternString) {
+ if (patternString != null) {
+ splitter = Splitter.onPattern(patternString);
+ } else {
+ splitter = null;
+ }
+ }
+
+ @Override
+ public boolean split(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr) {
+ String sourceStr = (String) PVarchar.INSTANCE.toObject(srcPtr);
+ if (sourceStr == null) { // sourceStr evaluated to null
+ outPtr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ } else {
+ List<String> splitStrings = Lists.newArrayList(splitter.split(sourceStr));
+ PhoenixArray splitArray = new PhoenixArray(PVarchar.INSTANCE, splitStrings.toArray());
+ outPtr.set(PVarcharArray.INSTANCE.toBytes(splitArray));
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JONIPattern.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JONIPattern.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JONIPattern.java
new file mode 100644
index 0000000..5c0b1bc
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JONIPattern.java
@@ -0,0 +1,201 @@
+/*
+ * 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.util.regex;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.schema.SortOrder;
+import org.apache.phoenix.schema.types.PArrayDataType.PArrayDataTypeBytesArrayBuilder;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.StringUtil;
+import org.jcodings.Encoding;
+import org.jcodings.specific.UTF8Encoding;
+import org.joni.Matcher;
+import org.joni.Option;
+import org.joni.Regex;
+import org.joni.Syntax;
+
+import com.google.common.base.Preconditions;
+
+public class JONIPattern extends AbstractBasePattern implements AbstractBaseSplitter {
+
+ private final Regex pattern;
+ private final String patternString;
+
+ public JONIPattern(String patternString) {
+ this(patternString, 0);
+ }
+
+ public JONIPattern(String patternString, int flags) {
+ this(patternString, flags, UTF8Encoding.INSTANCE);
+ }
+
+ public JONIPattern(String patternString, int flags, Encoding coding) {
+ this.patternString = patternString;
+ if (patternString != null) {
+ byte[] bytes = patternString.getBytes();
+ pattern = new Regex(bytes, 0, bytes.length, flags, coding, Syntax.Java);
+ } else {
+ pattern = null;
+ }
+ }
+
+ @Override
+ public void matches(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(outPtr);
+ boolean ret = matches(srcPtr.get(), srcPtr.getOffset(), srcPtr.getLength());
+ outPtr.set(ret ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
+ }
+
+ private boolean matches(byte[] bytes, int offset, int len) {
+ int range = offset + len;
+ Matcher matcher = pattern.matcher(bytes, offset, range);
+ int ret = matcher.match(offset, range, Option.DEFAULT);
+ return len == ret;
+ }
+
+ @Override
+ public String pattern() {
+ return patternString;
+ }
+
+ @Override
+ public void replaceAll(ImmutableBytesWritable srcPtr, ImmutableBytesWritable replacePtr,
+ ImmutableBytesWritable replacedPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(replacePtr);
+ Preconditions.checkNotNull(replacedPtr);
+ byte[] replacedBytes =
+ replaceAll(srcPtr.get(), srcPtr.getOffset(), srcPtr.getLength(), replacePtr.get(),
+ replacePtr.getOffset(), replacePtr.getLength());
+ replacedPtr.set(replacedBytes);
+ }
+
+ private byte[] replaceAll(byte[] srcBytes, int srcOffset, int srcLen, byte[] replaceBytes,
+ int replaceOffset, int replaceLen) {
+ class PairInt {
+ public int begin, end;
+
+ public PairInt(int begin, int end) {
+ this.begin = begin;
+ this.end = end;
+ }
+ }
+ int srcRange = srcOffset + srcLen;
+ Matcher matcher = pattern.matcher(srcBytes, 0, srcRange);
+ int cur = srcOffset;
+ List<PairInt> searchResults = new LinkedList<PairInt>();
+ int totalBytesNeeded = 0;
+ while (true) {
+ int nextCur = matcher.search(cur, srcRange, Option.DEFAULT);
+ if (nextCur < 0) {
+ totalBytesNeeded += srcRange - cur;
+ break;
+ }
+ searchResults.add(new PairInt(matcher.getBegin(), matcher.getEnd()));
+ totalBytesNeeded += (nextCur - cur) + replaceLen;
+ cur = matcher.getEnd();
+ }
+ byte[] ret = new byte[totalBytesNeeded];
+ int curPosInSrc = srcOffset, curPosInRet = 0;
+ for (PairInt pair : searchResults) {
+ System.arraycopy(srcBytes, curPosInSrc, ret, curPosInRet, pair.begin - curPosInSrc);
+ curPosInRet += pair.begin - curPosInSrc;
+ System.arraycopy(replaceBytes, replaceOffset, ret, curPosInRet, replaceLen);
+ curPosInRet += replaceLen;
+ curPosInSrc = pair.end;
+ }
+ System.arraycopy(srcBytes, curPosInSrc, ret, curPosInRet, srcRange - curPosInSrc);
+ return ret;
+ }
+
+ @Override
+ public boolean substr(ImmutableBytesWritable srcPtr, int offsetInStr,
+ ImmutableBytesWritable outPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(outPtr);
+ int offsetInBytes = StringUtil.calculateUTF8Offset(srcPtr.get(), srcPtr.getOffset(),
+ srcPtr.getLength(), SortOrder.ASC, offsetInStr);
+ if (offsetInBytes < 0) return false;
+ substr(srcPtr.get(), offsetInBytes, srcPtr.getOffset() + srcPtr.getLength(), outPtr);
+ return true;
+ }
+
+ private boolean substr(byte[] srcBytes, int offset, int range, ImmutableBytesWritable outPtr) {
+ Matcher matcher = pattern.matcher(srcBytes, 0, range);
+ boolean ret = matcher.search(offset, range, Option.DEFAULT) >= 0;
+ if (ret) {
+ int len = matcher.getEnd() - matcher.getBegin();
+ outPtr.set(srcBytes, matcher.getBegin(), len);
+ } else {
+ outPtr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ }
+ return ret;
+ }
+
+ @Override
+ public boolean split(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr) {
+ return split(srcPtr.get(), srcPtr.getOffset(), srcPtr.getLength(), outPtr);
+ }
+
+ private boolean
+ split(byte[] srcBytes, int srcOffset, int srcLen, ImmutableBytesWritable outPtr) {
+ PArrayDataTypeBytesArrayBuilder builder =
+ new PArrayDataTypeBytesArrayBuilder(PVarchar.INSTANCE, SortOrder.ASC);
+ int srcRange = srcOffset + srcLen;
+ Matcher matcher = pattern.matcher(srcBytes, 0, srcRange);
+ int cur = srcOffset;
+ boolean append;
+ while (true) {
+ int nextCur = matcher.search(cur, srcRange, Option.DEFAULT);
+ if (nextCur < 0) {
+ append = builder.appendElem(srcBytes, cur, srcRange - cur);
+ if (!append) return false;
+ break;
+ }
+
+ // To handle the following case, which adds null at first.
+ // REGEXP_SPLIT("12ONE34TWO56THREE78","[0-9]+")={null, "ONE", "TWO", "THREE", null}
+ if (cur == matcher.getBegin()) {
+ builder.appendElem(srcBytes, cur, 0);
+ }
+
+ if (cur < matcher.getBegin()) {
+ append = builder.appendElem(srcBytes, cur, matcher.getBegin() - cur);
+ if (!append) return false;
+ }
+ cur = matcher.getEnd();
+
+ // To handle the following case, which adds null at last.
+ // REGEXP_SPLIT("12ONE34TWO56THREE78","[0-9]+")={null, "ONE", "TWO", "THREE", null}
+ if (cur == srcRange) {
+ builder.appendElem(srcBytes, cur, 0);
+ break;
+ }
+ }
+ byte[] bytes = builder.getBytesAndClose();
+ if (bytes == null) return false;
+ outPtr.set(bytes);
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JavaPattern.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JavaPattern.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JavaPattern.java
new file mode 100644
index 0000000..be1188c
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/util/regex/JavaPattern.java
@@ -0,0 +1,93 @@
+/*
+ * 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.util.regex;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
+import org.apache.phoenix.schema.types.PDataType;
+import org.apache.phoenix.schema.types.PVarchar;
+import org.apache.phoenix.util.ByteUtil;
+
+import com.google.common.base.Preconditions;
+
+public class JavaPattern extends AbstractBasePattern {
+
+ private final Pattern pattern;
+
+ public JavaPattern(String patternString) {
+ this(patternString, 0);
+ }
+
+ public JavaPattern(String patternString, int flags) {
+ if (patternString != null) {
+ pattern = Pattern.compile(patternString, flags);
+ } else {
+ pattern = null;
+ }
+ }
+
+ @Override
+ public void matches(ImmutableBytesWritable srcPtr, ImmutableBytesWritable outPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(outPtr);
+ String matcherSourceStr = (String) PVarchar.INSTANCE.toObject(srcPtr);
+ if (srcPtr.get().length == 0 && matcherSourceStr == null) matcherSourceStr = "";
+ boolean ret = pattern.matcher(matcherSourceStr).matches();
+ outPtr.set(ret ? PDataType.TRUE_BYTES : PDataType.FALSE_BYTES);
+ }
+
+ @Override
+ public String pattern() {
+ return pattern.pattern();
+ }
+
+ @Override
+ public void replaceAll(ImmutableBytesWritable srcPtr, ImmutableBytesWritable replacePtr,
+ ImmutableBytesWritable replacedPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(replacePtr);
+ Preconditions.checkNotNull(replacedPtr);
+ String sourceStr = (String) PVarchar.INSTANCE.toObject(srcPtr);
+ String replaceStr = (String) PVarchar.INSTANCE.toObject(replacePtr);
+ if (srcPtr.get().length == 0 && sourceStr == null) sourceStr = "";
+ if (replacePtr.get().length == 0 && replaceStr == null) replaceStr = "";
+ String replacedStr = pattern.matcher(sourceStr).replaceAll(replaceStr);
+ replacedPtr.set(PVarchar.INSTANCE.toBytes(replacedStr));
+ }
+
+ @Override
+ public boolean substr(ImmutableBytesWritable srcPtr, int offsetInStr,
+ ImmutableBytesWritable outPtr) {
+ Preconditions.checkNotNull(srcPtr);
+ Preconditions.checkNotNull(outPtr);
+ String sourceStr = (String) PVarchar.INSTANCE.toObject(srcPtr);
+ if (srcPtr.get().length == 0 && sourceStr == null) sourceStr = "";
+ if (offsetInStr < 0) offsetInStr += sourceStr.length();
+ if (offsetInStr < 0 || offsetInStr >= sourceStr.length()) return false;
+ Matcher matcher = pattern.matcher(sourceStr);
+ boolean ret = matcher.find(offsetInStr);
+ if (ret) {
+ outPtr.set(PVarchar.INSTANCE.toBytes(matcher.group()));
+ } else {
+ outPtr.set(ByteUtil.EMPTY_BYTE_ARRAY);
+ }
+ return true;
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
index f415b01..e6ede7c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/expression/visitor/CloneExpressionVisitor.java
@@ -107,7 +107,8 @@ public class CloneExpressionVisitor extends TraverseAllExpressionVisitor<Express
@Override
public Expression visitLeave(LikeExpression node, List<Expression> l) {
- return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 ? node : new LikeExpression(l);
+ return Determinism.PER_INVOCATION.compareTo(node.getDeterminism()) > 0 ? node : node
+ .clone(l);
}
@Override
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpReplaceParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpReplaceParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpReplaceParseNode.java
new file mode 100644
index 0000000..4d98405
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpReplaceParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * 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.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.ByteBasedRegexpReplaceFunction;
+import org.apache.phoenix.expression.function.RegexpReplaceFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpReplaceFunction;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+
+/**
+ * Parse node corresponding to {@link RegexpReplaceFunction}. It also acts as a factory for creating
+ * the right kind of RegexpReplaceFunction according to setting in
+ * QueryServices.USE_BYTE_BASED_REGEX_ATTRIB
+ */
+public class RegexpReplaceParseNode extends FunctionParseNode {
+
+ RegexpReplaceParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+ super(name, children, info);
+ }
+
+ @Override
+ public Expression create(List<Expression> children, StatementContext context)
+ throws SQLException {
+ QueryServices services = context.getConnection().getQueryServices();
+ boolean useByteBasedRegex =
+ services.getProps().getBoolean(QueryServices.USE_BYTE_BASED_REGEX_ATTRIB,
+ QueryServicesOptions.DEFAULT_USE_BYTE_BASED_REGEX);
+ if (useByteBasedRegex) {
+ return new ByteBasedRegexpReplaceFunction(children);
+ } else {
+ return new StringBasedRegexpReplaceFunction(children);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/3f6b2594/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSplitParseNode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSplitParseNode.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSplitParseNode.java
new file mode 100644
index 0000000..74bee07
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/RegexpSplitParseNode.java
@@ -0,0 +1,55 @@
+/*
+ * 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.parse;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.phoenix.compile.StatementContext;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.function.ByteBasedRegexpSplitFunction;
+import org.apache.phoenix.expression.function.RegexpSplitFunction;
+import org.apache.phoenix.expression.function.StringBasedRegexpSplitFunction;
+import org.apache.phoenix.query.QueryServices;
+import org.apache.phoenix.query.QueryServicesOptions;
+
+/**
+ * Parse node corresponding to {@link RegexpSplitFunction}. It also acts as a factory for creating
+ * the right kind of RegexpSplitFunction according to setting in
+ * QueryServices.USE_BYTE_BASED_REGEX_ATTRIB
+ */
+public class RegexpSplitParseNode extends FunctionParseNode {
+
+ RegexpSplitParseNode(String name, List<ParseNode> children, BuiltInFunctionInfo info) {
+ super(name, children, info);
+ }
+
+ @Override
+ public Expression create(List<Expression> children, StatementContext context)
+ throws SQLException {
+ QueryServices services = context.getConnection().getQueryServices();
+ boolean useByteBasedRegex =
+ services.getProps().getBoolean(QueryServices.USE_BYTE_BASED_REGEX_ATTRIB,
+ QueryServicesOptions.DEFAULT_USE_BYTE_BASED_REGEX);
+ if (useByteBasedRegex) {
+ return new ByteBasedRegexpSplitFunction(children);
+ } else {
+ return new StringBasedRegexpSplitFunction(children);
+ }
+ }
+}