### Eclipse Workspace Patch 1.0 #P oak-core Index: src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (revision 1587461) +++ src/main/java/org/apache/jackrabbit/oak/query/ast/SelectorImpl.java (working copy) @@ -42,6 +42,7 @@ import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.memory.PropertyBuilder; import org.apache.jackrabbit.oak.query.QueryImpl; import org.apache.jackrabbit.oak.query.fulltext.FullTextExpression; import org.apache.jackrabbit.oak.query.index.FilterImpl; @@ -533,12 +534,33 @@ readOakProperties(list, t, oakPropertyName, propertyType); if (list.size() == 0) { return null; + } else if (list.size() == 1) { + return list.get(0); + } + Type type = list.get(0).getType(); + for (int i = 1; i < list.size(); i++) { + Type t2 = list.get(i).getType(); + if (t2 != type) { + // types don't match + type = Type.STRING; + break; + } + } + if (type == Type.STRING) { + ArrayList strings = new ArrayList(); + for (PropertyValue p : list) { + Iterables.addAll(strings, p.getValue(Type.STRINGS)); + } + return PropertyValues.newString(strings); } - ArrayList strings = new ArrayList(); - for (PropertyValue p : list) { - Iterables.addAll(strings, p.getValue(Type.STRINGS)); + @SuppressWarnings("unchecked") + PropertyBuilder builder = (PropertyBuilder) PropertyBuilder.array(type); + builder.setName(""); + for (PropertyValue v : list) { + builder.addValue(v.getValue(type)); } - return PropertyValues.newString(strings); + PropertyState s = builder.getPropertyState(); + return PropertyValues.create(s); } boolean relative = oakPropertyName.indexOf('/') >= 0; Tree t = currentTree(); @@ -590,6 +612,7 @@ } private void readOakProperties(ArrayList target, Tree t, String oakPropertyName, Integer propertyType) { + boolean skipCurrentNode = false; while (true) { if (t == null || !t.exists()) { return; @@ -608,10 +631,14 @@ for (Tree child : t.getChildren()) { readOakProperties(target, child, oakPropertyName, propertyType); } + skipCurrentNode = true; } else { t = t.getChild(parent); } } + if (skipCurrentNode) { + return; + } if (!"*".equals(oakPropertyName)) { PropertyValue value = currentOakProperty(t, oakPropertyName, propertyType); if (value != null) { @@ -619,12 +646,12 @@ } return; } - for (PropertyState p : t.getProperties()) { - if (propertyType == null || p.getType().tag() == propertyType) { - PropertyValue v = PropertyValues.create(p); - target.add(v); - } - } + for (PropertyState p : t.getProperties()) { + if (propertyType == null || p.getType().tag() == propertyType) { + PropertyValue v = PropertyValues.create(p); + target.add(v); + } + } } @Override Index: src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java (revision 1587461) +++ src/test/java/org/apache/jackrabbit/oak/query/index/TraversingIndexQueryTest.java (working copy) @@ -13,6 +13,9 @@ */ package org.apache.jackrabbit.oak.query.index; +import java.util.ArrayList; +import java.util.Arrays; + import org.apache.jackrabbit.oak.Oak; import org.apache.jackrabbit.oak.api.ContentRepository; import org.apache.jackrabbit.oak.api.Tree; @@ -204,4 +207,82 @@ .of("/home/users/testing/socialgraph_test_user_4/social/relationships/friend/socialgraph_test_group")); } + + @Test + public void testRelativeProperties() throws Exception { + root.getTree("/").addChild("content").addChild("node1") + .setProperty("prop", 128); + root.commit(); + + assertQuery("//*[(@prop > 1)]", "xpath", + ImmutableList.of("/content/node1")); + assertQuery("//*[(@prop > 2)]", "xpath", + ImmutableList.of("/content/node1")); + assertQuery("//*[(@prop > 20)]", "xpath", + ImmutableList.of("/content/node1")); + assertQuery("//*[(@prop > 100)]", "xpath", + ImmutableList.of("/content/node1")); + assertQuery("//*[(@prop > 200)]", "xpath", new ArrayList()); + assertQuery("//*[(@prop > 1000)]", "xpath", new ArrayList()); + + assertQuery("//*[(*/@prop > 1)]", "xpath", ImmutableList.of("/content")); + assertQuery("//*[(*/@prop > 2)]", "xpath", ImmutableList.of("/content")); + assertQuery("//*[(*/@prop > 20)]", "xpath", + ImmutableList.of("/content")); + assertQuery("//*[(*/@prop > 100)]", "xpath", + ImmutableList.of("/content")); + assertQuery("//*[(*/@prop > 200)]", "xpath", new ArrayList()); + assertQuery("//*[(*/@prop > 1000)]", "xpath", new ArrayList()); + } + + @Test + public void testMultipleRelativeProperties() throws Exception { + Tree content = root.getTree("/").addChild("content"); + + content.addChild("node1").setProperty("a", 128); + content.addChild("node2").setProperty("a", "abc"); + content.addChild("node3").setProperty("a", "1280"); + + content.addChild("node1").setProperty("b", 128); + content.addChild("node2").setProperty("b", 1024); + content.addChild("node3").setProperty("b", 2048); + + content.addChild("node1").setProperty("c", 10.3); + content.addChild("node2").setProperty("c", -10.3); + content.addChild("node3").setProperty("c", 9.8); + + content.addChild("node1").setProperty("d", Arrays.asList("x", "y"), Type.STRINGS); + content.addChild("node2").setProperty("d", 10); + content.addChild("node3").setProperty("d", Arrays.asList(1L, 2L), Type.LONGS); + + + root.commit(); + + assertQuery("//*[*/@a > 2]", "xpath", Arrays.asList()); + assertQuery("//*[*/@a > '1']", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@a > 'abb']", "xpath", Arrays.asList()); + assertQuery("//*[*/@a = 'abc']", "xpath", Arrays.asList("/content")); + // this may be unexpected: it is evalucated as + // ['128', 'abc', '1280'] >= 'abc' + assertQuery("//*[*/@a >= 'abc']", "xpath", Arrays.asList()); + + assertQuery("//*[*/@b > 2]", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@b > 2048]", "xpath", Arrays.asList()); + assertQuery("//*[*/@b > '1']", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@b = 128]", "xpath", Arrays.asList("/content")); + + assertQuery("//*[*/@c > 10]", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@c > 11]", "xpath", Arrays.asList()); + assertQuery("//*[*/@c > '1']", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@c = 9.8]", "xpath", Arrays.asList("/content")); + + assertQuery("//*[*/@d > 10]", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@d > 11]", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@d > '1']", "xpath", Arrays.asList("/content")); + assertQuery("//*[*/@d = 10]", "xpath", Arrays.asList("/content")); + // this may be unexpected: it is evalucated as + // ['x', 'y', '10', '1', '2'] < '3' + assertQuery("//*[*/@d < 3]", "xpath", Arrays.asList()); +} + } Index: src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt =================================================================== --- src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt (revision 1587461) +++ src/test/resources/org/apache/jackrabbit/oak/query/sql2_measure.txt (working copy) @@ -42,7 +42,7 @@ select [jcr:path], p.[children/c1/*] from [nt:base] as p where p.[children/c1/*] is not null -/testRoot, [1] +/testRoot, 1 select [jcr:path], [jcr:score], * from [nt:base] as a where ([id] = '0' or [p0/id] = '0')