eXist-db / exist

eXist Native XML Database and Application Platform
https://exist-db.org
GNU Lesser General Public License v2.1
429 stars 179 forks source link

AST error when using attribute node test #1613

Closed joewiz closed 6 years ago

joewiz commented 7 years ago

What is the problem

eXist throws AST errors when using the node test @node(). No error is thrown when the verbose form, attribute::node(), is used.

What did you expect

I expected @node() to correctly perform a node test rather than throw AST errors.

Describe how to reproduce or add a test

Here's a test query:

<x y="z"/> ! @node()

The error thrown in eXide is:

<AST>:1:15: unexpected AST node: node.

The verbose form of this query returns the expected result:

<x y="z"/> ! attribute::node()
y="z" 

Context information

joewiz commented 7 years ago

Here's the corresponding entry from exist.log:


2017-11-11 01:20:29,182 [qtp2045196319-695] ERROR (XQueryServlet.java [process]:534) - Cannot compile xquery: exerr:ERROR <AST>:3:15: unexpected AST node: node

org.exist.EXistException: Cannot compile xquery: exerr:ERROR <AST>:3:15: unexpected AST node: node

    at org.exist.http.servlets.XQueryServlet.process(XQueryServlet.java:428) [exist-optional.jar:3.6.0-SNAPSHOT]
    at org.exist.http.servlets.XQueryServlet.doPost(XQueryServlet.java:191) [exist-optional.jar:3.6.0-SNAPSHOT]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:707) [servlet-api-3.1.jar:3.1.0]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [servlet-api-3.1.jar:3.1.0]
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:566) [jetty-security-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:163) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:73) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.exist.http.urlrewrite.Forward.doRewrite(Forward.java:50) [exist-optional.jar:3.6.0-SNAPSHOT]
    at org.exist.http.urlrewrite.XQueryURLRewrite.doRewrite(XQueryURLRewrite.java:548) [exist-optional.jar:3.6.0-SNAPSHOT]
    at org.exist.http.urlrewrite.XQueryURLRewrite.service(XQueryURLRewrite.java:352) [exist-optional.jar:3.6.0-SNAPSHOT]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:790) [servlet-api-3.1.jar:3.1.0]
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:841) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at de.betterform.agent.web.filter.XFormsFilter.doFilter(XFormsFilter.java:171) [betterform-exist-5.1-SNAPSHOT-20160615.jar:?]
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1629) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:533) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:524) [jetty-security-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:190) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:188) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1253) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:168) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) [jetty-servlet-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:166) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1155) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:219) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:454) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.Server.handle(Server.java:564) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:317) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:251) [jetty-server-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:279) [jetty-io-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:110) [jetty-io-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:124) [jetty-io-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.Invocable.invokePreferred(Invocable.java:128) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.Invocable$InvocableExecutor.invoke(Invocable.java:222) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:294) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:199) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:673) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:591) [jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
    at java.lang.Thread.run(Thread.java:748) [?:1.8.0_144]
Caused by: org.exist.xquery.StaticXQueryException: exerr:ERROR <AST>:3:15: unexpected AST node: node

    at org.exist.xquery.XQuery.compile(XQuery.java:133) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.XQuery.compile(XQuery.java:79) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.XQuery.compile(XQuery.java:71) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.http.servlets.XQueryServlet.process(XQueryServlet.java:425) ~[exist-optional.jar:3.6.0-SNAPSHOT]
    ... 59 more
Caused by: antlr.NoViableAltException: unexpected AST node: node
    at org.exist.xquery.parser.XQueryTreeParser.pathExpr(XQueryTreeParser.java:8661) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.expr(XQueryTreeParser.java:3596) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.pathExpr(XQueryTreeParser.java:8749) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.expr(XQueryTreeParser.java:3596) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.mainModule(XQueryTreeParser.java:4044) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.module(XQueryTreeParser.java:3987) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.parser.XQueryTreeParser.xpath(XQueryTreeParser.java:3642) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.XQuery.compile(XQuery.java:128) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.XQuery.compile(XQuery.java:79) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.xquery.XQuery.compile(XQuery.java:71) ~[exist.jar:3.6.0-SNAPSHOT]
    at org.exist.http.servlets.XQueryServlet.process(XQueryServlet.java:425) ~[exist-optional.jar:3.6.0-SNAPSHOT]
    ... 59 more
joewiz commented 7 years ago

For reference, see https://github.com/ryanjdew/XQuery-XML-Memory-Operations/commit/8fa6a98efa9525f4dda53ed94fd65353f0a694e6#commitcomment-25547695, where I discovered this problem.

adamretter commented 7 years ago

@joewiz I just looked into the specs, so it looks like @node() is valid since XQuery 1.0, and is really a AbbrevForwardStep followed by an AnyKindTest.

I am not sure why we haven't supported this in the past, apart from it is a slightly strange expression to use in practice, as you already know from the @ that the kind will be an attribute. I will dig deeper...

adamretter commented 7 years ago

It seems that just the query /@node() is enough to reproduce the problem.

adamretter commented 7 years ago

Tracing the parser seems to show the following:

> abbrevStep; [guessing]LA(1)==@
  > nodeTest; [guessing]LA(1)==node
    > kindTest; [guessing]LA(1)==node
      > anyKindTest; [guessing]LA(1)==node
      < anyKindTest; [guessing]LA(1)==null
    < kindTest; [guessing]LA(1)==null
  < nodeTest; [guessing]LA(1)==null
< abbrevStep; [guessing]LA(1)==null

So it seems that the expression doesn't match the anyKindTest rule, but I can't see why yet...

adamretter commented 7 years ago

Okay I see the problem. It seems that we only ever implemented NameTest on the abbrevStep when @ is used.

@joewiz You can see the lack of implementation on this parser rule for AT (which represents the @ literal - https://github.com/eXist-db/exist/blob/develop/src/org/exist/xquery/parser/XQueryTree.g#L2365

Unfortunately fixing this looks like it is going to be a bit of a pain unless we just do a load of copy and paste...