Return-Path: X-Original-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Delivered-To: apmail-jackrabbit-oak-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C77FDD64C for ; Thu, 20 Dec 2012 10:14:00 +0000 (UTC) Received: (qmail 45955 invoked by uid 500); 20 Dec 2012 10:14:00 -0000 Delivered-To: apmail-jackrabbit-oak-commits-archive@jackrabbit.apache.org Received: (qmail 45833 invoked by uid 500); 20 Dec 2012 10:13:57 -0000 Mailing-List: contact oak-commits-help@jackrabbit.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: oak-dev@jackrabbit.apache.org Delivered-To: mailing list oak-commits@jackrabbit.apache.org Received: (qmail 45761 invoked by uid 99); 20 Dec 2012 10:13:55 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 20 Dec 2012 10:13:55 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 20 Dec 2012 10:13:51 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 15FDF238890D; Thu, 20 Dec 2012 10:13:30 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1424389 - in /jackrabbit/oak/trunk/oak-core/src: main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java test/resources/org/apache/jackrabbit/oak/query/sql2.txt test/resources/org/apache/jackrabbit/oak/query/xpath.txt Date: Thu, 20 Dec 2012 10:13:29 -0000 To: oak-commits@jackrabbit.apache.org From: thomasm@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20121220101330.15FDF238890D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: thomasm Date: Thu Dec 20 10:13:29 2012 New Revision: 1424389 URL: http://svn.apache.org/viewvc?rev=1424389&view=rev Log: OAK-309 ParentNodeTest fails (XPath parent node navigation using "..") Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java jackrabbit/oak/trunk/oak-core/src/test/resources/org/apache/jackrabbit/oak/query/sql2.txt 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/XPathToSQL2Converter.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/query/XPathToSQL2Converter.java?rev=1424389&r1=1424388&r2=1424389&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 Dec 20 10:13:29 2012 @@ -85,9 +85,6 @@ public class XPathToSQL2Converter { currentSelector.name = "a"; ArrayList columnList = new ArrayList(); - - // TODO support "..", example: - // /jcr:root/etc/.. String pathPattern = ""; boolean startOfQuery = true; @@ -225,6 +222,29 @@ public class XPathToSQL2Converter { } } } + } else if (readIf(".")) { + // just "." this is simply ignored, so that + // "a/./b" is the same as "a/b" + if (readIf(".")) { + // ".." means "the parent of the node" + // handle like a regular path restriction + String name = ".."; + pathPattern += name; + if (!currentSelector.isChild) { + currentSelector.nodeName = name; + } else { + if (currentSelector.isChild) { + currentSelector.isChild = false; + currentSelector.isParent = true; + } + } + } else { + if (selectors.size() > 0) { + currentSelector = selectors.remove(selectors.size() - 1); + currentSelector.condition = null; + currentSelector.joinCondition = null; + } + } } else { throw getSyntaxError(); } @@ -346,7 +366,7 @@ public class XPathToSQL2Converter { boolean isFirstSelector = selectors.size() == 0; String path = currentSelector.path; Expression condition = currentSelector.condition; - Expression joinCondition = currentSelector.joinCondition; + Expression joinCondition = null; if (currentSelector.nodeName != null) { Function f = new Function("name"); f.params.add(new SelectorExpr(currentSelector)); @@ -372,6 +392,15 @@ public class XPathToSQL2Converter { c.params.add(new SelectorExpr(selectors.get(selectors.size() - 1))); joinCondition = c; } + } else if (currentSelector.isParent) { + if (isFirstSelector) { + throw getSyntaxError(); + } else { + Function c = new Function("ischildnode"); + c.params.add(new SelectorExpr(selectors.get(selectors.size() - 1))); + c.params.add(new SelectorExpr(currentSelector)); + joinCondition = c; + } } else if (currentSelector.isChild) { if (isFirstSelector) { if (!path.isEmpty()) { @@ -408,7 +437,7 @@ public class XPathToSQL2Converter { Selector nextSelector = new Selector(); nextSelector.name = nextSelectorName; currentSelector.condition = condition; - currentSelector.joinCondition = joinCondition; + currentSelector.joinCondition = add(currentSelector.joinCondition, joinCondition); selectors.add(currentSelector); currentSelector = nextSelector; } @@ -417,6 +446,8 @@ public class XPathToSQL2Converter { private static Expression add(Expression old, Expression add) { if (old == null) { return add; + } else if (add == null) { + return old; } return new Condition(old, "and", add, Expression.PRECEDENCE_AND); } @@ -985,22 +1016,33 @@ public class XPathToSQL2Converter { /** * Whether this is a child node of the previous selector or a given path. + * Examples: + *
  • /jcr:root/* + *
  • /jcr:root/test/* + *
  • /jcr:root/element() + *
  • /jcr:root/element(*) + *
*/ - // queries of the type - // jcr:root/* - // jcr:root/test/* - // jcr:root/element() - // jcr:root/element(*) boolean isChild; - + + /** + * Whether this is a parent node of the previous selector or given path. + * Examples: + *
  • testroot//child/..[@foo1] + *
  • /jcr:root/test/descendant/..[@test] + *
+ */ + boolean isParent; + /** * Whether this is a descendant of the previous selector or a given path. + * Examples: + *
  • /jcr:root//descendant + *
  • /jcr:root/test//descendant + *
  • /jcr:root[@x] + *
  • /jcr:root (just by itself) + *
*/ - // queries of the type - // /jcr:root//... - // /jcr:root/test//... - // /jcr:root[...] - // /jcr:root (just by itself) boolean isDescendant; /** 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=1424389&r1=1424388&r2=1424389&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 Dec 20 10:13:29 2012 @@ -23,9 +23,24 @@ # * new tests are typically be added on top, after the syntax docs # * use ascii character only +# test parent join + +commit / + "test": { "a": { "x": "1", "yes": { } }, "b": { "yes" : { } }, "c": { "x": "1", "no" : { } }} + +xpath test//yes/..[@x] +/test/a, null, /test/a + +select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'yes' and isdescendantnode(a, '/test') and b.[x] is not null +/test/a, null, /test/a + +explain select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'yes' and isdescendantnode(a, '/test') and b.[x] is not null +[nt:base] as [a] /* traverse "/test//*" where (name([a]) = cast('yes' as string)) and (isdescendantnode([a], [/test])) */ inner join [nt:base] as [b] /* traverse "//*" where [b].[x] is not null */ on ischildnode([a], [b]) + +commit / - "test" + # test spaces in identifiers -commit / + "test": { "space space": { }} +commit / + "test": { "space space": { "x": "1" }} select * from [nt:base] where issamenode([/test/space space]) /test/space space 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=1424389&r1=1424388&r2=1424389&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 Thu Dec 20 10:13:29 2012 @@ -25,6 +25,24 @@ # jackrabbit test queries +xpath2sql testroot//child/..[@foo1] +select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(a, b) where name(a) = 'child' and isdescendantnode(a, '/testroot') and b.[foo1] is not null + +xpath2sql testroot//child/.[@foo1] +select [jcr:path], [jcr:score], * from [nt:base] as a where [foo1] is not null and name(a) = 'child' and isdescendantnode(a, '/testroot') + +xpath2sql testroot//child[@foo1] +select [jcr:path], [jcr:score], * from [nt:base] as a where [foo1] is not null and name(a) = 'child' and isdescendantnode(a, '/testroot') + +xpath2sql /jcr:root/testroot/node11 +select [jcr:path], [jcr:score], * from [nt:base] as a where issamenode(a, '/testroot/node11') + +xpath2sql /jcr:root/testroot/./node11 +select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(b, a) where ischildnode(a, '/testroot') and name(b) = 'node11' + +xpath2sql /jcr:root/testroot/././node11 +select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(b, a) where ischildnode(a, '/testroot') and name(b) = 'node11' + xpath /jcr:root/testroot//*[0] java.text.ParseException: /jcr:root/testroot//*[0] converted to SQL-2 Query: select [jcr:path], [jcr:score], * from [nt:base] as a where 0(*)is not null and isdescendantnode(a, '/testroot'); expected: NOT, ( @@ -32,22 +50,22 @@ xpath2sql /test select [jcr:path], [jcr:score], * from [nt:base] as a where name(a) = 'test' and issamenode(a, '/') xpath2sql / -invalid: Query: (*)/; expected: jcr:root, /, *, text, element, @, ( +invalid: Query: (*)/; expected: jcr:root, /, *, text, element, @, (, . xpath2sql /[@name='data'] -invalid: Query: /[(*)@name='data']; expected: jcr:root, /, *, text, element, @, ( +invalid: Query: /[(*)@name='data']; expected: jcr:root, /, *, text, element, @, (, . xpath2sql //[@name='data'] -invalid: Query: //[(*)@name='data']; expected: *, text, element, @, ( +invalid: Query: //[(*)@name='data']; expected: *, text, element, @, (, . xpath2sql //child/[@id='2.1'] -invalid: Query: //child/[(*)@id='2.1']; expected: jcr:root, /, *, text, element, @, ( +invalid: Query: //child/[(*)@id='2.1']; expected: jcr:root, /, *, text, element, @, (, . xpath2sql // -invalid: Query: /(*)/; expected: *, text, element, @, ( +invalid: Query: /(*)/; expected: *, text, element, @, (, . xpath2sql [@name='data'] -invalid: Query: [(*)@name='data']; expected: /, *, text, element, @, ( +invalid: Query: [(*)@name='data']; expected: /, *, text, element, @, (, . xpath2sql test select [jcr:path], [jcr:score], * from [nt:base] as a where issamenode(a, '/test') @@ -130,9 +148,6 @@ select [jcr:path], [jcr:score], * from [ xpath2sql /jcr:root/testroot/*[jcr:contains(., 'jackrabbit')]/rep:excerpt(.) invalid: Query: /jcr:root/testroot/*[jcr:contains(., 'jackrabbit')]/rep:excerpt((*).); expected: -xpath2sql /jcr:root/testroot//child/..[@foo1] -invalid: Query: /jcr:root/testroot//child/.(*).[@foo1]; expected: jcr:root, /, *, text, element, @, ( - xpath2sql //testroot/*[@jcr:primaryType='nt:unstructured' and fn:not(@mytext)] select b.[jcr:path] as [jcr:path], b.[jcr:score] as [jcr:score], b.* from [nt:base] as a inner join [nt:base] as b on ischildnode(b, a) where name(a) = 'testroot' and b.[jcr:primaryType] = 'nt:unstructured' and b.[mytext] is null @@ -352,7 +367,7 @@ xpath2sql //element(*, my:type)[jcr:cont select [jcr:path], [jcr:score], * from [my:type] as a where contains([my:title], 'jcr') order by score(a) desc xpath2sql [invalid/query -invalid: Query: [(*)invalid/query; expected: /, *, text, element, @, ( +invalid: Query: [(*)invalid/query; expected: /, *, text, element, @, (, . xpath2sql //element(*, my:type)[@my:value = -'x'] invalid: Query: //element(*, my:type)[@my:value = -'x'(*)]