Author: davide Date: Tue Sep 2 11:24:56 2014 New Revision: 1621962 URL: http://svn.apache.org/r1621962 Log: OAK-2062 Range queries and relative properties resultset should be consistent with JR2
fixed loop in SelectorImpl, fixed unit test and increased test coverage. Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java?rev=1621962&r1=1621961&r2=1621962&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java Tue Sep 2 11:24:56 2014 @@ -58,6 +58,8 @@ import org.apache.jackrabbit.oak.spi.que import org.apache.jackrabbit.oak.spi.query.QueryIndex.AdvancedQueryIndex; import org.apache.jackrabbit.oak.spi.query.QueryIndex.IndexPlan; import org.apache.jackrabbit.oak.spi.state.NodeState; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; @@ -66,6 +68,7 @@ import com.google.common.collect.Iterabl * A selector within a query. */ public class SelectorImpl extends SourceImpl { + private static final Logger LOG = LoggerFactory.getLogger(SelectorImpl.class); // TODO possibly support using multiple indexes (using index intersection / index merge) private SelectorExecutionPlan plan; @@ -547,6 +550,10 @@ public class SelectorImpl extends Source boolean asterisk = oakPropertyName.indexOf('*') >= 0; if (asterisk) { Tree t = currentTree(); + if (t != null) { + LOG.trace("currentOakProperty() - '*' case. looking for '{}' in '{}'", + oakPropertyName, t.getPath()); + } ArrayList<PropertyValue> list = new ArrayList<PropertyValue>(); readOakProperties(list, t, oakPropertyName, propertyType); if (list.size() == 0) { @@ -630,10 +637,13 @@ public class SelectorImpl extends Source private void readOakProperties(ArrayList<PropertyValue> target, Tree t, String oakPropertyName, Integer propertyType) { boolean skipCurrentNode = false; - while (true) { + + while (!skipCurrentNode) { if (t == null || !t.exists()) { return; } + LOG.trace("readOakProperties() - reading '{}' for '{}'", t.getPath(), + oakPropertyName); int slash = oakPropertyName.indexOf('/'); if (slash < 0) { break; @@ -659,6 +669,7 @@ public class SelectorImpl extends Source if (!"*".equals(oakPropertyName)) { PropertyValue value = currentOakProperty(t, oakPropertyName, propertyType); if (value != null) { + LOG.trace("readOakProperties() - adding: '{}' from '{}'", value, t.getPath()); target.add(value); } return; Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java?rev=1621962&r1=1621961&r2=1621962&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java Tue Sep 2 11:24:56 2014 @@ -13,12 +13,22 @@ */ package org.apache.jackrabbit.oak.query.index; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.of; import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE; +import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED; +import static org.apache.jackrabbit.oak.api.Type.LONG; +import static org.apache.jackrabbit.oak.api.Type.NAME; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; 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.Tree; import org.apache.jackrabbit.oak.api.Type; @@ -237,7 +247,7 @@ public class TraversingIndexQueryTest ex assertQuery("//*[(*/@prop > 1000)]", "xpath", new ArrayList<String>()); } - @Test + @Test // OAK-2062 public void testRelativeProperties2() throws Exception { Tree t = root.getTree("/").addChild("content").addChild("nodes"); Tree a = t.addChild("a"); @@ -259,47 +269,190 @@ public class TraversingIndexQueryTest ex root.commit(); assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 9)]", "xpath", - ImmutableList.of("/content/nodes/a", "/content/nodes/a/b", - "/content/nodes/a/b/c")); + ImmutableList.of("/content/nodes/a")); assertQuery( "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 9)]", - "xpath", ImmutableList.of("/content/nodes/a", - "/content/nodes/a/b", "/content/nodes/a/b/c")); + "xpath", ImmutableList.of("/content/nodes/a")); assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 10)]", "xpath", - ImmutableList.of("/content/nodes/a", "/content/nodes/a/b", - "/content/nodes/a/b/c")); + ImmutableList.of("/content/nodes/a")); assertQuery( "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 10)]", - "xpath", ImmutableList.of("/content/nodes/a", - "/content/nodes/a/b", "/content/nodes/a/b/c")); + "xpath", ImmutableList.of("/content/nodes/a")); assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 15)]", "xpath", - ImmutableList.of("/content/nodes/a", "/content/nodes/a/b", - "/content/nodes/a/b/c")); + ImmutableList.of("/content/nodes/a")); assertQuery( "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 15)]", - "xpath", ImmutableList.of("/content/nodes/a", - "/content/nodes/a/b", "/content/nodes/a/b/c")); + "xpath", ImmutableList.of("/content/nodes/a")); assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 20)]", "xpath", - ImmutableList.of("/content/nodes/a", "/content/nodes/a/b", - "/content/nodes/a/b/c")); + ImmutableList.of("/content/nodes/a")); assertQuery( "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 20)]", - "xpath", ImmutableList.of("/content/nodes/a", - "/content/nodes/a/b", "/content/nodes/a/b/c")); + "xpath", ImmutableList.of("/content/nodes/a")); assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 30)]", "xpath", - ImmutableList.of("/content/nodes/a", "/content/nodes/a/b", - "/content/nodes/a/b/c")); + ImmutableList.of("/content/nodes/a")); assertQuery( "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 30)]", - "xpath", ImmutableList.of("/content/nodes/a", - "/content/nodes/a/b", "/content/nodes/a/b/c")); + "xpath", ImmutableList.of("/content/nodes/a")); } + + /** + * tests range queries, long comparisons and relative properties + * @throws CommitFailedException + */ + @Test // OAK-2062 + public void testRangeRelativeProperties() throws CommitFailedException { + final List<String> emptyList = new ArrayList<String>(); + final String property = "prop"; + Tree contentNodes, t; + + contentNodes = root.getTree("/").addChild("content").addChild("nodes"); + + /* creating content structure + * content : { + * nodes : { + * a9 { + * b : { + * c : { + * d9 : { + * prop : 9 + * } + * } + * } + * }, + * a10 { + * b : { + * c : { + * d10 : { + * prop : 10 + * } + * } + * } + * }, + * a20 { + * b : { + * c : { + * d20 : { + * prop : 20 + * } + * } + * } + * }, + * a30 { + * b : { + * c : { + * d30 : { + * prop : 30 + * } + * } + * } + * }, + * } + * } + * + */ + t = addNtUnstructuredChild(contentNodes, "a9", null, null); + t = addNtUnstructuredChild(t, "b", null, null); + t = addNtUnstructuredChild(t, "c", null, null); + t = addNtUnstructuredChild(t, "d9", property, 9L); + t = addNtUnstructuredChild(contentNodes, "a10", null, null); + t = addNtUnstructuredChild(t, "b", null, null); + t = addNtUnstructuredChild(t, "c", null, null); + t = addNtUnstructuredChild(t, "d10", property, 10L); + t = addNtUnstructuredChild(contentNodes, "a20", null, null); + t = addNtUnstructuredChild(t, "b", null, null); + t = addNtUnstructuredChild(t, "c", null, null); + t = addNtUnstructuredChild(t, "d20", property, 20L); + t = addNtUnstructuredChild(contentNodes, "a30", null, null); + t = addNtUnstructuredChild(t, "b", null, null); + t = addNtUnstructuredChild(t, "c", null, null); + t = addNtUnstructuredChild(t, "d30", property, 30L); + root.commit(); + + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 9)]", "xpath", + of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20", + "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 10)]", "xpath", + of("/content/nodes/a10", "/content/nodes/a20", "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 20)]", "xpath", + of("/content/nodes/a20", "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 30)]", "xpath", + of("/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop >= 40)]", "xpath", emptyList); + + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 8)]", "xpath", emptyList); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 9)]", "xpath", + of("/content/nodes/a9")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 10)]", "xpath", + of("/content/nodes/a9", "/content/nodes/a10")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 20)]", "xpath", + of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20")); + assertQuery("/jcr:root/content/nodes//*[(*/*/*/@prop <= 30)]", "xpath", + of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20", + "/content/nodes/a30")); + + assertQuery( + "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 9)]", + "xpath", + of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20", + "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 10)]", + "xpath", of("/content/nodes/a10", "/content/nodes/a20", "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 20)]", + "xpath", of("/content/nodes/a20", "/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 30)]", + "xpath", of("/content/nodes/a30")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop >= 40)]", + "xpath", emptyList); + + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 8)]", + "xpath", emptyList); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 9)]", + "xpath", of("/content/nodes/a9")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 10)]", + "xpath", of("/content/nodes/a9", "/content/nodes/a10")); + assertQuery("/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 20)]", + "xpath", of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20")); + assertQuery( + "/jcr:root/content/nodes//element(*, nt:unstructured)[(*/*/*/@prop <= 30)]", + "xpath", + of("/content/nodes/a9", "/content/nodes/a10", "/content/nodes/a20", + "/content/nodes/a30")); + } + + /** + * adds a child of type {@link JcrConstants#NT_UNSTRUCTURED} under the provided {@code parent} + * with the provided {@code name} and an optional {@code propertyName} and {@code value}. If + * either {@code propertyName} or {@code value} are null the property won't be set. + * + * @param parent + * @param name + * @param propertyName + * @param value + * @return + */ + private static Tree addNtUnstructuredChild(@Nonnull final Tree parent, + @Nonnull final String name, + @Nullable final String propertyName, + @Nullable final Long value) { + checkNotNull(parent); + checkNotNull(name); + + Tree ret = parent.addChild(name); + ret.setProperty(JCR_PRIMARYTYPE, NT_UNSTRUCTURED, NAME); + + if (propertyName != null && value != null) { + ret.setProperty(propertyName, value, LONG); + } + + return ret; + } + @Test public void testMultipleRelativeProperties() throws Exception { Tree content = root.getTree("/").addChild("content");