Author: thomasm Date: Tue May 15 08:48:03 2012 New Revision: 1338601 URL: http://svn.apache.org/viewvc?rev=1338601&view=rev Log: OAK-28 Query implementation (various changes and fixes)
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/mk/index/PropertyIndex.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueMapper.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.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/ast/SelectorImpl.java jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.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/query/index/PropertyContentIndex.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/queryTest.txt jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java 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=1338601&r1=1338600&r2=1338601&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 May 15 08:48:03 2012 @@ -44,7 +44,7 @@ import java.util.Map.Entry; public class Indexer implements QueryIndexProvider { // TODO discuss where to store index config data - static final String INDEX_CONFIG_ROOT = "/jcr:system/indexes"; + public static final String INDEX_CONFIG_ROOT = "/jcr:system/indexes"; private static final boolean DISABLED = Boolean.getBoolean("mk.indexDisabled"); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/index/PropertyIndex.java Tue May 15 08:48:03 2012 @@ -49,7 +49,7 @@ public class PropertyIndex implements In return null; } int index = nodeName.indexOf(':'); - String propertyName = nodeName.substring(0, index); + String propertyName = nodeName.substring(index + 1); return new PropertyIndex(indexer, propertyName, unique); } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueMapper.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueMapper.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueMapper.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/CoreValueMapper.java Tue May 15 08:48:03 2012 @@ -31,7 +31,7 @@ import java.util.Map; * CoreValueUtil provides methods to convert {@code CoreValue}s to the JSON * representation passed to MicroKernel and vice versa. */ -class CoreValueMapper { +public class CoreValueMapper { private static final Map<Integer, String> TYPE2HINT = new HashMap<Integer, String>(); private static final Map<String, Integer> HINT2TYPE = new HashMap<String, Integer>(); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/AstElement.java Tue May 15 08:48:03 2012 @@ -18,7 +18,12 @@ */ package org.apache.jackrabbit.oak.query.ast; +import org.apache.jackrabbit.mk.json.JsopReader; +import org.apache.jackrabbit.mk.json.JsopTokenizer; +import org.apache.jackrabbit.oak.api.CoreValue; +import org.apache.jackrabbit.oak.api.CoreValueFactory; import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.kernel.CoreValueMapper; import org.apache.jackrabbit.oak.query.Query; abstract class AstElement { @@ -60,10 +65,11 @@ abstract class AstElement { } /** - * Calculate the session local path (the path excluding the workspace name). + * Calculate the session local path (the path excluding the workspace name) + * if possible. * * @param path the absolute path - * @return the session local path + * @return the session local path, or null if not within this workspace */ protected String getLocalPath(String path) { String workspaceName = query.getWorkspaceName(); @@ -71,7 +77,27 @@ abstract class AstElement { return path; } String prefix = PathUtils.concat("/", workspaceName); - return PathUtils.concat("/", PathUtils.relativize(prefix, path)); + if (path.startsWith(prefix)) { + return PathUtils.concat("/", PathUtils.relativize(prefix, path)); + } + return null; + } + + /** + * Convert the JSON property value to a core value. + * + * @param propertyValue JSON property value + * @return the core value + */ + protected CoreValue getCoreValue(String propertyValue) { + // TODO data type mapping + CoreValueFactory vf = query.getValueFactory(); + JsopReader r = new JsopTokenizer(propertyValue); + if (r.matches('[')) { + // TODO support arrays, but only for comparisons + throw new IllegalArgumentException("Arrays are currently not supported: " + propertyValue); + } + return CoreValueMapper.fromJsopReader(r, vf); } } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ChildNodeImpl.java Tue May 15 08:48:03 2012 @@ -62,6 +62,10 @@ public class ChildNodeImpl extends Const public boolean evaluate() { String p = selector.currentPath(); String local = getLocalPath(p); + if (local == null) { + // not a local path + return false; + } // the parent of the root is the root, // so we need to special case this return !PathUtils.denotesRoot(local) && PathUtils.getParentPath(local).equals(parentPath); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ComparisonImpl.java Tue May 15 08:48:03 2012 @@ -18,6 +18,9 @@ */ package org.apache.jackrabbit.oak.query.ast; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import javax.jcr.PropertyType; import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.api.CoreValueFactory; import org.apache.jackrabbit.oak.query.index.FilterImpl; @@ -48,28 +51,96 @@ public class ComparisonImpl extends Cons @Override public boolean evaluate() { + // JCR 2.0 spec, 6.7.16 Comparison: + // "operand1 may evaluate to an array of values" + // TODO support arrays CoreValue v1 = operand1.currentValue(); + // "operand2 always evaluates to a scalar value" CoreValue v2 = operand2.currentValue(); if (v1 == null || v2 == null) { // TODO comparison: what about (null <> x) ? return false; } + if (v1.getType() != v2.getType()) { + // "the value of operand2 is converted to the + // property type of the value of operand1" + v2 = convert(query.getValueFactory(), v2, v1.getType()); + } switch (operator) { case EQUAL: return v1.equals(v2); case GREATER_OR_EQUAL: + return v1.compareTo(v2) >= 0; case GREATER_THAN: + return v1.compareTo(v2) > 0; case LESS_OR_EQUAL: + return v1.compareTo(v2) <= 0; case LESS_THAN: - return operand1.currentValue().equals(operand2.currentValue()); + return v1.compareTo(v2) < 0; case NOT_EQUAL: - return !operand1.currentValue().equals(operand2.currentValue()); + return !v1.equals(v2); case LIKE: return evaluateLike(v1, v2); } throw new IllegalArgumentException("Unknown operator: " + operator); } + private static CoreValue convert(CoreValueFactory vf, CoreValue v, int targetType) { + // TODO support full set of conversion features defined in the JCR spec + // at 3.6.4 Property Type Conversion + // re-use existing code if possible + int sourceType = v.getType(); + if (sourceType == targetType) { + return v; + } + switch (sourceType) { + case PropertyType.STRING: + switch(targetType) { + case PropertyType.BINARY: + try { + byte[] data = v.getString().getBytes("UTF-8"); + return vf.createValue(new ByteArrayInputStream(data)); + } catch (IOException e) { + // I don't know in what case that could really occur + // except if UTF-8 isn't supported + throw new IllegalArgumentException(v.getString(), e); + } + case PropertyType.DATE: + + } + case PropertyType.BOOLEAN: + return vf.createValue(v.getBoolean()); + case PropertyType.DATE: + return vf.createValue(v.getString(), PropertyType.DATE); + case PropertyType.LONG: + return vf.createValue(v.getLong()); + case PropertyType.DOUBLE: + return vf.createValue(v.getDouble()); + case PropertyType.DECIMAL: + return vf.createValue(v.getString(), PropertyType.DECIMAL); + case PropertyType.NAME: + return vf.createValue(v.getString(), PropertyType.NAME); + case PropertyType.PATH: + return vf.createValue(v.getString(), PropertyType.PATH); + case PropertyType.REFERENCE: + return vf.createValue(v.getString(), PropertyType.REFERENCE); + case PropertyType.WEAKREFERENCE: + return vf.createValue(v.getString(), PropertyType.WEAKREFERENCE); + case PropertyType.URI: + return vf.createValue(v.getString(), PropertyType.URI); + case PropertyType.BINARY: + try { + byte[] data = v.getString().getBytes("UTF-8"); + return vf.createValue(new ByteArrayInputStream(data)); + } catch (IOException e) { + // I don't know in what case that could really occur + // except if UTF-8 isn't supported + throw new IllegalArgumentException(v.getString(), e); + } + } + throw new IllegalArgumentException("Unknown property type: " + targetType); + } + private static boolean evaluateLike(CoreValue v1, CoreValue v2) { LikePattern like = new LikePattern(v2.getString()); return like.matches(v1.getString()); Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/ConstraintImpl.java Tue May 15 08:48:03 2012 @@ -28,7 +28,9 @@ public abstract class ConstraintImpl ext public abstract boolean evaluate(); /** - * Apply the condition to the filter, further restricting the filter if possible. + * Apply the condition to the filter, further restricting the filter if + * possible. This may also verify the data types are compatible, and that + * paths are valid. * * @param f the filter */ Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/EquiJoinConditionImpl.java Tue May 15 08:48:03 2012 @@ -83,7 +83,6 @@ public class EquiJoinConditionImpl exten if (v1 == null) { return false; } - // TODO data type mapping CoreValue v2 = selector2.currentProperty(property2Name); return v2 != null && v1.equals(v2); } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchScoreImpl.java Tue May 15 08:48:03 2012 @@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.query.i public class FullTextSearchScoreImpl extends DynamicOperandImpl { private final String selectorName; + private SelectorImpl selector; public FullTextSearchScoreImpl(String selectorName) { this.selectorName = selectorName; @@ -49,6 +50,13 @@ public class FullTextSearchScoreImpl ext return null; } + public void bindSelector(SourceImpl source) { + selector = source.getSelector(selectorName); + if (selector == null) { + throw new IllegalArgumentException("Unknown selector: " + selectorName); + } + } + @Override public void apply(FilterImpl f, Operator operator, CoreValue v) { // TODO support fulltext index conditions (score) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/JoinImpl.java Tue May 15 08:48:03 2012 @@ -70,30 +70,30 @@ public class JoinImpl extends SourceImpl } @Override - public void init(Query qom) { + public void init(Query query) { switch (joinType) { case INNER: left.setQueryConstraint(queryConstraint); right.setQueryConstraint(queryConstraint); right.setJoinCondition(joinCondition); - left.init(qom); - right.init(qom); + left.init(query); + right.init(query); break; case LEFT_OUTER: left.setQueryConstraint(queryConstraint); right.setOuterJoin(true); right.setQueryConstraint(queryConstraint); right.setJoinCondition(joinCondition); - left.init(qom); - right.init(qom); + left.init(query); + right.init(query); break; case RIGHT_OUTER: right.setQueryConstraint(queryConstraint); left.setOuterJoin(true); left.setQueryConstraint(queryConstraint); left.setJoinCondition(joinCondition); - right.init(qom); - left.init(qom); + right.init(query); + left.init(query); // TODO right outer join: verify whether converting // to left outer join is always correct (given the current restrictions) joinType = JoinType.LEFT_OUTER; @@ -169,7 +169,7 @@ public class JoinImpl extends SourceImpl @Override public String currentPath() { - // TODO + // TODO join: what is the path of a join? it this method ever called? return left.currentPath(); } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/LengthImpl.java Tue May 15 08:48:03 2012 @@ -18,6 +18,7 @@ */ package org.apache.jackrabbit.oak.query.ast; +import javax.jcr.PropertyType; import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.query.index.FilterImpl; @@ -49,15 +50,29 @@ public class LengthImpl extends DynamicO if (v == null) { return null; } - // TODO LENGTH(..) is the length of the string representation? - String value = v.getString(); - return query.getValueFactory().createValue(value.length()); + return query.getValueFactory().createValue(v.length()); } @Override public void apply(FilterImpl f, Operator operator, CoreValue v) { - // ignore - // TODO LENGTH(x) conditions: can use IS NOT NULL? + switch (v.getType()) { + case PropertyType.LONG: + case PropertyType.DECIMAL: + case PropertyType.DOUBLE: + // ok - comparison with a number + break; + case PropertyType.BINARY: + case PropertyType.STRING: + case PropertyType.DATE: + // ok - compare with a string literal + break; + default: + throw new IllegalArgumentException( + "Can not compare the length with a constant of type " + + PropertyType.nameFromValue(v.getType()) + + " and value " + v.toString()); + } + // TODO LENGTH(x) conditions: can use IS NOT NULL as a condition? } } 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=1338601&r1=1338600&r2=1338601&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 May 15 08:48:03 2012 @@ -18,10 +18,9 @@ */ package org.apache.jackrabbit.oak.query.ast; -import org.apache.jackrabbit.mk.json.JsopTokenizer; import org.apache.jackrabbit.mk.simple.NodeImpl; -import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.api.CoreValue; +import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.query.index.FilterImpl; public class PropertyValueImpl extends DynamicOperandImpl { @@ -76,11 +75,8 @@ public class PropertyValueImpl extends D if (!n.hasProperty(name)) { return null; } - // TODO data type mapping String value = n.getProperty(name); - value = JsopTokenizer.decodeQuoted(value); - return query.getValueFactory().createValue(value); - + return getCoreValue(value); } public void bindSelector(SourceImpl source) { 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=1338601&r1=1338600&r2=1338601&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 May 15 08:48:03 2012 @@ -19,7 +19,6 @@ package org.apache.jackrabbit.oak.query.ast; import org.apache.jackrabbit.mk.api.MicroKernel; -import org.apache.jackrabbit.mk.json.JsopTokenizer; import org.apache.jackrabbit.mk.simple.NodeImpl; import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.query.Query; @@ -32,6 +31,10 @@ public class SelectorImpl extends Source // TODO jcr:path isn't an official feature, support it? private static final String PATH = "jcr:path"; + private static final String JCR_PRIMARY_TYPE = "jcr:primaryType"; + + private static final String TYPE_BASE = "nt:base"; + protected QueryIndex index; private final String nodeTypeName, selectorName; @@ -79,6 +82,7 @@ public class SelectorImpl extends Source private FilterImpl createFilter() { FilterImpl f = new FilterImpl(this); + f.setNodeType(nodeTypeName); if (joinCondition != null) { joinCondition.apply(f); } @@ -94,7 +98,28 @@ public class SelectorImpl extends Source @Override public boolean next() { - return cursor == null ? false : cursor.next(); + if (cursor == null) { + return false; + } + while (true) { + boolean result = cursor.next(); + if (!result) { + return false; + } + if (nodeTypeName.equals(TYPE_BASE)) { + return true; + } + NodeImpl n = cursor.currentNode(); + String primaryType = n.getProperty(JCR_PRIMARY_TYPE); + if (primaryType == null) { + return true; + } + CoreValue v = getCoreValue(primaryType); + // TODO node type matching + if (nodeTypeName.equals(v.getString())) { + return true; + } + } } @Override @@ -110,7 +135,15 @@ public class SelectorImpl extends Source public CoreValue currentProperty(String propertyName) { if (propertyName.equals(PATH)) { String p = currentPath(); - return p == null ? null : query.getValueFactory().createValue(p); + if (p == null) { + return null; + } + String local = getLocalPath(p); + if (local == null) { + // not a local path + return null; + } + return query.getValueFactory().createValue(local); } NodeImpl n = currentNode(); if (n == null) { @@ -120,13 +153,11 @@ public class SelectorImpl extends Source if (value == null) { return null; } - // TODO data type mapping - value = JsopTokenizer.decodeQuoted(value); - return query.getValueFactory().createValue(value); + return getCoreValue(value); } @Override - public void init(Query qom) { + public void init(Query query) { // nothing to do } Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/SourceImpl.java Tue May 15 08:48:03 2012 @@ -29,32 +29,90 @@ public abstract class SourceImpl extends protected boolean join; protected boolean outerJoin; + /** + * Set the complete constraint of the query (the WHERE ... condition). + * + * @param queryConstraint the constraint + */ public void setQueryConstraint(ConstraintImpl queryConstraint) { this.queryConstraint = queryConstraint; } + /** + * Set the join condition (the ON ... condition). + * + * @param joinCondition the join condition + */ public void setJoinCondition(JoinConditionImpl joinCondition) { this.joinCondition = joinCondition; } + /** + * Set whether this source is the right hand side of a left outer join. + * + * @param outerJoin true if yes + */ public void setOuterJoin(boolean outerJoin) { this.outerJoin = outerJoin; } - public abstract void init(Query qom); - + /** + * Initialize the query. This will 'wire' the selectors with the + * constraints. + * + * @param query the query + */ + public abstract void init(Query query); + + /** + * Get the selector with the given name, or null if not found. + * + * @param selectorName the selector name + * @return the selector, or null + */ public abstract SelectorImpl getSelector(String selectorName); + /** + * Get the query plan. + * + * @return the query plan + */ public abstract String getPlan(); + /** + * Prepare executing the query. This method will decide which index to use. + * + * @param mk the MicroKernel + */ public abstract void prepare(MicroKernel mk); + /** + * Execute the query. The current node is set to before the first row. + * + * @param revisionId the revision to use + */ public abstract void execute(String revisionId); + /** + * Go to the next node for the given source. This will also filter the + * result for the right node type if required. + * + * @return true if there is a next row + */ public abstract boolean next(); + /** + * Get the current absolute path (including workspace name) + * + * @return the path + */ public abstract String currentPath(); + /** + * Get the current node. + * + * @return the node + */ public abstract NodeImpl currentNode(); } 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=1338601&r1=1338600&r2=1338601&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 May 15 08:48:03 2012 @@ -119,7 +119,7 @@ public class FilterImpl implements Filte public void setAlwaysFalse() { propertyRestrictions.clear(); valuePrefix = "none"; - nodeType = "none"; + nodeType = ""; path = "/"; pathRestriction = PathRestriction.EXACT; alwaysFalse = true; Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/index/PropertyContentIndex.java Tue May 15 08:48:03 2012 @@ -121,6 +121,7 @@ public class PropertyContentIndex implem public boolean next() { if (it.hasNext()) { currentPath = it.next(); + currentNode = null; return true; } return false; Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/AbstractQueryTest.java Tue May 15 08:48:03 2012 @@ -16,22 +16,39 @@ */ package org.apache.jackrabbit.oak.query; +import javax.jcr.GuestCredentials; +import org.apache.jackrabbit.mk.api.MicroKernel; import org.apache.jackrabbit.mk.core.MicroKernelImpl; import org.apache.jackrabbit.mk.index.IndexWrapper; +import org.apache.jackrabbit.mk.index.Indexer; +import org.apache.jackrabbit.oak.api.ContentSession; import org.apache.jackrabbit.oak.api.CoreValueFactory; -import org.apache.jackrabbit.oak.kernel.KernelNodeStore; -import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.apache.jackrabbit.oak.api.QueryEngine; +import org.apache.jackrabbit.oak.core.ContentRepositoryImpl; /** * AbstractQueryTest... */ public abstract class AbstractQueryTest { - // TODO improve: use ContentRepository here instead of creating mk instance. - protected final IndexWrapper mk = new IndexWrapper(new MicroKernelImpl()); - - protected final NodeStore store = new KernelNodeStore(mk); - - protected final CoreValueFactory vf = store.getValueFactory(); + protected final IndexWrapper mk; + protected final ContentRepositoryImpl rep; + protected final CoreValueFactory vf; + protected final QueryEngine qe; + protected final ContentSession session; + + { + MicroKernel rawMk = new MicroKernelImpl(); + mk = new IndexWrapper(rawMk); + Indexer indexer = new Indexer(mk, rawMk, Indexer.INDEX_CONFIG_ROOT); + rep = new ContentRepositoryImpl(mk, indexer); + try { + session = rep.login(new GuestCredentials(), "default"); + vf = session.getCoreValueFactory(); + qe = session.getQueryEngine(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } } \ No newline at end of file Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java (original) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/QueryTest.java Tue May 15 08:48:03 2012 @@ -16,7 +16,6 @@ package org.apache.jackrabbit.oak.query; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.FileOutputStream; -import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.LineNumberReader; @@ -28,15 +27,9 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; -import org.apache.jackrabbit.oak.api.AuthInfo; -import org.apache.jackrabbit.oak.api.ContentSession; import org.apache.jackrabbit.oak.api.CoreValue; -import org.apache.jackrabbit.oak.api.CoreValueFactory; -import org.apache.jackrabbit.oak.api.QueryEngine; import org.apache.jackrabbit.oak.api.Result; import org.apache.jackrabbit.oak.api.ResultRow; -import org.apache.jackrabbit.oak.api.Root; -import org.apache.jackrabbit.oak.spi.QueryIndexProvider; import org.junit.Test; /** @@ -44,42 +37,6 @@ import org.junit.Test; */ public class QueryTest extends AbstractQueryTest { - private QueryIndexProvider ip = mk.getIndexer(); - private QueryEngineImpl qe = new QueryEngineImpl(store, mk, ip); - private ContentSession session = new ContentSession() { - - @Override - public AuthInfo getAuthInfo() { - return null; - } - - @Override - public CoreValueFactory getCoreValueFactory() { - return null; - } - - @Override - public Root getCurrentRoot() { - return null; - } - - @Override - public QueryEngine getQueryEngine() { - return null; - } - - @Override - public String getWorkspaceName() { - return "/"; - } - - @Override - public void close() throws IOException { - // ignore - } - - }; - @Test public void script() throws Exception { test("queryTest.txt"); 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=1338601&r1=1338600&r2=1338601&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 May 15 08:48:03 2012 @@ -23,14 +23,14 @@ # test the property content index -commit / + "test": { "a": { "id": "10" }, "b": { "id" : "20" }} +commit /default + "test": { "a": { "id": "10" }, "b": { "id" : "20" }} commit /jcr:system/indexes + "property:id": {} explain select * from [nt:base] where id = '10' nt:base AS nt:base /* propertyIndex "id [10..10]" */ select * from [nt:base] where id = '10' -/test/a +/default/test/a select [jcr:path], * from [nt:base] where id = '10' /test/a, null @@ -38,68 +38,64 @@ select [jcr:path], * from [nt:base] wher explain select * from [nt:base] where id > '10' nt:base AS nt:base /* traverse "//*" */ -commit / - "test" +commit /default - "test" commit /jcr:system/indexes - "property:id" # other tests -commit / + "test": { "jcr:resource": {}, "resource": { "x" : {}}} +commit /default + "test": { "jcr:resource": {}, "resource": { "x" : {}}} select * from [nt:base] where id = -1 explain select * from [nt:base] as b where ischildnode(b, '/test') -nt:base AS b /* traverse "/test/*" */ +nt:base AS b /* traverse "/default/test/*" */ explain select * from [nt:base] as b where isdescendantnode(b, '/test') -nt:base AS b /* traverse "/test//*" */ +nt:base AS b /* traverse "/default/test//*" */ select * from [nt:base] as b where ischildnode(b, '/test') -/test/jcr:resource -/test/resource +/default/test/jcr:resource +/default/test/resource select * from [nt:base] as b where issamenode(b, '/test') -/test +/default/test select * from [nt:base] where name() = 'resource' -/test/resource +/default/test/resource select * from [nt:base] as b where localname(b) = 'resource' -/test/jcr:resource -/test/resource +/default/test/jcr:resource +/default/test/resource select * from [nt:base] as x where isdescendantnode(x, '/') -/ -/jcr:system -/jcr:system/indexes -/test -/test/jcr:resource -/test/resource -/test/resource/x +/default/test +/default/test/jcr:resource +/default/test/resource +/default/test/resource/x -commit / - "test" +commit /default - "test" -commit / + "parents": { "p0": {"id": "0"}, "p1": {"id": "1"}, "p2": {"id": "2"}} -commit / + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}} +commit /default + "parents": { "p0": {"id": "0"}, "p1": {"id": "1"}, "p2": {"id": "2"}} +commit /default + "children": { "c1": {"p": "1"}, "c2": {"p": "1"}, "c3": {"p": "2"}, "c4": {"p": "3"}} # relative property select * from [nt:base] where [c1/p] = '1' -/children +/default/children select * from [nt:base] as p where p.[jcr:path] = '/parents' -/parents +/default/parents select * from [nt:base] as p inner join [nt:base] as p2 on ischildnode(p2, p) where p.[jcr:path] = '/' -/, /children -/, /jcr:system -/, /parents +/default, /default/children +/default, /default/parents select * from [nt:base] as p inner join [nt:base] as p2 on isdescendantnode(p2, p) where p.[jcr:path] = '/parents' -/parents, /parents/p0 -/parents, /parents/p1 -/parents, /parents/p2 +/default/parents, /default/parents/p0 +/default/parents, /default/parents/p1 +/default/parents, /default/parents/p2 select * from [nt:base] as p inner join [nt:base] as p2 on issamenode(p2, p) where p.[jcr:path] = '/parents' -/parents, /parents +/default/parents, /default/parents select id from [nt:base] where id is not null 0 @@ -112,79 +108,82 @@ select id from [nt:base] where id is not 0 select * from [nt:base] as c right outer join [nt:base] as p on p.id = c.p where p.id is not null -/children/c1, /parents/p1 -/children/c2, /parents/p1 -/children/c3, /parents/p2 -null, /parents/p0 +/default/children/c1, /default/parents/p1 +/default/children/c2, /default/parents/p1 +/default/children/c3, /default/parents/p2 +null, /default/parents/p0 select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null -/parents/p0, null -/parents/p1, /children/c1 -/parents/p1, /children/c2 -/parents/p2, /children/c3 +/default/parents/p0, null +/default/parents/p1, /default/children/c1 +/default/parents/p1, /default/children/c2 +/default/parents/p2, /default/children/c3 select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is null -/parents/p0, null +/default/parents/p0, null select * from [nt:base] as p left outer join [nt:base] as c on p.id = c.p where p.id is not null and c.p is not null -/parents/p1, /children/c1 -/parents/p1, /children/c2 -/parents/p2, /children/c3 +/default/parents/p1, /default/children/c1 +/default/parents/p1, /default/children/c2 +/default/parents/p2, /default/children/c3 select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p -/parents/p1, /children/c1 -/parents/p1, /children/c2 -/parents/p2, /children/c3 +/default/parents/p1, /default/children/c1 +/default/parents/p1, /default/children/c2 +/default/parents/p2, /default/children/c3 explain select * from [nt:base] as p inner join [nt:base] as c on p.id = c.p nt:base AS p /* traverse "//*" */ INNER JOIN nt:base AS c /* traverse "//*" */ -commit / - "parents" -commit / - "children" +commit /default - "parents" +commit /default - "children" -commit / + "test": { "hello": { "x": "1" }, "world": { "x": "2" } } -commit / + "test2": { "id":"1", "x": "2" } +commit /default + "test": { "hello": { "x": "1" }, "world": { "x": "2" } } +commit /default + "test2": { "id":"1", "x": "2" } select * from [nt:base] / +/default +/default/test +/default/test/hello +/default/test/world +/default/test2 /jcr:system /jcr:system/indexes -/test -/test/hello -/test/world -/test2 select * from [nt:base] where id = '1' -/test2 +/default/test2 select * from [nt:base] where id = '1' and x = '2' -/test2 +/default/test2 select * from [nt:base] where id = '1' or x = '2' -/test/world -/test2 +/default/test/world +/default/test2 select * from [nt:base] where not (id = '1' or x = '2') / +/default +/default/test +/default/test/hello /jcr:system /jcr:system/indexes -/test -/test/hello select * from [nt:base] where x is null / +/default +/default/test /jcr:system /jcr:system/indexes -/test -commit / - "test" -commit / - "test2" +commit /default - "test" +commit /default - "test2" -commit / + "test": { "name": "hello" } -commit / + "test2": { "name": "World!" } -commit / + "test3": { "name": "Hallo" } -commit / + "test4": { "name": "10%" } -commit / + "test5": { "name": "10 percent" } +commit /default + "test": { "name": "hello" } +commit /default + "test2": { "name": "World!" } +commit /default + "test3": { "name": "Hallo" } +commit /default + "test4": { "name": "10%" } +commit /default + "test5": { "name": "10 percent" } select name from [nt:base] order by upper(name) 10 percent @@ -195,37 +194,38 @@ World! null null null +null select * from [nt:base] where length(name) = 5 -/test -/test3 +/default/test +/default/test3 select * from [nt:base] where upper(name) = 'HELLO' -/test +/default/test select * from [nt:base] where lower(name) = 'world!' -/test2 +/default/test2 select * from [nt:base] where name like 'W%' -/test2 +/default/test2 select * from [nt:base] where name like '%o_%' -/test2 +/default/test2 select * from [nt:base] where name like '__llo' -/test -/test3 +/default/test +/default/test3 select * from [nt:base] where upper(name) like 'H_LLO' -/test -/test3 +/default/test +/default/test3 select * from [nt:base] where upper(name) like 'H\_LLO' select * from [nt:base] where upper(name) like '10%' -/test4 -/test5 +/default/test4 +/default/test5 select * from [nt:base] where upper(name) like '10\%' -/test4 +/default/test4 Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java Tue May 15 08:48:03 2012 @@ -32,6 +32,7 @@ import javax.jcr.NodeIterator; import javax.jcr.RepositoryException; import javax.jcr.query.QueryResult; import javax.jcr.query.RowIterator; +import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; @@ -61,7 +62,7 @@ public class QueryResultImpl implements } @Override - public String[] getSelectorNames() throws RepositoryException { + public String[] getSelectorNames() { return result.getSelectorNames(); } @@ -80,10 +81,12 @@ public class QueryResultImpl implements current = null; while(it.hasNext()) { ResultRow r = it.next(); - String path = r.getPath(); - if (PathUtils.isAncestor(pathFilter, path)) { - current = new RowImpl(r, valueFactory); - break; + for (String s : getSelectorNames()) { + String path = r.getPath(s); + if (PathUtils.isAncestor(pathFilter, path)) { + current = new RowImpl(sessionDelegate, r, valueFactory); + break; + } } } } @@ -114,6 +117,9 @@ public class QueryResultImpl implements @Override public NodeIterator getNodes() throws RepositoryException { + if (getSelectorNames().length > 1) { + throw new RepositoryException("Query contains more than one selector: " + Arrays.toString(getSelectorNames())); + } Iterator<NodeImpl> it = new Iterator<NodeImpl>() { private final Iterator<? extends ResultRow> it = result.getRows().iterator(); Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/RowImpl.java Tue May 15 08:48:03 2012 @@ -20,6 +20,9 @@ package org.apache.jackrabbit.oak.jcr.qu import org.apache.jackrabbit.oak.api.CoreValue; import org.apache.jackrabbit.oak.api.ResultRow; +import org.apache.jackrabbit.oak.jcr.NodeDelegate; +import org.apache.jackrabbit.oak.jcr.NodeImpl; +import org.apache.jackrabbit.oak.jcr.SessionDelegate; import org.apache.jackrabbit.oak.jcr.value.ValueFactoryImpl; import javax.jcr.Node; @@ -32,34 +35,47 @@ import javax.jcr.query.Row; */ public class RowImpl implements Row { + private final SessionDelegate sessionDelegate; private final ResultRow row; private final ValueFactoryImpl valueFactory; - public RowImpl(ResultRow row, ValueFactoryImpl valueFactory) { + public RowImpl(SessionDelegate sessionDelegate, ResultRow row, ValueFactoryImpl valueFactory) { + this.sessionDelegate = sessionDelegate; this.row = row; this.valueFactory = valueFactory; } @Override public Node getNode() throws RepositoryException { - // TODO row node - return null; + return getNodeForPath(getPath()); } @Override public Node getNode(String selectorName) throws RepositoryException { - // TODO row node - return null; + return getNodeForPath(getPath(selectorName)); + } + + private Node getNodeForPath(String path) { + NodeDelegate d = sessionDelegate.getNode(path); + return new NodeImpl(d); } @Override public String getPath() throws RepositoryException { - return row.getPath(); + try { + return row.getPath(); + } catch (IllegalArgumentException e) { + throw new RepositoryException(e); + } } @Override public String getPath(String selectorName) throws RepositoryException { - return row.getPath(selectorName); + try { + return row.getPath(selectorName); + } catch (IllegalArgumentException e) { + throw new RepositoryException(e); + } } @Override @@ -76,7 +92,11 @@ public class RowImpl implements Row { @Override public Value getValue(String columnName) throws RepositoryException { - return valueFactory.createValue(row.getValue(columnName)); + try { + return valueFactory.createValue(row.getValue(columnName)); + } catch (IllegalArgumentException e) { + throw new RepositoryException(e); + } } @Override Modified: jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/qom/QueryObjectModelImpl.java Tue May 15 08:48:03 2012 @@ -64,7 +64,7 @@ public class QueryObjectModelImpl implem @Override public Column[] getColumns() { - return columns; + return columns == null ? new Column[0] : columns; } @Override @@ -74,7 +74,7 @@ public class QueryObjectModelImpl implem @Override public Ordering[] getOrderings() { - return orderings; + return orderings == null ? new Ordering[0] : orderings; } @Override @@ -155,7 +155,7 @@ public class QueryObjectModelImpl implem buff.append(" where "); buff.append(constraint); } - if (orderings != null) { + if (orderings != null && orderings.length > 0) { buff.append(" order by "); i = 0; for (Ordering o : orderings) { @@ -170,18 +170,21 @@ public class QueryObjectModelImpl implem @Override public String getStoredQueryPath() throws RepositoryException { - // TODO Auto-generated method stub + // TODO not implemented yet return null; } @Override - public Node storeAsNode(String arg0) throws RepositoryException { - // TODO Auto-generated method stub - return null; + public Node storeAsNode(String absPath) throws RepositoryException { + return queryManager.createQuery(getStatement(), Query.JCR_SQL2).storeAsNode(absPath); } public void addBindVariable(BindVariableValueImpl var) { this.bindVariableMap.put(var.getBindVariableName(), null); } + public String toString() { + return getStatement(); + } + } Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java Tue May 15 08:48:03 2012 @@ -23,7 +23,6 @@ import static junit.framework.Assert.ass import static org.junit.Assert.assertFalse; import javax.jcr.Node; import javax.jcr.NodeIterator; -import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.ValueFactory; @@ -48,7 +47,6 @@ public class QueryTest extends AbstractR @Test public void simple() throws RepositoryException { - Repository repository = getRepository(); Session session = createAnonymousSession(); try { Node hello = session.getRootNode().addNode("hello"); Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java?rev=1338601&r1=1338600&r2=1338601&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java (original) +++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/qom/QomTest.java Tue May 15 08:48:03 2012 @@ -19,7 +19,6 @@ package org.apache.jackrabbit.oak.jcr.query.qom; import static org.junit.Assert.assertEquals; -import javax.jcr.Repository; import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.Value;