Bug #2550
closedNo watch found for xsl:element
100%
Description
This XQuery
for $x in saxon:stream(doc('uriresolver:resolve')/*/*/element {node-name()} {node()}) return $x
did not qualify for streaming in 9.6, but fell back to non-streaming mode.
With 9.7, it throws this exception:
net.sf.saxon.s9api.SaxonApiUncheckedException: No watch found for xsl:element
at net.sf.saxon.s9api.XdmSequenceIterator.hasNext(XdmSequenceIterator.java:66)
at net.sf.saxon.s9api.XdmSequenceIterator.next(XdmSequenceIterator.java:90)
at NonStreamableQuery.testNonStreamableQueryUsingSaxonStream(NonStreamableQuery.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:84)
at org.testng.internal.Invoker.invokeMethod(Invoker.java:714)
at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:901)
at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1231)
at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
at org.testng.TestRunner.privateRun(TestRunner.java:767)
at org.testng.TestRunner.run(TestRunner.java:617)
at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
at org.testng.SuiteRunner.run(SuiteRunner.java:240)
at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
at org.testng.TestNG.run(TestNG.java:1057)
at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
Caused by: net.sf.saxon.trans.XPathException: No watch found for xsl:element
at com.saxonica.ee.bytecode.util.Callback.makeXPathException(Callback.java:143)
at gen_SlashContextMappingFunction_1.map(Unknown Source)
at net.sf.saxon.expr.ContextMappingIterator.next(ContextMappingIterator.java:61)
at net.sf.saxon.query.XQueryExpression$ErrorReportingIterator.next(XQueryExpression.java:846)
at net.sf.saxon.s9api.XdmSequenceIterator.hasNext(XdmSequenceIterator.java:57)
... 26 more
Updated by Michael Kay almost 9 years ago
- Status changed from New to In Progress
Note, replacing "for $x in XXX return $x" by the simpler expression XXX gives a different internal error.
My first reaction is that I may have to document restrictions here. saxon:stream() is designed to deliver a subset of XSLT's streaming capability to XQuery users, but this example is doing things that don't map directly to anything in XSLT, and where it's therefore not possible to rely on all the streamability analysis available for the XSLT case.
Updated by Michael Kay almost 9 years ago
The test becomes streamable if it is rewritten as
for $x in saxon:stream(doc('uri')/*/*)/element {node-name()} {node()} return $x"
or equivalently
saxon:stream(doc('uri')/*/*)/element {node-name()} {node()}
Note the changed position of the closing paren.
There's a fundamental difference here: the way you wrote the query, you were trying to apply streaming to a sequence of constructed element nodes; the way I rewrote it, streaming is applied to a sequence of input nodes, and for each of these, a new element node is constructed.
I'm going to see if I can find a way to improve the diagnostics on this, but I'm not going to attempt to make it actually work.
Updated by Michael Kay almost 9 years ago
The query can also be made streamable by changing it to
saxon:stream(doc('uri')/*/*/element {node-name()} {copy-of(node())})
which suggests that a possible solution is to insert the copy-of() automatically.
With the help of some experimentation I have found that adding a copy-of operation into the inverted evaluation pipeline appears to be safe in the case where:
(a) the parent expression is grounded (e.g. an element constructor)
(b) the child expression is not grounded
(c) the operand usage of the consuming child operand is absorption
(d) the parent expression is not a copy-of() or snapshot() operation
With this change both versions of the query become streamable.
However, another version of the query written as:
streaming("saxon:stream(doc('uri')/*/* ! element {node-name()} {node()})");
fails to terminate, so I will now investigate that one.
Updated by Michael Kay almost 9 years ago
- Category set to Streaming
- Status changed from In Progress to Resolved
- Assignee set to Michael Kay
- Priority changed from Low to Normal
- Fix Committed on Branch 9.7 added
The final version of the expression (using "!") violates the rule that the argument to saxon:stream() must be a path expression, so I won't pursue that one further. Closing this with the change identified, applied to Inversion.java on the 9.7 branch.
Updated by O'Neil Delpratt almost 9 years ago
- % Done changed from 0 to 100
- Fixed in Maintenance Release 9.7.0.2 added
Bug fix applied in the Saxon 9.7.0.2 maintenance release
Updated by O'Neil Delpratt almost 9 years ago
- Status changed from Resolved to Closed
Please register to edit this issue