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 2019/09/13 12:53:26 UTC

svn commit: r1866903 - in /jackrabbit/oak/trunk: oak-core/src/main/java/org/apache/jackrabbit/oak/query/ oak-core/src/test/java/org/apache/jackrabbit/oak/query/ oak-core/src/test/resources/org/apache/jackrabbit/oak/query/ oak-jcr/src/test/java/org/apac...

Author: thomasm
Date: Fri Sep 13 12:53:26 2019
New Revision: 1866903

URL: http://svn.apache.org/viewvc?rev=1866903&view=rev
Log:
OAK-8245 Add column for explained statement to explain Query result, next to 'plan' column

Added:
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ExplainResultTest.java
    jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/explain_result.txt
Modified:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.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/UnionQueryTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryPlanTest.java

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java?rev=1866903&r1=1866902&r2=1866903&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/QueryImpl.java Fri Sep 13 12:53:26 2019
@@ -541,10 +541,18 @@ public class QueryImpl implements Query
             if (measure) {
                 plan += " cost: { " + getIndexCostInfo() + " }";
             }
-            columns = new ColumnImpl[] { new ColumnImpl("explain", "plan", "plan")};
+            columns = new ColumnImpl[] {
+                    new ColumnImpl("explain", "plan", "plan"),
+                    new ColumnImpl("explain", "statement", "statement")
+            };
             ResultRowImpl r = new ResultRowImpl(this,
                     Tree.EMPTY_ARRAY,
-                    new PropertyValue[] { PropertyValues.newString(plan)},
+                    new PropertyValue[] {
+                            PropertyValues.newString(plan),
+                            // remove "explain" keyword from query statement to produce explained statement
+                            PropertyValues.newString(getStatement()
+                                    .replaceFirst("(?i)\\bexplain\\s+", ""))
+                    },
                     null, null);
             return Arrays.asList(r).iterator();
         }

Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java?rev=1866903&r1=1866902&r2=1866903&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/UnionQueryImpl.java Fri Sep 13 12:53:26 2019
@@ -284,10 +284,17 @@ public class UnionQueryImpl implements Q
         prepare();
         if (explain) {
             String plan = getPlan();
-            columns = new ColumnImpl[] { new ColumnImpl("explain", "plan", "plan")};
+            columns = new ColumnImpl[] {
+                    new ColumnImpl("explain", "plan", "plan"),
+                    new ColumnImpl("explain", "statement", "statement")
+            };
             ResultRowImpl r = new ResultRowImpl(this,
                     Tree.EMPTY_ARRAY,
-                    new PropertyValue[] { PropertyValues.newString(plan)},
+                    new PropertyValue[] {
+                            PropertyValues.newString(plan),
+                            // retrieve the original statement from either of the unioned subqueries, i.e., the left one
+                            PropertyValues.newString(left.getStatement().replaceFirst("(?i)\\bexplain\\s+", ""))
+                    },
                     null, null);
             return Arrays.asList(r).iterator();
         }

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=1866903&r1=1866902&r2=1866903&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 Fri Sep 13 12:53:26 2019
@@ -261,12 +261,13 @@ public abstract class AbstractQueryTest
         List<String> lines = new ArrayList<String>();
         try {
             Result result = executeQuery(query, language, NO_BINDINGS);
-            for (ResultRow row : result.getRows()) {
-                String r = readRow(row, pathsOnly);
-                if (query.startsWith("explain ")) {
-                    r = formatPlan(r);
+            if (query.startsWith("explain ")) {
+                lines.add(formatPlan(readPlan(result.getRows().iterator().next())));
+            } else {
+                for (ResultRow row : result.getRows()) {
+                    String r = readRow(row, pathsOnly);
+                    lines.add(r);
                 }
-                lines.add(r);
             }
             if (!query.contains("order by") && !skipSort) {
                 Collections.sort(lines);
@@ -364,6 +365,10 @@ public abstract class AbstractQueryTest
         return buff.toString();
     }
 
+    protected static String readPlan(ResultRow row) {
+        return row.getValue("plan").getValue(Type.STRING);
+    }
+
     /**
      * Check whether the test is running in debug mode.
      * 

Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ExplainResultTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ExplainResultTest.java?rev=1866903&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ExplainResultTest.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/ExplainResultTest.java Fri Sep 13 12:53:26 2019
@@ -0,0 +1,160 @@
+/*
+ * 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.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+
+import org.apache.jackrabbit.oak.InitialContentHelper;
+import org.apache.jackrabbit.oak.Oak;
+import org.apache.jackrabbit.oak.api.ContentRepository;
+import org.apache.jackrabbit.oak.api.Result;
+import org.apache.jackrabbit.oak.api.ResultRow;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexProvider;
+import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
+import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
+import org.junit.Test;
+
+public class ExplainResultTest extends AbstractQueryTest {
+
+    @Override
+    protected ContentRepository createRepository() {
+        return new Oak(new MemoryNodeStore(InitialContentHelper.INITIAL_CONTENT))
+                .with(new OpenSecurityProvider())
+                .with(new PropertyIndexProvider())
+                .with(new PropertyIndexEditorProvider()).createContentRepository();
+    }
+
+    @Test
+    public void test_explain_xpath() throws Exception {
+        test("explain_result.txt");
+        final String xpath = "/jcr:root/test//*";
+        Result result = executeQuery(xpath, "xpath", Collections.emptyMap());
+        int count = 0;
+        for (Iterator<? extends ResultRow> rows = result.getRows().iterator(); rows.hasNext(); ) {
+            rows.next();
+            count = count + 1;
+        }
+
+        assertEquals("should exist 2 nodes", 2, count);
+
+        Result explainResult = executeQuery("explain " + xpath,
+                "xpath", Collections.emptyMap());
+        int explainCount = 0;
+        ResultRow explainRow = null;
+        for (ResultRow row : explainResult.getRows()) {
+            if (explainCount == 0) {
+                explainRow = row;
+            }
+            explainCount = explainCount + 1;
+        }
+
+        assertEquals("should exist 1 result", 1, explainCount);
+        assertNotNull("explain row should not be null", explainRow);
+
+        assertTrue("result should have 'plan' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("plan"));
+        assertTrue("result should have 'statement' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("statement"));
+
+        final String explainedStatement = explainRow.getValue("statement").getValue(Type.STRING);
+        assertTrue("'statement' should begin with 'select'", explainedStatement.startsWith("select"));
+        assertTrue("statement should contain original xpath with prefix 'xpath: '",
+                explainedStatement.contains("xpath: " + xpath));
+    }
+
+    @Test
+    public void test_explain_sql1() throws Exception {
+        test("explain_result.txt");
+        final String sql1 = "select [jcr:path] from [nt:base] as a where isdescendantnode(a, '/test')";
+        Result result = executeQuery(sql1, "sql", Collections.emptyMap());
+        int count = 0;
+        for (ResultRow row : result.getRows()) {
+            count = count + 1;
+        }
+
+        assertEquals("should exist 2 nodes", 2, count);
+
+        Result explainResult = executeQuery("explain " + sql1,
+                "sql", Collections.emptyMap());
+        int explainCount = 0;
+        ResultRow explainRow = null;
+        for (ResultRow row : explainResult.getRows()) {
+            if (explainCount == 0) {
+                explainRow = row;
+            }
+            explainCount = explainCount + 1;
+        }
+
+        assertEquals("should exist 1 result", 1, explainCount);
+        assertNotNull("explain row should not be null", explainRow);
+
+        assertTrue("result should have 'plan' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("plan"));
+        assertTrue("result should have 'statement' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("statement"));
+
+        final String explainedStatement = explainRow.getValue("statement").getValue(Type.STRING);
+        assertTrue("'statement' should begin with 'select'", explainedStatement.startsWith("select"));
+        assertEquals("explained statement should be same as original, without 'explain'",
+                sql1, explainedStatement);
+    }
+
+    @Test
+    public void test_explain_sql2() throws Exception {
+        test("explain_result.txt");
+        final String sql2 = "select [jcr:path] from [nt:base] as a where isdescendantnode(a, '/test')";
+        Result result = executeQuery(sql2, "JCR-SQL2", Collections.emptyMap());
+        int count = 0;
+        for (ResultRow row : result.getRows()) {
+            count = count + 1;
+        }
+
+        assertEquals("should exist 2 nodes", 2, count);
+
+        Result explainResult = executeQuery("explain " + sql2,
+                "JCR-SQL2", Collections.emptyMap());
+        int explainCount = 0;
+        ResultRow explainRow = null;
+        for (ResultRow row : explainResult.getRows()) {
+            if (explainCount == 0) {
+                explainRow = row;
+            }
+            explainCount = explainCount + 1;
+        }
+
+        assertEquals("should exist 1 result", 1, explainCount);
+        assertNotNull("explain row should not be null", explainRow);
+
+        assertTrue("result should have 'plan' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("plan"));
+        assertTrue("result should have 'statement' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("statement"));
+
+        final String explainedStatement = explainRow.getValue("statement").getValue(Type.STRING);
+        assertTrue("'statement' should begin with 'select'", explainedStatement.startsWith("select"));
+        assertEquals("explained statement should be same as original, without 'explain'",
+                sql2, explainedStatement);
+    }
+}

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UnionQueryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UnionQueryTest.java?rev=1866903&r1=1866902&r2=1866903&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UnionQueryTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/query/UnionQueryTest.java Fri Sep 13 12:53:26 2019
@@ -17,23 +17,28 @@
 
 package org.apache.jackrabbit.oak.query;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
 import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.InitialContent;
 import org.apache.jackrabbit.oak.Oak;
 import org.apache.jackrabbit.oak.api.ContentRepository;
 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.Tree;
-import org.apache.jackrabbit.oak.InitialContent;
+import org.apache.jackrabbit.oak.api.Type;
 import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
 public class UnionQueryTest extends AbstractQueryTest {
 
     @Override
@@ -89,6 +94,112 @@ public class UnionQueryTest extends Abst
                 QueryEngine.NO_BINDINGS, QueryEngine.NO_MAPPINGS);
 
         List<ResultRow> rows = Lists.newArrayList(result.getRows());
+        assertEquals(expected.length, rows.size());
+
+        int i = 0;
+        for (ResultRow rr: result.getRows()) {
+            assertEquals(rr.getPath(), expected[i++]);
+        }
+    }
+
+    @Test
+    public void testExplainStatement() throws Exception {
+        final String left = "SELECT [jcr:path] FROM [nt:base] AS a WHERE ISDESCENDANTNODE(a, '/UnionQueryTest')";
+        final String right = "SELECT [jcr:path] FROM [nt:base] AS a WHERE ISDESCENDANTNODE(a, '/UnionQueryTest')";
+        final String order = "ORDER BY [jcr:path]";
+        final String union = String.format("%s UNION %s %s", left, right, order);
+        final String explainUnion = "explain " + union;
+
+        Result explainResult = executeQuery(explainUnion, QueryEngineImpl.SQL2, QueryEngine.NO_BINDINGS);
+
+        int explainCount = 0;
+        ResultRow explainRow = null;
+        for (ResultRow row : explainResult.getRows()) {
+            if (explainCount == 0) {
+                explainRow = row;
+            }
+            explainCount = explainCount + 1;
+        }
+
+        assertEquals("should exist 1 result", 1, explainCount);
+        assertNotNull("explain row should not be null", explainRow);
+
+        assertTrue("result should have 'plan' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("plan"));
+        assertTrue("result should have 'statement' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("statement"));
+
+        final String explainedStatement = explainRow.getValue("statement").getValue(Type.STRING);
+
+        assertTrue("'statement' should begin with 'select': " + explainedStatement,
+                explainedStatement.startsWith("SELECT"));
+        assertTrue("'statement' should contain ' UNION ': " + explainedStatement,
+                explainedStatement.contains(" UNION "));
+
+        final int limit = 3;
+        final int offset = 2;
+
+        String[] expected = {
+                "/UnionQueryTest/a/b/c",
+                "/UnionQueryTest/a/b/c/d",
+                "/UnionQueryTest/a/b/c/d/e"
+        };
+
+        Result result = qe.executeQuery(explainedStatement, QueryEngineImpl.SQL2, limit, offset,
+                QueryEngine.NO_BINDINGS, QueryEngine.NO_MAPPINGS);
+
+        List<ResultRow> rows = Lists.newArrayList(result.getRows());
+        assertEquals(expected.length, rows.size());
+
+        int i = 0;
+        for (ResultRow rr: result.getRows()) {
+            assertEquals(rr.getPath(), expected[i++]);
+        }
+    }
+
+    @Test
+    public void testExplainStatementXPath() throws Exception {
+        final String xpath = "/jcr:root/UnionQueryTest//(element(*, nt:base) | element(*, nt:folder)) order by jcr:path";
+        final String explainUnion = "explain " + xpath;
+
+        Result explainResult = executeQuery(explainUnion, QueryEngineImpl.XPATH, QueryEngine.NO_BINDINGS);
+
+        int explainCount = 0;
+        ResultRow explainRow = null;
+        for (ResultRow row : explainResult.getRows()) {
+            if (explainCount == 0) {
+                explainRow = row;
+            }
+            explainCount = explainCount + 1;
+        }
+
+        assertEquals("should exist 1 result", 1, explainCount);
+        assertNotNull("explain row should not be null", explainRow);
+
+        assertTrue("result should have 'plan' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("plan"));
+        assertTrue("result should have 'statement' column",
+                Arrays.asList(explainResult.getColumnNames()).contains("statement"));
+
+        final String explainedStatement = explainRow.getValue("statement").getValue(Type.STRING);
+        assertTrue("'statement' should begin with 'select': " + explainedStatement,
+                explainedStatement.startsWith("select"));
+        assertTrue("'statement' should contain ' union ': " + explainedStatement,
+                explainedStatement.contains(" union "));
+
+        final int limit = 3;
+        final int offset = 2;
+
+        String[] expected = {
+                "/UnionQueryTest/a/b/c",
+                "/UnionQueryTest/a/b/c/d",
+                "/UnionQueryTest/a/b/c/d/e"
+        };
+
+        Result result = qe.executeQuery(explainedStatement, QueryEngineImpl.SQL2, limit, offset,
+                QueryEngine.NO_BINDINGS, QueryEngine.NO_MAPPINGS);
+
+        List<ResultRow> rows = Lists.newArrayList(result.getRows());
         assertEquals(expected.length, rows.size());
 
         int i = 0;

Added: jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/explain_result.txt
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/explain_result.txt?rev=1866903&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/explain_result.txt (added)
+++ jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/explain_result.txt Fri Sep 13 12:53:26 2019
@@ -0,0 +1,28 @@
+# 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.
+#
+# Syntax:
+# * lines that start with spaces belong to the previous line
+# * lines starting with "#" are remarks.
+# * lines starting with "select" are queries, followed by expected results and an empty line
+# * lines starting with "explain" are followed by expected query plan and an empty line
+# * lines starting with "sql1" are run using the sql1 language
+# * lines starting with "xpath2sql" are just converted
+  from xpath to sql2
+# * all other lines are are committed into the microkernel (line by line)
+# * new tests are typically be added on top, after the syntax docs
+# * use ascii character only
+
+commit / + "test": { "a": { "name": "Hello" }, "b": { "name" : "World" }}

Modified: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryPlanTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryPlanTest.java?rev=1866903&r1=1866902&r2=1866903&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryPlanTest.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/query/QueryPlanTest.java Fri Sep 13 12:53:26 2019
@@ -29,6 +29,7 @@ import javax.jcr.Session;
 import javax.jcr.query.Query;
 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.fixture.NodeStoreFixture;
@@ -74,7 +75,8 @@ public class QueryPlanTest extends Abstr
         result = q.execute();
         it = result.getRows();
         assertTrue(it.hasNext());
-        String plan = it.nextRow().getValue("plan").getString();
+        Row row = it.nextRow();
+        String plan = row.getValue("plan").getString();
         // System.out.println("plan: " + plan);
         // should use the node type index
         assertEquals("[oak:Unstructured] as [a] " + 
@@ -85,6 +87,12 @@ public class QueryPlanTest extends Abstr
                 ", path=//*) where isdescendantnode([a], [/]) */", 
                 plan);
 
+        String sql2 = row.getValue("statement").getString();
+        assertEquals("select [jcr:path], [jcr:score], * " +
+                "from [oak:Unstructured] as a " +
+                "where isdescendantnode(a, '/') " +
+                "/* xpath: /jcr:root//element(*, oak:Unstructured) */", sql2);
+
         String xpath2 = "/jcr:root//element(*, oak:Unstructured)[@jcr:uuid]";
         q = qm.createQuery("explain " + xpath2 + "", "xpath");
         result = q.execute();