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/10/19 12:20:57 UTC

svn commit: r1765583 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-cor...

Author: thomasm
Date: Wed Oct 19 12:20:56 2016
New Revision: 1765583

URL: http://svn.apache.org/viewvc?rev=1765583&view=rev
Log:
OAK-4888 Warn or fail queries above a configurable cost value

Added:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java
    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/UnionQueryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java Wed Oct 19 12:20:56 2016
@@ -51,4 +51,19 @@ public interface QueryEngineSettingsMBea
      */
     void setLimitReads(long limitReads);
     
+    /**
+     * Whether queries that don't use an index will fail (throw an exception).
+     * The default is false.
+     * 
+     * @return true if they fail
+     */
+    boolean getFailTraversal();
+
+    /**
+     * Set whether queries that don't use an index will fail (throw an exception).
+     * 
+     * @param failTraversal the new value for this setting
+     */
+    void setFailTraversal(boolean failTraversal);
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java Wed Oct 19 12:20:56 2016
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("4.0.0")
+@Version("5.0.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.api.jmx;
 

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java Wed Oct 19 12:20:56 2016
@@ -434,7 +434,7 @@ public class ContentMirrorStoreStrategy
                         readCount++;
                         if (readCount % TRAVERSING_WARN == 0) {
                             FilterIterators.checkReadLimit(readCount, settings);
-                            LOG.warn("Traversed {} nodes ({} index entries) using index {} with filter {}", readCount, intermediateNodeReadCount, indexName, filter);
+                            LOG.warn("Index-Traversed {} nodes ({} index entries) using index {} with filter {}", readCount, intermediateNodeReadCount, indexName, filter);
                         }
                         return;
                     } else {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Wed Oct 19 12:20:56 2016
@@ -183,4 +183,11 @@ public interface Query {
      */    
     boolean containsUnfilteredFullTextCondition();
 
+    /**
+     * Set the query option to be used for this query.
+     * 
+     * @param options the options
+     */
+    void setQueryOptions(QueryOptions options);
+
 }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java Wed Oct 19 12:20:56 2016
@@ -35,7 +35,10 @@ public class QueryEngineSettings impleme
             Integer.getInteger("oak.queryLimitInMemory", Integer.MAX_VALUE);
     
     private static final int DEFAULT_QUERY_LIMIT_READS = 
-            Integer.getInteger("oak.queryLimitReads", Integer.MAX_VALUE);    
+            Integer.getInteger("oak.queryLimitReads", Integer.MAX_VALUE);
+    
+    private static final boolean DEFAULT_FAIL_TRAVERSAL =
+            Boolean.getBoolean("oak.queryFailTraversal");
     
     private static final boolean DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX = 
             Boolean.getBoolean("oak.queryFullTextComparisonWithoutIndex");
@@ -44,6 +47,8 @@ public class QueryEngineSettings impleme
     
     private long limitReads = DEFAULT_QUERY_LIMIT_READS;
     
+    private boolean failTraversal = DEFAULT_FAIL_TRAVERSAL;
+    
     private boolean fullTextComparisonWithoutIndex = 
             DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX;
     
@@ -72,6 +77,16 @@ public class QueryEngineSettings impleme
         this.limitReads = limitReads;
     }
     
+    @Override
+    public boolean getFailTraversal() {
+        return failTraversal;
+    }
+
+    @Override
+    public void setFailTraversal(boolean failTraversal) {
+        this.failTraversal = failTraversal;
+    }
+    
     public void setFullTextComparisonWithoutIndex(boolean fullTextComparisonWithoutIndex) {
         this.fullTextComparisonWithoutIndex = fullTextComparisonWithoutIndex;
     }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java Wed Oct 19 12:20:56 2016
@@ -70,6 +70,16 @@ public class QueryEngineSettingsMBeanImp
         settings.setLimitReads(limitReads);
     }
     
+    @Override
+    public boolean getFailTraversal() {
+        return settings.getFailTraversal();
+    }
+
+    @Override
+    public void setFailTraversal(boolean failQueriesWithoutIndex) {
+        settings.setFailTraversal(failQueriesWithoutIndex);
+    }
+    
     public void setFullTextComparisonWithoutIndex(boolean fullTextComparisonWithoutIndex) {
         settings.setFullTextComparisonWithoutIndex(fullTextComparisonWithoutIndex);
     }

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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
@@ -36,6 +36,7 @@ import org.apache.jackrabbit.oak.api.Res
 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.QueryOptions.Traversal;
 import org.apache.jackrabbit.oak.query.ast.AndImpl;
 import org.apache.jackrabbit.oak.query.ast.AstVisitorBase;
 import org.apache.jackrabbit.oak.query.ast.BindVariableValueImpl;
@@ -160,6 +161,11 @@ public class QueryImpl implements Query
      * purposes.
      */
     private boolean traversalEnabled = true;
+    
+    /**
+     * The query option to be used for this query.
+     */
+    private QueryOptions queryOptions = new QueryOptions();
 
     private OrderingImpl[] orderings;
     private ColumnImpl[] columns;
@@ -948,6 +954,11 @@ public class QueryImpl implements Query
         this.traversalEnabled = traversalEnabled;
     }
 
+    @Override
+    public void setQueryOptions(QueryOptions options) {
+        this.queryOptions = options;
+    }
+
     public SelectorExecutionPlan getBestSelectorExecutionPlan(FilterImpl filter) {
         return getBestSelectorExecutionPlan(context.getBaseState(), filter,
                 context.getIndexProvider(), traversalEnabled);
@@ -1036,7 +1047,27 @@ public class QueryImpl implements Query
                 bestPlan = indexPlan;
             }
         }
-
+        if (bestIndex == null) {
+            QueryOptions.Traversal traversal = queryOptions.traversal;
+            if (traversal == Traversal.DEFAULT) {
+                // use the (configured) default
+                traversal = settings.getFailTraversal() ? Traversal.FAIL : Traversal.WARN;
+            } else {
+                // explicitly set in the query
+                traversal = queryOptions.traversal;
+            }
+            String message = "Traversal query (query without index): " + statement + "; consider creating an index";
+            switch (traversal) {
+            case OK:
+                break;
+            case WARN:
+                LOG.warn(message);
+                break;
+            case FAIL:
+                LOG.warn(message);
+                throw new IllegalArgumentException(message);
+            }
+        }
         if (traversalEnabled) {
             QueryIndex traversal = new TraversingIndex();
             double cost = traversal.getCost(filter, rootState);

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java?rev=1765583&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java Wed Oct 19 12:20:56 2016
@@ -0,0 +1,34 @@
+/*
+ * 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.jackrabbit.oak.query;
+
+/**
+ * A query options (or "hints") that are used to customize the way the query is processed.
+ */
+public class QueryOptions {
+    
+    public Traversal traversal = Traversal.DEFAULT;
+    
+    public enum Traversal {
+        // traversing without index is OK for this query, and does not fail or log a warning
+        OK, 
+        // traversing is OK, but logs a warning
+        WARN, 
+        // traversing will fail the query
+        FAIL,
+        // the default setting
+        DEFAULT
+    };
+
+}

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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
@@ -24,6 +24,7 @@ import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.jcr.PropertyType;
@@ -34,6 +35,7 @@ import org.apache.jackrabbit.oak.api.Que
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
 import org.apache.jackrabbit.oak.query.ast.AstElementFactory;
 import org.apache.jackrabbit.oak.query.ast.BindVariableValueImpl;
 import org.apache.jackrabbit.oak.query.ast.ColumnImpl;
@@ -161,6 +163,15 @@ public class SQL2Parser {
             read("BY");
             orderings = parseOrder();
         }
+        QueryOptions options = new QueryOptions();
+        if (readIf("OPTION")) {
+            read("(");
+            if (readIf("TRAVERSAL")) {
+                String n = readName().toUpperCase(Locale.ENGLISH);
+                options.traversal = Traversal.valueOf(n);
+            }
+            read(")");
+        }
         if (!currentToken.isEmpty()) {
             throw getSyntaxError("<end>");
         }
@@ -168,6 +179,7 @@ public class SQL2Parser {
         q.setExplain(explain);
         q.setMeasure(measure);
         q.setInternal(isInternal(query));
+        q.setQueryOptions(options);
 
         if (initialise) {
             try {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java Wed Oct 19 12:20:56 2016
@@ -118,6 +118,12 @@ public class UnionQueryImpl implements Q
         left.setTraversalEnabled(traversal);
         right.setTraversalEnabled(traversal);
     }
+    
+    @Override
+    public  void setQueryOptions(QueryOptions options) {
+        left.setQueryOptions(options);
+        right.setQueryOptions(options);
+    }
 
     @Override
     public void prepare() {

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java Wed Oct 19 12:20:56 2016
@@ -19,6 +19,8 @@ package org.apache.jackrabbit.oak.query.
 import java.util.ArrayList;
 
 import org.apache.jackrabbit.oak.query.QueryImpl;
+import org.apache.jackrabbit.oak.query.QueryOptions;
+import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
 import org.apache.jackrabbit.oak.query.xpath.Expression.AndCondition;
 import org.apache.jackrabbit.oak.query.xpath.Expression.OrCondition;
 import org.apache.jackrabbit.oak.query.xpath.Expression.Property;
@@ -50,6 +52,8 @@ public class Statement {
     
     String xpathQuery;
     
+    QueryOptions queryOptions = new QueryOptions();
+    
     public Statement optimize() {
         ignoreOrderByScoreDesc();
         if (where == null) {
@@ -80,6 +84,7 @@ public class Statement {
         union.xpathQuery = xpathQuery;
         union.measure = measure;
         union.explain = explain;
+        union.queryOptions = queryOptions;
 
         return union;
     }
@@ -209,6 +214,9 @@ public class Statement {
                 buff.append(orderList.get(i));
             }
         }
+        if (queryOptions.traversal != Traversal.DEFAULT) {
+            buff.append(" option(traversal " + queryOptions.traversal +")");
+        }
         // leave original xpath string as a comment
         appendXPathAsComment(buff, xpathQuery);
         return buff.toString();        
@@ -296,6 +304,9 @@ public class Statement {
                     buff.append(orderList.get(i));
                 }
             }
+            if (queryOptions.traversal != Traversal.DEFAULT) {
+                buff.append(" option(traversal " + queryOptions.traversal +")");
+            }
             // leave original xpath string as a comment
             appendXPathAsComment(buff, xpathQuery);
             return buff.toString();
@@ -314,4 +325,8 @@ public class Statement {
         buff.append(" */");        
     }
 
+    public  void setQueryOptions(QueryOptions options) {
+        this.queryOptions = options;
+    }
+
 }

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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
@@ -17,6 +17,8 @@
 package org.apache.jackrabbit.oak.query.xpath;
 
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.query.QueryOptions;
+import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
 import org.apache.jackrabbit.oak.query.xpath.Statement.UnionStatement;
 import org.apache.jackrabbit.util.ISO9075;
 import org.slf4j.Logger;
@@ -25,6 +27,7 @@ import org.slf4j.LoggerFactory;
 import java.math.BigDecimal;
 import java.text.ParseException;
 import java.util.ArrayList;
+import java.util.Locale;
 
 /**
  * This class can can convert a XPATH query to a SQL2 query.
@@ -324,11 +327,21 @@ public class XPathToSQL2Converter {
                 statement.addOrderBy(order);
             } while (readIf(","));
         }
+        QueryOptions options = new QueryOptions();
+        if (readIf("option")) {
+            read("(");
+            if (readIf("traversal")) {
+                String type = readIdentifier().toUpperCase(Locale.ENGLISH);
+                options.traversal = Traversal.valueOf(type);
+            }
+            read(")");
+        }
         if (!currentToken.isEmpty()) {
             throw getSyntaxError("<end>");
         }
         statement.setColumnSelector(currentSelector);
         statement.setSelectors(selectors);
+        statement.setQueryOptions(options);
         
         Expression where = null;
         for (Selector s : selectors) {
@@ -1105,10 +1118,14 @@ public class XPathToSQL2Converter {
             } else {
                 UnionStatement union = new UnionStatement(result, stat);
                 union.orderList = stat.orderList;
+                union.queryOptions = stat.queryOptions;
                 result = union;
             }
-            // can not use clear, because it is shared
+            // reset fields that are used in the union,
+            // but no longer in the individual statements
+            // (can not use clear, because it is shared)
             stat.orderList = new ArrayList<Order>();
+            stat.queryOptions = new QueryOptions();
         }
         return result;
     }

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java Wed Oct 19 12:20:56 2016
@@ -54,7 +54,6 @@ public class SQL2ParserTest {
                 .convert("/jcr:root/test/*/nt:resource[@jcr:encoding]"));
         p.parse(new XPathToSQL2Converter()
                 .convert("/jcr:root/test/*/*/nt:resource[@jcr:encoding]"));        
-        
         String xpath = "/jcr:root/etc/commerce/products//*[@cq:commerceType = 'product' " +
                 "and ((@size = 'M' or */@size= 'M' or */*/@size = 'M' " +
                 "or */*/*/@size = 'M' or */*/*/*/@size = 'M' or */*/*/*/*/@size = 'M'))]";

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java Wed Oct 19 12:20:56 2016
@@ -34,6 +34,45 @@ public class XPathTest {
             new NodeStateNodeTypeInfoProvider(INITIAL_CONTENT);
     
     @Test
+    public void queryOptions() throws ParseException {
+        verify("/jcr:root/content//*[@a] order by @c option(traversal fail)",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "and isdescendantnode(a, '/content') " +
+                "order by [c] option(traversal FAIL) " +
+                "/* xpath: /jcr:root/content//*[@a] " +
+                "order by @c " + 
+                "option(traversal fail) */");            
+        verify("//*[@a or @b] order by @c option(traversal warn)",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [b] is not null " +
+                "order by [c] option(traversal WARN) " +
+                "/* xpath: //*[@a or @b] " + 
+                "order by @c " + 
+                "option(traversal warn) */");
+        verify("/jcr:root/(content|libs)//*[@a] order by @c option(traversal ok)",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "and isdescendantnode(a, '/content') " +
+                "/* xpath: /jcr:root/content//*[@a] " +
+                "order by @c option(traversal ok) */ " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "and isdescendantnode(a, '/libs') " +
+                "/* xpath: /jcr:root/libs//*[@a] " +
+                "order by @c option(traversal ok) */ " +
+                "order by [c] " + 
+                "option(traversal OK)");            
+    }
+    
+    @Test
     public void test() throws ParseException {
         verify("(/jcr:root/content//*[@a] | /jcr:root/lib//*[@b]) order by @c",
                 "select [jcr:path], [jcr:score], * " + 
@@ -121,6 +160,7 @@ public class XPathTest {
         sql = sql.replaceAll(" and ", "\nand ");
         sql = sql.replaceAll(" union ", "\nunion ");
         sql = sql.replaceAll(" order by ", "\norder by ");
+        sql = sql.replaceAll(" option\\(", "\noption\\(");
         sql = sql.replaceAll(" \\/\\* ", "\n/* ");
         return sql;
     }

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java Wed Oct 19 12:20:56 2016
@@ -69,6 +69,34 @@ public class QueryTest extends AbstractR
     }
     
     @Test
+    public void traversalOption() throws Exception {
+        Session session = getAdminSession();
+        QueryManager qm = session.getWorkspace().getQueryManager();
+        try {
+            qm.createQuery("//*[@test] option(traversal fail)", 
+                    "xpath").execute();
+            fail();
+        } catch (InvalidQueryException e) {
+            // expected
+        }
+        try {
+            qm.createQuery("select * from [nt:base] option(traversal fail)", 
+                    Query.JCR_SQL2).execute();
+            fail();
+        } catch (InvalidQueryException e) {
+            // expected
+        }
+        qm.createQuery("//*[@test] option(traversal ok)", 
+                "xpath").execute();
+        qm.createQuery("//*[@test] option(traversal warn)", 
+                "xpath").execute();
+        qm.createQuery("select * from [nt:base] option(traversal ok)", 
+                Query.JCR_SQL2).execute();
+        qm.createQuery("select * from [nt:base] option(traversal warn)", 
+                Query.JCR_SQL2).execute();
+    }    
+    
+    @Test
     public void firstSelector() throws Exception {
         Session session = getAdminSession();
         Node root = session.getRootNode();



Re: svn commit: r1765583 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-cor...

Posted by Julian Sedding <js...@gmail.com>.
Thanks Chetan!

On Fri, Oct 21, 2016 at 2:59 PM, Chetan Mehrotra
<ch...@gmail.com> wrote:
> On Thu, Oct 20, 2016 at 6:08 PM, Julian Sedding <js...@gmail.com> wrote:
>> I think we could get away with increasing this to 4.1.0 if we can
>> annotate QueryEngineSettingsMBean with @ProviderType.
>
> Makes sense. Opened OAK-4977 for that
>
> Chetan Mehrotra

Re: svn commit: r1765583 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-cor...

Posted by Chetan Mehrotra <ch...@gmail.com>.
On Thu, Oct 20, 2016 at 6:08 PM, Julian Sedding <js...@gmail.com> wrote:
> I think we could get away with increasing this to 4.1.0 if we can
> annotate QueryEngineSettingsMBean with @ProviderType.

Makes sense. Opened OAK-4977 for that

Chetan Mehrotra

Re: svn commit: r1765583 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/ oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-cor...

Posted by Julian Sedding <js...@gmail.com>.
> -@Version("4.0.0")
> +@Version("5.0.0")
>  @Export(optional = "provide:=true")
>  package org.apache.jackrabbit.oak.api.jmx;

I think we could get away with increasing this to 4.1.0 if we can
annotate QueryEngineSettingsMBean with @ProviderType. I.e. we don't
expect API consumers to  implement QueryEngineSettingsMBean and
therefore the API change is irrelevant for them.

WDYT?

Regards
Julian



On Wed, Oct 19, 2016 at 2:20 PM,  <th...@apache.org> wrote:
> Author: thomasm
> Date: Wed Oct 19 12:20:56 2016
> New Revision: 1765583
>
> URL: http://svn.apache.org/viewvc?rev=1765583&view=rev
> Log:
> OAK-4888 Warn or fail queries above a configurable cost value
>
> Added:
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
> Modified:
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java
>     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/UnionQueryImpl.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
>     jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
>     jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
>     jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
>     jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java Wed Oct 19 12:20:56 2016
> @@ -51,4 +51,19 @@ public interface QueryEngineSettingsMBea
>       */
>      void setLimitReads(long limitReads);
>
> +    /**
> +     * Whether queries that don't use an index will fail (throw an exception).
> +     * The default is false.
> +     *
> +     * @return true if they fail
> +     */
> +    boolean getFailTraversal();
> +
> +    /**
> +     * Set whether queries that don't use an index will fail (throw an exception).
> +     *
> +     * @param failTraversal the new value for this setting
> +     */
> +    void setFailTraversal(boolean failTraversal);
> +
>  }
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java Wed Oct 19 12:20:56 2016
> @@ -15,7 +15,7 @@
>   * limitations under the License.
>   */
>
> -@Version("4.0.0")
> +@Version("5.0.0")
>  @Export(optional = "provide:=true")
>  package org.apache.jackrabbit.oak.api.jmx;
>
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/index/property/strategy/ContentMirrorStoreStrategy.java Wed Oct 19 12:20:56 2016
> @@ -434,7 +434,7 @@ public class ContentMirrorStoreStrategy
>                          readCount++;
>                          if (readCount % TRAVERSING_WARN == 0) {
>                              FilterIterators.checkReadLimit(readCount, settings);
> -                            LOG.warn("Traversed {} nodes ({} index entries) using index {} with filter {}", readCount, intermediateNodeReadCount, indexName, filter);
> +                            LOG.warn("Index-Traversed {} nodes ({} index entries) using index {} with filter {}", readCount, intermediateNodeReadCount, indexName, filter);
>                          }
>                          return;
>                      } else {
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Wed Oct 19 12:20:56 2016
> @@ -183,4 +183,11 @@ public interface Query {
>       */
>      boolean containsUnfilteredFullTextCondition();
>
> +    /**
> +     * Set the query option to be used for this query.
> +     *
> +     * @param options the options
> +     */
> +    void setQueryOptions(QueryOptions options);
> +
>  }
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettings.java Wed Oct 19 12:20:56 2016
> @@ -35,7 +35,10 @@ public class QueryEngineSettings impleme
>              Integer.getInteger("oak.queryLimitInMemory", Integer.MAX_VALUE);
>
>      private static final int DEFAULT_QUERY_LIMIT_READS =
> -            Integer.getInteger("oak.queryLimitReads", Integer.MAX_VALUE);
> +            Integer.getInteger("oak.queryLimitReads", Integer.MAX_VALUE);
> +
> +    private static final boolean DEFAULT_FAIL_TRAVERSAL =
> +            Boolean.getBoolean("oak.queryFailTraversal");
>
>      private static final boolean DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX =
>              Boolean.getBoolean("oak.queryFullTextComparisonWithoutIndex");
> @@ -44,6 +47,8 @@ public class QueryEngineSettings impleme
>
>      private long limitReads = DEFAULT_QUERY_LIMIT_READS;
>
> +    private boolean failTraversal = DEFAULT_FAIL_TRAVERSAL;
> +
>      private boolean fullTextComparisonWithoutIndex =
>              DEFAULT_FULL_TEXT_COMPARISON_WITHOUT_INDEX;
>
> @@ -72,6 +77,16 @@ public class QueryEngineSettings impleme
>          this.limitReads = limitReads;
>      }
>
> +    @Override
> +    public boolean getFailTraversal() {
> +        return failTraversal;
> +    }
> +
> +    @Override
> +    public void setFailTraversal(boolean failTraversal) {
> +        this.failTraversal = failTraversal;
> +    }
> +
>      public void setFullTextComparisonWithoutIndex(boolean fullTextComparisonWithoutIndex) {
>          this.fullTextComparisonWithoutIndex = fullTextComparisonWithoutIndex;
>      }
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsMBeanImpl.java Wed Oct 19 12:20:56 2016
> @@ -70,6 +70,16 @@ public class QueryEngineSettingsMBeanImp
>          settings.setLimitReads(limitReads);
>      }
>
> +    @Override
> +    public boolean getFailTraversal() {
> +        return settings.getFailTraversal();
> +    }
> +
> +    @Override
> +    public void setFailTraversal(boolean failQueriesWithoutIndex) {
> +        settings.setFailTraversal(failQueriesWithoutIndex);
> +    }
> +
>      public void setFullTextComparisonWithoutIndex(boolean fullTextComparisonWithoutIndex) {
>          settings.setFullTextComparisonWithoutIndex(fullTextComparisonWithoutIndex);
>      }
>
> 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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
> @@ -36,6 +36,7 @@ import org.apache.jackrabbit.oak.api.Res
>  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.QueryOptions.Traversal;
>  import org.apache.jackrabbit.oak.query.ast.AndImpl;
>  import org.apache.jackrabbit.oak.query.ast.AstVisitorBase;
>  import org.apache.jackrabbit.oak.query.ast.BindVariableValueImpl;
> @@ -160,6 +161,11 @@ public class QueryImpl implements Query
>       * purposes.
>       */
>      private boolean traversalEnabled = true;
> +
> +    /**
> +     * The query option to be used for this query.
> +     */
> +    private QueryOptions queryOptions = new QueryOptions();
>
>      private OrderingImpl[] orderings;
>      private ColumnImpl[] columns;
> @@ -948,6 +954,11 @@ public class QueryImpl implements Query
>          this.traversalEnabled = traversalEnabled;
>      }
>
> +    @Override
> +    public void setQueryOptions(QueryOptions options) {
> +        this.queryOptions = options;
> +    }
> +
>      public SelectorExecutionPlan getBestSelectorExecutionPlan(FilterImpl filter) {
>          return getBestSelectorExecutionPlan(context.getBaseState(), filter,
>                  context.getIndexProvider(), traversalEnabled);
> @@ -1036,7 +1047,27 @@ public class QueryImpl implements Query
>                  bestPlan = indexPlan;
>              }
>          }
> -
> +        if (bestIndex == null) {
> +            QueryOptions.Traversal traversal = queryOptions.traversal;
> +            if (traversal == Traversal.DEFAULT) {
> +                // use the (configured) default
> +                traversal = settings.getFailTraversal() ? Traversal.FAIL : Traversal.WARN;
> +            } else {
> +                // explicitly set in the query
> +                traversal = queryOptions.traversal;
> +            }
> +            String message = "Traversal query (query without index): " + statement + "; consider creating an index";
> +            switch (traversal) {
> +            case OK:
> +                break;
> +            case WARN:
> +                LOG.warn(message);
> +                break;
> +            case FAIL:
> +                LOG.warn(message);
> +                throw new IllegalArgumentException(message);
> +            }
> +        }
>          if (traversalEnabled) {
>              QueryIndex traversal = new TraversingIndex();
>              double cost = traversal.getCost(filter, rootState);
>
> Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java?rev=1765583&view=auto
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java (added)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryOptions.java Wed Oct 19 12:20:56 2016
> @@ -0,0 +1,34 @@
> +/*
> + * 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.jackrabbit.oak.query;
> +
> +/**
> + * A query options (or "hints") that are used to customize the way the query is processed.
> + */
> +public class QueryOptions {
> +
> +    public Traversal traversal = Traversal.DEFAULT;
> +
> +    public enum Traversal {
> +        // traversing without index is OK for this query, and does not fail or log a warning
> +        OK,
> +        // traversing is OK, but logs a warning
> +        WARN,
> +        // traversing will fail the query
> +        FAIL,
> +        // the default setting
> +        DEFAULT
> +    };
> +
> +}
>
> 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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
> @@ -24,6 +24,7 @@ import java.text.ParseException;
>  import java.util.ArrayList;
>  import java.util.Collection;
>  import java.util.HashMap;
> +import java.util.Locale;
>  import java.util.Map;
>
>  import javax.jcr.PropertyType;
> @@ -34,6 +35,7 @@ import org.apache.jackrabbit.oak.api.Que
>  import org.apache.jackrabbit.oak.api.Type;
>  import org.apache.jackrabbit.oak.commons.PathUtils;
>  import org.apache.jackrabbit.oak.namepath.NamePathMapper;
> +import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
>  import org.apache.jackrabbit.oak.query.ast.AstElementFactory;
>  import org.apache.jackrabbit.oak.query.ast.BindVariableValueImpl;
>  import org.apache.jackrabbit.oak.query.ast.ColumnImpl;
> @@ -161,6 +163,15 @@ public class SQL2Parser {
>              read("BY");
>              orderings = parseOrder();
>          }
> +        QueryOptions options = new QueryOptions();
> +        if (readIf("OPTION")) {
> +            read("(");
> +            if (readIf("TRAVERSAL")) {
> +                String n = readName().toUpperCase(Locale.ENGLISH);
> +                options.traversal = Traversal.valueOf(n);
> +            }
> +            read(")");
> +        }
>          if (!currentToken.isEmpty()) {
>              throw getSyntaxError("<end>");
>          }
> @@ -168,6 +179,7 @@ public class SQL2Parser {
>          q.setExplain(explain);
>          q.setMeasure(measure);
>          q.setInternal(isInternal(query));
> +        q.setQueryOptions(options);
>
>          if (initialise) {
>              try {
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java Wed Oct 19 12:20:56 2016
> @@ -118,6 +118,12 @@ public class UnionQueryImpl implements Q
>          left.setTraversalEnabled(traversal);
>          right.setTraversalEnabled(traversal);
>      }
> +
> +    @Override
> +    public  void setQueryOptions(QueryOptions options) {
> +        left.setQueryOptions(options);
> +        right.setQueryOptions(options);
> +    }
>
>      @Override
>      public void prepare() {
>
> Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java Wed Oct 19 12:20:56 2016
> @@ -19,6 +19,8 @@ package org.apache.jackrabbit.oak.query.
>  import java.util.ArrayList;
>
>  import org.apache.jackrabbit.oak.query.QueryImpl;
> +import org.apache.jackrabbit.oak.query.QueryOptions;
> +import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
>  import org.apache.jackrabbit.oak.query.xpath.Expression.AndCondition;
>  import org.apache.jackrabbit.oak.query.xpath.Expression.OrCondition;
>  import org.apache.jackrabbit.oak.query.xpath.Expression.Property;
> @@ -50,6 +52,8 @@ public class Statement {
>
>      String xpathQuery;
>
> +    QueryOptions queryOptions = new QueryOptions();
> +
>      public Statement optimize() {
>          ignoreOrderByScoreDesc();
>          if (where == null) {
> @@ -80,6 +84,7 @@ public class Statement {
>          union.xpathQuery = xpathQuery;
>          union.measure = measure;
>          union.explain = explain;
> +        union.queryOptions = queryOptions;
>
>          return union;
>      }
> @@ -209,6 +214,9 @@ public class Statement {
>                  buff.append(orderList.get(i));
>              }
>          }
> +        if (queryOptions.traversal != Traversal.DEFAULT) {
> +            buff.append(" option(traversal " + queryOptions.traversal +")");
> +        }
>          // leave original xpath string as a comment
>          appendXPathAsComment(buff, xpathQuery);
>          return buff.toString();
> @@ -296,6 +304,9 @@ public class Statement {
>                      buff.append(orderList.get(i));
>                  }
>              }
> +            if (queryOptions.traversal != Traversal.DEFAULT) {
> +                buff.append(" option(traversal " + queryOptions.traversal +")");
> +            }
>              // leave original xpath string as a comment
>              appendXPathAsComment(buff, xpathQuery);
>              return buff.toString();
> @@ -314,4 +325,8 @@ public class Statement {
>          buff.append(" */");
>      }
>
> +    public  void setQueryOptions(QueryOptions options) {
> +        this.queryOptions = options;
> +    }
> +
>  }
>
> 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=1765583&r1=1765582&r2=1765583&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 Wed Oct 19 12:20:56 2016
> @@ -17,6 +17,8 @@
>  package org.apache.jackrabbit.oak.query.xpath;
>
>  import org.apache.jackrabbit.oak.commons.PathUtils;
> +import org.apache.jackrabbit.oak.query.QueryOptions;
> +import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
>  import org.apache.jackrabbit.oak.query.xpath.Statement.UnionStatement;
>  import org.apache.jackrabbit.util.ISO9075;
>  import org.slf4j.Logger;
> @@ -25,6 +27,7 @@ import org.slf4j.LoggerFactory;
>  import java.math.BigDecimal;
>  import java.text.ParseException;
>  import java.util.ArrayList;
> +import java.util.Locale;
>
>  /**
>   * This class can can convert a XPATH query to a SQL2 query.
> @@ -324,11 +327,21 @@ public class XPathToSQL2Converter {
>                  statement.addOrderBy(order);
>              } while (readIf(","));
>          }
> +        QueryOptions options = new QueryOptions();
> +        if (readIf("option")) {
> +            read("(");
> +            if (readIf("traversal")) {
> +                String type = readIdentifier().toUpperCase(Locale.ENGLISH);
> +                options.traversal = Traversal.valueOf(type);
> +            }
> +            read(")");
> +        }
>          if (!currentToken.isEmpty()) {
>              throw getSyntaxError("<end>");
>          }
>          statement.setColumnSelector(currentSelector);
>          statement.setSelectors(selectors);
> +        statement.setQueryOptions(options);
>
>          Expression where = null;
>          for (Selector s : selectors) {
> @@ -1105,10 +1118,14 @@ public class XPathToSQL2Converter {
>              } else {
>                  UnionStatement union = new UnionStatement(result, stat);
>                  union.orderList = stat.orderList;
> +                union.queryOptions = stat.queryOptions;
>                  result = union;
>              }
> -            // can not use clear, because it is shared
> +            // reset fields that are used in the union,
> +            // but no longer in the individual statements
> +            // (can not use clear, because it is shared)
>              stat.orderList = new ArrayList<Order>();
> +            stat.queryOptions = new QueryOptions();
>          }
>          return result;
>      }
>
> Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/SQL2ParserTest.java Wed Oct 19 12:20:56 2016
> @@ -54,7 +54,6 @@ public class SQL2ParserTest {
>                  .convert("/jcr:root/test/*/nt:resource[@jcr:encoding]"));
>          p.parse(new XPathToSQL2Converter()
>                  .convert("/jcr:root/test/*/*/nt:resource[@jcr:encoding]"));
> -
>          String xpath = "/jcr:root/etc/commerce/products//*[@cq:commerceType = 'product' " +
>                  "and ((@size = 'M' or */@size= 'M' or */*/@size = 'M' " +
>                  "or */*/*/@size = 'M' or */*/*/*/@size = 'M' or */*/*/*/*/@size = 'M'))]";
>
> Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java (original)
> +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java Wed Oct 19 12:20:56 2016
> @@ -34,6 +34,45 @@ public class XPathTest {
>              new NodeStateNodeTypeInfoProvider(INITIAL_CONTENT);
>
>      @Test
> +    public void queryOptions() throws ParseException {
> +        verify("/jcr:root/content//*[@a] order by @c option(traversal fail)",
> +                "select [jcr:path], [jcr:score], * " +
> +                "from [nt:base] as a " +
> +                "where [a] is not null " +
> +                "and isdescendantnode(a, '/content') " +
> +                "order by [c] option(traversal FAIL) " +
> +                "/* xpath: /jcr:root/content//*[@a] " +
> +                "order by @c " +
> +                "option(traversal fail) */");
> +        verify("//*[@a or @b] order by @c option(traversal warn)",
> +                "select [jcr:path], [jcr:score], * " +
> +                "from [nt:base] as a " +
> +                "where [a] is not null " +
> +                "union select [jcr:path], [jcr:score], * " +
> +                "from [nt:base] as a " +
> +                "where [b] is not null " +
> +                "order by [c] option(traversal WARN) " +
> +                "/* xpath: //*[@a or @b] " +
> +                "order by @c " +
> +                "option(traversal warn) */");
> +        verify("/jcr:root/(content|libs)//*[@a] order by @c option(traversal ok)",
> +                "select [jcr:path], [jcr:score], * " +
> +                "from [nt:base] as a " +
> +                "where [a] is not null " +
> +                "and isdescendantnode(a, '/content') " +
> +                "/* xpath: /jcr:root/content//*[@a] " +
> +                "order by @c option(traversal ok) */ " +
> +                "union select [jcr:path], [jcr:score], * " +
> +                "from [nt:base] as a " +
> +                "where [a] is not null " +
> +                "and isdescendantnode(a, '/libs') " +
> +                "/* xpath: /jcr:root/libs//*[@a] " +
> +                "order by @c option(traversal ok) */ " +
> +                "order by [c] " +
> +                "option(traversal OK)");
> +    }
> +
> +    @Test
>      public void test() throws ParseException {
>          verify("(/jcr:root/content//*[@a] | /jcr:root/lib//*[@b]) order by @c",
>                  "select [jcr:path], [jcr:score], * " +
> @@ -121,6 +160,7 @@ public class XPathTest {
>          sql = sql.replaceAll(" and ", "\nand ");
>          sql = sql.replaceAll(" union ", "\nunion ");
>          sql = sql.replaceAll(" order by ", "\norder by ");
> +        sql = sql.replaceAll(" option\\(", "\noption\\(");
>          sql = sql.replaceAll(" \\/\\* ", "\n/* ");
>          return sql;
>      }
>
> Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
> URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java?rev=1765583&r1=1765582&r2=1765583&view=diff
> ==============================================================================
> --- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java (original)
> +++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java Wed Oct 19 12:20:56 2016
> @@ -69,6 +69,34 @@ public class QueryTest extends AbstractR
>      }
>
>      @Test
> +    public void traversalOption() throws Exception {
> +        Session session = getAdminSession();
> +        QueryManager qm = session.getWorkspace().getQueryManager();
> +        try {
> +            qm.createQuery("//*[@test] option(traversal fail)",
> +                    "xpath").execute();
> +            fail();
> +        } catch (InvalidQueryException e) {
> +            // expected
> +        }
> +        try {
> +            qm.createQuery("select * from [nt:base] option(traversal fail)",
> +                    Query.JCR_SQL2).execute();
> +            fail();
> +        } catch (InvalidQueryException e) {
> +            // expected
> +        }
> +        qm.createQuery("//*[@test] option(traversal ok)",
> +                "xpath").execute();
> +        qm.createQuery("//*[@test] option(traversal warn)",
> +                "xpath").execute();
> +        qm.createQuery("select * from [nt:base] option(traversal ok)",
> +                Query.JCR_SQL2).execute();
> +        qm.createQuery("select * from [nt:base] option(traversal warn)",
> +                Query.JCR_SQL2).execute();
> +    }
> +
> +    @Test
>      public void firstSelector() throws Exception {
>          Session session = getAdminSession();
>          Node root = session.getRootNode();
>
>