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 2016/04/27 12:18:27 UTC

svn commit: r1741199 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java test/java/org/apache/jackrabbit/oak/query/XPathTest.java

Author: thomasm
Date: Wed Apr 27 10:18:27 2016
New Revision: 1741199

URL: http://svn.apache.org/viewvc?rev=1741199&view=rev
Log:
OAK-4265 XPath: support limited form of "union" (work in progress)

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java

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=1741199&r1=1741198&r2=1741199&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 Wed Apr 27 10:18:27 2016
@@ -17,6 +17,7 @@
 package org.apache.jackrabbit.oak.query.xpath;
 
 import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.query.xpath.Statement.UnionStatement;
 import org.apache.jackrabbit.util.ISO9075;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -80,6 +81,12 @@ public class XPathToSQL2Converter {
      * @throws ParseException if parsing fails
      */
     public String convert(String query) throws ParseException {
+        Statement statement = convertToStatement(query);
+        statement = statement.optimize();
+        return statement.toString();
+    }
+    
+    private Statement convertToStatement(String query) throws ParseException {
         
         query = query.trim();
         
@@ -165,6 +172,7 @@ public class XPathToSQL2Converter {
                     currentSelector.isChild = true;
                 }
             }
+            int startParseIndex = parseIndex;
             if (shortcut) {
                 // "*" and so on are not allowed now
             } else if (readIf("*")) {
@@ -238,6 +246,9 @@ public class XPathToSQL2Converter {
                         statement.addSelectColumn(p);
                     }
                 } while (readIf("|"));
+                if (!readIf(")")) {
+                    return convertToUnion(query, statement, startParseIndex - 1);
+                }
                 read(")");
             } else if (currentTokenType == IDENTIFIER) {
                 // path restriction
@@ -311,11 +322,7 @@ public class XPathToSQL2Converter {
             where = Expression.and(where, s.condition);
         }
         statement.setWhere(where);
-        
-        statement = statement.optimize();
-        
-        return statement.toString();
-
+        return statement;
     }
     
     private void appendNodeName(String name) {
@@ -1021,6 +1028,57 @@ public class XPathToSQL2Converter {
         }
         return new ParseException("Query:\n" + query, index);
     }
+    
+    private Statement convertToUnion(String query, Statement statement,
+            int startParseIndex) throws ParseException {
+        int start = query.indexOf("(", startParseIndex);
+        String begin = query.substring(0, start);
+        XPathToSQL2Converter converter = new XPathToSQL2Converter();
+        String partList = query.substring(start);
+        converter.initialize(partList);
+        converter.read();
+        int lastParseIndex = converter.parseIndex;
+        int lastOrIndex = lastParseIndex;
+        converter.read("(");
+        int level = 0;
+        ArrayList<String> parts = new ArrayList<String>();
+        while (true) {
+            int parseIndex = converter.parseIndex;
+            if (converter.readIf("(")) {
+                level++;
+            } else if (converter.readIf(")") && level-- <= 0) {
+                break;
+            } else if (converter.readIf("|") && level == 0) {
+                String or = partList.substring(lastOrIndex, lastParseIndex);
+                parts.add(or);
+                lastOrIndex = parseIndex;
+            } else if (currentTokenType == END) {
+                throw getSyntaxError("the query may not be empty");
+            } else {
+                converter.read();
+            }
+            lastParseIndex = parseIndex;
+        }
+        String or = partList.substring(lastOrIndex, lastParseIndex);
+        parts.add(or);        
+        String end = partList.substring(lastParseIndex + 1);
+        Statement result = null;
+        for(String p : parts) {
+            String q = begin + p + end;
+            converter = new XPathToSQL2Converter();
+            Statement stat = converter.convertToStatement(q);
+            if (result == null) {
+                result = stat;
+            } else {
+                UnionStatement union = new UnionStatement(result, stat);
+                union.orderList = stat.orderList;
+                result = union;
+            }
+            // can not use clear, because it is shared
+            stat.orderList = new ArrayList<Order>();
+        }
+        return result;
+    }
 
 }
 

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java?rev=1741199&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/XPathTest.java Wed Apr 27 10:18:27 2016
@@ -0,0 +1,130 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.query;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_SYSTEM;
+import static org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants.JCR_NODE_TYPES;
+import static org.apache.jackrabbit.oak.plugins.nodetype.write.InitialContent.INITIAL_CONTENT;
+import static org.junit.Assert.assertEquals;
+
+import java.text.ParseException;
+
+import org.apache.jackrabbit.oak.query.xpath.XPathToSQL2Converter;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Test;
+
+/**
+ * Tests the XPathToSQL2Converter
+ */
+public class XPathTest {
+    
+    private final NodeState types =
+            INITIAL_CONTENT.getChildNode(JCR_SYSTEM).getChildNode(JCR_NODE_TYPES);
+    
+    @Test
+    public void test() throws ParseException {
+        verify("(/jcr:root/content//*[@a] | /jcr:root/lib//*[@b]) order by @c",
+                "select [jcr:path], [jcr:score], * " + 
+                "from [nt:base] as a " + 
+                "where [a] is not null " + 
+                "and isdescendantnode(a, '/content') " + 
+                "/* xpath: /jcr:root/content//*[@a] " + 
+                "order by @c */ " + 
+                "union select [jcr:path], [jcr:score], * " + 
+                "from [nt:base] as a " + 
+                "where [b] is not null " + 
+                "and isdescendantnode(a, '/lib') " + 
+                "/* xpath: /jcr:root/lib//*[@b] " + 
+                "order by @c */ " + 
+                "order by [c]");       
+        verify("/jcr:root/(content|lib)/element(*, nt:base) order by @title",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where ischildnode(a, '/content') " +
+                "/* xpath: /jcr:root/content/element(*, nt:base) " +
+                "order by @title */ " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where ischildnode(a, '/lib') " +
+                "/* xpath: /jcr:root/lib/element(*, nt:base) " +
+                "order by @title */ " +
+                "order by [title]");        
+        verify("/jcr:root/(content|lib)",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where issamenode(a, '/content') " +
+                "/* xpath: /jcr:root/content */ " + 
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where issamenode(a, '/lib') " +
+                "/* xpath: /jcr:root/lib */");
+        verify("(/jcr:root/content|/jcr:root/lib)//*",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where isdescendantnode(a, '/content') " +
+                "/* xpath: /jcr:root/content//* */ " + 
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where isdescendantnode(a, '/lib') " +
+                "/* xpath: /jcr:root/lib//* */");
+        verify("/jcr:root/content/(a|b|c)/thumbnails/*",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where ischildnode(a, '/content/a/thumbnails') " +
+                "/* xpath: /jcr:root/content/a/thumbnails/* */ " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where ischildnode(a, '/content/b/thumbnails') " +
+                "/* xpath: /jcr:root/content/b/thumbnails/* */ " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where ischildnode(a, '/content/c/thumbnails') " +
+                "/* xpath: /jcr:root/content/c/thumbnails/* */");        
+        verify("/jcr:root/(content|lib)//*[@a]",
+                "select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "and isdescendantnode(a, '/content') " +
+                "/* xpath: /jcr:root/content//*[@a] */ " +
+                "union select [jcr:path], [jcr:score], * " +
+                "from [nt:base] as a " +
+                "where [a] is not null " +
+                "and isdescendantnode(a, '/lib') " +
+                "/* xpath: /jcr:root/lib//*[@a] */");        
+    }
+
+    private void verify(String xpath, String expectedSql2) throws ParseException {
+        String sql2 = new XPathToSQL2Converter().convert(xpath);
+        sql2 = formatSQL(sql2);
+        expectedSql2 = formatSQL(expectedSql2);
+        assertEquals(expectedSql2, sql2);
+        SQL2Parser p = new SQL2Parser(null, types, new QueryEngineSettings());
+        p.parse(sql2);
+    }
+    
+    static String formatSQL(String sql) {
+        sql = sql.replace("\n", " ");
+        sql = sql.replaceAll(" from ", "\nfrom ");
+        sql = sql.replaceAll(" where ", "\nwhere ");
+        sql = sql.replaceAll(" and ", "\nand ");
+        sql = sql.replaceAll(" union ", "\nunion ");
+        sql = sql.replaceAll(" order by ", "\norder by ");
+        sql = sql.replaceAll(" \\/\\* ", "\n/* ");
+        return sql;
+    }
+
+}



Re: svn commit: r1741199 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/xpath/XPathToSQL2Converter.java test/java/org/apache/jackrabbit/oak/query/XPathTest.java

Posted by Julian Reschke <ju...@gmx.de>.
On 2016-04-27 12:18, thomasm@apache.org wrote:
> Author: thomasm
> Date: Wed Apr 27 10:18:27 2016
> New Revision: 1741199
>
> URL: http://svn.apache.org/viewvc?rev=1741199&view=rev
> Log:
> OAK-4265 XPath: support limited form of "union" (work in progress)
> ...

This seems to break PropertyIndexQueryTest.xpath().

Best regards, Julian