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>
