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]


Reply via email to