Difference in query behavior between BaseX 7.7 beta and BaseX 7.8.2

Saturday, 14 June 2014 · 6 messages · last reply 17 Jun 2014
SM
Srinivasan Muthu14 Jun 2014 05:06 #
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}addPrefix
- 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}addPrefix#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
SM
Srinivasan Muthu14 Jun 2014 05:56 #
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.
Quoted text · Srinivasan Muthu · 143 lines
On Fri, Jun 13, 2014 at 6:06 PM, Srinivasan Muthu <newsrini at 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}addPrefix > - 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}addPrefix#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 >
M
marco.lettere14 Jun 2014 10:40 #
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.
Quoted text · Srinivasan Muthu · 162 lines
> 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 at 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}addPrefix >> - 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}addPrefix#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 >> >
CG
Christian Grünin reply to Srinivasan Muthu, 14 Jun 2014, 05:0616 Jun 2014 12:26 #
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
Quoted text · Srinivasan Muthu · 141 lines
On Sat, Jun 14, 2014 at 3:06 AM, Srinivasan Muthu <newsrini at 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}addPrefix > - 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}addPrefix#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
CG
Christian Grünin reply to Srinivasan Muthu, 14 Jun 2014, 05:0616 Jun 2014 13:00 #
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
Quoted text · Srinivasan Muthu · 141 lines
On Sat, Jun 14, 2014 at 3:06 AM, Srinivasan Muthu <newsrini at 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}addPrefix > - 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}addPrefix#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
SM
Srinivasan Muthu17 Jun 2014 13:47 #
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
Quoted text · Christian Grün · 186 lines
On Mon, Jun 16, 2014 at 4:00 AM, Christian Grün <christian.gruen at 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 at 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}addPrefix > > - 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}addPrefix#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 >

⚡Generated with XQuery