Index: src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java (revision 1668924) +++ src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java (working copy) @@ -28,6 +28,7 @@ import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.query.index.FilterImpl; import org.apache.jackrabbit.oak.spi.query.PropertyValues; +import org.apache.jackrabbit.oak.spi.query.QueryConstants; /** * The function "localname(..)". @@ -68,24 +69,45 @@ @Override public PropertyValue currentProperty() { String name = PathUtils.getName(selector.currentPath()); - int colon = name.indexOf(':'); - // TODO LOCALNAME: evaluation of local name might not be correct - String localName = colon < 0 ? name : name.substring(colon + 1); + String localName = getLocalName(name); // TODO reverse namespace remapping? return PropertyValues.newString(localName); } + + static String getLocalName(String name) { + int colon = name.indexOf(':'); + // TODO LOCALNAME: evaluation of local name might not be correct + return colon < 0 ? name : name.substring(colon + 1); + } @Override public void restrict(FilterImpl f, Operator operator, PropertyValue v) { - // TODO support LOCALNAME index conditions + if (v == null) { + return; + } + + String name = NodeNameImpl.getName(query, v); + if (name == null) { + throw new IllegalArgumentException("Invalid name value: " + v.toString()); + } + if (f.getSelector().equals(selector) + && NodeNameImpl.supportedOperator(operator)) { + f.restrictProperty(QueryConstants.RESTRICTION_LOCAL_NAME, + operator, PropertyValues.newString(name)); + } } - + @Override public void restrictList(FilterImpl f, List list) { // optimizations of type "LOCALNAME(..) IN(A, B)" are not supported } @Override + public boolean supportsRangeConditions() { + return false; + } + + @Override public boolean canRestrictSelector(SelectorImpl s) { return s.equals(selector); } Index: src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java (revision 1668924) +++ src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java (working copy) @@ -28,8 +28,10 @@ import org.apache.jackrabbit.oak.api.Type; import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.namepath.JcrNameParser; +import org.apache.jackrabbit.oak.query.QueryImpl; import org.apache.jackrabbit.oak.query.index.FilterImpl; import org.apache.jackrabbit.oak.spi.query.PropertyValues; +import org.apache.jackrabbit.oak.spi.query.QueryConstants; import org.apache.jackrabbit.util.ISO9075; /** @@ -86,11 +88,16 @@ if (v == null) { return; } - String name = getName(v); + String name = getName(query, v); if (name == null) { throw new IllegalArgumentException("Invalid name value: " + v.toString()); } - // TODO support NAME(..) index conditions + if (f.getSelector().equals(selector) + && NodeNameImpl.supportedOperator(operator)) { + String localName = NodeLocalNameImpl.getLocalName(name); + f.restrictProperty(QueryConstants.RESTRICTION_LOCAL_NAME, + operator, PropertyValues.newString(localName)); + } } @Override @@ -110,7 +117,7 @@ * @param v the value * @return name value, or {@code null} if the value can not be converted */ - private String getName(PropertyValue v) { + static String getName(QueryImpl query, PropertyValue v) { // TODO correctly validate JCR names - see JCR 2.0 spec 3.2.4 Naming Restrictions switch (v.getType().tag()) { case PropertyType.DATE: @@ -133,7 +140,11 @@ } return name; } - + + static boolean supportedOperator(Operator o) { + return o == Operator.EQUAL || o == Operator.LIKE; + } + @Override int getPropertyType() { return PropertyType.NAME; Index: src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java =================================================================== --- src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java (revision 0) +++ src/main/java/org/apache/jackrabbit/oak/spi/query/QueryConstants.java (working copy) @@ -0,0 +1,30 @@ +/* + * 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.spi.query; + +public abstract class QueryConstants { + + /** + * Name of the property restriction used to express query performed + * via NAME and LOCALNAME functions + */ + public static final String RESTRICTION_LOCAL_NAME = ":localname"; + +} \ No newline at end of file Index: src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java =================================================================== --- src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java (revision 1668924) +++ src/test/java/org/apache/jackrabbit/oak/query/FilterTest.java (working copy) @@ -46,6 +46,23 @@ QueryImpl q = (QueryImpl) p.parse(sql); return q.createFilter(true); } + + private Filter createFilterSQL(String sql) throws ParseException { + QueryImpl q = (QueryImpl) p.parse(sql); + return q.createFilter(true); + } + + @Test + public void localName() throws Exception { + Filter f = createFilterSQL("select * from [nt:base] where localname() = 'resource'"); + assertEquals("[resource]", f.getPropertyRestrictions(":localname").toString()); + } + + @Test + public void name() throws Exception { + Filter f = createFilter("//*[fn:name() = 'nt:resource']"); + assertEquals("[resource]", f.getPropertyRestrictions(":localname").toString()); + } @Test public void mvp() throws Exception {