You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2020/05/05 08:30:52 UTC
svn commit: r1877376 - in /jackrabbit/oak/trunk/oak-search/src:
main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java
test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java
Author: thomasm
Date: Tue May 5 08:30:52 2020
New Revision: 1877376
URL: http://svn.apache.org/viewvc?rev=1877376&view=rev
Log:
OAK-9046 Index function string-length should index size for binary
Modified:
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java
jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java
Modified: jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java?rev=1877376&r1=1877375&r2=1877376&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessor.java Tue May 5 08:30:52 2020
@@ -37,10 +37,10 @@ import org.slf4j.LoggerFactory;
* definition (XPath) to the internal Polish notation.
*/
public class FunctionIndexProcessor {
-
+
private static final Logger LOG =
LoggerFactory.getLogger(FunctionIndexProcessor.class);
-
+
private String remaining;
private static final PropertyState EMPTY_PROPERTY_STATE = EmptyPropertyState.emptyProperty("empty", Type.STRINGS);
@@ -48,10 +48,10 @@ public class FunctionIndexProcessor {
protected FunctionIndexProcessor(String function) {
this.remaining = function;
}
-
+
/**
* Get the list of properties used in the given function code.
- *
+ *
* @param functionCode the tokens, for example ["function", "lower", "@name"]
* @return the list of properties, for example ["name"]
*/
@@ -68,7 +68,7 @@ public class FunctionIndexProcessor {
/**
* Try to calculate the value for the given function code.
- *
+ *
* @param path the path of the node
* @param state the node state
* @param functionCode the tokens, for example ["function", "lower", "@name"]
@@ -94,10 +94,10 @@ public class FunctionIndexProcessor {
PropertyState ret = stack.pop();
return ret==EMPTY_PROPERTY_STATE ? null : ret;
}
-
+
/**
* Split the polish notation into a tokens that can more easily be processed.
- *
+ *
* @param functionDescription in polish notation, for example "function*lower*{@literal @}name"
* @return tokens, for example ["function", "lower", "{@literal @}name"]
*/
@@ -107,7 +107,7 @@ public class FunctionIndexProcessor {
}
return functionDescription.split("\\*");
}
-
+
private static PropertyState calculateFunction(String functionName,
Deque<PropertyState> stack) {
PropertyState ps = stack.pop();
@@ -126,19 +126,20 @@ public class FunctionIndexProcessor {
Type<?> type = null;
ArrayList<Object> values = new ArrayList<>(ps.count());
for (int i = 0; i < ps.count(); i++) {
- String s = ps.getValue(Type.STRING, i);
Object x;
if ("lower".equals(functionName)) {
+ String s = ps.getValue(Type.STRING, i);
x = s.toLowerCase();
type = Type.STRING;
- } else if ("coalesce".equals(functionName)) {
- x = s;
- type = Type.STRING;
} else if ("upper".equals(functionName)) {
+ String s = ps.getValue(Type.STRING, i);
x = s.toUpperCase();
type = Type.STRING;
+ } else if ("coalesce".equals(functionName)) {
+ x = ps.getValue(Type.STRING, i);
+ type = Type.STRING;
} else if ("length".equals(functionName)) {
- x = (long) s.length();
+ x = ps.size(i);
type = Type.LONG;
} else {
LOG.debug("Unknown function {}", functionName);
@@ -155,7 +156,7 @@ public class FunctionIndexProcessor {
}
return result;
}
-
+
private static PropertyState getProperty(String path, NodeState state,
String propertyName) {
if (PathUtils.getDepth(propertyName) != 1) {
@@ -182,16 +183,16 @@ public class FunctionIndexProcessor {
}
return ps;
}
-
+
private static String getLocalName(String name) {
int colon = name.indexOf(':');
// TODO LOCALNAME: evaluation of local name might not be correct
return colon < 0 ? name : name.substring(colon + 1);
}
-
+
/**
* Convert a function (in human-readable form) to the polish notation.
- *
+ *
* @param function the function, for example "lower([name])"
* @return the polish notation, for example "function*lower*{@literal @}name"
*/
@@ -202,7 +203,7 @@ public class FunctionIndexProcessor {
FunctionIndexProcessor p = new FunctionIndexProcessor(function);
return QueryConstants.FUNCTION_RESTRICTION_PREFIX + p.parse();
}
-
+
String parse() {
if (match("fn:local-name()") || match("localname()")) {
return "@:localname";
@@ -248,11 +249,11 @@ public class FunctionIndexProcessor {
return property(prop.replaceAll("@", ""));
}
}
-
+
String property(String p) {
return "@" + p;
}
-
+
private String read(String string) {
match(string);
return "";
@@ -267,7 +268,7 @@ public class FunctionIndexProcessor {
}
return "*";
}
-
+
private boolean match(String string) {
if (remaining.startsWith(string)) {
remaining = remaining.substring(string.length());
Modified: jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java?rev=1877376&r1=1877375&r2=1877376&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java (original)
+++ jackrabbit/oak/trunk/oak-search/src/test/java/org/apache/jackrabbit/oak/plugins/index/search/util/FunctionIndexProcessorTest.java Tue May 5 08:30:52 2020
@@ -18,14 +18,17 @@
*/
package org.apache.jackrabbit.oak.plugins.index.search.util;
+import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE;
+import static org.junit.Assert.assertEquals;
+
import java.util.Arrays;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.ArrayBasedBlob;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-
public class FunctionIndexProcessorTest {
-
+
@Test
public void getProperties() {
assertEquals(
@@ -34,29 +37,54 @@ public class FunctionIndexProcessorTest
FunctionIndexProcessor.getProperties(new String[] { "function",
"multiply", "@a", "add", "@test/b", "@test/:name" })));
}
-
+
+ @Test
+ public void tryCalculateValue() {
+ // length of a string
+ assertEquals("value = 11",
+ FunctionIndexProcessor.tryCalculateValue("x",
+ EMPTY_NODE.builder().setProperty("data", "Hello World").getNodeState(),
+ new String[]{"function", "length", "@data"}).toString());
+ // length of a binary property
+ assertEquals("value = 100",
+ FunctionIndexProcessor.tryCalculateValue("x",
+ EMPTY_NODE.builder().setProperty("data",
+ new ArrayBasedBlob(new byte[100]), Type.BINARY).getNodeState(),
+ new String[]{"function", "length", "@data"}).toString());
+ // uppercase
+ assertEquals("value = HELLO WORLD",
+ FunctionIndexProcessor.tryCalculateValue("x",
+ EMPTY_NODE.builder().setProperty("data", "Hello World").getNodeState(),
+ new String[]{"function", "upper", "@data"}).toString());
+ // lowercase
+ assertEquals("value = hello world",
+ FunctionIndexProcessor.tryCalculateValue("x",
+ EMPTY_NODE.builder().setProperty("data", "Hello World").getNodeState(),
+ new String[]{"function", "lower", "@data"}).toString());
+ }
+
@Test
public void xpath() {
checkConvert(
- "fn:upper-case(@data)",
+ "fn:upper-case(@data)",
"function*upper*@data");
checkConvert(
- "fn:lower-case(test/@data)",
+ "fn:lower-case(test/@data)",
"function*lower*@test/data");
checkConvert(
- "fn:lower-case(fn:name())",
- "function*lower*@:name");
+ "fn:lower-case(fn:name())",
+ "function*lower*@:name");
checkConvert(
- "fn:lower-case(fn:local-name())",
+ "fn:lower-case(fn:local-name())",
"function*lower*@:localname");
checkConvert(
- "fn:string-length(test/@data)",
+ "fn:string-length(test/@data)",
"function*length*@test/data");
checkConvert(
- "fn:string-length(fn:name())",
+ "fn:string-length(fn:name())",
"function*length*@:name");
checkConvert(
- "fn:lower-case(fn:upper-case(test/@data))",
+ "fn:lower-case(fn:upper-case(test/@data))",
"function*lower*upper*@test/data");
checkConvert("fn:coalesce(jcr:content/@foo2, jcr:content/@foo)",
"function*coalesce*@jcr:content/foo2*@jcr:content/foo");
@@ -71,29 +99,29 @@ public class FunctionIndexProcessorTest
@Test
public void sql2() {
checkConvert(
- "upper([data])",
+ "upper([data])",
"function*upper*@data");
checkConvert(
- "lower([test/data])",
+ "lower([test/data])",
"function*lower*@test/data");
checkConvert(
- "lower(name())",
+ "lower(name())",
"function*lower*@:name");
checkConvert(
- "lower(localname())",
+ "lower(localname())",
"function*lower*@:localname");
checkConvert(
- "length([test/data])",
+ "length([test/data])",
"function*length*@test/data");
checkConvert(
- "length(name())",
+ "length(name())",
"function*length*@:name");
checkConvert(
- "lower(upper([test/data]))",
+ "lower(upper([test/data]))",
"function*lower*upper*@test/data");
// the ']' character is escaped as ']]'
checkConvert(
- "[strange[0]]]",
+ "[strange[0]]]",
"function*@strange[0]");
checkConvert("coalesce([jcr:content/foo2],[jcr:content/foo])",
"function*coalesce*@jcr:content/foo2*@jcr:content/foo");