We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a different optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
------------------------------------------------------------------ declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) ------------------------------------------------------------------
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX 7.7 beta:
*Compiling:* - rewriting for tail calls: Q{ http://www.w3.org/2005/xquery-local-functions%7DaddPrefix - rewriting fn:exists($a/c) - inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) } - removing variable $prefixed-data *Optimized Query: * declare function local:addPrefix($arg as element()?) { fn:concat("prefix-", $arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) } else "no input data"
------------------------------------------------------------------
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
*Error:* Stopped at C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3, 1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling: - inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1 - inlining let $arg_3 as element()? := $a_1/b - simplifying flwor expression - rewriting fn:exists($a_1/c) *Query:* declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) *Optimized Query:* let $a_1 := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-", ((: element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2 else "no input data" Query plan: <QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
------------------------------------------------------------------
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like 7.7 was doing the right thing. Can you confirm please?
Thanks, Srini
Forgot to mention that sending a sequence instead of element() as input to the function local:addPrefix() was intentional to match our production query and should not matter (i think) to recreate the problem.
On Fri, Jun 13, 2014 at 6:06 PM, Srinivasan Muthu newsrini@gmail.com wrote:
We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a different optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a :=
<a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' )
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX 7.7 beta:
*Compiling:*
- rewriting for tail calls: Q{
http://www.w3.org/2005/xquery-local-functions%7DaddPrefix
- rewriting fn:exists($a/c)
- inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) }
- removing variable $prefixed-data
*Optimized Query: * declare function local:addPrefix($arg as element()?) { fn:concat("prefix-", $arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) } else "no input data"
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
*Error:* Stopped at C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3, 1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling:
- inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1
- inlining let $arg_3 as element()? := $a_1/b
- simplifying flwor expression
- rewriting fn:exists($a_1/c)
*Query:* declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) *Optimized Query:* let $a_1 := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-", ((: element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2 else "no input data" Query plan:
<QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like 7.7 was doing the right thing. Can you confirm please?
Thanks, Srini
Hi Srinivasan, looks like the empty sequence issue we were reporting few weeks ago. The latest snapshot should have fixed this. I'll point you to the github page if I will be able to get back to the mail. Hope this helps. Marco.
Forgot to mention that sending a sequence instead of element() as input to the function local:addPrefix() was intentional to match our production query and should not matter (i think) to recreate the problem.
On Fri, Jun 13, 2014 at 6:06 PM, Srinivasan Muthu newsrini@gmail.com wrote:
We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a different optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a :=
<a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' )
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX 7.7 beta:
*Compiling:*
- rewriting for tail calls: Q{
http://www.w3.org/2005/xquery-local-functions%7DaddPrefix
- rewriting fn:exists($a/c)
- inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) }
- removing variable $prefixed-data
*Optimized Query: * declare function local:addPrefix($arg as element()?) { fn:concat("prefix-", $arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) } else "no input data"
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
*Error:* Stopped at C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3, 1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling:
- inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1
- inlining let $arg_3 as element()? := $a_1/b
- simplifying flwor expression
- rewriting fn:exists($a_1/c)
*Query:* declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) *Optimized Query:* let $a_1 := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-", ((: element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2 else "no input data" Query plan:
<QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like 7.7 was doing the right thing. Can you confirm please?
Thanks, Srini
Hi Srinivasan,
thanks for your excellent error feedback. First, I thought of the same issue reported by Marco, but it seems that the error still exists. I will have at this today.
By the way, we will try our best to release 7.9 until end of June.
Best regards, Christian
On Sat, Jun 14, 2014 at 3:06 AM, Srinivasan Muthu newsrini@gmail.com wrote:
We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a different optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a :=
<a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' )
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX 7.7 beta:
Compiling:
- rewriting for tail calls:
Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix
- rewriting fn:exists($a/c)
- inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) }
- removing variable $prefixed-data
Optimized Query: declare function local:addPrefix($arg as element()?) { fn:concat("prefix-", $arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) } else "no input data"
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
Error: Stopped at C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3, 1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling:
- inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1
- inlining let $arg_3 as element()? := $a_1/b
- simplifying flwor expression
- rewriting fn:exists($a_1/c)
Query: declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) Optimized Query: let $a_1 := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-", ((: element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2 else "no input data" Query plan:
<QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like 7.7 was doing the right thing. Can you confirm please?
Thanks, Srini
Hi Srinivasan,
I found out that we prevented the inlining of let clauses with XML constructors some times in order to tackle some namespace bugs. The following query..
let $x := <X/> return <X xmlns='xx'>{ $x/self::X }</X>
..would be evaluated in a wrong way when inlining <X/>.
The current behavior is correct in terms of the XQuery spec., but I agree that, in the given case, it could be worth to find some new optimizations patterns in order to avoid the evaluation of ununsed code. If you want to enforce this behavior, you can inline the code by yourself:
if (exists($a/c)) then ( <ele>{local:addPrefix($a/b)}</ele> ) else ( 'no input data' )
Code in the negative branch will always be ignored.
Hope this helps, Christian
On Sat, Jun 14, 2014 at 3:06 AM, Srinivasan Muthu newsrini@gmail.com wrote:
We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a different optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a :=
<a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' )
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX 7.7 beta:
Compiling:
- rewriting for tail calls:
Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix
- rewriting fn:exists($a/c)
- inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) }
- removing variable $prefixed-data
Optimized Query: declare function local:addPrefix($arg as element()?) { fn:concat("prefix-", $arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) } else "no input data"
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
Error: Stopped at C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3, 1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling:
- inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1
- inlining let $arg_3 as element()? := $a_1/b
- simplifying flwor expression
- rewriting fn:exists($a_1/c)
Query: declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) Optimized Query: let $a_1 := element a { (element b { ("1") }, element b { ("2") }, element b { ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-", ((: element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2 else "no input data" Query plan:
<QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like 7.7 was doing the right thing. Can you confirm please?
Thanks, Srini
Thanks Marco and Christian. We are glad we could help with our testing. We have about 500 xQueries and several tests for each of those queries and good to know that only two of them failed since we upgraded to 7.8.2 - this confirms BaseX code quality - great job you guys. The other failure is probably due to the same issue that you explained and I am working on confirming that.
We already have a fix for our issue and we will keep in mind about the new behavior to optimize our future queries. Thanks for confirming.
-Srini
On Mon, Jun 16, 2014 at 4:00 AM, Christian Grün christian.gruen@gmail.com wrote:
Hi Srinivasan,
I found out that we prevented the inlining of let clauses with XML constructors some times in order to tackle some namespace bugs. The following query..
let $x := <X/> return <X xmlns='xx'>{ $x/self::X }</X>
..would be evaluated in a wrong way when inlining <X/>.
The current behavior is correct in terms of the XQuery spec., but I agree that, in the given case, it could be worth to find some new optimizations patterns in order to avoid the evaluation of ununsed code. If you want to enforce this behavior, you can inline the code by yourself:
if (exists($a/c)) then ( <ele>{local:addPrefix($a/b)}</ele> ) else ( 'no input data' )
Code in the negative branch will always be ignored.
Hope this helps, Christian
On Sat, Jun 14, 2014 at 3:06 AM, Srinivasan Muthu newsrini@gmail.com wrote:
We have been using BaseX 7.7 beta for a while and recently we switched to 7.8.2 and found two queries failed with the existing unit tests. After research, we found that the query is now getting compiled into a
different
optimized query (from 7.7) and results in evaluating a variable, even if that variable will never be used, as it is inside an IF condition for particular input. Here is the query:
declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) };
let $a :=
<a> <b>1</b> <b>2</b> <b>3</b> </a>
let $prefixed-data:= <ele>{local:addPrefix($a/b)}</ele>
return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' )
In BaseX 7.7beta the output is 'no input data' which is correct. Here $prefixed-data does not get evaluated in BaseX 7.7 beta, as exists($a/c) is FALSE. The optimized query in GUI also shows '$prefixed-data' variable removed. Here is the optimized query in BaseX
7.7
beta:
Compiling:
- rewriting for tail calls:
Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix
- rewriting fn:exists($a/c)
- inlining let $prefixed-data := element ele { (local:addPrefix($a/b)) }
- removing variable $prefixed-data
Optimized Query: declare function local:addPrefix($arg as element()?) {
fn:concat("prefix-",
$arg) }; let $a := element a { (element b { ("1") }, element b { ("2") }, element
b {
("3") }) } return if($a/c) then element ele { (local:addPrefix($a/b)) }
else
"no input data"
In BaseX 7.8.2 the query throws an error.
In 7.8.2, $prefixed-data gets evaluated even though the 'IF" condition is FALSE. See optimized query from GUI here:
Error: Stopped at
C:/source/perforce/PSODepot/health-analyzer/ha-rel504/libs/catalog/src/main/resources/analysis/vsphere/6.5/CO-001/file3,
1/18: [XPTY0004] Cannot treat item() sequence as element()?: (<b>...</b>, <b>...</b>, <b>...</b>). Compiling:
- inlining Q{http://www.w3.org/2005/xquery-local-functions%7DaddPrefix#1
- inlining let $arg_3 as element()? := $a_1/b
- simplifying flwor expression
- rewriting fn:exists($a_1/c)
Query: declare function local:addPrefix($arg as element()?){ concat("prefix-", $arg) }; let $a := <a> <b>1</b> <b>2</b> <b>3</b> </a> let
$prefixed-data:=
<ele>{local:addPrefix($a/b)}</ele> return if (exists($a/c)) then ( $prefixed-data ) else ( 'no input data' ) Optimized Query: let $a_1 := element a { (element b { ("1") }, element b { ("2") },
element b
{ ("3") }) } let $prefixed-data_2 := element ele { (fn:concat("prefix-",
((:
element()?, true :) $a_1/b))) } return if($a_1/c) then $prefixed-data_2
else
"no input data" Query plan:
<QueryPlan> <GFLWOR> <Let> <Var name="$a" id="1"/> <CElem> <QNm value="a" type="xs:QName"/> <CElem> <QNm value="b" type="xs:QName"/> <Str value="1" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="2" type="xs:string"/> </CElem> <CElem> <QNm value="b" type="xs:QName"/> <Str value="3" type="xs:string"/> </CElem> </CElem> </Let> <Let> <Var name="$prefixed-data" id="2"/> <CElem> <QNm value="ele" type="xs:QName"/> <FNStr name="concat(atom1,atom2[,...])"> <Str value="prefix-" type="xs:string"/> <TypeCheck type="element()?" function="true"> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="b"/> </IterPath> </TypeCheck> </FNStr> </CElem> </Let> <If> <IterPath> <VarRef> <Var name="$a" id="1"/> </VarRef> <IterStep axis="child" test="c"/> </IterPath> <VarRef> <Var name="$prefixed-data" id="2"/> </VarRef> <Str value="no input data" type="xs:string"/> </If> </GFLWOR> </QueryPlan>
We wanted to make sure that this is due to the way queries are executed differently now in BaseX 7.8.2 and not a bug in BaseX 7.8.2. Removing the unused variable makes sense for optimization purposes, so it looks like
7.7
was doing the right thing. Can you confirm please?
Thanks, Srini
basex-talk@mailman.uni-konstanz.de