/xbird-open/main/src/java/xbird/xquery/optim/FLWORArranger.java
http://xbird.googlecode.com/ · Java · 1010 lines · 695 code · 40 blank · 275 comment · 215 complexity · f4f2ad18d7c094d618aa8c66ce68b7b5 MD5 · raw file
- /*
- * @(#)$Id: FLWORArranger.java 3619 2008-03-26 07:23:03Z yui $
- *
- * Copyright 2006-2008 Makoto YUI
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Contributors:
- * Makoto YUI - initial implementation
- */
- package xbird.xquery.optim;
-
- import java.util.*;
-
- import xbird.xquery.XQueryException;
- import xbird.xquery.expr.XQExpression;
- import xbird.xquery.expr.comp.ComparisonOp;
- import xbird.xquery.expr.comp.GeneralComp;
- import xbird.xquery.expr.cond.IfExpr;
- import xbird.xquery.expr.dyna.ContextItemExpr;
- import xbird.xquery.expr.flwr.*;
- import xbird.xquery.expr.func.DirectFunctionCall;
- import xbird.xquery.expr.func.RecursiveCall;
- import xbird.xquery.expr.logical.AndExpr;
- import xbird.xquery.expr.opt.PathVariable;
- import xbird.xquery.expr.opt.TypePromotedExpr;
- import xbird.xquery.expr.path.*;
- import xbird.xquery.expr.path.PathExpr.CompositePath;
- import xbird.xquery.expr.path.axis.SelfStep;
- import xbird.xquery.expr.var.*;
- import xbird.xquery.expr.var.BindingVariable.*;
- import xbird.xquery.func.Function;
- import xbird.xquery.func.FunctionSignature;
- import xbird.xquery.func.context.Position;
- import xbird.xquery.meta.XQueryContext;
- import xbird.xquery.misc.TypeUtil;
- import xbird.xquery.parser.visitor.AbstractXQueryParserVisitor;
- import xbird.xquery.type.Type;
- import xbird.xquery.type.Type.Occurrence;
- import xbird.xquery.type.xs.*;
-
- /**
- *
- * <DIV lang="en"></DIV>
- * <DIV lang="ja"></DIV>
- *
- * @author Makoto YUI (yuin405+xbird@gmail.com)
- */
- public final class FLWORArranger {
-
- private FLWORArranger() {}
-
- public static Map<Binding, XQExpression> getDependentInWhereExpr(final FLWRExpr flwr, final List<XQExpression> nodeps)
- throws XQueryException {
- final XQExpression whereExpr = flwr.getWhereExpr();
- if(whereExpr == null) {
- return Collections.<Binding, XQExpression> emptyMap();
- }
- final List<Binding> clauses = flwr.getClauses();
- // try to split 'and' expr
- final Map<Binding, XQExpression> dependancies = new IdentityHashMap<Binding, XQExpression>(4);
- final DependancyChecker dependancyChecker = new DependancyChecker(clauses);
- if(whereExpr instanceof AndExpr) {
- final List<XQExpression> andExprs = ((AndExpr) whereExpr).getExpressions();
- for(final XQExpression andExpr : andExprs) {
- andExpr.visit(dependancyChecker, null);
- if(dependancyChecker.hasDependancy()) {
- final Binding dep = dependancyChecker.getDependent();
- if(dependancies.containsKey(dep)) {
- final AndExpr e = new AndExpr(dependancies.get(dep), andExpr);
- e.copyLocations(andExpr);
- dependancies.put(dep, e);
- } else {
- dependancies.put(dep, andExpr);
- }
- } else {
- nodeps.add(andExpr);
- }
- }
- } else {
- whereExpr.visit(dependancyChecker, null);
- if(dependancyChecker.hasDependancy()) {
- dependancies.put(dependancyChecker.getDependent(), whereExpr);
- } else {
- nodeps.add(whereExpr);
- }
- }
- return dependancies;
- }
-
- /**
- * Apply 'for' bindings normalization.
- * <pre>
- * <b>[For unnesting]</b>
- * Before normalization:
- * for $a in /aaa, $b in /bbb, $c in /ccc
- * return ($a, $b, $c)
- *
- * After normalization:
- * for $a in /aaa
- * return (
- * for $b in /bbb
- * return (
- * for $c in /ccc
- * return ($a, $b, $c)
- * )
- * )
- *
- * - eg#1 has dependancies
- * Before normalization
- * for $a in /aaa, $b in /bbb, $c in /ccc
- * where $b = $c
- * return ($a, $b, $c)
- *
- * After normalization
- * for $a in /aaa
- * return (
- * for $b in /bbb
- * return (
- * for $c in /ccc[. = $b]
- * return ($a, $b, $c)
- * )
- * )
- *
- * - eg#2 no dependancies
- * Before normalization
- * let $d := $doc/ddd
- * for $a in /aaa, $b in /bbb, $c in /ccc
- * where $d = 3
- * return ($a, $b, $c)
- *
- * After normalization
- * if ($d = 3) then -- pull up to cond
- * let $d := $doc/ddd
- * for $a in /aaa
- * return (
- * for $b in /bbb
- * return (
- * for $c in /ccc
- * return ($a, $b, $c)
- * )
- * )
- * else ()
- *
- * - eg#3 has multiple(in this case 2) dependancies
- * Before normalization
- * let $d := $doc/ddd
- * for $a in /aaa, $b in /bbb, $c in /ccc
- * where $d = 3 and $c = $b -- `and` expression is optimized (or is not).
- * return ($a, $b, $c)
- *
- * After normalization
- * if ($d = 3) then -- pull up to cond
- * let $d := $doc/ddd
- * for $a in /aaa
- * return (
- * for $b in /bbb
- * return (
- * for $c in /ccc
- * where $c = $b -- put to right position
- * return ($a, $b, $c)
- * )
- * )
- * else ()
- *
- * -- eg#4 for + where case(no dep)
- * Before normalization
- * for $d in $doc/ddd
- * where $e = 3
- * return $d
- *
- * After normalization
- * if ($e = 3) then
- * for $d in $doc/ddd
- * return $d
- * else ()
- * </pre>
- */
- public static XQExpression applyForNormalization(final FLWRExpr flwr, final Map<Binding, XQExpression> dependancies)
- throws XQueryException {
- assert (flwr != null);
- final List<Binding> clauses = flwr.getClauses();
- // apply for unnesting
- int size;
- for(int i = 0; i < ((size = clauses.size()) - 1); i++) {
- final Binding first = clauses.get(i);
- if(first.getExpressionType() == Binding.FOR_CLAUSE) {
- while((i + 1) < size) { // find next 'for'
- final Binding second = clauses.get(i + 1);
- if(second.getExpressionType() == Binding.FOR_CLAUSE) { // found nesting
- final FLWRExpr parent = new FLWRExpr();
- if(dependancies.containsKey(second)) {
- final XQExpression old = flwr.getWhereExpr();
- if(old != null) {
- dependancies.put(first, old);
- }
- flwr.setWhereExpr(dependancies.remove(second));
- } else {
- flwr.setWhereExpr(null);
- }
- final List<OrderSpec> specs = flwr.getOrderSpecs();
- if(!specs.isEmpty()) {
- parent.setOrderSpecs(specs);
- flwr.setOrderSpecs(Collections.<OrderSpec> emptyList());
- }
- for(int j = 0; j <= i; j++) {
- final Binding b = clauses.remove(0);
- if(dependancies.containsKey(b)) { // copy depended where clauses
- parent.addWhereExpr(dependancies.remove(b));
- }
- parent.addClause(b); // copy for, let.. to be parent
- }
- if(size > (i + 2)) {
- final XQExpression forUnnested = applyForNormalization(flwr, dependancies);
- parent.setReturnExpr(forUnnested);
- } else { // inner most
- final XQExpression transformed = transform(flwr, dependancies);
- parent.setReturnExpr(transformed);
- }
- return transform(parent, dependancies);
- } else {
- i++;
- }
- }
- break;
- } else {
- final FLWRExpr letUnnested = applyLetWhereToIfCondConversion(flwr, dependancies);
- if(letUnnested != flwr) {
- return transform(letUnnested, dependancies);
- }
- }
- }
- if(!dependancies.isEmpty()) {
- for(XQExpression expr : dependancies.values()) {
- flwr.addWhereExpr(expr);
- }
- dependancies.clear();
- }
- return transform(flwr, dependancies);
- }
-
- /**
- * Convert where clause with If Conditional expression.
- * <pre>
- * -- eg#1 has relation to binding variable
- * Before:
- * for $i in /aaa
- * where $i/bbb > 0
- * return $r
- *
- * After:
- * for $i in /aaa
- * return
- * if ($i/bbb > 0) then $r
- * else ()
- * </pre>
- */
- private static void applyWhereToIfCondConversion(final FLWRExpr flwr) {
- if(flwr._filteredReturnExpr == null) {
- if(flwr.getWhereExpr() == null) {
- flwr._filteredReturnExpr = flwr.getReturnExpr();
- } else {
- flwr._filteredReturnExpr = new IfExpr(flwr.getWhereExpr(), flwr.getReturnExpr());
- flwr.setWhereExpr(null);
- }
- flwr.setReturnExpr(null);
- }
- }
-
- /**
- * Pull up IF conditional expr that does not have dependancies.
- * <pre>
- * -- eg#1 no decpendancies
- * Before:
- * for $i in /aaa/bbb
- * return
- * if $j = 3 then $r
- * else ()
- *
- * After:
- * if ($j = 3) then
- * for $i in /aaa/bbb
- * return $r
- * else ()
- * </pre>
- * @throws XQueryException
- * @depends {@link #applyWhereToIfCondConversion(FLWRExpr)}
- */
- private static XQExpression applyIfCondPullup(final FLWRExpr flwr) throws XQueryException {
- final XQExpression retExpr = flwr.getFilteredReturnExpr();
- if(retExpr instanceof IfExpr) {
- final DependancyChecker dependancyChecker = new DependancyChecker(flwr.getClauses());
- retExpr.visit(dependancyChecker, null);
- if(!dependancyChecker.hasDependancy()) {
- final IfExpr ifExpr = (IfExpr) retExpr;
- flwr._filteredReturnExpr = ifExpr.getThenExpr();
- flwr.setReturnExpr(null);
- ifExpr.setThenExpr(flwr);
- return ifExpr;
- }
- }
- return flwr;
- }
-
- /**
- * <pre>
- * -- eg#1
- * Before:
- * for $i in /aaa/bbb return $i/ccc
- * After:
- * /aaa/bbb/ccc
- *
- * -- eg#2
- * Before:
- * let $i := /aaa/bbb
- * return $i/ccc
- * After:
- * /aaa/bbb/ccc
- *
- * -- eg#3
- * Before
- * for $i in /aaa/bbb return $i
- * After
- * /aaa/bbb
- *
- * -- eg#3
- * Before
- * for $b in a/b/c return $b/d[text()=$b/name]
- *
- * After
- * -- if $b's reference count is greater than 1, could not cut flwr.
- * for $b in a/b/c return $b/d[text()=$b/name]
- * </pre>
- * @throws XQueryException
- */
- private static XQExpression applyFLWRCutting(final FLWRExpr flwr) throws XQueryException {
- if(flwr.getWhereExpr() == null) {
- final XQExpression retExpr = flwr.getFilteredReturnExpr();
- if(retExpr instanceof DirectFunctionCall && !(retExpr instanceof RecursiveCall)) {
- final DirectFunctionCall funcall = (DirectFunctionCall) retExpr;
- final List<XQExpression> params = funcall.getParams();
- if(params.size() == 1) {
- FunctionSignature sig = funcall.getFunction().getFunctionSignature(1);
- Type type = sig.getArgumentType(0);
- Occurrence occ = type.quantifier();
- if(!occ.accepts(Occurrence.OCC_ZERO_OR_MORE.getAlignment())) {
- return flwr; //TODO REVIEWME
- }
- final XQExpression firstArg = params.get(0);
- final XQExpression cutted = recApplyFLWRCuttingInternal(flwr, firstArg);
- if(cutted != flwr) {
- return retExpr;
- }
- }
- } else {
- return recApplyFLWRCuttingInternal(flwr, retExpr);
- }
- }
- return flwr;
- }
-
- private static XQExpression recApplyFLWRCuttingInternal(final FLWRExpr flwr, final XQExpression retExpr) {
- if(retExpr instanceof RelativePath) {//find the front item
- final RelativePath pathExpr = ((RelativePath) retExpr);
- final XQExpression firstStep = pathExpr.getSteps().get(0);
- if(firstStep instanceof VarRef) {
- final Variable referent = ((VarRef) firstStep).getValue();
- if(referent instanceof BindingVariable) {
- final int refcnt = ((BindingVariable) referent).getReferenceCount();
- if(refcnt == 1) {
- final int csize = flwr.getClauses().size();
- if(csize > 0) {
- final Binding clause = flwr.getClauses().get(0);
- final BindingVariable bindingVar = clause.getVariable();
- if(bindingVar == referent) {
- final XQExpression bindingExpr = bindingVar.getValue();
- pathExpr.setStep(0, bindingExpr);
- return pathExpr;
- }
- }
- }
- }
- }
- } else if(retExpr instanceof VarRef) {
- final Variable referent = ((VarRef) retExpr).getValue();
- if(referent instanceof BindingVariable) {
- final int refcnt = ((BindingVariable) referent).getReferenceCount();
- if(refcnt == 1) {
- for(Binding clause : flwr.getClauses()) {
- final BindingVariable bindingVar = clause.getVariable();
- if(bindingVar == referent) {
- XQExpression bindingExpr = bindingVar.getValue();
- Type type = bindingVar.getType();
- if(type != Untyped.UNTYPED) {
- return new TypePromotedExpr(bindingExpr, type);
- } else {
- return bindingExpr;
- }
- }
- }
- }
- }
- }
- return flwr;
- }
-
- private static XQExpression applyRemoveUnnessaryLetClause(final FLWRExpr flwr) {
- assert ((flwr.getReturnExpr() == null) && (flwr.getWhereExpr() == null));
- assert (flwr._filteredReturnExpr != null);
- final List<Binding> clauses = flwr.getClauses();
- int csize = clauses.size();
- for(int i = 0; i < csize; i++) {
- final Binding binding = clauses.get(i);
- if(binding.getExpressionType() == Binding.LET_CLAUSE) {
- BindingVariable bv = binding.getVariable();
- final int refcnt = bv.getReferenceCount();
- if((refcnt == 0) || (refcnt == 1)) {
- clauses.remove(i--);
- --csize;
- }
- }
- }
- final int cleanAfter = clauses.size();
- if(cleanAfter == 0) {
- return flwr.getFilteredReturnExpr();
- }
- return flwr;
- }
-
- private static XQExpression applyFLWRFlatting(final FLWRExpr flwr) {
- if(!flwr.getOrderSpecs().isEmpty()) {
- return flwr;
- }
- final XQExpression ret = flwr.getFilteredReturnExpr();
- if(ret == null) {
- throw new IllegalStateException();
- }
- final List<Binding> clauses = flwr.getClauses();
- final int clen = clauses.size();
- if(clen == 0) {
- return ret;
- } else if(clen == 1) {
- final Binding firstBinding = clauses.get(0);
- if(ret instanceof VarRef) {
- return applyFLWRFlattingInternal((VarRef) ret, firstBinding, flwr);
- } else if(ret instanceof RelativePath) {
- final RelativePath path = (RelativePath) ret;
- final List<XQExpression> steps = path.getSteps();
- final XQExpression firstStep = steps.get(0);
- if(firstStep instanceof VarRef) {
- final XQExpression cutted = applyFLWRFlattingInternal((VarRef) firstStep, firstBinding, flwr);
- if(cutted != flwr) {
- steps.set(0, cutted);
- return path;
- }
- }
- }
- }
- return flwr;
- }
-
- private static final XQExpression applyFLWRFlattingInternal(final VarRef ret, final Binding firstBinding, final FLWRExpr flwr) {
- final Variable referent = ret.getValue();
- final BindingVariable bindingVar = firstBinding.getVariable();
- if(referent == bindingVar) {
- return bindingVar.getValue();
- }
- final XQExpression bindingExpr = firstBinding.getExpression();
- if(referent == bindingExpr) {
- return bindingExpr;
- }
- return flwr;
- }
-
- /**
- * <pre>
- * -- eg#1
- * Before
- * let $p = /aaa/bbb
- * for $i in /ccc
- * return
- * for $j in /ddd
- * return $p
- *
- * After
- * -- $p will be rewritten.
- * for $i in /ccc
- * return
- * for $j in /ddd
- * return /aaa/bbb
- * </pre>
- */
- private static void applyConstantLetVariableFolding(final FLWRExpr flwr) {
- final List<Binding> clauses = flwr.getClauses();
- final int clen = clauses.size();
- if(clen > 0) {
- final Binding clause = clauses.get(0);
- final XQExpression bindingExpr = clause.getVariable().getValue();
- if(bindingExpr instanceof RelativePath) {
- final RelativePath pathExpr = ((RelativePath) bindingExpr);
- final XQExpression firstStep = pathExpr.getSteps().get(0);
- if(firstStep instanceof VarRef) {
- final Variable referent = ((VarRef) firstStep).getValue();
- if(referent instanceof LetVariable) {
- final int refcnt = ((LetVariable) referent).getReferenceCount();
- if(refcnt == 1) { // varref variable seems to be a constant.
- final XQExpression refExpr = referent.getValue();
- pathExpr.setStep(0, refExpr);
- }
- }
- }
- } else if(bindingExpr instanceof VarRef) {
- final Variable referent = ((VarRef) bindingExpr).getValue();
- if(referent instanceof LetVariable) {
- final int refcnt = ((LetVariable) referent).getReferenceCount();
- if(refcnt == 1) {
- final XQExpression refExpr = referent.getValue();
- final BindingVariable bv = clause.getVariable();
- bv.setValue(refExpr);
- }
- }
- }
- }
- }
-
- /**
- * <pre>
- * -- eg#1
- * Before:
- * for $c in /ccc
- * where $b = $c
- * return ($a, $b, $c)
- * After:
- * for $c in /ccc[. = $b]
- * return ($a, $b, $c)
- *
- * -- eg#2
- * Before:
- * let $c := /ccc
- * where $b = $c
- * return ($a, $b, $c)
- * After:
- * let $c in /ccc[. = $b]
- * return ($a, $b, $c)
- *
- * -- eg#3
- * Before:
- * for $x in /aaa/bbb
- * where $x/ccc eq "zzz"
- * return true
- * After:
- * for $x in /aaa/bbb[ccc eq "zzz"]
- * return true
- *
- * -- eg#4
- * Before normalization
- * for $a in /aaa at $pos where $pos = 2 return $a,
- * for $a in /aaa where fn:position() = 2 return $a
- *
- * After normalization
- * for $a in /aaa[2] return $a
- *
- * -- eg#5
- * Before:
- * for $c in /aaa
- * where $d = 3 and $c = $b
- * return $a
- *
- * After:
- * if ($d = 3) then
- * for $c in /aaa[. = $b]
- * return $a
- * else ()
- * </pre>
- * @param dependancies
- */
- private static void applyWhereToPredicateConversion(final FLWRExpr flwr, final Map<Binding, XQExpression> dependancies)
- throws XQueryException {
- final XQExpression whereExpr = flwr.getWhereExpr();
- if(whereExpr == null) {
- return;
- }
-
- // first binding entries
- final List<Binding> clauses = flwr.getClauses();
- final Binding firstBinding = clauses.get(0);
- final int firstBindingType = firstBinding.getExpressionType();
- final BindingVariable firstBindingVar = firstBinding.getVariable();
- XQExpression firstBindingExpr = firstBinding.getExpression();
-
- final List<XQExpression> whereExprs;
- if(whereExpr instanceof AndExpr) {
- whereExprs = ((AndExpr) whereExpr).flatten();
- } else {
- whereExprs = new ArrayList<XQExpression>(1);
- whereExprs.add(whereExpr);
- }
- int nWhereSize = whereExprs.size();
- for(int oi = 0; oi < nWhereSize; oi++) {
- final XQExpression eachExpr = whereExprs.get(oi);
- boolean innerModified = false;
- if(eachExpr instanceof ComparisonOp) {
- final ComparisonOp cmpOpr = (ComparisonOp) eachExpr;
- XQExpression replaceVarRef = null;
- inner: for(int ii = 0; ii < 2; ii++) {
- final XQExpression left = cmpOpr.getLeftOperand();
- final XQExpression right = cmpOpr.getRightOperand();
- if(left instanceof VarRef) {
- final Variable referent = ((VarRef) left).getValue();
- if(firstBindingExpr instanceof PathExpr) {
- final PathExpr bindingPathExpr = (PathExpr) firstBindingExpr;
- if(firstBindingVar == referent) {
- cmpOpr.setLeftOperand(new ContextItemExpr(bindingPathExpr.getType()));
- bindingPathExpr.addPredicate(cmpOpr);
- innerModified = true;
- replaceVarRef = firstBindingVar;
- break inner;
- } else if((firstBindingType == Binding.FOR_CLAUSE)
- && (cmpOpr instanceof GeneralComp)) {
- final PositionalVariable posVar = ((ForClause) firstBinding).getPositionVariable();
- if(posVar == referent) {
- bindingPathExpr.addPredicate(right);
- innerModified = true;
- replaceVarRef = posVar;
- break inner;
- }
- }
- }
- } else if(left instanceof RelativePath) {
- final RelativePath leftPathExpr = ((RelativePath) left);
- final List<XQExpression> steps = leftPathExpr.getSteps();
- final XQExpression firstStep = steps.get(0);
- if(firstStep instanceof VarRef) {
- final Variable referent = ((VarRef) firstStep).getValue();
- if(firstBindingVar == referent) {
- if(firstBindingExpr instanceof VarRef) {
- final Variable ref = ((VarRef) firstBindingExpr).getValue();
- final XQExpression refval = ref.getValue();
- if(refval instanceof PathExpr) {
- firstBindingExpr = refval;
- }
- }
- if(firstBindingExpr instanceof PathExpr) {
- final PathExpr bindingPathExpr = (PathExpr) firstBindingExpr;
- steps.remove(0);
- assert (!steps.isEmpty());
- bindingPathExpr.addPredicate(cmpOpr);
- innerModified = true;
- replaceVarRef = firstBindingVar;
- break inner;
- }
- } else if(ii == 1) {// delete an unnessesary where clause
- innerModified = true;
- break inner;
- }
- }
- } else if(left instanceof DirectFunctionCall) {
- final Function func = ((DirectFunctionCall) left).getFunction();
- if(func instanceof Position) {
- if(firstBindingExpr instanceof PathExpr) {
- final PathExpr bindingPathExpr = (PathExpr) firstBindingExpr;
- if(TypeUtil.subtypeOf(right.getType(), NumericType.getInstance())) {
- bindingPathExpr.addPredicate(right);
- } else {
- TypePromotedExpr typePromoted = new TypePromotedExpr(right, IntegerType.INTEGER);
- bindingPathExpr.addPredicate(typePromoted);
- }
- innerModified = true;
- break inner;
- }
- }
- } else {
- if(firstBindingExpr instanceof PathExpr) {
- final PathExpr bindingPathExpr = (PathExpr) firstBindingExpr;
- final VarRefDetector detector1 = new VarRefDetector(firstBindingVar, true);
- detector1.visit(left, null);
- if(detector1.isDetected()) {
- final VarRefDetector detector2 = new VarRefDetector(firstBindingVar, false);
- detector2.visit(right, null);
- if(detector2.isJoinDisabled() || detector2.isDetected()) {
- break inner;
- } else {
- bindingPathExpr.addPredicate(cmpOpr);
- innerModified = true;
- break inner;
- }
- }
- }
- }
- cmpOpr.switchOperand();
- }//inner
- if(replaceVarRef != null) {
- final PredicateReplacer replacer = new PredicateReplacer(replaceVarRef);
- replacer.visit(cmpOpr, null);
- }
- }//outer
- if(innerModified) {
- whereExprs.remove(oi--);
- --nWhereSize;
- }
- }
- if(nWhereSize == 0) {
- flwr.setWhereExpr(null);
- } else if(nWhereSize == 1) {
- flwr.setWhereExpr(whereExprs.get(0));
- } else {
- flwr.setWhereExpr(new AndExpr(whereExprs));
- }
- }
-
- private static XQExpression transform(final FLWRExpr flwr, final Map<Binding, XQExpression> dependancies)
- throws XQueryException {
- applyWhereToPredicateConversion(flwr, dependancies);
- applyConstantLetVariableFolding(flwr);
- applyWhereToIfCondConversion(flwr);
- XQExpression normedRet = applyIfCondPullup(flwr);
- if(normedRet instanceof FLWRExpr) {
- normedRet = applyFLWRCutting((FLWRExpr) normedRet);
- }
- if(normedRet instanceof FLWRExpr) {
- normedRet = applyRemoveUnnessaryLetClause((FLWRExpr) normedRet);
- }
- if(normedRet instanceof FLWRExpr) {
- normedRet = applyFLWRFlatting((FLWRExpr) normedRet);
- }
- return normedRet;
- }
-
- /**
- * <pre>
- * -- eg#1
- * Before:
- * let $i := 3
- * for $j in /aaa/ccc
- * where $i > 2
- * return $j
- *
- * After:
- * let $i := 3
- * return
- * if $i > 2 then
- * for $j in /aaa/ccc
- * return $j
- * else ()
- * </pre>
- */
- private static FLWRExpr applyLetWhereToIfCondConversion(final FLWRExpr flwr, final Map<Binding, XQExpression> dependancies)
- throws XQueryException {
- final List<Binding> clauses = flwr.getClauses();
- final int size = clauses.size();
- if(size > 0) {
- final Binding b = clauses.get(0);
- if(b.getExpressionType() == Binding.LET_CLAUSE) {
- if(dependancies.containsKey(b)) {
- clauses.remove(0);
- final FLWRExpr parent = new FLWRExpr();
- final List<OrderSpec> specs = flwr.getOrderSpecs();
- if(!specs.isEmpty()) {
- parent.setOrderSpecs(specs);
- flwr.setOrderSpecs(Collections.<OrderSpec> emptyList());
- }
- parent.addClause(b);
- final XQExpression cond = dependancies.remove(b);
- final XQExpression then = applyForNormalization(flwr, dependancies);
- final IfExpr ifExpr = new IfExpr(cond, then);
- parent.setReturnExpr(ifExpr);
- return parent;
- } else {
- final LetVariable lv = ((LetClause) b).getVariable();
- final int refcnt = lv.getReferenceCount();
- if((refcnt == 0) || (refcnt == 1)) {
- clauses.remove(0);
- }
- }
- }
- }
- return flwr;
- }
-
- private static final class VarRefDetector extends AbstractXQueryParserVisitor {
- private final BindingVariable _targetVar;
- private final int _birthId;
- private final boolean _doReplace;
-
- private boolean _detected = false;
- private boolean _disableJoin = false;
-
- VarRefDetector(final BindingVariable var, final boolean doReplace) {
- super();
- this._targetVar = var;
- this._birthId = var.getBirthId();
- this._doReplace = doReplace;
- }
-
- boolean isDetected() {
- return _detected;
- }
-
- boolean isJoinDisabled() {
- return _disableJoin;
- }
-
- @Override
- public XQExpression visit(final PathExpr path, final XQueryContext ctxt)
- throws XQueryException {
- if(path instanceof RelativePath) {
- final List<XQExpression> steps = path.getSteps();
- final int steplen = steps.size();
- for(int i = 0; i < steplen; i++) {
- final XQExpression step = steps.get(i);
- if(step instanceof VarRef) {
- final VarRef ref = (VarRef) step;
- final Variable referent = ref.getValue();
- if(_targetVar == referent) {
- if(_doReplace) {
- steps.remove(i);
- }
- _detected = true;
- return path;
- }
- }
- step.visit(this, ctxt);
- }
- }
- super.visit(path, ctxt);
- return path;
- }
-
- @Override
- public XQExpression visit(BindingVariable variable, XQueryContext ctxt)
- throws XQueryException {
- final int targetBirthId = variable.getBirthId();
- if(targetBirthId > _birthId) {
- this._disableJoin = true;
- return variable;
- }
- return super.visit(variable, ctxt);
- }
-
- }
-
- private static final class PredicateReplacer extends AbstractXQueryParserVisitor {
-
- private final XQExpression _target;
-
- PredicateReplacer(final XQExpression target) {
- super();
- assert (target != null);
- _target = target;
- }
-
- @Override
- public XQExpression visit(final PathVariable variable, final XQueryContext ctxt)
- throws XQueryException {
- final XQExpression pathExpr = variable.getValue();
- if(pathExpr instanceof CompositePath) {
- final CompositePath cp = (CompositePath) pathExpr;
- final XQExpression srcExpr = cp.getSourceExpr();
- assert (srcExpr != null);
- final XQExpression filterExpr = cp.getFilterExpr();
- assert (filterExpr != null);
- srcExpr.visit(this, ctxt);
- if(srcExpr == _target) {
- variable.setValue(filterExpr);
- }
- filterExpr.visit(this, ctxt);
- }
- return variable;
- }
-
- @Override
- public XQExpression visit(final PathExpr path, final XQueryContext ctxt)
- throws XQueryException {
- final List<XQExpression> steps = path.getSteps();
- int steplen = steps.size();
- for(int i = 0; i < steplen; i++) {
- final XQExpression s = steps.get(i);
- if(s instanceof VarRef) {
- final Variable var = ((VarRef) s).getValue();
- if(var == _target) {
- if(steplen > 1) {
- final XQExpression next = steps.get(i + 1);
- if(next instanceof StepExpr) {
- steps.remove(i);
- --steplen;
- continue;
- }
- }
- steps.set(i, new SelfStep(NodeTest.ANYNODE));
- }
- s.visit(this, ctxt);
- }
- }
- return path;
- }
- }
-
- private static final class DependancyChecker extends AbstractXQueryParserVisitor {
- private final List<Binding> _clauses;
- private Binding _dependent = null;
- private boolean _found = false;
-
- DependancyChecker(final List<Binding> clauses) {
- super();
- _clauses = clauses;
- }
-
- Binding getDependent() {
- return _dependent;
- }
-
- boolean hasDependancy() {
- return _found;
- }
-
- @Override
- public XQExpression visit(final FLWRExpr expr, final XQueryContext ctxt)
- throws XQueryException {
- for(final Binding b : expr.getClauses()) {
- b.visit(this, ctxt);
- }
- return expr;
- }
-
- @Override
- public XQExpression visit(final VarRef ref, final XQueryContext ctxt)
- throws XQueryException {
- XQExpression referent = ref.getValue();
- if(referent instanceof ParametricVariable) {
- XQExpression argv = ((ParametricVariable) referent).getValue();
- if(argv instanceof TypePromotedExpr) {
- argv = ((TypePromotedExpr) argv).getPromotedExpr();
- if(argv instanceof VarRef) {
- referent = ((VarRef) argv).getValue();
- }
- }
- }
- ForClause lastForClause = null;
- for(final Binding target : _clauses) {
- final int type = target.getExpressionType();
- if(type == Binding.FOR_CLAUSE) {
- lastForClause = (ForClause) target;
- final Variable bvar = lastForClause.getVariable();
- final PositionalVariable posVar = lastForClause.getPositionVariable();
- if((bvar == referent) || (posVar == referent)) {
- if(_found) {
- final int posTrgDep = _clauses.indexOf(target);
- final int posLastDep = _clauses.indexOf(_dependent); // return -1 with null arg
- if(posLastDep > posTrgDep) {
- // Considering following case.
- // | for $a in /aaa, $b in /bbb, $c in /ccc
- // | where $c = $b ..
- // | .. ~~~~~~~
- continue;
- }
- }
- _found = true;
- _dependent = target;
- }
- } else {
- LetClause letClause = (LetClause) target;
- final LetVariable lv = letClause.getVariable();
- if(lv == referent) {
- if(_found) {
- final int posTrgDep = _clauses.indexOf(target);
- final int posLastDep = _clauses.indexOf(_dependent);
- if(posLastDep > posTrgDep) {
- continue;
- }
- }
- _found = true;
- _dependent = target;
- }
- }
- }
- return ref;
- }
-
- @Override
- public XQExpression visit(final DirectFunctionCall call, final XQueryContext ctxt)
- throws XQueryException {
- final Function func = (call).getFunction();
- if(func instanceof Position) {
- for(final Binding target : _clauses) {
- final int type = target.getExpressionType();
- if(type == Binding.FOR_CLAUSE) {
- _dependent = target;
- break;
- }
- }
- _found = true;
- assert (_dependent != null);
- } else {
- super.visit(call, ctxt);
- }
- return call;
- }
- }
-
- }