Author: thomasm
Date: Wed Jul 10 13:20:50 2019
New Revision: 1862879

URL: http://svn.apache.org/viewvc?rev=1862879&view=rev
Log:
OAK-7254 Indexes with excludedPaths, or includedPaths should not be picked for 
queries without path

Added:
    
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/StrictPathRestriction.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionEnableTest.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionWarnTest.java
Modified:
    
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
    
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
    
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/package-info.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.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/QueryEngineSettingsService.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/plan/SelectorExecutionPlan.java
    
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
    
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java
    
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
    
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
    
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java

Added: 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/StrictPathRestriction.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/StrictPathRestriction.java?rev=1862879&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/StrictPathRestriction.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/StrictPathRestriction.java
 Wed Jul 10 13:20:50 2019
@@ -0,0 +1,31 @@
+/*
+ * 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.api;
+
+import java.util.Locale;
+
+public enum StrictPathRestriction {
+    ENABLE,
+    WARN,
+    DISABLE;
+
+    public static StrictPathRestriction stringToEnum(String 
strictPathRestrictionInString) {
+    // OAK-260 : Locale english is being used explicitly. (DISABLE[in turkish] 
 = DİSABLE[in English]--- Mind the dot above I)
+        return 
StrictPathRestriction.valueOf(strictPathRestrictionInString.toUpperCase(Locale.ENGLISH));
+    }
+
+}

Modified: 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/QueryEngineSettingsMBean.java
 Wed Jul 10 13:20:50 2019
@@ -87,6 +87,32 @@ public interface QueryEngineSettingsMBea
     void setFastQuerySize(boolean fastQuerySize);
 
     /**
+     * Whether Path restrictions are enabled while figuring out index plan
+     *
+     * @return true if enabled
+     */
+    String getStrictPathRestriction();
+
+    /**
+     *  Whether path restrictions of indexes (excludedPaths / includedPaths) 
are taken into account during query execution,
+     *  for Lucene indexes. When enabled, only indexes are considered if the 
index path restriction is compatible with the
+     *  query path restrictions. When disabled, only the queryPaths of the 
index is taken into account.
+     *
+     * @param pathRestriction Set path restriction: Expected value is either 
of ENABLE/DISABLE/WARN
+     *                        ENABLE: enable path restriction- Index won't be 
used if index definition path restrictions are not compatible with query's path 
restriction
+     *                        DISABLE: path restrictions are not taken into 
account while querying
+     *                        WARN: path restrictions are not taken into 
account but a warning will be logged if query path restrictions are not 
compatible with index path restrictions 
+     */
+     @Description("Set path restriction: Expected value is either of 
ENABLE/DISABLE/WARN.   " +
+                    "ENABLE: enable path restriction- Index won't be used if 
index definition path restrictions are not compatible with query's path 
restriction.  " +
+                    "DISABLE: path restrictions are not taken into account 
while querying.  " +
+                    "WARN: path restrictions are not taken into account but a 
warning will be logged if query path restrictions are not compatible with index 
path restrictions."
+                    )
+    void setStrictPathRestriction(
+            @Name("pathRestriction")
+                    String pathRestriction);
+
+    /**
      * Set or remove a query validator pattern.
      *
      * @param key the key

Modified: 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/jmx/package-info.java
 Wed Jul 10 13:20:50 2019
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-@Version("4.8.0")
+@Version("4.9.0")
 package org.apache.jackrabbit.oak.api.jmx;
 
 import org.osgi.annotation.versioning.Version;

Modified: 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/package-info.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-api/src/main/java/org/apache/jackrabbit/oak/api/package-info.java
 Wed Jul 10 13:20:50 2019
@@ -18,7 +18,7 @@
 /**
  * Oak repository API
  */
-@Version("3.1.2")
+@Version("3.2.0")
 package org.apache.jackrabbit.oak.api;
 
 import org.osgi.annotation.versioning.Version;

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java 
(original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/Oak.java 
Wed Jul 10 13:20:50 2019
@@ -411,6 +411,7 @@ public class Oak {
         
this.queryEngineSettings.setFullTextComparisonWithoutIndex(settings.getFullTextComparisonWithoutIndex());
         this.queryEngineSettings.setLimitInMemory(settings.getLimitInMemory());
         this.queryEngineSettings.setLimitReads(settings.getLimitReads());
+        
this.queryEngineSettings.setStrictPathRestriction(settings.getStrictPathRestriction());
         return this;
     }
 
@@ -933,6 +934,14 @@ public class Oak {
             settings.setFastQuerySize(fastQuerySize);
         }
 
+        public String getStrictPathRestriction() {
+            return settings.getStrictPathRestriction();
+        }
+
+        public void setStrictPathRestriction(String strictPathRestriction) {
+            settings.setStrictPathRestriction(strictPathRestriction);
+        }
+
         @Override
         public void setQueryValidatorPattern(String key, String pattern, 
String comment, boolean failQuery) {
             settings.getQueryValidator().setPattern(key, pattern, comment, 
failQuery);

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=1862879&r1=1862878&r2=1862879&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 Jul 10 13:20:50 2019
@@ -18,6 +18,7 @@
  */
 package org.apache.jackrabbit.oak.query;
 
+import org.apache.jackrabbit.oak.api.StrictPathRestriction;
 import org.apache.jackrabbit.oak.api.jmx.QueryEngineSettingsMBean;
 import org.apache.jackrabbit.oak.query.stats.QueryStatsMBean;
 import org.apache.jackrabbit.oak.query.stats.QueryStatsMBeanImpl;
@@ -76,6 +77,8 @@ public class QueryEngineSettings impleme
     public static final boolean DEFAULT_FAST_QUERY_SIZE = 
Boolean.getBoolean(OAK_FAST_QUERY_SIZE);
     private boolean fastQuerySize = DEFAULT_FAST_QUERY_SIZE;
 
+    private StrictPathRestriction strictPathRestriction = 
StrictPathRestriction.DISABLE;
+
     private final QueryStatsMBeanImpl queryStats = new 
QueryStatsMBeanImpl(this);
 
     /**
@@ -134,6 +137,14 @@ public class QueryEngineSettings impleme
         System.setProperty(OAK_FAST_QUERY_SIZE, String.valueOf(fastQuerySize));
     }
 
+    public String getStrictPathRestriction() {
+        return strictPathRestriction.name();
+    }
+
+    public void setStrictPathRestriction(String strictPathRestriction) {
+        this.strictPathRestriction = 
StrictPathRestriction.stringToEnum(strictPathRestriction);
+    }
+
     public void setFullTextComparisonWithoutIndex(boolean 
fullTextComparisonWithoutIndex) {
         this.fullTextComparisonWithoutIndex = fullTextComparisonWithoutIndex;
     }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryEngineSettingsService.java
 Wed Jul 10 13:20:50 2019
@@ -68,6 +68,16 @@ public class QueryEngineSettingsService
                         "Note: even if enabled, getSize may still return -1 if 
the index used does not support the feature." 
         )
         boolean fastQuerySize() default false;
+
+        @AttributeDefinition(
+                name = "Enable Strict Path restrictions for indexes to be 
used",
+                description = "Whether path restrictions of indexes 
(excludedPaths / includedPaths) are taken into" +
+                        "account during query execution, for Lucene indexes. 
When enabled, only indexes are considered if" +
+                        "the index path restriction is compatible with the 
query path restrictions. When disabled, only" +
+                        "the queryPaths of the index is taken into account."
+        )
+        String getStrictPathRestrictionsForIndexes() default 
DISABLED_STRICT_PATH_RESTRICTION;
+
     }
 
     // should be the same as QueryEngineSettings.DEFAULT_QUERY_LIMIT_IN_MEMORY
@@ -82,6 +92,7 @@ public class QueryEngineSettingsService
     static final String QUERY_FAIL_TRAVERSAL = "queryFailTraversal";
     
     static final String QUERY_FAST_QUERY_SIZE = "fastQuerySize";
+    static final String DISABLED_STRICT_PATH_RESTRICTION = "DISABLE";
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
@@ -114,6 +125,8 @@ public class QueryEngineSettingsService
         boolean fastQuerySizeSysProp = 
QueryEngineSettings.DEFAULT_FAST_QUERY_SIZE;
         boolean fastQuerySizeFromConfig = config.fastQuerySize();
         queryEngineSettings.setFastQuerySize(fastQuerySizeFromConfig || 
fastQuerySizeSysProp);
+        
+        
queryEngineSettings.setStrictPathRestriction(config.getStrictPathRestrictionsForIndexes());
 
         log.info("Initialize QueryEngine settings {}", queryEngineSettings);
     }

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=1862879&r1=1862878&r2=1862879&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 Jul 10 13:20:50 2019
@@ -37,6 +37,7 @@ import org.apache.jackrabbit.oak.namepat
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.plugins.index.counter.jmx.NodeCounter;
 import org.apache.jackrabbit.oak.plugins.memory.PropertyValues;
+import 
org.apache.jackrabbit.oak.plugins.observation.filter.UniversalFilter.Selector;
 import org.apache.jackrabbit.oak.query.QueryOptions.Traversal;
 import org.apache.jackrabbit.oak.query.ast.AndImpl;
 import org.apache.jackrabbit.oak.query.ast.AstVisitorBase;
@@ -133,8 +134,17 @@ public class QueryImpl implements Query
     SourceImpl source;
     private String statement;
     final HashMap<String, PropertyValue> bindVariableMap = new HashMap<String, 
PropertyValue>();
+    
+    /**
+     * The map of indexes (each selector uses one index)
+     */
     final HashMap<String, Integer> selectorIndexes = new HashMap<String, 
Integer>();
+    
+    /**
+     * The list of selectors of this query. For a join, there can be multiple 
selectors.
+     */
     final ArrayList<SelectorImpl> selectors = new ArrayList<SelectorImpl>();
+    
     ConstraintImpl constraint;
 
     /**
@@ -492,9 +502,40 @@ public class QueryImpl implements Query
         return new ResultImpl(this);
     }
 
+    /**
+     * If one of the indexes wants a warning to be logged due to path mismatch,
+     * then get the warning message. Otherwise, return null.
+     * 
+     * @return null (in the normal case) or the list of index plan names (if
+     *         some index wants a warning to be logged)
+     */
+    private String getWarningForPathFilterMismatch() {
+        StringBuilder buff = null;
+        for (SelectorImpl s : selectors) {
+            if (s.getExecutionPlan() != null &&
+                    s.getExecutionPlan().getIndexPlan() != null &&
+                    
s.getExecutionPlan().getIndexPlan().logWarningForPathFilterMismatch()) {
+                if (buff == null) {
+                    buff = new StringBuilder();
+                }
+                if (buff.length() > 0) {
+                    buff.append(", ");
+                }
+                buff.append(s.getExecutionPlan().getIndexPlanName());
+            }
+        }
+        return buff == null ? null : buff.toString();
+    }
+    
     @Override
     public Iterator<ResultRowImpl> getRows() {
         prepare();
+        String warn = getWarningForPathFilterMismatch();
+        if (warn != null) {
+            LOG.warn("Index definition of index used have path restrictions 
and query won't return nodes from " +
+             "those restricted paths; query={}, plan={}", statement, warn);
+        }
+        
         if (explain) {
             String plan = getPlan();
             if (measure) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/plan/SelectorExecutionPlan.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/plan/SelectorExecutionPlan.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/plan/SelectorExecutionPlan.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/plan/SelectorExecutionPlan.java
 Wed Jul 10 13:20:50 2019
@@ -17,7 +17,9 @@
 package org.apache.jackrabbit.oak.query.plan;
 
 import org.apache.jackrabbit.oak.query.ast.SelectorImpl;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex;
+import org.apache.jackrabbit.oak.spi.query.QueryIndex.AdvancedQueryIndex;
 import org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan;
 
 /**
@@ -56,5 +58,18 @@ public class SelectorExecutionPlan imple
     public IndexPlan getIndexPlan() {
         return plan;
     }
+    
+    /**
+     * Get the index name, or index type (may not always be the exact index 
name).
+     * 
+     * @return the name
+     */
+    public String getIndexPlanName() {
+        if (plan != null) {
+            return plan.getPlanName();
+        } else {
+            return index.getIndexName();
+        }
+    }
 
 }

Modified: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LucenePropertyIndexTest.java
 Wed Jul 10 13:20:50 2019
@@ -86,6 +86,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.InitialContentHelper;
 import org.apache.jackrabbit.oak.plugins.nodetype.write.NodeTypeRegistry;
 import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
 import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
 import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
 import org.apache.jackrabbit.oak.spi.commit.Observer;
@@ -173,6 +174,8 @@ public class LucenePropertyIndexTest ext
 
     private ResultCountingIndexProvider queryIndexProvider;
 
+    private QueryEngineSettings queryEngineSettings = new 
QueryEngineSettings();
+
     @After
     public void after() {
         new ExecutorCloser(executorService).close();
@@ -199,6 +202,7 @@ public class LucenePropertyIndexTest ext
                 .with(optionalEditorProvider)
                 .with(new PropertyIndexEditorProvider())
                 .with(new NodeTypeIndexProvider())
+                .with(queryEngineSettings)
                 .createContentRepository();
     }
 
@@ -865,32 +869,6 @@ public class LucenePropertyIndexTest ext
         assertQuery("select [jcr:path] from [nt:base] where [propa] = 10", 
asList("/test/a", "/test/a/b"));
     }
 
-    @Test
-    public void pathExclude() throws Exception{
-        Tree idx = createIndex("test1", of("propa", "propb"));
-        idx.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
-        //Do not provide type information
-        root.commit();
-
-        Tree test = root.getTree("/").addChild("test");
-        test.addChild("a").setProperty("propa", 10);
-        test.addChild("a").addChild("b").setProperty("propa", 10);
-        test.addChild("c").setProperty("propa", 10);
-        root.commit();
-
-        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10"), containsString("lucene:test1"));
-
-        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10", 
asList("/test/c"));
-
-        //Make some change and then check
-        test = root.getTree("/").getChild("test");
-        test.addChild("a").addChild("e").setProperty("propa", 10);
-        test.addChild("f").setProperty("propa", 10);
-        root.commit();
-
-        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10", 
asList("/test/c", "/test/f"));
-    }
-
     //OAK-4516
     @Test
     public void wildcardQueryToLookupUnanalyzedText() throws Exception {

Added: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionEnableTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionEnableTest.java?rev=1862879&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionEnableTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionEnableTest.java
 Wed Jul 10 13:20:50 2019
@@ -0,0 +1,244 @@
+/*
+ * 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.plugins.index.lucene;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.InitialContentHelper;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.StrictPathRestriction;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import 
org.apache.jackrabbit.oak.plugins.index.lucene.directory.CopyOnReadDirectory;
+import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
+import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.FilterDirectory;
+import org.junit.After;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static java.util.Arrays.asList;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static 
org.apache.jackrabbit.oak.spi.filter.PathFilter.PROP_EXCLUDED_PATHS;
+import static 
org.apache.jackrabbit.oak.spi.filter.PathFilter.PROP_INCLUDED_PATHS;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+
+@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
+public class LuceneStrictPathRestrictionEnableTest extends AbstractQueryTest {
+
+    private ExecutorService executorService = Executors.newFixedThreadPool(2);
+    @Rule
+    public TemporaryFolder temporaryFolder = new TemporaryFolder(new 
File("target"));
+
+    private String corDir = null;
+    private String cowDir = null;
+
+    private LuceneIndexEditorProvider editorProvider;
+
+    private TestUtil.OptionalEditorProvider optionalEditorProvider = new 
TestUtil.OptionalEditorProvider();
+
+    private NodeStore nodeStore;
+
+    private LuceneIndexProvider provider;
+
+    private ResultCountingIndexProvider queryIndexProvider;
+
+    private QueryEngineSettings queryEngineSettings = new 
QueryEngineSettings();
+
+    @After
+    public void after() {
+        new ExecutorCloser(executorService).close();
+        IndexDefinition.setDisableStoredIndexDefinition(false);
+    }
+
+    @Override
+    protected void createTestIndexNode() throws Exception {
+        setTraversalEnabled(false);
+    }
+
+    @Override
+    protected ContentRepository createRepository() {
+        IndexCopier copier = createIndexCopier();
+        editorProvider = new LuceneIndexEditorProvider(copier, new 
ExtractedTextCache(10 * FileUtils.ONE_MB, 100));
+        provider = new LuceneIndexProvider(copier);
+        queryIndexProvider = new ResultCountingIndexProvider(provider);
+        nodeStore = new MemoryNodeStore(InitialContentHelper.INITIAL_CONTENT);
+        
queryEngineSettings.setStrictPathRestriction(StrictPathRestriction.ENABLE.name());
+        return new Oak(nodeStore)
+                .with(new OpenSecurityProvider())
+                .with(queryIndexProvider)
+                .with((Observer) provider)
+                .with(editorProvider)
+                .with(optionalEditorProvider)
+                .with(new PropertyIndexEditorProvider())
+                .with(new NodeTypeIndexProvider())
+                .with(queryEngineSettings)
+                .createContentRepository();
+    }
+
+    private IndexCopier createIndexCopier() {
+        try {
+            return new IndexCopier(executorService, temporaryFolder.getRoot()) 
{
+                @Override
+                public Directory wrapForRead(String indexPath, 
LuceneIndexDefinition definition,
+                                             Directory remote, String dirName) 
throws IOException {
+                    Directory ret = super.wrapForRead(indexPath, definition, 
remote, dirName);
+                    corDir = getFSDirPath(ret);
+                    return ret;
+                }
+
+                @Override
+                public Directory wrapForWrite(LuceneIndexDefinition definition,
+                                              Directory remote, boolean 
reindexMode, String dirName,
+                                              COWDirectoryTracker 
cowDirectoryTracker) throws IOException {
+                    Directory ret = super.wrapForWrite(definition, remote, 
reindexMode, dirName, cowDirectoryTracker);
+                    cowDir = getFSDirPath(ret);
+                    return ret;
+                }
+
+                private String getFSDirPath(Directory dir) {
+                    if (dir instanceof CopyOnReadDirectory) {
+                        dir = ((CopyOnReadDirectory) dir).getLocal();
+                    }
+
+                    dir = unwrap(dir);
+
+                    if (dir instanceof FSDirectory) {
+                        return ((FSDirectory) 
dir).getDirectory().getAbsolutePath();
+                    }
+                    return null;
+                }
+
+                private Directory unwrap(Directory dir) {
+                    if (dir instanceof FilterDirectory) {
+                        return unwrap(((FilterDirectory) dir).getDelegate());
+                    }
+                    return dir;
+                }
+
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @After
+    public void shutdownExecutor() {
+        executorService.shutdown();
+    }
+
+    @Test
+    public void pathIncludeWithPathRestrictionsEnabled() throws Exception {
+
+        Tree idx = createIndex("test1", of("propa", "propb"));
+        idx.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        root.commit();
+
+        Tree test = root.getTree("/").addChild("test");
+        test.addChild("a").setProperty("propa", 10);
+        test.addChild("a").addChild("b").setProperty("propa", 10);
+        test.addChild("c").setProperty("propa", 10);
+        root.commit();
+
+        assertFalse(explain("select [jcr:path] from [nt:base] where [propa] = 
10").contains("lucene:test1"));
+        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10 and isDescendantNode('/test/a')"), containsString("lucene:test1"));
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/a')", asList("/test/a/b"));
+
+    }
+
+    @Test
+    public void pathExcludeWithPathRestrictionsEnabled() throws Exception {
+        Tree idx = createIndex("test1", of("propa", "propb"));
+        idx.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        root.commit();
+
+        Tree test = root.getTree("/").addChild("test");
+        test.addChild("a").setProperty("propa", 10);
+        test.addChild("a").addChild("b").setProperty("propa", 10);
+        test.addChild("c").setProperty("propa", 10);
+        test.addChild("c").addChild("d").setProperty("propa", 10);
+        root.commit();
+
+        assertFalse(explain("select [jcr:path] from [nt:base] where [propa] = 
10").contains("lucene:test1"));
+        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10 and isDescendantNode('/test/c')"), containsString("lucene:test1"));
+
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/c')", asList("/test/c/d"));
+
+        //Make some change and then check
+        Tree testc = root.getTree("/").getChild("test").getChild("c");
+        testc.addChild("e").addChild("f").setProperty("propa", 10);
+        root.commit();
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/c')", asList("/test/c/d", "/test/c/e/f"));
+        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10 and isDescendantNode('/test/c') and not(isDescendantNode('/test/c/e'))"), 
containsString("lucene:test1"));
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/c') and not(isDescendantNode('/test/c/e'))", 
asList("/test/c/d"));
+    }
+
+    private String explain(String query) {
+        String explain = "explain " + query;
+        return executeQuery(explain, "JCR-SQL2").get(0);
+    }
+
+    private Tree createIndex(String name, Set<String> propNames) throws 
CommitFailedException {
+        Tree index = root.getTree("/");
+        return createIndex(index, name, propNames);
+    }
+
+    public static Tree createIndex(Tree index, String name, Set<String> 
propNames) throws CommitFailedException {
+        Tree def = index.addChild(INDEX_DEFINITIONS_NAME).addChild(name);
+        def.setProperty(JcrConstants.JCR_PRIMARYTYPE,
+                INDEX_DEFINITIONS_NODE_TYPE, Type.NAME);
+        def.setProperty(TYPE_PROPERTY_NAME, LuceneIndexConstants.TYPE_LUCENE);
+        def.setProperty(REINDEX_PROPERTY_NAME, true);
+        def.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+        
def.setProperty(PropertyStates.createProperty(FulltextIndexConstants.INCLUDE_PROPERTY_NAMES,
 propNames, Type.STRINGS));
+        def.setProperty(LuceneIndexConstants.SAVE_DIR_LISTING, true);
+        return index.getChild(INDEX_DEFINITIONS_NAME).getChild(name);
+    }
+
+}

Added: 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionWarnTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionWarnTest.java?rev=1862879&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionWarnTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-lucene/src/test/java/org/apache/jackrabbit/oak/plugins/index/lucene/LuceneStrictPathRestrictionWarnTest.java
 Wed Jul 10 13:20:50 2019
@@ -0,0 +1,279 @@
+/*
+ * 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.plugins.index.lucene;
+
+import ch.qos.logback.classic.LoggerContext;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import org.apache.commons.io.FileUtils;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.oak.InitialContentHelper;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.StrictPathRestriction;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.commons.concurrent.ExecutorCloser;
+import 
org.apache.jackrabbit.oak.plugins.index.lucene.directory.CopyOnReadDirectory;
+import org.apache.jackrabbit.oak.plugins.index.nodetype.NodeTypeIndexProvider;
+import 
org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.search.ExtractedTextCache;
+import org.apache.jackrabbit.oak.plugins.index.search.FulltextIndexConstants;
+import org.apache.jackrabbit.oak.plugins.index.search.IndexDefinition;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.query.AbstractQueryTest;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.spi.commit.Observer;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.apache.jackrabbit.oak.spi.state.NodeStore;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.lucene.store.FilterDirectory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static java.util.Arrays.asList;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NODE_TYPE;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.REINDEX_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.index.IndexConstants.TYPE_PROPERTY_NAME;
+import static 
org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+import static 
org.apache.jackrabbit.oak.spi.filter.PathFilter.PROP_EXCLUDED_PATHS;
+import static 
org.apache.jackrabbit.oak.spi.filter.PathFilter.PROP_INCLUDED_PATHS;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+@SuppressWarnings("ArraysAsListWithZeroOrOneArgument")
+public class LuceneStrictPathRestrictionWarnTest extends AbstractQueryTest {
+
+    private ExecutorService executorService = Executors.newFixedThreadPool(2);
+    @Rule
+    public TemporaryFolder temporaryFolder = new TemporaryFolder(new 
File("target"));
+
+    ListAppender<ILoggingEvent> listAppender = null;
+
+    private String corDir = null;
+    private String cowDir = null;
+
+    private LuceneIndexEditorProvider editorProvider;
+
+    private TestUtil.OptionalEditorProvider optionalEditorProvider = new 
TestUtil.OptionalEditorProvider();
+
+    private NodeStore nodeStore;
+
+    private LuceneIndexProvider provider;
+
+    private ResultCountingIndexProvider queryIndexProvider;
+
+    private QueryEngineSettings queryEngineSettings = new 
QueryEngineSettings();
+
+    private final String warnMessage = "Index definition of index used have 
path restrictions and query won't return nodes from " +
+            "those restricted paths";
+
+    private final String queryImplLogger = 
"org.apache.jackrabbit.oak.query.QueryImpl";
+
+    @Before
+    public void loggingAppenderStart() {
+        LoggerContext context = (LoggerContext) 
LoggerFactory.getILoggerFactory();
+        listAppender = new ListAppender<>();
+        listAppender.start();
+        context.getLogger(queryImplLogger).addAppender(listAppender);
+    }
+
+    @After
+    public void loggingAppenderStop() {
+        listAppender.stop();
+    }
+
+    @After
+    public void after() {
+        new ExecutorCloser(executorService).close();
+        IndexDefinition.setDisableStoredIndexDefinition(false);
+    }
+
+    @Override
+    protected void createTestIndexNode() throws Exception {
+        setTraversalEnabled(false);
+    }
+
+    @Override
+    protected ContentRepository createRepository() {
+        IndexCopier copier = createIndexCopier();
+        editorProvider = new LuceneIndexEditorProvider(copier, new 
ExtractedTextCache(10 * FileUtils.ONE_MB, 100));
+        provider = new LuceneIndexProvider(copier);
+        queryIndexProvider = new ResultCountingIndexProvider(provider);
+        nodeStore = new MemoryNodeStore(InitialContentHelper.INITIAL_CONTENT);
+        
queryEngineSettings.setStrictPathRestriction(StrictPathRestriction.WARN.name());
+        return new Oak(nodeStore)
+                .with(new OpenSecurityProvider())
+                .with(queryIndexProvider)
+                .with((Observer) provider)
+                .with(editorProvider)
+                .with(optionalEditorProvider)
+                .with(new PropertyIndexEditorProvider())
+                .with(new NodeTypeIndexProvider())
+                .with(queryEngineSettings)
+                .createContentRepository();
+    }
+
+    private IndexCopier createIndexCopier() {
+        try {
+            return new IndexCopier(executorService, temporaryFolder.getRoot()) 
{
+                @Override
+                public Directory wrapForRead(String indexPath, 
LuceneIndexDefinition definition,
+                                             Directory remote, String dirName) 
throws IOException {
+                    Directory ret = super.wrapForRead(indexPath, definition, 
remote, dirName);
+                    corDir = getFSDirPath(ret);
+                    return ret;
+                }
+
+                @Override
+                public Directory wrapForWrite(LuceneIndexDefinition definition,
+                                              Directory remote, boolean 
reindexMode, String dirName,
+                                              COWDirectoryTracker 
cowDirectoryTracker) throws IOException {
+                    Directory ret = super.wrapForWrite(definition, remote, 
reindexMode, dirName, cowDirectoryTracker);
+                    cowDir = getFSDirPath(ret);
+                    return ret;
+                }
+
+                private String getFSDirPath(Directory dir) {
+                    if (dir instanceof CopyOnReadDirectory) {
+                        dir = ((CopyOnReadDirectory) dir).getLocal();
+                    }
+
+                    dir = unwrap(dir);
+
+                    if (dir instanceof FSDirectory) {
+                        return ((FSDirectory) 
dir).getDirectory().getAbsolutePath();
+                    }
+                    return null;
+                }
+
+                private Directory unwrap(Directory dir) {
+                    if (dir instanceof FilterDirectory) {
+                        return unwrap(((FilterDirectory) dir).getDelegate());
+                    }
+                    return dir;
+                }
+
+            };
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @After
+    public void shutdownExecutor() {
+        executorService.shutdown();
+    }
+
+    @Test
+    public void pathIncludeWithPathRestrictionsWarn() throws Exception {
+
+        Tree idx = createIndex("test1", of("propa", "propb"));
+        idx.setProperty(createProperty(PROP_INCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        //Do not provide type information
+        root.commit();
+
+        Tree test = root.getTree("/").addChild("test");
+        test.addChild("a").setProperty("propa", 10);
+        test.addChild("a").addChild("b").setProperty("propa", 10);
+        test.addChild("c").setProperty("propa", 10);
+        root.commit();
+
+        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10 and isDescendantNode('/test/a')"), containsString("lucene:test1"));
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/a')", asList("/test/a/b"));
+        // List appender should not have any warn logs as we are searching 
under right descendant as per path restrictions
+        assertFalse(isWarnMessagePresent(listAppender));
+        assertTrue(explain("select [jcr:path] from [nt:base] where [propa] = 
10").contains("lucene:test1"));
+        // List appender now will have warn log as we are searching under 
root(/) but index definition have include path restriction.
+        assertTrue(isWarnMessagePresent(listAppender));
+    }
+
+    @Test
+    public void pathExcludeWithPathRestrictionsWarn() throws Exception {
+        Tree idx = createIndex("test1", of("propa", "propb"));
+        idx.setProperty(createProperty(PROP_EXCLUDED_PATHS, of("/test/a"), 
Type.STRINGS));
+        //Do not provide type information
+        root.commit();
+
+        Tree test = root.getTree("/").addChild("test");
+        test.addChild("a").setProperty("propa", 10);
+        test.addChild("a").addChild("b").setProperty("propa", 10);
+        test.addChild("c").setProperty("propa", 10);
+        test.addChild("c").addChild("d").setProperty("propa", 10);
+        root.commit();
+        
+        assertThat(explain("select [jcr:path] from [nt:base] where [propa] = 
10 and isDescendantNode('/test/c')"), containsString("lucene:test1"));
+        assertQuery("select [jcr:path] from [nt:base] where [propa] = 10 and 
isDescendantNode('/test/c')", asList("/test/c/d"));
+        // List appender should not have any warn logs as we are searching 
under right descendant as per path restrictions
+        assertFalse(isWarnMessagePresent(listAppender));
+        assertTrue(explain("select [jcr:path] from [nt:base] where [propa] = 
10").contains("lucene:test1"));
+        // List appender now will have warn log as we are searching under 
root(/) but index definition have exclude path restriction.
+        assertTrue(isWarnMessagePresent(listAppender));
+    }
+
+    private boolean isWarnMessagePresent(ListAppender<ILoggingEvent> 
listAppender) {
+        for (ILoggingEvent loggingEvent : listAppender.list) {
+            if (loggingEvent.getMessage().contains(warnMessage)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private String explain(String query) {
+        String explain = "explain " + query;
+        return executeQuery(explain, "JCR-SQL2").get(0);
+    }
+
+    private Tree createIndex(String name, Set<String> propNames) throws 
CommitFailedException {
+        Tree index = root.getTree("/");
+        return createIndex(index, name, propNames);
+    }
+
+    public static Tree createIndex(Tree index, String name, Set<String> 
propNames) throws CommitFailedException {
+        Tree def = index.addChild(INDEX_DEFINITIONS_NAME).addChild(name);
+        def.setProperty(JcrConstants.JCR_PRIMARYTYPE,
+                INDEX_DEFINITIONS_NODE_TYPE, Type.NAME);
+        def.setProperty(TYPE_PROPERTY_NAME, LuceneIndexConstants.TYPE_LUCENE);
+        def.setProperty(REINDEX_PROPERTY_NAME, true);
+        def.setProperty(FulltextIndexConstants.FULL_TEXT_ENABLED, false);
+        
def.setProperty(PropertyStates.createProperty(FulltextIndexConstants.INCLUDE_PROPERTY_NAMES,
 propNames, Type.STRINGS));
+        def.setProperty(LuceneIndexConstants.SAVE_DIR_LISTING, true);
+        return index.getChild(INDEX_DEFINITIONS_NAME).getChild(name);
+    }
+
+}

Modified: 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryIndex.java
 Wed Jul 10 13:20:50 2019
@@ -348,6 +348,10 @@ public interface QueryIndex {
          * @return if it is deprecated
          */
         boolean isDeprecated();
+        
+        default boolean logWarningForPathFilterMismatch() {
+            return false;
+        }
 
         /**
          * A builder for index plans.
@@ -369,6 +373,7 @@ public interface QueryIndex {
             protected Map<String, Object> attributes = Maps.newHashMap();
             protected String planName;
             protected boolean deprecated;
+            protected boolean logWarningForPathFilterMismatch;
 
             public Builder setCostPerExecution(double costPerExecution) {
                 this.costPerExecution = costPerExecution;
@@ -394,6 +399,11 @@ public interface QueryIndex {
                 this.isDelayed = isDelayed;
                 return this;
             }
+            
+            public Builder setLogWarningForPathFilterMismatch(boolean value) {
+                this.logWarningForPathFilterMismatch = value;
+                return this;
+            }
 
             public Builder setFulltextIndex(boolean isFulltextIndex) {
                 this.isFulltextIndex = isFulltextIndex;
@@ -480,6 +490,7 @@ public interface QueryIndex {
                     private final String planName = Builder.this.planName;
                     private final boolean deprecated =
                             Builder.this.deprecated;
+                    private final boolean logWarningForPathFilterMismatch = 
Builder.this.logWarningForPathFilterMismatch;
 
                     @Override
                     public String toString() {
@@ -496,7 +507,8 @@ public interface QueryIndex {
                             + " propertyRestriction : %s,"
                             + " pathPrefix : %s,"
                             + " deprecated : %s,"
-                            + " supportsPathRestriction : %s }",
+                            + " supportsPathRestriction : %s," 
+                            + " logWarningForPathFilterMismatch : %s }",
                             costPerExecution,
                             costPerEntry,
                             estimatedEntryCount,
@@ -509,7 +521,8 @@ public interface QueryIndex {
                             propRestriction,
                             pathPrefix,
                             deprecated,
-                            supportsPathRestriction
+                            supportsPathRestriction,
+                            logWarningForPathFilterMismatch
                             );
                     }
 
@@ -606,6 +619,11 @@ public interface QueryIndex {
                     public boolean isDeprecated() {
                         return deprecated;
                     }
+                    
+                    @Override
+                    public boolean logWarningForPathFilterMismatch() {
+                        return logWarningForPathFilterMismatch;
+                    }
 
                 };
             }

Modified: 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/QueryLimits.java
 Wed Jul 10 13:20:50 2019
@@ -18,6 +18,8 @@
  */
 package org.apache.jackrabbit.oak.spi.query;
 
+import org.apache.jackrabbit.oak.api.StrictPathRestriction;
+
 public interface QueryLimits {
 
     long getLimitInMemory();
@@ -28,4 +30,8 @@ public interface QueryLimits {
 
     boolean getFailTraversal();
 
+    default String getStrictPathRestriction() {
+        return StrictPathRestriction.DISABLE.name();
+    }
+
 }

Modified: 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-query-spi/src/main/java/org/apache/jackrabbit/oak/spi/query/package-info.java
 Wed Jul 10 13:20:50 2019
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.2.0")
+@Version("1.3.0")
 package org.apache.jackrabbit.oak.spi.query;
 
 import org.osgi.annotation.versioning.Version;

Modified: 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java?rev=1862879&r1=1862878&r2=1862879&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-search/src/main/java/org/apache/jackrabbit/oak/plugins/index/search/spi/query/FulltextIndexPlanner.java
 Wed Jul 10 13:20:50 2019
@@ -34,6 +34,7 @@ import com.google.common.collect.Iterabl
 import com.google.common.collect.Multimap;
 import org.apache.jackrabbit.JcrConstants;
 import org.apache.jackrabbit.oak.api.PropertyValue;
+import org.apache.jackrabbit.oak.api.StrictPathRestriction;
 import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.index.IndexConstants;
@@ -44,6 +45,7 @@ import org.apache.jackrabbit.oak.plugins
 import org.apache.jackrabbit.oak.plugins.index.search.IndexNode;
 import org.apache.jackrabbit.oak.plugins.index.search.IndexStatistics;
 import org.apache.jackrabbit.oak.plugins.index.search.PropertyDefinition;
+import org.apache.jackrabbit.oak.spi.filter.PathFilter;
 import org.apache.jackrabbit.oak.spi.query.Filter;
 import org.apache.jackrabbit.oak.spi.query.Filter.PropertyRestriction;
 import org.apache.jackrabbit.oak.spi.query.QueryConstants;
@@ -152,6 +154,9 @@ public class FulltextIndexPlanner {
         if (wrongIndex()) {
             return null;
         }
+        if 
(filter.getQueryLimits().getStrictPathRestriction().equals(StrictPathRestriction.ENABLE.name())
 && !isPlanWithValidPathFilter()) {
+            return null;
+        }
 
         FullTextExpression ft = filter.getFullTextConstraint();
 
@@ -286,6 +291,11 @@ public class FulltextIndexPlanner {
             costPerEntryFactor += sortOrder.size();
 
             IndexPlan.Builder plan = defaultPlan();
+
+            if 
(filter.getQueryLimits().getStrictPathRestriction().equals(StrictPathRestriction.WARN.name())
 && !isPlanWithValidPathFilter()) {
+                plan.setLogWarningForPathFilterMismatch(true);
+            }
+            
             if (plan == null) {
                 return null;
             }
@@ -333,6 +343,12 @@ public class FulltextIndexPlanner {
         return null;
     }
 
+    private boolean isPlanWithValidPathFilter() {
+        String pathFilter = filter.getPath();
+        PathFilter definitionPathFilter = definition.getPathFilter();
+        return definitionPathFilter.areAllDescendantsIncluded(pathFilter);
+    }
+
     private boolean matchesValuePattern(PropertyRestriction pr, 
PropertyDefinition pd) {
         if (!pd.valuePattern.matchesAll()){
             //So we have a valuePattern defined. So determine if


Reply via email to