Author: thomasm
Date: Tue Aug 21 14:15:04 2012
New Revision: 1375560

URL: http://svn.apache.org/viewvc?rev=1375560&view=rev
Log:
OAK-261 Support querying on property types

Added:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PrefixContentIndex.java
Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/SQL2Parser.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
    
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/Indexer.java
 Tue Aug 21 14:15:04 2012
@@ -26,6 +26,7 @@ import org.apache.jackrabbit.mk.simple.N
 import org.apache.jackrabbit.mk.simple.NodeMap;
 import org.apache.jackrabbit.mk.util.SimpleLRUCache;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.query.index.PrefixContentIndex;
 import org.apache.jackrabbit.oak.query.index.PropertyContentIndex;
 import org.apache.jackrabbit.oak.spi.QueryIndex;
 import org.apache.jackrabbit.oak.spi.QueryIndexProvider;
@@ -674,7 +675,7 @@ public class Indexer implements QueryInd
                 if (index instanceof PropertyIndex) {
                     qi = new PropertyContentIndex((PropertyIndex) index);
                 } else if (index instanceof PrefixIndex) {
-                    // TODO support prefix indexes in the query engine?
+                    qi = new PrefixContentIndex((PrefixIndex) index);
                 }
                 queryIndexList.add(qi);
             }

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=1375560&r1=1375559&r2=1375560&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
 Tue Aug 21 14:15:04 2012
@@ -503,8 +503,12 @@ public class SQL2Parser {
             op = factory.lowerCase(parseDynamicOperand());
         } else if ("UPPER".equalsIgnoreCase(functionName)) {
             op = factory.upperCase(parseDynamicOperand());
+        } else if ("PROPERTY".equalsIgnoreCase(functionName)) {
+            PropertyValueImpl pv = parsePropertyValue(readName());
+            read(",");
+            op = factory.propertyValue(pv.getSelectorName(), 
pv.getPropertyName(), readString().getString());
         } else {
-            throw getSyntaxError("LENGTH, NAME, LOCALNAME, SCORE, LOWER, 
UPPER, or CAST");
+            throw getSyntaxError("LENGTH, NAME, LOCALNAME, SCORE, LOWER, 
UPPER, or PROPERTY");
         }
         read(")");
         return op;
@@ -609,35 +613,81 @@ public class SQL2Parser {
     }
 
     private CoreValue parseCastAs(CoreValue value) throws ParseException {
-        if (readIfPropertyType(PropertyType.STRING)) {
+        if (currentTokenQuoted) {
+            throw getSyntaxError("data type (STRING|BINARY|...)");
+        }
+        int propertyType = getPropertyTypeFromName(currentToken);
+        read();
+        switch (propertyType) {
+        case PropertyType.STRING:
             return valueFactory.createValue(value.getString());
-        } else if (readIfPropertyType(PropertyType.BINARY)) {
+        case PropertyType.BINARY:
             return valueFactory.createValue(value.getString(), 
PropertyType.BINARY);
-        } else if (readIfPropertyType(PropertyType.DATE)) {
+        case PropertyType.DATE:
             return valueFactory.createValue(value.getString(), 
PropertyType.DATE);
-        } else if (readIfPropertyType(PropertyType.LONG)) {
+        case PropertyType.LONG:
             return valueFactory.createValue(value.getLong());
-        } else if (readIfPropertyType(PropertyType.DOUBLE)) {
+        case PropertyType.DOUBLE:
             return valueFactory.createValue(value.getDouble());
-        } else if (readIfPropertyType(PropertyType.DECIMAL)) {
+        case PropertyType.DECIMAL:
             return valueFactory.createValue(value.getDecimal());
-        } else if (readIfPropertyType(PropertyType.BOOLEAN)) {
+        case PropertyType.BOOLEAN:
             return valueFactory.createValue(value.getBoolean());
-        } else if (readIfPropertyType(PropertyType.NAME)) {
+        case PropertyType.NAME:
             return valueFactory.createValue(value.getString(), 
PropertyType.NAME);
-        } else if (readIfPropertyType(PropertyType.PATH)) {
+        case PropertyType.PATH:
             return valueFactory.createValue(value.getString(), 
PropertyType.PATH);
-        } else if (readIfPropertyType(PropertyType.REFERENCE)) {
+        case PropertyType.REFERENCE:
             return valueFactory.createValue(value.getString(), 
PropertyType.REFERENCE);
-        } else if (readIfPropertyType(PropertyType.WEAKREFERENCE)) {
+        case PropertyType.WEAKREFERENCE:
             return valueFactory.createValue(value.getString(), 
PropertyType.WEAKREFERENCE);
-        } else if (readIfPropertyType(PropertyType.URI)) {
+        case PropertyType.URI:
             return valueFactory.createValue(value.getString(), 
PropertyType.URI);
-        } else {
+        default:
             throw getSyntaxError("data type (STRING|BINARY|...)");
         }
     }
 
+    /**
+     * Get the property type from the given case insensitive name.
+     *
+     * @param name the property type name (case insensitive)
+     * @return the type, or {@code PropertyType.UNDEFINED} if unknown
+     */
+    public static int getPropertyTypeFromName(String name) {
+        if (matchesPropertyType(PropertyType.STRING, name)) {
+            return PropertyType.STRING;
+        } else if (matchesPropertyType(PropertyType.BINARY, name)) {
+            return PropertyType.BINARY;
+        } else if (matchesPropertyType(PropertyType.DATE, name)) {
+            return PropertyType.DATE;
+        } else if (matchesPropertyType(PropertyType.LONG, name)) {
+            return PropertyType.LONG;
+        } else if (matchesPropertyType(PropertyType.DOUBLE, name)) {
+            return PropertyType.DOUBLE;
+        } else if (matchesPropertyType(PropertyType.DECIMAL, name)) {
+            return PropertyType.DECIMAL;
+        } else if (matchesPropertyType(PropertyType.BOOLEAN, name)) {
+            return PropertyType.BOOLEAN;
+        } else if (matchesPropertyType(PropertyType.NAME, name)) {
+            return PropertyType.NAME;
+        } else if (matchesPropertyType(PropertyType.PATH, name)) {
+            return PropertyType.PATH;
+        } else if (matchesPropertyType(PropertyType.REFERENCE, name)) {
+            return PropertyType.REFERENCE;
+        } else if (matchesPropertyType(PropertyType.WEAKREFERENCE, name)) {
+            return PropertyType.WEAKREFERENCE;
+        } else if (matchesPropertyType(PropertyType.URI, name)) {
+            return PropertyType.URI;
+        }
+        return PropertyType.UNDEFINED;
+    }
+
+    private static boolean matchesPropertyType(int propertyType, String name) {
+        String typeName = PropertyType.nameFromValue(propertyType);
+        return typeName.equalsIgnoreCase(name);
+    }
+
     private OrderingImpl[] parseOrder() throws ParseException {
         ArrayList<OrderingImpl> orderList = new ArrayList<OrderingImpl>();
         do {
@@ -715,11 +765,6 @@ public class SQL2Parser {
         return array;
     }
 
-    private boolean readIfPropertyType(int propertyType) throws ParseException 
{
-        String propertyName = PropertyType.nameFromValue(propertyType);
-        return readIf(propertyName);
-    }
-
     private boolean readIf(String token) throws ParseException {
         if (isToken(token)) {
             read();

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElementFactory.java
 Tue Aug 21 14:15:04 2012
@@ -116,6 +116,10 @@ public class AstElementFactory {
         return new PropertyValueImpl(selectorName, propertyName);
     }
 
+    public PropertyValueImpl propertyValue(String selectorName, String 
propertyName, String propertyType) {
+        return new PropertyValueImpl(selectorName, propertyName, propertyType);
+    }
+
     public SameNodeImpl sameNode(String selectorName, String path) {
         return new SameNodeImpl(selectorName, path);
     }

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/PropertyValueImpl.java
 Tue Aug 21 14:15:04 2012
@@ -18,10 +18,16 @@
  */
 package org.apache.jackrabbit.oak.query.ast;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import javax.jcr.PropertyType;
 import org.apache.jackrabbit.oak.api.CoreValue;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.memory.MultiPropertyState;
+import org.apache.jackrabbit.oak.query.SQL2Parser;
 import org.apache.jackrabbit.oak.query.index.FilterImpl;
 
 /**
@@ -31,11 +37,19 @@ public class PropertyValueImpl extends D
 
     private final String selectorName;
     private final String propertyName;
+    private final int propertyType;
     private SelectorImpl selector;
 
     public PropertyValueImpl(String selectorName, String propertyName) {
+        this(selectorName, propertyName, null);
+    }
+
+    public PropertyValueImpl(String selectorName, String propertyName, String 
propertyType) {
         this.selectorName = selectorName;
         this.propertyName = propertyName;
+        this.propertyType = propertyType == null ?
+                PropertyType.UNDEFINED :
+                SQL2Parser.getPropertyTypeFromName(propertyType);
     }
 
     public String getSelectorName() {
@@ -54,33 +68,77 @@ public class PropertyValueImpl extends D
     @Override
     public String toString() {
         // TODO quote property names?
-        return getSelectorName() + '.' + propertyName;
+        String s = getSelectorName() + '.' + propertyName;
+        if (propertyType != PropertyType.UNDEFINED) {
+            s = "property(" + s + ", '" +
+                    
PropertyType.nameFromValue(propertyType).toLowerCase(Locale.ENGLISH) +
+                    "')";
+        }
+        return s;
     }
 
     @Override
     public PropertyState currentProperty() {
-        if (propertyName.indexOf('/') < 0) {
-            return selector.currentProperty(propertyName);
+        boolean relative = propertyName.indexOf('/') >= 0;
+        boolean asterisk = propertyName.equals("*");
+        if (!relative && !asterisk) {
+            PropertyState p = selector.currentProperty(propertyName);
+            return matchesPropertyType(p) ? p : null;
         }
-        // TODO really support relative properties?
         Tree tree = getTree(selector.currentPath());
-        for (String p : 
PathUtils.elements(PathUtils.getParentPath(propertyName))) {
+        if (relative) {
+            for (String p : 
PathUtils.elements(PathUtils.getParentPath(propertyName))) {
+                if (tree == null) {
+                    return null;
+                }
+                if (!tree.hasChild(p)) {
+                    return null;
+                }
+                tree = tree.getChild(p);
+            }
             if (tree == null) {
                 return null;
             }
-            if (!tree.hasChild(p)) {
+        }
+        if (!asterisk) {
+            String name = PathUtils.getName(propertyName);
+            if (!tree.hasProperty(name)) {
                 return null;
             }
-            tree = tree.getChild(p);
+            PropertyState p = tree.getProperty(name);
+            return matchesPropertyType(p) ? p : null;
         }
-        if (tree == null) {
-            return null;
+        // asterisk - create a multi-value property
+        // warning: the returned property state may have a mixed type
+        // (not all values may have the same type)
+        ArrayList<CoreValue> values = new ArrayList<CoreValue>();
+        for (PropertyState p : tree.getProperties()) {
+            if (matchesPropertyType(p)) {
+                if (p.isArray()) {
+                    values.addAll(p.getValues());
+                } else {
+                    values.add(p.getValue());
+                }
+            }
         }
-        String name = PathUtils.getName(propertyName);
-        if (!tree.hasProperty(name)) {
-            return null;
+        MultiPropertyState mv = new MultiPropertyState("*", values);
+        return mv;
+    }
+
+    private boolean matchesPropertyType(PropertyState state) {
+        if (propertyType == PropertyType.UNDEFINED) {
+            return true;
         }
-        return tree.getProperty(name);
+        if (state.isArray()) {
+            List<CoreValue> values = state.getValues();
+            if (values.isEmpty()) {
+                // TODO how to retrieve the property type of an empty 
multi-value property?
+                // currently it matches all property types
+                return true;
+            }
+            return values.get(0).getType() == propertyType;
+        }
+        return state.getValue().getType() == propertyType;
     }
 
     public void bindSelector(SourceImpl source) {
@@ -95,6 +153,9 @@ public class PropertyValueImpl extends D
                 return;
             }
             f.restrictProperty(propertyName, operator, v);
+            if (propertyType != PropertyType.UNDEFINED) {
+                f.restrictPropertyType(propertyName, operator, propertyType);
+            }
         }
     }
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/FilterImpl.java
 Tue Aug 21 14:15:04 2012
@@ -29,6 +29,7 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map.Entry;
+import javax.jcr.PropertyType;
 
 /**
  * A filter or lookup condition.
@@ -58,11 +59,6 @@ public class FilterImpl implements Filte
     private String nodeType;
 
     /**
-     *  The value prefix, or null if not set.
-     */
-    private String valuePrefix;
-
-    /**
      * The fulltext search conditions, if any.
      */
     private final ArrayList<String> fulltextConditions = new 
ArrayList<String>();
@@ -108,14 +104,6 @@ public class FilterImpl implements Filte
         this.nodeType = nodeType;
     }
 
-    public String getValuePrefix() {
-        return valuePrefix;
-    }
-
-    public void setValuePrefix(String valuePrefix) {
-        this.valuePrefix = valuePrefix;
-    }
-
     public boolean isDistinct() {
         return distinct;
     }
@@ -126,7 +114,6 @@ public class FilterImpl implements Filte
 
     public void setAlwaysFalse() {
         propertyRestrictions.clear();
-        valuePrefix = "none";
         nodeType = "";
         path = "/";
         pathRestriction = PathRestriction.EXACT;
@@ -175,6 +162,25 @@ public class FilterImpl implements Filte
         }
     }
 
+    public void restrictPropertyType(String propertyName, Operator operator,
+            int propertyType) {
+        if (propertyType == PropertyType.UNDEFINED) {
+            // not restricted
+            return;
+        }
+        PropertyRestriction x = propertyRestrictions.get(propertyName);
+        if (x == null) {
+            x = new PropertyRestriction();
+            x.propertyName = propertyName;
+            propertyRestrictions.put(propertyName, x);
+        }
+        if (x.propertyType != PropertyType.UNDEFINED && x.propertyType != 
propertyType) {
+            // already restricted to another property type - always false
+            setAlwaysFalse();
+        }
+        x.propertyType = propertyType;
+    }
+
     public void restrictProperty(String propertyName, Operator op, CoreValue 
value) {
         PropertyRestriction x = propertyRestrictions.get(propertyName);
         if (x == null) {

Added: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PrefixContentIndex.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PrefixContentIndex.java?rev=1375560&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PrefixContentIndex.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PrefixContentIndex.java
 Tue Aug 21 14:15:04 2012
@@ -0,0 +1,124 @@
+/*
+ * 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.index;
+
+import java.util.Iterator;
+import javax.jcr.PropertyType;
+import org.apache.jackrabbit.mk.index.PrefixIndex;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.kernel.CoreValueMapper;
+import org.apache.jackrabbit.oak.spi.Cursor;
+import org.apache.jackrabbit.oak.spi.Filter;
+import org.apache.jackrabbit.oak.spi.IndexRow;
+import org.apache.jackrabbit.oak.spi.QueryIndex;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * An index that stores the index data in a {@code MicroKernel}.
+ */
+public class PrefixContentIndex implements QueryIndex {
+
+    private final PrefixIndex index;
+
+    public PrefixContentIndex(PrefixIndex index) {
+        this.index = index;
+    }
+
+    @Override
+    public double getCost(Filter filter) {
+        Filter.PropertyRestriction restriction = 
filter.getPropertyRestriction("*");
+        if (restriction == null) {
+            return Double.MAX_VALUE;
+        }
+        if (restriction.first != restriction.last) {
+            // only support equality matches (for now)
+            return Double.MAX_VALUE;
+        }
+        if (restriction.propertyType == PropertyType.UNDEFINED) {
+            return Double.MAX_VALUE;
+        }
+        String hint = CoreValueMapper.getHintForType(restriction.propertyType);
+        String prefix = hint + ":";
+        if (!prefix.equals(index.getPrefix())) {
+            // wrong prefix (wrong property type)
+            return Double.MAX_VALUE;
+        }
+        return 100;
+    }
+
+    @Override
+    public String getPlan(Filter filter) {
+        Filter.PropertyRestriction restriction = 
filter.getPropertyRestriction("*");
+        if (restriction == null) {
+            throw new IllegalArgumentException("No restriction for *");
+        }
+        // TODO need to use correct json representation
+        String v = restriction.first.getString();
+        v = index.getPrefix() + v;
+        return "prefixIndex \"" + v + '"';
+    }
+
+    @Override
+    public Cursor query(Filter filter, String revisionId, NodeState root) {
+        Filter.PropertyRestriction restriction = 
filter.getPropertyRestriction("*");
+        if (restriction == null) {
+            throw new IllegalArgumentException("No restriction for *");
+        }
+        // TODO need to use correct json representation
+        String v = restriction.first.getString();
+        v = index.getPrefix() + v;
+        Iterator<String> it = index.getPaths(v, revisionId);
+        return new ContentCursor(it);
+    }
+
+    @Override
+    public String getIndexName() {
+        return index.getIndexNodeName();
+    }
+
+    /**
+     * The cursor to for this index.
+     */
+    static class ContentCursor implements Cursor {
+
+        private final Iterator<String> it;
+
+        private String currentPath;
+
+        public ContentCursor(Iterator<String> it) {
+            this.it = it;
+        }
+
+        @Override
+        public IndexRow currentRow() {
+            return new IndexRowImpl(currentPath);
+        }
+
+        @Override
+        public boolean next() {
+            if (it.hasNext()) {
+                String pathAndProperty = it.next();
+                currentPath = PathUtils.getParentPath(pathAndProperty);
+                return true;
+            }
+            return false;
+        }
+    }
+
+}

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/Filter.java
 Tue Aug 21 14:15:04 2012
@@ -19,6 +19,7 @@
 package org.apache.jackrabbit.oak.spi;
 
 import java.util.Collection;
+import javax.jcr.PropertyType;
 
 import org.apache.jackrabbit.oak.api.CoreValue;
 
@@ -93,6 +94,12 @@ public interface Filter {
          */
         public boolean lastIncluding;
 
+        /**
+         * The property type, if restricted.
+         * If not restricted, this field is set to PropertyType.UNDEFINED.
+         */
+        public int propertyType = PropertyType.UNDEFINED;
+
         @Override
         public String toString() {
             return (first == null ? "" : ((firstIncluding ? "[" : "(") + 
first)) + ".." +

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt?rev=1375560&r1=1375559&r2=1375560&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt
 Tue Aug 21 14:15:04 2012
@@ -21,6 +21,27 @@
 # * new tests are typically be added on top, after the syntax docs
 # * use ascii character only
 
+# property type (value prefix) index
+
+commit / + "test": { "a": { "id": "ref:123" }, "b": { "id" : "str:123" }}
+
+explain select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' 
AS REFERENCE)
+nt:base as nt:base /* traverse "//*" */
+
+select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS 
REFERENCE)
+/test/a
+
+commit /jcr:system/indexes + "prefix@ref:": {}
+
+explain select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' 
AS REFERENCE)
+nt:base as nt:base /* prefixIndex "ref:123" */
+
+select * from [nt:base] where property([*], 'REFERENCE') = CAST('123' AS 
REFERENCE)
+/test/a
+
+commit / - "test"
+commit /jcr:system/indexes - "prefix@ref:"
+
 # sql-1 query (nt:unstructured needs to be escaped in sql-2)
 
 sql1 select prop1 from nt:unstructured where prop1 is not null order by prop1 
asc


Reply via email to