Author: thomasm
Date: Tue Jan 28 14:45:13 2014
New Revision: 1562083
URL: http://svn.apache.org/r1562083
Log:
OAK-1336 Query: use "union" for complex XPath queries that use "or"
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java?rev=1562083&r1=1562082&r2=1562083&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Expression.java
Tue Jan 28 14:45:13 2014
@@ -256,6 +256,37 @@ abstract class Expression {
}
}
+
+ /**
+ * A contains call.
+ */
+ static class Contains extends Expression {
+
+ final Expression left, right;
+
+ Contains(Expression left, Expression right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buff = new StringBuilder("contains").
+ append('(').append(left).append(",
").append(right).append(')');
+ return buff.toString();
+ }
+
+ @Override
+ boolean isCondition() {
+ return true;
+ }
+
+ @Override
+ boolean isName() {
+ return left.isName();
+ }
+
+ }
/**
* A function call.
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java?rev=1562083&r1=1562082&r2=1562083&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/Statement.java
Tue Jan 28 14:45:13 2014
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import org.apache.jackrabbit.oak.query.QueryImpl;
import org.apache.jackrabbit.oak.query.xpath.Expression.AndCondition;
+import org.apache.jackrabbit.oak.query.xpath.Expression.Contains;
import org.apache.jackrabbit.oak.query.xpath.Expression.OrCondition;
import org.apache.jackrabbit.oak.query.xpath.Expression.Property;
@@ -64,6 +65,8 @@ public class Statement {
// is automatically converted to
// @x in (1, 2)
// within the query engine
+ } else if (or.left instanceof Contains && or.right instanceof
Contains) {
+ // do not optimize "contains"
} else {
// conditions of type
// @x = 1 or @y = 2
@@ -80,14 +83,44 @@ public class Statement {
s2.columnList = columnList;
s2.where = or.right;
s2.xpathQuery = xpathQuery;
- return new UnionStatement(s1, s2);
+ return new UnionStatement(s1.optimize(), s2.optimize());
}
} else if (where instanceof AndCondition) {
- // TODO
// conditions of type
// @a = 1 and (@x = 1 or @y = 2)
- // could be automatically converted to
+ // are automatically converted to
// (@a = 1 and @x = 1) union (@a = 1 and @y = 2)
+ AndCondition and = (AndCondition) where;
+ if (and.left instanceof OrCondition && !(and.right instanceof
OrCondition)) {
+ // swap left and right
+ and = new AndCondition(and.right, and.left);
+ }
+ if (and.right instanceof OrCondition) {
+ OrCondition or = (OrCondition) and.right;
+ if (or.getCommonLeftPart() != null) {
+ // @x = 1 or @x = 2
+ // is automatically converted to
+ // @x in (1, 2)
+ // within the query engine
+ } else if (or.left instanceof Contains && or.right instanceof
Contains) {
+ // do not optimize "contains"
+ } else {
+ // same as above, but with the added "and"
+ // TODO avoid code duplication if possible
+ Statement s1 = new Statement();
+ s1.columnSelector = columnSelector;
+ s1.selectors = selectors;
+ s1.columnList = columnList;
+ s1.where = new AndCondition(and.left, or.left);
+ Statement s2 = new Statement();
+ s2.columnSelector = columnSelector;
+ s2.selectors = selectors;
+ s2.columnList = columnList;
+ s2.where = new AndCondition(and.left, or.right);
+ s2.xpathQuery = xpathQuery;
+ return new UnionStatement(s1.optimize(), s2.optimize());
+ }
+ }
}
return this;
}
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java?rev=1562083&r1=1562082&r2=1562083&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
(original)
+++
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java
Tue Jan 28 14:45:13 2014
@@ -570,11 +570,11 @@ public class XPathToSQL2Converter {
read(")");
return c;
} else if ("jcr:contains".equals(functionName)) {
- Expression.Function f = new Expression.Function("contains");
- f.params.add(parseExpression());
+ Expression left = parseExpression();
read(",");
- f.params.add(parseExpression());
+ Expression right = parseExpression();
read(")");
+ Expression.Contains f = new Expression.Contains(left, right);
return f;
} else if ("jcr:score".equals(functionName)) {
Expression.Function f = new Expression.Function("score");
Modified:
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt?rev=1562083&r1=1562082&r2=1562083&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
(original)
+++
jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/xpath.txt
Tue Jan 28 14:45:13 2014
@@ -23,6 +23,22 @@
# * new tests are typically be added on top, after the syntax docs
# * use ascii character only
+# union (complex)
+
+xpath2sql //*[((@jcr:primaryType = 'nt:unstructured') and (@resources =
'/data' or @resolved = '/data'))]
+select [jcr:path], [jcr:score], * from [nt:base] as a where [jcr:primaryType]
= 'nt:unstructured' and [resources] = '/data' union select [jcr:path],
[jcr:score], * from [nt:base] as a where [jcr:primaryType] = 'nt:unstructured'
and [resolved] = '/data' /* xpath: //*[((@jcr:primaryType = 'nt:unstructured')
and (@resources = '/data' or @resolved = '/data'))] */
+
+xpath2sql //*[(((@jcr:primaryType = 'nt:unstructured') and (@resources =
'/data' or @resolved = '/data')) or (@content = '/data' and (@jcr:primaryType =
'nt:folder'))) ]
+select [jcr:path], [jcr:score], * from [nt:base] as a where [jcr:primaryType]
= 'nt:unstructured' and [resources] = '/data' union select [jcr:path],
[jcr:score], * from [nt:base] as a where [jcr:primaryType] = 'nt:unstructured'
and [resolved] = '/data' union select [jcr:path], [jcr:score], * from [nt:base]
as a where [content] = '/data' and [jcr:primaryType] = 'nt:folder' /* xpath:
//*[(((@jcr:primaryType = 'nt:unstructured') and (@resources = '/data' or
@resolved = '/data')) or (@content = '/data' and (@jcr:primaryType =
'nt:folder'))) ] */
+
+# union must not be used for "contains or contains"
+
+xpath2sql //*[((@jcr:primaryType = 'nt:unstructured') and (jcr:contains(.,
'hello') or jcr:contains(., 'world')))]
+select [jcr:path], [jcr:score], * from [nt:base] as a where [jcr:primaryType]
= 'nt:unstructured' and (contains(*, 'hello') or contains(*, 'world')) /*
xpath: //*[((@jcr:primaryType = 'nt:unstructured') and (jcr:contains(.,
'hello') or jcr:contains(., 'world')))] */
+
+xpath2sql //*[(((@jcr:primaryType = 'nt:unstructured') and (jcr:contains(.,
'hello') or jcr:contains(., 'world'))) or (@content = '/data' and
(@jcr:primaryType = 'nt:folder'))) ]
+select [jcr:path], [jcr:score], * from [nt:base] as a where [jcr:primaryType]
= 'nt:unstructured' and (contains(*, 'hello') or contains(*, 'world')) union
select [jcr:path], [jcr:score], * from [nt:base] as a where [content] = '/data'
and [jcr:primaryType] = 'nt:folder' /* xpath: //*[(((@jcr:primaryType =
'nt:unstructured') and (jcr:contains(., 'hello') or jcr:contains(., 'world')))
or (@content = '/data' and (@jcr:primaryType = 'nt:folder'))) ] */
+
# de-escape _x00.._
xpath2sql
/jcr:root//_x002e_test/element(*,rep:User)[_x002e_tokens/@jcr:primaryType]