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 2016/09/08 13:34:38 UTC

svn commit: r1759820 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/ main/java/org/apache/jackrabbit/oak/query/ast/ main/java/org/apache/jackrabbit/oak/query/xpath/ main/java/org/apache/jackrabbit/oak/spi/query/ test...

Author: thomasm
Date: Thu Sep  8 13:34:38 2016
New Revision: 1759820

URL: http://svn.apache.org/viewvc?rev=1759820&view=rev
Log:
OAK-3574 Query engine: support p=lowercase('x') and other function-based indexes

Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Thu Sep  8 13:34:38 2016
@@ -31,16 +31,9 @@ import java.util.Set;
 
 import javax.annotation.Nonnull;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.AbstractIterator;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-
 import org.apache.jackrabbit.oak.api.PropertyValue;
-import org.apache.jackrabbit.oak.api.Tree;
-import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.api.Result.SizePrecision;
+import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.namepath.JcrPathParser;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.query.ast.AndImpl;
@@ -98,6 +91,12 @@ import org.apache.jackrabbit.oak.spi.sta
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Strings;
+import com.google.common.collect.AbstractIterator;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Ordering;
+
 /**
  * Represents a parsed query.
  */
@@ -987,21 +986,10 @@ public class QueryImpl implements Query
                     sortOrder = new ArrayList<OrderEntry>();
                     for (OrderingImpl o : orderings) {
                         DynamicOperandImpl op = o.getOperand();
-                        if (!(op instanceof PropertyValueImpl)) {
-                            // ordered by a function: currently not supported
-                            break;
-                        }
-                        PropertyValueImpl p = (PropertyValueImpl) op;
-                        SelectorImpl s = p.getSelectors().iterator().next();
-                        if (!s.equals(filter.getSelector())) {
-                            // ordered by a different selector
+                        OrderEntry e = op.getOrderEntry(filter.getSelector(), o);
+                        if (e == null) {
                             continue;
                         }
-                        OrderEntry e = new OrderEntry(
-                                p.getPropertyName(), 
-                                Type.UNDEFINED, 
-                                o.isDescending() ? 
-                                OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
                         sortOrder.add(e);
                     }
                     if (sortOrder.size() == 0) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java Thu Sep  8 13:34:38 2016
@@ -626,7 +626,7 @@ public class SQL2Parser {
     private DynamicOperandImpl parseExpressionFunction(String functionName) throws ParseException {
         DynamicOperandImpl op;
         if ("LENGTH".equalsIgnoreCase(functionName)) {
-            op = factory.length(parsePropertyValue(readName()));
+            op = factory.length(parseDynamicOperand());
         } else if ("NAME".equalsIgnoreCase(functionName)) {
             if (isToken(")")) {
                 op = factory.nodeName(getOnlySelectorName());

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java Thu Sep  8 13:34:38 2016
@@ -94,8 +94,8 @@ public class AstElementFactory {
         return new JoinImpl(left, right, joinType, joinCondition);
     }
 
-    public LengthImpl length(PropertyValueImpl propertyValue) {
-        return new LengthImpl(propertyValue);
+    public LengthImpl length(DynamicOperandImpl operand) {
+        return new LengthImpl(operand);
     }
 
     public LiteralImpl literal(PropertyValue literalValue) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstVisitorBase.java Thu Sep  8 13:34:38 2016
@@ -117,7 +117,7 @@ public abstract class AstVisitorBase imp
      */
     @Override
     public boolean visit(LengthImpl node) {
-        return node.getPropertyValue().accept(this);
+        return node.getOperand().accept(this);
     }
 
     /**

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java Thu Sep  8 13:34:38 2016
@@ -21,6 +21,7 @@ import java.util.Set;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 /**
  * The base class for dynamic operands (such as a function or property).
@@ -47,15 +48,12 @@ public abstract class DynamicOperandImpl
     public abstract void restrictList(FilterImpl f, List<PropertyValue> list);
     
     /**
-     * Apply a restriction of type "function(this) = value" to the given filter.
+     * Get the function of a function-based index, in Polish notation.
      * 
-     * @param functionName the function name (for example "upper")
-     * @param f the filter where the restriction is applied.
-     * @param operator the operator (for example "=").
-     * @param v the value
+     * @param s the selector
+     * @return the function, or null if not supported
      */
-    public abstract void restrictFunction(FilterImpl f, String functionName, Operator operator,
-            PropertyValue v);
+    public abstract String getFunction(SelectorImpl s);
 
     /**
      * Check whether the condition can be applied to a selector (to restrict the
@@ -106,5 +104,14 @@ public abstract class DynamicOperandImpl
     }
     
     public abstract DynamicOperandImpl createCopy();
+    
+    /**
+     * Create an entry for the "order by" list for a given filter.
+     * 
+     * @param s the selector
+     * @param o the ordering
+     * @return the entry
+     */
+    public abstract OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o);
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java Thu Sep  8 13:34:38 2016
@@ -28,6 +28,7 @@ import org.apache.jackrabbit.oak.api.Pro
 import org.apache.jackrabbit.oak.query.QueryImpl;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 /**
  * A fulltext search score expression.
@@ -92,8 +93,9 @@ public class FullTextSearchScoreImpl ext
     }
 
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
+    public String getFunction(SelectorImpl s) {
         // optimizations of the type "upper(jcr:score()) = '1'" are not supported
+        return null;
     }
 
     @Override
@@ -111,4 +113,9 @@ public class FullTextSearchScoreImpl ext
         return new FullTextSearchScoreImpl(selectorName);
     }
 
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        return null;
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java Thu Sep  8 13:34:38 2016
@@ -24,22 +24,25 @@ import java.util.Set;
 import javax.jcr.PropertyType;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 /**
  * The function "length(..)".
  */
 public class LengthImpl extends DynamicOperandImpl {
 
-    private final PropertyValueImpl propertyValue;
+    private final DynamicOperandImpl operand;
 
-    public LengthImpl(PropertyValueImpl propertyValue) {
-        this.propertyValue = propertyValue;
+    public LengthImpl(DynamicOperandImpl operand) {
+        this.operand = operand;
     }
 
-    public PropertyValueImpl getPropertyValue() {
-        return propertyValue;
+    public DynamicOperandImpl getOperand() {
+        return operand;
     }
 
     @Override
@@ -49,22 +52,22 @@ public class LengthImpl extends DynamicO
 
     @Override
     public String toString() {
-        return "length(" + propertyValue + ')';
+        return "length(" + operand + ')';
     }
     
     @Override
     public PropertyExistenceImpl getPropertyExistence() {
-        return propertyValue.getPropertyExistence();
+        return operand.getPropertyExistence();
     }
     
     @Override
     public Set<SelectorImpl> getSelectors() {
-        return propertyValue.getSelectors();
+        return operand.getSelectors();
     }
 
     @Override
     public PropertyValue currentProperty() {
-        PropertyValue p = propertyValue.currentProperty();
+        PropertyValue p = operand.currentProperty();
         if (p == null) {
             return null;
         }
@@ -99,8 +102,16 @@ public class LengthImpl extends DynamicO
             }
         }
         // LENGTH(x) implies x is not null
-        propertyValue.restrict(f, Operator.NOT_EQUAL, null);
-        propertyValue.restrictFunction(f, "length", operator, v);
+        operand.restrict(f, Operator.NOT_EQUAL, null);
+        if (operator == Operator.NOT_EQUAL && v != null) {
+            // not supported
+            return;
+        }        
+        String fn = getFunction(f.getSelector());
+        if (fn != null) {
+            f.restrictProperty(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, 
+                    operator, v, PropertyType.LONG);
+        }
     }
     
     @Override
@@ -109,13 +120,17 @@ public class LengthImpl extends DynamicO
     }
 
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        // optimizations of the type "upper(length(x)) = '1'" are not supported
+    public String getFunction(SelectorImpl s) {
+        String f = operand.getFunction(s);
+        if (f == null) {
+            return null;
+        }
+        return "length*" + f;
     }
 
     @Override
     public boolean canRestrictSelector(SelectorImpl s) {
-        return propertyValue.canRestrictSelector(s);
+        return operand.canRestrictSelector(s);
     }
     
     @Override
@@ -125,7 +140,20 @@ public class LengthImpl extends DynamicO
     
     @Override
     public DynamicOperandImpl createCopy() {
-        return new LengthImpl(propertyValue.createCopy());
+        return new LengthImpl(operand.createCopy());
+    }
+
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        String fn = getFunction(s);
+        if (fn != null) {
+            return new OrderEntry(
+                QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn,                     
+                Type.LONG, 
+                o.isDescending() ? 
+                OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+        }
+        return null;
     }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LowerCaseImpl.java Thu Sep  8 13:34:38 2016
@@ -24,8 +24,11 @@ import java.util.Set;
 import javax.jcr.PropertyType;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 import com.google.common.base.Function;
 
@@ -94,7 +97,15 @@ public class LowerCaseImpl extends Dynam
     public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
         // LOWER(x) implies x is not null
         operand.restrict(f, Operator.NOT_EQUAL, null);
-        operand.restrictFunction(f, "lower", operator, v);
+        if (operator == Operator.NOT_EQUAL && v != null) {
+            // not supported
+            return;
+        }
+        String fn = getFunction(f.getSelector());
+        if (fn != null) {
+            f.restrictProperty(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, 
+                    operator, v, PropertyType.STRING);
+        }
     }
     
     @Override
@@ -102,10 +113,14 @@ public class LowerCaseImpl extends Dynam
         // "LOWER(x) IN (A, B)" implies x is not null
         operand.restrict(f, Operator.NOT_EQUAL, null);
     }
-
+    
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        // optimizations of the type "lower(upper(x)) = 'x'" are not currently supported
+    public String getFunction(SelectorImpl s) {
+        String f = operand.getFunction(s);
+        if (f == null) {
+            return null;
+        }
+        return "lower*" + f;
     }
 
     @Override
@@ -122,5 +137,18 @@ public class LowerCaseImpl extends Dynam
     public DynamicOperandImpl createCopy() {
         return new LowerCaseImpl(operand.createCopy());
     }
+    
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        String fn = getFunction(s);
+        if (fn != null) {
+            return new OrderEntry(
+                QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn,                     
+                Type.STRING, 
+                o.isDescending() ? 
+                OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+        }
+        return null;
+    }        
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java Thu Sep  8 13:34:38 2016
@@ -25,10 +25,12 @@ import java.util.Set;
 import javax.jcr.PropertyType;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 /**
  * The function "localname(..)".
@@ -89,6 +91,10 @@ public class NodeLocalNameImpl extends D
         if (v == null) {
             return;
         }
+        if (operator == Operator.NOT_EQUAL && v != null) {
+            // not supported
+            return;
+        }
         String name = NodeNameImpl.getName(query, v);
         if (name != null && f.getSelector().equals(selector)
                 && NodeNameImpl.supportedOperator(operator)) {
@@ -103,25 +109,13 @@ public class NodeLocalNameImpl extends D
     }
     
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        // optimizations of the type "lower(LOCALNAME(x)) = 'x'"
-        if (operator == Operator.NOT_EQUAL) {
-            // not supported
-            return;
-        }
-        if (v == null) {
-            return;
-        }
-        String name = NodeNameImpl.getName(query, v);
-        if (name != null && f.getSelector().equals(selector)
-                && NodeNameImpl.supportedOperator(operator)) {
-            String restrictionName = QueryConstants.FUNCTION_RESTRICTION_PREFIX + 
-                    functionName + "*@" + QueryConstants.RESTRICTION_LOCAL_NAME;            
-            f.restrictProperty(restrictionName,
-                    operator, PropertyValues.newString(name));
+    public String getFunction(SelectorImpl s) {
+        if (!s.equals(selector)) {
+            return null;
         }
+        return "@" + QueryConstants.RESTRICTION_LOCAL_NAME;
     }
-
+    
     @Override
     public boolean supportsRangeConditions() {
         return false;
@@ -141,5 +135,18 @@ public class NodeLocalNameImpl extends D
     public DynamicOperandImpl createCopy() {
         return new NodeLocalNameImpl(selectorName);
     }
+    
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        if (!s.equals(selector)) {
+            // ordered by a different selector
+            return null;
+        }
+        return new OrderEntry(
+                QueryConstants.RESTRICTION_LOCAL_NAME, 
+            Type.STRING, 
+            o.isDescending() ? 
+            OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java Thu Sep  8 13:34:38 2016
@@ -32,6 +32,7 @@ import org.apache.jackrabbit.oak.query.Q
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
 import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 import org.apache.jackrabbit.util.ISO9075;
 
 /**
@@ -91,6 +92,10 @@ public class NodeNameImpl extends Dynami
         if (v == null) {
             return;
         }
+        if (operator == Operator.NOT_EQUAL && v != null) {
+            // not supported
+            return;
+        }
         String name = getName(query, v);
         if (name != null && f.getSelector().equals(selector)
                 && NodeNameImpl.supportedOperator(operator)) {
@@ -106,23 +111,11 @@ public class NodeNameImpl extends Dynami
     }
 
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        if (operator == Operator.NOT_EQUAL) {
-            // not supported
-            return;
-        }
-        if (v == null) {
-            return;
-        }
-        String name = getName(query, v);
-        if (name != null && f.getSelector().equals(selector)
-                && NodeNameImpl.supportedOperator(operator)) {
-            String localName = NodeLocalNameImpl.getLocalName(name);
-            String restrictionName = QueryConstants.FUNCTION_RESTRICTION_PREFIX + 
-                    functionName + "*@" + QueryConstants.RESTRICTION_LOCAL_NAME;            
-            f.restrictProperty(restrictionName,
-                    operator, PropertyValues.newString(localName));
+    public String getFunction(SelectorImpl s) {
+        if (!s.equals(selector)) {
+            return null;
         }
+        return "@" + QueryConstants.RESTRICTION_NAME;
     }
 
     @Override
@@ -179,5 +172,18 @@ public class NodeNameImpl extends Dynami
     public DynamicOperandImpl createCopy() {
         return new NodeNameImpl(selectorName);
     }
+    
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        if (!s.equals(selector)) {
+            // ordered by a different selector
+            return null;
+        }
+        return new OrderEntry(
+                QueryConstants.RESTRICTION_NAME, 
+            Type.STRING, 
+            o.isDescending() ? 
+            OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+    }
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java Thu Sep  8 13:34:38 2016
@@ -31,7 +31,7 @@ import org.apache.jackrabbit.oak.query.Q
 import org.apache.jackrabbit.oak.query.SQL2Parser;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.Filter.PathRestriction;
-import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 /**
  * A property expression.
@@ -143,17 +143,12 @@ public class PropertyValueImpl extends D
     }
     
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        if (operator == Operator.NOT_EQUAL) {
-            // not supported
-            return;
-        }
-        if (f.getSelector().equals(selector)) {
-            String pn = normalizePropertyName(propertyName);
-            String restrictionName = QueryConstants.FUNCTION_RESTRICTION_PREFIX +
-                    functionName + "*@" + pn;
-            f.restrictProperty(restrictionName, operator, v, propertyType);
+    public String getFunction(SelectorImpl s) {
+        if (!s.equals(selector)) {
+            return null;
         }
+        String pn = normalizePropertyName(propertyName);
+        return "@" + pn;
     }
 
     @Override
@@ -170,4 +165,19 @@ public class PropertyValueImpl extends D
     public PropertyValueImpl createCopy() {
         return new PropertyValueImpl(selectorName, propertyName);
     }
+
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        if (!s.equals(selector)) {
+            // ordered by a different selector
+            return null;
+        }
+        String pn = normalizePropertyName(propertyName);
+        return new OrderEntry(
+            pn, 
+            Type.UNDEFINED, 
+            o.isDescending() ? 
+            OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+    }
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/UpperCaseImpl.java Thu Sep  8 13:34:38 2016
@@ -24,8 +24,11 @@ import java.util.Set;
 import javax.jcr.PropertyType;
 
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.PropertyValues;
+import org.apache.jackrabbit.oak.spi.query.QueryConstants;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.OrderEntry;
 
 import static org.apache.jackrabbit.oak.api.Type.STRING;
 
@@ -80,7 +83,15 @@ public class UpperCaseImpl extends Dynam
     public void restrict(FilterImpl f, Operator operator, PropertyValue v) {
         // UPPER(x) implies x is not null
         operand.restrict(f, Operator.NOT_EQUAL, null);
-        operand.restrictFunction(f, "upper", operator, v);
+        if (operator == Operator.NOT_EQUAL && v != null) {
+            // not supported
+            return;
+        }        
+        String fn = getFunction(f.getSelector());
+        if (fn != null) {
+            f.restrictProperty(QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn, 
+                    operator, v, PropertyType.STRING);
+        }
     }
     
     @Override
@@ -90,9 +101,13 @@ public class UpperCaseImpl extends Dynam
     }
     
     @Override
-    public void restrictFunction(FilterImpl f, String functionName, Operator operator, PropertyValue v) {
-        // optimizations of the type "lower(upper(x)) = 'x'" are not supported
-    }    
+    public String getFunction(SelectorImpl s) {
+        String f = operand.getFunction(s);
+        if (f == null) {
+            return null;
+        }
+        return "upper*" + f;
+    }
 
     @Override
     public boolean canRestrictSelector(SelectorImpl s) {
@@ -108,5 +123,18 @@ public class UpperCaseImpl extends Dynam
     public DynamicOperandImpl createCopy() {
         return new UpperCaseImpl(operand.createCopy());
     }
+    
+    @Override
+    public OrderEntry getOrderEntry(SelectorImpl s, OrderingImpl o) {
+        String fn = getFunction(s);
+        if (fn != null) {
+            return new OrderEntry(
+                QueryConstants.FUNCTION_RESTRICTION_PREFIX + fn,                     
+                Type.STRING, 
+                o.isDescending() ? 
+                OrderEntry.Order.DESCENDING : OrderEntry.Order.ASCENDING);
+        }
+        return null;
+    }    
 
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java Thu Sep  8 13:34:38 2016
@@ -651,6 +651,11 @@ public class XPathToSQL2Converter {
             f.params.add(parseExpression());
             read(")");
             return f;
+        } else if ("fn:string-length".equals(functionName)) {
+            Expression.Function f = new Expression.Function("length");
+            f.params.add(parseExpression());
+            read(")");
+            return f;
         } else if ("fn:name".equals(functionName)) {
             Expression.Function f = new Expression.Function("name");
             if (!readIf(")")) {
@@ -658,6 +663,15 @@ public class XPathToSQL2Converter {
                 read(".");
                 read(")");
             }
+            f.params.add(new Expression.SelectorExpr(currentSelector));
+            return f;
+        } else if ("fn:local-name".equals(functionName)) {
+            Expression.Function f = new Expression.Function("localname");
+            if (!readIf(")")) {
+                // only localname(.) and localname() are currently supported
+                read(".");
+                read(")");
+            }
             f.params.add(new Expression.SelectorExpr(currentSelector));
             return f;
         } else if ("jcr:deref".equals(functionName)) {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java Thu Sep  8 13:34:38 2016
@@ -26,7 +26,13 @@ public abstract class QueryConstants {
      * via NAME and LOCALNAME functions
      */
     public static final String RESTRICTION_LOCAL_NAME = ":localname";
-    
+
+    /**
+     * Name of the property restriction used to express query performed
+     * via NAME and LOCALNAME functions
+     */
+    public static final String RESTRICTION_NAME = ":name";
+
     /**
      * The prefix for restrictions for function-based indexes, for example
      * upper(propertyName). Syntax: "function*expression". In order to support

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java Thu Sep  8 13:34:38 2016
@@ -321,7 +321,7 @@ public abstract class AbstractQueryTest
             assertTrue("Expected path " + p + " not found, got " + actual, checkNotNull(actual)
                 .contains(p));
         }
-        assertEquals("Result set size is different", expected.size(),
+        assertEquals("Result set size is different: " + actual, expected.size(),
                 actual.size());
     }
 

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java Thu Sep  8 13:34:38 2016
@@ -71,13 +71,13 @@ public class FilterTest {
         assertEquals("Filter(query=select [jcr:path] from [nt:base] " + 
                 "where upper(name()) = 'ACME:TEST', " + 
                 "path=*, property=[" + 
-                "function*upper*@:localname=[TEST]])", createFilterSQL(sql2).toString());
+                "function*upper*@:name=[ACME:TEST]])", createFilterSQL(sql2).toString());
         
-        sql2 = "select [jcr:path] from [nt:base] where lower(localname()) = 'test'";
+        sql2 = "select [jcr:path] from [nt:base] where lower(localname()) > 'test'";
         assertEquals("Filter(query=select [jcr:path] from [nt:base] " + 
-                "where lower(localname()) = 'test', " + 
+                "where lower(localname()) > 'test', " + 
                 "path=*, property=[" + 
-                "function*lower*@:localname=[test]])", createFilterSQL(sql2).toString());
+                "function*lower*@:localname=[(test..]])", createFilterSQL(sql2).toString());
 
         sql2 = "select [jcr:path] from [nt:base] where length([test]) <= 10";
         assertEquals("Filter(query=select [jcr:path] from [nt:base] " + 
@@ -85,13 +85,11 @@ public class FilterTest {
                 "path=*, property=[function*length*@test=[..10]], " + 
                 "test=[is not null]])", createFilterSQL(sql2).toString());
         
-        sql2 = "select [jcr:path] from [nt:base] where length([test]) > 2";
+        sql2 = "select [jcr:path] from [nt:base] where length([data/test]) > 2";
         assertEquals("Filter(query=select [jcr:path] from [nt:base] " + 
-                "where length([test]) > 2, " + 
-                "path=*, property=[function*length*@test=[(2..], " + 
-                "test=[is not null]])", createFilterSQL(sql2).toString());
-        
-
+                "where length([data/test]) > 2, " + 
+                "path=*, property=[data/test=[is not null], " + 
+                "function*length*@data/test=[(2..]])", createFilterSQL(sql2).toString());
     }
     
     @Test

Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt?rev=1759820&r1=1759819&r2=1759820&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt Thu Sep  8 13:34:38 2016
@@ -468,6 +468,11 @@ select [jcr:path]
 
 select [jcr:path]
   from [nt:base]
+  where upper(name) = '10%'
+/testRoot/test4
+
+select [jcr:path]
+  from [nt:base]
   where upper(name) like '10\%'
 /testRoot/test4