You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by th...@apache.org on 2012/08/30 11:20:10 UTC
svn commit: r1378867 - in /jackrabbit/oak/trunk:
oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/
oak-core/src/main/java/org/apache/jackrabbit/oak/api/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/
oak-core/src/main/java/org/...
Author: thomasm
Date: Thu Aug 30 09:20:10 2012
New Revision: 1378867
URL: http://svn.apache.org/viewvc?rev=1378867&view=rev
Log:
OAK-237 Run Jackrabbit query tests - implement missing features and improve compatibility with Jackrabbit 2.x (fulltext search, result size, join and order by multi-valued properties, order by nulls first, order by value type, compatibility with Jackrabbit 2.x identifiers in SQL-1, node name ISO9075 escaping)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/BranchMergeMicroKernel.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryValue.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.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/XPathToSQL2Converter.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/ComparisonImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.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/FullTextSearchImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.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/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
jackrabbit/oak/trunk/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/query/QueryResultImpl.java
jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/BranchMergeMicroKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/BranchMergeMicroKernel.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/BranchMergeMicroKernel.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/mk/wrapper/BranchMergeMicroKernel.java Thu Aug 30 09:20:10 2012
@@ -66,6 +66,9 @@ public class BranchMergeMicroKernel impl
}
private static String getBranchId(String revisionId) {
+ if (revisionId == null) {
+ return TRUNK;
+ }
int idx = revisionId.indexOf('-');
if (idx <= 0) {
return TRUNK;
@@ -129,7 +132,7 @@ public class BranchMergeMicroKernel impl
public long getChildNodeCount(String path, String revisionId) {
String branch = getBranchId(revisionId);
String rev = getRevisionId(branch, revisionId);
- return getChildNodeCount(path, rev);
+ return base.getChildNodeCount(path, rev);
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/api/Result.java Thu Aug 30 09:20:10 2012
@@ -21,10 +21,33 @@ package org.apache.jackrabbit.oak.api;
*/
public interface Result {
+ /**
+ * Get the list of column names.
+ *
+ * @return the column names
+ */
String[] getColumnNames();
+ /**
+ * Get the list of selector names.
+ *
+ * @return the selector names
+ */
String[] getSelectorNames();
+ /**
+ * Get the rows.
+ *
+ * @return the rows
+ */
Iterable<? extends ResultRow> getRows();
+ /**
+ * Get the number of rows, if known. If the size is not known, -1 is
+ * returned.
+ *
+ * @return the size or -1 if unknown
+ */
+ long getSize();
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryValue.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryValue.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryValue.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/MemoryValue.java Thu Aug 30 09:20:10 2012
@@ -73,7 +73,7 @@ public abstract class MemoryValue implem
int type = getType();
if (type != o.getType()) {
- return type - o.getType();
+ return o.getType() - type;
} else if (type == PropertyType.LONG) {
return Long.signum(getLong() - o.getLong());
} else if (type == PropertyType.DOUBLE) {
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/Query.java Thu Aug 30 09:20:10 2012
@@ -13,12 +13,15 @@
*/
package org.apache.jackrabbit.oak.query;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
+import javax.jcr.PropertyType;
import org.apache.jackrabbit.mk.api.MicroKernel;
import org.apache.jackrabbit.oak.api.ContentSession;
import org.apache.jackrabbit.oak.api.CoreValue;
@@ -74,6 +77,7 @@ public class Query {
private boolean explain;
private long limit = Long.MAX_VALUE;
private long offset;
+ private long size = -1;
private boolean prepared;
private final CoreValueFactory valueFactory;
private ContentSession session;
@@ -146,7 +150,7 @@ public class Query {
public boolean visit(FullTextSearchImpl node) {
node.setQuery(query);
node.bindSelector(source);
- return true;
+ return super.visit(node);
}
@Override
@@ -309,6 +313,7 @@ public class Query {
ResultRowImpl r = it.next();
list.add(r);
}
+ size = list.size();
Collections.sort(list);
it = list.iterator();
}
@@ -316,22 +321,22 @@ public class Query {
return it;
}
- public int compareRows(CoreValue[] orderValues, CoreValue[] orderValues2) {
+ public int compareRows(CoreValue[][] orderValues, CoreValue[][] orderValues2) {
int comp = 0;
for (int i = 0, size = orderings.length; i < size; i++) {
- CoreValue a = orderValues[i];
- CoreValue b = orderValues2[i];
+ CoreValue[] a = orderValues[i];
+ CoreValue[] b = orderValues2[i];
if (a == null || b == null) {
if (a == b) {
comp = 0;
} else if (a == null) {
- // TODO order by: nulls first, last, low or high?
- comp = 1;
- } else {
+ // TODO order by: nulls first (it looks like), or low?
comp = -1;
+ } else {
+ comp = 1;
}
} else {
- comp = a.compareTo(b);
+ comp = compareValues(a, b);
}
if (comp != 0) {
if (orderings[i].isDescending()) {
@@ -343,6 +348,112 @@ public class Query {
return comp;
}
+ public static int compareValues(CoreValue[] orderValues, CoreValue[] orderValues2) {
+ int l1 = orderValues.length;
+ int l2 = orderValues2.length;
+ int len = Math.max(l1, l2);
+ for (int i = 0; i < len; i++) {
+ CoreValue a = i < l1 ? orderValues[i] : null;
+ CoreValue b = i < l2 ? orderValues2[i] : null;
+ int comp;
+ if (a == null) {
+ comp = 1;
+ } else if (b == null) {
+ comp = -1;
+ } else {
+ comp = a.compareTo(b);
+ }
+ if (comp != 0) {
+ return comp;
+ }
+ }
+ return 0;
+ }
+
+ public static int getType(PropertyState p, int ifUnknown) {
+ if (!p.isArray()) {
+ return p.getValue().getType();
+ }
+ Iterator<CoreValue> it = p.getValues().iterator();
+ if (it.hasNext()) {
+ return it.next().getType();
+ }
+ return ifUnknown;
+ }
+
+ public CoreValue convert(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;
+ }
+ CoreValueFactory vf = getValueFactory();
+ 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);
+ }
+ }
+ return vf.createValue(v.getString(), targetType);
+ }
+ switch (targetType) {
+ case PropertyType.STRING:
+ return vf.createValue(v.getString());
+ 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(getOakPath(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);
+ }
+
+ public String getOakPath(String jcrPath) {
+ NamePathMapper m = getNamePathMapper();
+ if (m == null) {
+ // to simplify testing, a getNamePathMapper isn't required
+ return jcrPath;
+ }
+ String p = m.getOakPath(jcrPath);
+ if (p == null) {
+ throw new IllegalArgumentException("Not a valid JCR path: " + jcrPath);
+ }
+ return p;
+ }
+
void prepare() {
if (prepared) {
return;
@@ -444,17 +555,24 @@ public class Query {
PropertyState p = c.currentProperty();
values[i] = p == null ? null : p.getValue();
}
- CoreValue[] orderValues;
+ CoreValue[][] orderValues;
if (orderings == null) {
orderValues = null;
} else {
int size = orderings.length;
- orderValues = new CoreValue[size];
+ orderValues = new CoreValue[size][];
for (int i = 0; i < size; i++) {
PropertyState p = orderings[i].getOperand().currentProperty();
- // TODO how is order by multi-values properties defined?
- // currently throws an exception
- orderValues[i] = p == null ? null : p.getValue();
+ CoreValue[] x;
+ if (p == null) {
+ x = null;
+ } else if (p.isArray()) {
+ List<CoreValue> list = p.getValues();
+ x = list.toArray(new CoreValue[list.size()]);
+ } else {
+ x = new CoreValue[] { p.getValue() };
+ }
+ orderValues[i] = x;
}
}
return new ResultRowImpl(this, paths, values, orderValues);
@@ -550,4 +668,8 @@ public class Query {
return buff.toString();
}
+ public long getSize() {
+ return size;
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultImpl.java Thu Aug 30 09:20:10 2012
@@ -67,7 +67,13 @@ public class ResultImpl implements Resul
public Iterator<ResultRowImpl> iterator() {
return query.getRows(revisionId, root);
}
+
};
}
+ @Override
+ public long getSize() {
+ return query.getSize();
+ }
+
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ResultRowImpl.java Thu Aug 30 09:20:10 2012
@@ -29,9 +29,9 @@ public class ResultRowImpl implements Re
private final Query query;
private final String[] paths;
private final CoreValue[] values;
- private final CoreValue[] orderValues;
+ private final CoreValue[][] orderValues;
- ResultRowImpl(Query query, String[] paths, CoreValue[] values, CoreValue[] orderValues) {
+ ResultRowImpl(Query query, String[] paths, CoreValue[] values, CoreValue[][] orderValues) {
this.query = query;
this.paths = paths;
this.values = values;
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -1029,6 +1029,7 @@ public class SQL2Parser {
// (not in the JCR 1.0 spec)
// (confusing isn't it?)
currentTokenType = IDENTIFIER;
+ currentToken = currentValue.getString();
}
return;
case CHAR_END:
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java Thu Aug 30 09:20:10 2012
@@ -441,7 +441,11 @@ public class XPathToSQL2Converter {
read(")");
return f;
} else if ("jcr:deref".equals(functionName)) {
+ // TODO support jcr:deref
throw getSyntaxError("jcr:deref is not supported");
+ } else if ("rep:similar".equals(functionName)) {
+ // TODO support rep:similar
+ throw getSyntaxError("rep:similar is not supported");
} else {
throw getSyntaxError("jcr:like | jcr:contains | jcr:score | jcr:deref | fn:lower-case | fn:upper-case");
}
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -18,17 +18,9 @@
*/
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.api.Tree;
-import org.apache.jackrabbit.oak.kernel.CoreValueMapper;
-import org.apache.jackrabbit.oak.namepath.NamePathMapper;
import org.apache.jackrabbit.oak.query.Query;
-import javax.jcr.PropertyType;
-
/**
* The base class for all abstract syntax tree nodes.
*/
@@ -76,59 +68,6 @@ abstract class AstElement {
return path;
}
- /**
- * 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);
- }
-
- /**
- * Validate that the given value can be converted to a JCR name.
- *
- * @param v the value
- * @return true if it can be converted
- */
- protected boolean isName(CoreValue v) {
- // TODO correctly validate JCR names - see JCR 2.0 spec 3.2.4 Naming Restrictions
- switch (v.getType()) {
- case PropertyType.DATE:
- case PropertyType.DECIMAL:
- case PropertyType.DOUBLE:
- case PropertyType.LONG:
- case PropertyType.BOOLEAN:
- return false;
- }
- String n = v.getString();
- if (n.startsWith("[") && !n.endsWith("]")) {
- return false;
- }
- return true;
- }
-
- protected String getOakPath(String jcrPath) {
- NamePathMapper m = query.getNamePathMapper();
- if (m == null) {
- // to simplify testing, a getNamePathMapper isn't required
- return jcrPath;
- }
- String p = m.getOakPath(jcrPath);
- if (p == null) {
- throw new IllegalArgumentException("Not a valid JCR path: " + jcrPath);
- }
- return p;
- }
-
protected Tree getTree(String path) {
return query.getTree(path);
}
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -18,13 +18,10 @@
*/
package org.apache.jackrabbit.oak.query.ast;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.util.Iterator;
-import javax.jcr.PropertyType;
import org.apache.jackrabbit.oak.api.CoreValue;
import org.apache.jackrabbit.oak.api.CoreValueFactory;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.query.Query;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
/**
@@ -69,22 +66,11 @@ public class ComparisonImpl extends Cons
return false;
}
boolean isArray = p1.isArray();
- int v1Type;
- if (isArray) {
- Iterator<CoreValue> it = p1.getValues().iterator();
- if (it.hasNext()) {
- v1Type = it.next().getType();
- } else {
- // workaround for OAK-140: PropertyState: data type of empty array property
- v1Type = v2.getType();
- }
- } else {
- v1Type = p1.getValue().getType();
- }
+ int v1Type = Query.getType(p1, v2.getType());
if (v1Type != v2.getType()) {
// "the value of operand2 is converted to the
// property type of the value of operand1"
- v2 = convert(v2, v1Type);
+ v2 = query.convert(v2, v1Type);
}
if (!isArray) {
return evaluate(p1.getValue(), v2);
@@ -119,66 +105,6 @@ public class ComparisonImpl extends Cons
throw new IllegalArgumentException("Unknown operator: " + operator);
}
- private CoreValue convert(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;
- }
- CoreValueFactory vf = query.getValueFactory();
- 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);
- }
- }
- return vf.createValue(v.getString(), targetType);
- }
- switch (targetType) {
- case PropertyType.STRING:
- return vf.createValue(v.getString());
- 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(getOakPath(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());
@@ -206,7 +132,7 @@ public class ComparisonImpl extends Cons
String upperBound = p.getUpperBound();
if (lowerBound == null && upperBound == null) {
// ignore
- } else {
+ } else if (operand1.supportsRangeConditions()) {
CoreValueFactory vf = query.getValueFactory();
if (lowerBound != null) {
operand1.apply(f, Operator.GREATER_OR_EQUAL, vf.createValue(lowerBound));
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/DynamicOperandImpl.java Thu Aug 30 09:20:10 2012
@@ -29,4 +29,8 @@ public abstract class DynamicOperandImpl
public abstract void apply(FilterImpl f, Operator operator, CoreValue v);
+ public boolean supportsRangeConditions() {
+ return true;
+ }
+
}
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -18,7 +18,9 @@
*/
package org.apache.jackrabbit.oak.query.ast;
+import org.apache.jackrabbit.oak.api.CoreValue;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.query.Query;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
/**
@@ -89,27 +91,49 @@ public class EquiJoinConditionImpl exten
return p1.getValue().equals(p2.getValue());
}
// TODO what is the expected result of an equi join for multi-valued properties?
- throw new IllegalArgumentException("Join on multi-valued properties is currently not supported");
+ if (!p1.isArray() && p2.isArray()) {
+ CoreValue x = p1.getValue();
+ for (CoreValue y : p2.getValues()) {
+ if (y.getType() != x.getType()) {
+ y = query.convert(y, x.getType());
+ }
+ if (x.equals(y)) {
+ return true;
+ }
+ }
+ return false;
+ } else if (p1.isArray() && !p2.isArray()) {
+ CoreValue x = p2.getValue();
+ for (CoreValue y : p1.getValues()) {
+ if (y.getType() != x.getType()) {
+ y = query.convert(y, x.getType());
+ }
+ if (x.equals(y)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ CoreValue[] l1 = p1.getValues().toArray(new CoreValue[p1.getValues().size()]);
+ CoreValue[] l2 = p2.getValues().toArray(new CoreValue[p2.getValues().size()]);
+ return Query.compareValues(l1, l2) == 0;
}
@Override
public void apply(FilterImpl f) {
- // TODO what is the expected result of an equi join for multi-valued properties?
PropertyState p1 = selector1.currentProperty(property1Name);
PropertyState p2 = selector2.currentProperty(property2Name);
if (f.getSelector() == selector1 && p2 != null) {
- if (p2.isArray()) {
- // TODO what is the expected result of an equi join for multi-valued properties?
- throw new IllegalArgumentException("Join on multi-valued properties is currently not supported");
+ if (!p2.isArray()) {
+ // TODO support join on multi-valued properties
+ f.restrictProperty(property1Name, Operator.EQUAL, p2.getValue());
}
- f.restrictProperty(property1Name, Operator.EQUAL, p2.getValue());
}
if (f.getSelector() == selector2 && p1 != null) {
- if (p1.isArray()) {
- // TODO what is the expected result of an equi join for multi-valued properties?
- throw new IllegalArgumentException("Join on multi-valued properties is currently not supported");
+ if (!p1.isArray()) {
+ // TODO support join on multi-valued properties
+ f.restrictProperty(property2Name, Operator.EQUAL, p1.getValue());
}
- f.restrictProperty(property2Name, Operator.EQUAL, p1.getValue());
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/FullTextSearchImpl.java Thu Aug 30 09:20:10 2012
@@ -23,6 +23,7 @@ import java.util.ArrayList;
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.query.ast.ComparisonImpl.LikePattern;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
/**
@@ -34,7 +35,6 @@ public class FullTextSearchImpl extends
private final String propertyName;
private final StaticOperandImpl fullTextSearchExpression;
private SelectorImpl selector;
- private FullTextExpression expr;
public FullTextSearchImpl(String selectorName, String propertyName,
StaticOperandImpl fullTextSearchExpression) {
@@ -77,48 +77,51 @@ public class FullTextSearchImpl extends
return builder.toString();
}
- private boolean evaluateContains(PropertyState p) {
- for (CoreValue v : p.getValues()) {
- if (evaluateContains(v)) {
- return true;
- }
- }
- return false;
- }
-
- private boolean evaluateContains(CoreValue value) {
- String v = value.getString();
- return expr.evaluate(v);
- }
-
@Override
public boolean evaluate() {
+ StringBuilder buff = new StringBuilder();
if (propertyName != null) {
PropertyState p = selector.currentProperty(propertyName);
if (p == null) {
return false;
}
- return evaluateContains(p);
- }
- Tree tree = getTree(selector.currentPath());
- for (PropertyState p : tree.getProperties()) {
- if (evaluateContains(p)) {
- return true;
+ appendString(buff, p);
+ } else {
+ Tree tree = getTree(selector.currentPath());
+ if (tree == null) {
+ return false;
+ }
+ for (PropertyState p : tree.getProperties()) {
+ appendString(buff, p);
}
}
- return false;
- }
-
- public void bindSelector(SourceImpl source) {
- selector = source.getExistingSelector(selectorName);
+ // TODO fulltext conditions: need a way to disable evaluation
+ // if a fulltext index is used, to avoid filtering too much
+ // (we don't know what exact options are used in the fulltext index)
+ // (stop word, special characters,...)
CoreValue v = fullTextSearchExpression.currentValue();
try {
- expr = FullTextParser.parse(v.getString());
+ FullTextExpression expr = FullTextParser.parse(v.getString());
+ return expr.evaluate(buff.toString());
} catch (ParseException e) {
throw new IllegalArgumentException("Invalid expression: " + fullTextSearchExpression, e);
}
}
+ private static void appendString(StringBuilder buff, PropertyState p) {
+ if (p.isArray()) {
+ for (CoreValue v : p.getValues()) {
+ buff.append(v.getString()).append(' ');
+ }
+ } else {
+ buff.append(p.getValue().getString()).append(' ');
+ }
+ }
+
+ public void bindSelector(SourceImpl source) {
+ selector = source.getExistingSelector(selectorName);
+ }
+
@Override
public void apply(FilterImpl f) {
if (propertyName != null) {
@@ -183,15 +186,16 @@ public class FullTextSearchImpl extends
if (parseIndex >= text.length()) {
throw getSyntaxError("term");
}
- FullTextTerm term = new FullTextTerm();
+ boolean not = false;
StringBuilder buff = new StringBuilder();
char c = text.charAt(parseIndex);
if (c == '-') {
if (++parseIndex >= text.length()) {
throw getSyntaxError("term");
}
- term.not = true;
+ not = true;
}
+ boolean escaped = false;
if (c == '\"') {
parseIndex++;
while (true) {
@@ -200,7 +204,7 @@ public class FullTextSearchImpl extends
}
c = text.charAt(parseIndex++);
if (c == '\\') {
- // escape
+ escaped = true;
if (parseIndex >= text.length()) {
throw getSyntaxError("escaped char");
}
@@ -220,7 +224,7 @@ public class FullTextSearchImpl extends
do {
c = text.charAt(parseIndex++);
if (c == '\\') {
- // escape
+ escaped = true;
if (parseIndex >= text.length()) {
throw getSyntaxError("escaped char");
}
@@ -236,7 +240,8 @@ public class FullTextSearchImpl extends
if (buff.length() == 0) {
throw getSyntaxError("term");
}
- term.text = buff.toString();
+ String text = buff.toString();
+ FullTextTerm term = new FullTextTerm(text, not, escaped);
return term.simplify();
}
@@ -335,15 +340,62 @@ public class FullTextSearchImpl extends
* A fulltext term, or a "not" term.
*/
static class FullTextTerm extends FullTextExpression {
- boolean not;
- String text;
+ private final boolean not;
+ private final String text;
+ private final String filteredText;
+ private final LikePattern like;
+
+ FullTextTerm(String text, boolean not, boolean escaped) {
+ this.text = text;
+ this.not = not;
+ // for testFulltextIntercapSQL
+ // filter special characters such as '
+ // to make tests pass, for example the
+ // FulltextQueryTest.testFulltextExcludeSQL,
+ // which searches for:
+ // "text ''fox jumps'' -other"
+ // (please note the two single quotes instead of
+ // double quotes before for and after jumps)
+ boolean pattern = false;
+ if (escaped) {
+ filteredText = text;
+ } else {
+ StringBuilder buff = new StringBuilder();
+ for (int i = 0; i < text.length(); i++) {
+ char c = text.charAt(i);
+ if (c == '*') {
+ buff.append('%');
+ pattern = true;
+ } else if (c == '?') {
+ buff.append('_');
+ pattern = true;
+ } else if (c == '_') {
+ buff.append("\\_");
+ pattern = true;
+ } else if (Character.isLetterOrDigit(c) || " +-:&".indexOf(c) >= 0) {
+ buff.append(c);
+ }
+ }
+ this.filteredText = buff.toString().toLowerCase();
+ }
+ if (pattern) {
+ like = new LikePattern("%" + filteredText + "%");
+ } else {
+ like = null;
+ }
+ }
@Override
public boolean evaluate(String value) {
+ // for testFulltextIntercapSQL
+ value = value.toLowerCase();
+ if (like != null) {
+ return like.matches(value);
+ }
if (not) {
- return value.indexOf(text) < 0;
+ return value.indexOf(filteredText) < 0;
}
- return value.indexOf(text) >= 0;
+ return value.indexOf(filteredText) >= 0;
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeLocalNameImpl.java Thu Aug 30 09:20:10 2012
@@ -23,6 +23,7 @@ import org.apache.jackrabbit.oak.api.Cor
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.plugins.memory.SinglePropertyState;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.util.ISO9075;
/**
* The function "localname(..)".
@@ -57,6 +58,8 @@ public class NodeLocalNameImpl extends D
@Override
public PropertyState currentProperty() {
String name = PathUtils.getName(selector.currentPath());
+ // Name escaping (convert space to _x0020_)
+ name = ISO9075.encode(name);
int colon = name.indexOf(':');
// TODO LOCALNAME: evaluation of local name might not be correct
String localName = colon < 0 ? name : name.substring(colon + 1);
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/ast/NodeNameImpl.java Thu Aug 30 09:20:10 2012
@@ -24,6 +24,7 @@ import org.apache.jackrabbit.oak.api.Pro
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.plugins.memory.SinglePropertyState;
import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.util.ISO9075;
/**
* The function "name(..)".
@@ -56,13 +57,16 @@ public class NodeNameImpl extends Dynami
}
@Override
+ public boolean supportsRangeConditions() {
+ return false;
+ }
+
+ @Override
public PropertyState currentProperty() {
- String name = PathUtils.getName(selector.currentPath());
- CoreValue v = query.getValueFactory().createValue(name);
- String path = v.getString();
- // normalize paths (./name > name)
- path = getOakPath(path);
- CoreValue v2 = query.getValueFactory().createValue(path, PropertyType.NAME);
+ String path = selector.currentPath();
+ // Name escaping (convert space to _x0020_)
+ String name = ISO9075.encode(PathUtils.getName(path));
+ CoreValue v2 = query.getValueFactory().createValue(name, PropertyType.NAME);
return new SinglePropertyState("NAME", v2);
}
@@ -72,8 +76,8 @@ public class NodeNameImpl extends Dynami
throw new IllegalArgumentException("Invalid name value: " + v.toString());
}
String path = v.getString();
- // normalize paths (./name > name)
- path = getOakPath(path);
+ // Name escaping (convert _x0020_ to space)
+ path = decodeName(path);
if (PathUtils.isAbsolute(path)) {
throw new IllegalArgumentException("NAME() comparison with absolute path are not allowed: " + path);
}
@@ -83,4 +87,35 @@ public class NodeNameImpl extends Dynami
// TODO support NAME(..) index conditions
}
+ private String decodeName(String path) {
+ // Name escaping (convert _x0020_ to space)
+ path = ISO9075.decode(path);
+ // normalize paths (./name > name)
+ path = query.getOakPath(path);
+ return path;
+ }
+
+ /**
+ * Validate that the given value can be converted to a JCR name.
+ *
+ * @param v the value
+ * @return true if it can be converted
+ */
+ private static boolean isName(CoreValue v) {
+ // TODO correctly validate JCR names - see JCR 2.0 spec 3.2.4 Naming Restrictions
+ switch (v.getType()) {
+ case PropertyType.DATE:
+ case PropertyType.DECIMAL:
+ case PropertyType.DOUBLE:
+ case PropertyType.LONG:
+ case PropertyType.BOOLEAN:
+ return false;
+ }
+ String n = v.getString();
+ if (n.startsWith("[") && !n.endsWith("]")) {
+ return false;
+ }
+ return true;
+ }
+
}
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -86,6 +86,9 @@ public class PropertyValueImpl extends D
return matchesPropertyType(p) ? p : null;
}
Tree tree = getTree(selector.currentPath());
+ if (tree == null) {
+ return null;
+ }
if (relative) {
for (String p : PathUtils.elements(PathUtils.getParentPath(propertyName))) {
if (tree == null) {
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -119,6 +119,9 @@ public class SelectorImpl extends Source
return true;
}
Tree tree = getTree(cursor.currentRow().getPath());
+ if (tree == null) {
+ return false;
+ }
PropertyState p = tree.getProperty(JCR_PRIMARY_TYPE);
if (p == null) {
return true;
@@ -171,7 +174,8 @@ public class SelectorImpl extends Source
if (path == null) {
return null;
}
- return getTree(path).getProperty(propertyName);
+ Tree t = getTree(path);
+ return t == null ? null : t.getProperty(propertyName);
}
@Override
Modified: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt?rev=1378867&r1=1378866&r2=1378867&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt Thu Aug 30 09:20:10 2012
@@ -77,6 +77,13 @@ commit / - "test"
# other tests
+commit / + "test": { "My Documents": { "x" : {}}}
+
+select [jcr:path] from [nt:base] where name() = 'My_x0020_Documents'
+/test/My Documents
+
+commit / - "test"
+
commit / + "test": { "jcr:resource": {}, "resource": { "x" : {}}}
select * from [nt:base] where id = -1
@@ -242,11 +249,6 @@ commit / + "test4": { "name": "10%" }
commit / + "test5": { "name": "10 percent" }
select name from [nt:base] order by upper(name)
-10 percent
-10%
-Hallo
-hello
-World!
null
null
null
@@ -256,6 +258,11 @@ null
null
null
null
+10 percent
+10%
+Hallo
+hello
+World!
select * from [nt:base] where length(name) = 5
/test
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -123,7 +123,11 @@ public class QueryResultImpl implements
}
};
- return new RowIteratorAdapter(rowIterator);
+ return new RowIteratorAdapter(rowIterator) {
+ public long getSize() {
+ return result.getSize();
+ }
+ };
}
@CheckForNull
@@ -184,11 +188,11 @@ public class QueryResultImpl implements
}
};
- return new NodeIteratorAdapter(nodeIterator);
+ return new NodeIteratorAdapter(nodeIterator, result.getSize());
}
Value createValue(CoreValue value) {
- return sessionDelegate.getValueFactory().createValue(value);
+ return value == null ? null : sessionDelegate.getValueFactory().createValue(value);
}
}
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=1378867&r1=1378866&r2=1378867&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 Thu Aug 30 09:20:10 2012
@@ -18,6 +18,10 @@
*/
package org.apache.jackrabbit.oak.jcr.query;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+import java.util.NoSuchElementException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.RepositoryException;
@@ -28,14 +32,9 @@ import javax.jcr.query.QueryManager;
import javax.jcr.query.QueryResult;
import javax.jcr.query.Row;
import javax.jcr.query.RowIterator;
-
import org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest;
import org.junit.Test;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-
/**
* Tests the query feature.
*/
@@ -83,4 +82,46 @@ public class QueryTest extends AbstractR
q.execute();
}
+ @Test
+ public void skip() throws RepositoryException {
+ Session session = getAdminSession();
+ Node hello1 = session.getRootNode().addNode("hello1");
+ hello1.setProperty("id", "1");
+ hello1.setProperty("data", "x");
+ Node hello2 = session.getRootNode().addNode("hello2");
+ hello2.setProperty("id", "2");
+ hello2.setProperty("data", "y");
+ session.save();
+ ValueFactory vf = session.getValueFactory();
+ QueryManager qm = session.getWorkspace().getQueryManager();
+ Query q = qm.createQuery("select id from [nt:base] where data >= $data order by id", Query.JCR_SQL2);
+ q.bindValue("data", vf.createValue("x"));
+ for (int i = -1; i < 4; i++) {
+ QueryResult r = q.execute();
+ RowIterator it = r.getRows();
+ assertEquals(2, r.getRows().getSize());
+ assertEquals(2, r.getNodes().getSize());
+ Row row;
+ try {
+ it.skip(i);
+ assertTrue(i >= 0 && i <= 2);
+ } catch (IllegalArgumentException e) {
+ assertEquals(-1, i);
+ } catch (NoSuchElementException e) {
+ assertTrue(i >= 2);
+ }
+ if (i <= 0) {
+ assertTrue(it.hasNext());
+ row = it.nextRow();
+ assertEquals("1", row.getValue("id").getString());
+ }
+ if (i <= 1) {
+ assertTrue(it.hasNext());
+ row = it.nextRow();
+ assertEquals("2", row.getValue("id").getString());
+ }
+ assertFalse(it.hasNext());
+ }
+ }
+
}