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");