From: Joe W. <jo...@gm...> - 2012-12-29 06:47:34
|
Hi all, I am trying to find the source of the "no supertype for empty()" warning that appears whenever I submit a query that imports the FunctX module. Steps to reproduce: 1. Using trunk, install the FunctX module 2. Submit the following query in eXide: --- xquery version "3.0"; import module namespace functx="http://www.functx.com"; 1 --- 3. Observe the warning in exist.log: 2012-12-29 01:31:58,431 [eXistThread-48] WARN (Type.java [getSuperType]:396) - no supertype for empty() java.lang.Throwable at org.exist.xquery.value.Type.getSuperType(Type.java:396) at org.exist.xquery.value.Type.getCommonSuperType(Type.java:422) at org.exist.xquery.ConditionalExpression.returnsType(ConditionalExpression.java:149) at org.exist.xquery.PathExpr.returnsType(PathExpr.java:393) at org.exist.xquery.CastExpression.setExpression(CastExpression.java:63) at org.exist.xquery.CastExpression.<init>(CastExpression.java:54) at org.exist.xquery.FunctionFactory.castExpression(FunctionFactory.java:299) at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:92) at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:57) at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:53) at org.exist.xquery.parser.XQueryTreeParser.functionCall(XQueryTreeParser.java:9740) at org.exist.xquery.parser.XQueryTreeParser.primaryExpr(XQueryTreeParser.java:7008) at org.exist.xquery.parser.XQueryTreeParser.expr(XQueryTreeParser.java:3632) at org.exist.xquery.parser.XQueryTreeParser.functionDecl(XQueryTreeParser.java:5627) at org.exist.xquery.parser.XQueryTreeParser.prolog(XQueryTreeParser.java:4823) at org.exist.xquery.parser.XQueryTreeParser.libraryModule(XQueryTreeParser.java:4087) at org.exist.xquery.parser.XQueryTreeParser.module(XQueryTreeParser.java:3923) at org.exist.xquery.parser.XQueryTreeParser.xpath(XQueryTreeParser.java:3712) at org.exist.xquery.XQuery.compile(XQuery.java:157) at org.exist.xquery.XQuery.compile(XQuery.java:106) at org.exist.xquery.XQuery.compile(XQuery.java:90) I have read through this warning many times and cannot trace the cause of the warning. I would like to get to the bottom of the warning, since it causes confusion. I'd appreciate any tips you might have on debugging this issue. Thanks, Joe |
From: Adam R. <ad...@ex...> - 2012-12-29 13:11:17
|
Hey Joe, Unfortunately you made this too interesting and easy to dig into for me to resist! So the problem is caused at compilation time, and its caused by this function from FunctX: declare function functx:duration-from-timezone ( $timezone as xs:string ) as xs:dayTimeDuration { xs:dayTimeDuration( if (not(matches($timezone,'Z|[\+\-]\d{2}:\d{2}'))) then error(xs:QName('functx:Invalid_Timezone_Value')) else if ($timezone = 'Z') then 'PT0S' else replace($timezone,'\+?(\d{2}):\d{2}','PT$1H') ) } ; If I run this through the debugger, I can reduce this expression to the following reproducible test case to cause your warning: xs:string( if(current-date() eq current-date() - xs:dayTimeDuration("P1D"))then error(xs:QName("someError")) else "thing" ) Basically the outer xs:string uses the CastExpression class in eXist, and at compilation time it needs to understand what the possible type of the evaluated if/else expression could be. As such it gets the type of the result of the 'then' branch of the if expression, and also get the type of the result of the 'else' branch of the if expression. It then tries to find a super-type of these two types (Type.getCommonSuperType(x, y) in eXist Java code). You can see the XDM type hierarchy here: http://www.w3.org/TR/xpath-datamodel/#types-hierarchy In the case above, the type of the 'then' branch is "empty()", and the type of the 'else' branch is "xs:string". eXist simply complains that there is no super-type which satisfies both empty() and xs:string, and defaults to returning the common super-type as "item". So is this correct? The XDM spec says this about sequences - http://www.w3.org/TR/xpath-datamodel/#sequences It does not define this case, and so its open to interpretation somewhat, however it says clearly "An item is equivalent to a singleton sequence containing that item and vice versa." So what is an Empty Sequence? IMHO an Empty Sequence cannot have a super-type of Item, rather both Empty Sequence have xs:string have a super-type of Sequence. eXist has no Type concept for Sequence. The good news, is that eXist continues to function correctly, and that this warning can probably just be ignored. However whilst experimenting to find a short reproducible test-case, I came upon this: xs:string( if(current-date() eq current-date() - xs:dayTimeDuration("P1D"))then () else "thing" ) Now this code should do exactly the same as the above code, as both () and fn:error(...) are evaluated to an empty sequence. However they dont, and this code does not cause the warning you were seeing. In fact if I debug it, it seems that () is being evaluated not to the type "empty()" but instead to the type "node()". This definitely stikes me as a bug in eXist, as () is certainly an empty sequence and not a node... Wolf any thoughts please? On 29 December 2012 06:47, Joe Wicentowski <jo...@gm...> wrote: > Hi all, > > I am trying to find the source of the "no supertype for empty()" > warning that appears whenever I submit a query that imports the FunctX > module. Steps to reproduce: > > 1. Using trunk, install the FunctX module > > 2. Submit the following query in eXide: > > --- > xquery version "3.0"; > > import module namespace functx="http://www.functx.com"; > > 1 > --- > > 3. Observe the warning in exist.log: > > 2012-12-29 01:31:58,431 [eXistThread-48] WARN (Type.java > [getSuperType]:396) - no supertype for empty() > java.lang.Throwable > at org.exist.xquery.value.Type.getSuperType(Type.java:396) > at org.exist.xquery.value.Type.getCommonSuperType(Type.java:422) > at org.exist.xquery.ConditionalExpression.returnsType(ConditionalExpression.java:149) > at org.exist.xquery.PathExpr.returnsType(PathExpr.java:393) > at org.exist.xquery.CastExpression.setExpression(CastExpression.java:63) > at org.exist.xquery.CastExpression.<init>(CastExpression.java:54) > at org.exist.xquery.FunctionFactory.castExpression(FunctionFactory.java:299) > at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:92) > at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:57) > at org.exist.xquery.FunctionFactory.createFunction(FunctionFactory.java:53) > at org.exist.xquery.parser.XQueryTreeParser.functionCall(XQueryTreeParser.java:9740) > at org.exist.xquery.parser.XQueryTreeParser.primaryExpr(XQueryTreeParser.java:7008) > at org.exist.xquery.parser.XQueryTreeParser.expr(XQueryTreeParser.java:3632) > at org.exist.xquery.parser.XQueryTreeParser.functionDecl(XQueryTreeParser.java:5627) > at org.exist.xquery.parser.XQueryTreeParser.prolog(XQueryTreeParser.java:4823) > at org.exist.xquery.parser.XQueryTreeParser.libraryModule(XQueryTreeParser.java:4087) > at org.exist.xquery.parser.XQueryTreeParser.module(XQueryTreeParser.java:3923) > at org.exist.xquery.parser.XQueryTreeParser.xpath(XQueryTreeParser.java:3712) > at org.exist.xquery.XQuery.compile(XQuery.java:157) > at org.exist.xquery.XQuery.compile(XQuery.java:106) > at org.exist.xquery.XQuery.compile(XQuery.java:90) > > > I have read through this warning many times and cannot trace the cause > of the warning. I would like to get to the bottom of the warning, > since it causes confusion. > > I'd appreciate any tips you might have on debugging this issue. > > Thanks, > Joe > > ------------------------------------------------------------------------------ > Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS, > MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current > with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft > MVPs and experts. SALE $99.99 this month only -- learn more at: > http://p.sf.net/sfu/learnmore_122912 > _______________________________________________ > Exist-development mailing list > Exi...@li... > https://lists.sourceforge.net/lists/listinfo/exist-development -- Adam Retter eXist Developer { United Kingdom } ad...@ex... irc://irc.freenode.net/existdb |
From: Adam R. <ad...@ex...> - 2012-12-29 13:19:19
|
> However whilst experimenting to find a short reproducible test-case, I > came upon this: > > xs:string( > if(current-date() eq current-date() - xs:dayTimeDuration("P1D"))then > () > else > "thing" > ) > > Now this code should do exactly the same as the above code, as both () > and fn:error(...) are evaluated to an empty sequence. However they > dont, and this code does not cause the warning you were seeing. In > fact if I debug it, it seems that () is being evaluated not to the > type "empty()" but instead to the type "node()". > > This definitely stikes me as a bug in eXist, as () is certainly an > empty sequence and not a node... > > Wolf any thoughts please? Digging a little deeper into this one, it looks to me like PathExpr.returnsType() should be re-written from: public int returnsType() { if (steps.size() == 0) //Not so simple. ITEM should be re-tuned in some circumstances that have to be determined return Type.NODE; return steps.get(steps.size() - 1).returnsType(); } to: @Override public int returnsType() { if(steps.isEmpty()) { return Type.EMPTY; } else { return steps.get(steps.size() - 1).returnsType(); } } I havent run the test suite yet, but a quick play with eXist and a few demo apps and all appears to work - I will run the test suite shortly... -- Adam Retter eXist Developer { United Kingdom } ad...@ex... irc://irc.freenode.net/existdb |
From: Wolfgang M. <wol...@ex...> - 2012-12-29 15:17:44
|
> @Override > public int returnsType() { > if(steps.isEmpty()) { > return Type.EMPTY; > } else { > return steps.get(steps.size() - 1).returnsType(); > } > } This seems like the best solution, but I'm not sure if it has any effects on the query optimizer, which relies on the type information. I just think there must have been a reason why Type.NODE is returned and not Type.EMPTY. I suggest I change the code locally for a while and see if it triggers something we can't overlook right now. Wolfgang |
From: Wolfgang M. <wol...@ex...> - 2012-12-29 15:46:59
|
> Basically the outer xs:string uses the CastExpression class in eXist, > and at compilation time it needs to understand what the possible type > of the evaluated if/else expression could be. As such it gets the type > of the result of the 'then' branch of the if expression, and also get > the type of the result of the 'else' branch of the if expression. It > then tries to find a super-type of these two types > (Type.getCommonSuperType(x, y) in eXist Java code). Correct. Expression.returnsType is called to make a "best guess" of the possible return type of an expression. This is not always possible though (due to a lack of static type information), in which case Type.ITEM is returned. The important point here is that returnsType should return a specific type like Type.NODE, if and only if we can be sure both clauses of the if...then...else return nodes. In this case the optimizer may choose a different evaluation strategy. On the other hand, if Type.ITEM is returned, the query engine should not make any assumption about the type of the sequence to be expected. The optimizer interprets Type.ITEM as: it's not possible to determine the correct type. I would expect eXist to correctly process expressions returning empty() despite the warning in the logs. I actually think the EMPTY case should be handled by Type.getSuperType instead of printing a warning. I will check this. Wolfgang |
From: Joe W. <jo...@gm...> - 2012-12-30 01:24:24
|
Adam and Wolfgang, Fascinating discussion. I always enjoy learning about how eXist-db works under the hood. So many optimization that are there to help our queries run quickly and efficiently. Adam - I'd love to know more about how you tracked this down. The idea to add handling for this case sounds good. Thanks, Joe Sent from my iPhone On Saturday, December 29, 2012 at 10:46 AM, Wolfgang Meier wrote: > > Basically the outer xs:string uses the CastExpression class in eXist, > > and at compilation time it needs to understand what the possible type > > of the evaluated if/else expression could be. As such it gets the type > > of the result of the 'then' branch of the if expression, and also get > > the type of the result of the 'else' branch of the if expression. It > > then tries to find a super-type of these two types > > (Type.getCommonSuperType(x, y) in eXist Java code). > > > > > Correct. Expression.returnsType is called to make a "best guess" of the possible return type of an expression. This is not always possible though (due to a lack of static type information), in which case Type.ITEM is returned. > > The important point here is that returnsType should return a specific type like Type.NODE, if and only if we can be sure both clauses of the if...then...else return nodes. In this case the optimizer may choose a different evaluation strategy. On the other hand, if Type.ITEM is returned, the query engine should not make any assumption about the type of the sequence to be expected. The optimizer interprets Type.ITEM as: it's not possible to determine the correct type. > > I would expect eXist to correctly process expressions returning empty() despite the warning in the logs. I actually think the EMPTY case should be handled by Type.getSuperType instead of printing a warning. I will check this. > > Wolfgang |