Пример #1
0
 @Override
 public int exprSize() {
   int sz = 1;
   for (final Let lt : copies) sz += lt.exprSize();
   for (final Expr e : expr) sz += e.exprSize();
   return sz;
 }
Пример #2
0
  @Override
  public Expr inline(final QueryContext qc, final VarScope scp, final Var var, final Expr ex)
      throws QueryException {

    boolean change = false;
    try {
      final Expr sub = expr.inline(qc, scp, var, ex);
      if (sub != null) {
        if (sub.isValue()) return optPre(sub, qc);
        expr = sub;
        change = true;
      }
    } catch (final QueryException qe) {
      if (!qe.isCatchable()) throw qe;
      for (final Catch c : catches) {
        if (c.matches(qe)) {
          // found a matching clause, inline variable and error message
          final Catch nw = c.inline(qc, scp, var, ex);
          return optPre((nw == null ? c : nw).asExpr(qe, qc, scp), qc);
        }
      }
      throw qe;
    }

    for (final Catch c : catches) change |= c.inline(qc, scp, var, ex) != null;
    return change ? this : null;
  }
Пример #3
0
 @Override
 public boolean has(final Flag flag) {
   for (final Expr pred : preds) {
     if (flag == Flag.FCS && pred.seqType().mayBeNumber() || pred.has(flag)) return true;
   }
   return false;
 }
Пример #4
0
  @Override
  public final Expr optimize(final QueryContext qc, final VarScope scp) throws QueryException {
    final Value v = initial(qc);
    if (v != null && v.isEmpty() || emptyPath(v)) return optPre(qc);

    // merge descendant steps
    Expr e = mergeSteps(qc);
    if (e == this && v != null && v.type == NodeType.DOC) {
      // check index access
      e = index(qc, v);
      // rewrite descendant to child steps
      if (e == this) e = children(qc, v);
    }
    // recompile path if it has changed
    if (e != this) return e.compile(qc, scp);

    // set atomic type for single attribute steps to speed up predicate tests
    if (root == null && steps.length == 1 && steps[0] instanceof Step) {
      final Step curr = (Step) steps[0];
      if (curr.axis == ATTR && curr.test.kind == Kind.URI_NAME) curr.seqType(SeqType.NOD_ZO);
    }

    // choose best path implementation and set type information
    final Path path = get(info, root, steps);
    path.size = path.size(qc);
    path.seqType = SeqType.get(steps[steps.length - 1].seqType().type, size);
    return path;
  }
Пример #5
0
 @Override
 public int exprSize() {
   int sz = 0;
   for (final Expr e : preExpr) sz += e.exprSize();
   for (final Expr e : specs) sz += e.exprSize();
   return sz;
 }
Пример #6
0
 @Override
 public int exprSize() {
   int sz = 1;
   if (occ != null) for (final Expr o : occ) sz += o.exprSize();
   for (final Expr e : exprs) sz += e.exprSize();
   return sz + query.exprSize();
 }
Пример #7
0
  @Override
  public final Expr compile(final QueryContext qc, final VarScope scp) throws QueryException {
    if (root != null) root = root.compile(qc, scp);
    // no steps
    if (steps.length == 0) return root == null ? new Context(info) : root;

    final Value init = qc.value, cv = initial(qc);
    final boolean doc = cv != null && cv.type == NodeType.DOC;
    qc.value = cv;
    try {
      final int sl = steps.length;
      for (int s = 0; s < sl; s++) {
        Expr e = steps[s];

        // axis step: if input is a document, its type is temporarily generalized
        final boolean as = e instanceof Step;
        if (as && s == 0 && doc) cv.type = NodeType.NOD;

        e = e.compile(qc, scp);
        if (e.isEmpty()) return optPre(qc);
        steps[s] = e;

        // no axis step: invalidate context value
        if (!as) qc.value = null;
      }
    } finally {
      if (doc) cv.type = NodeType.DOC;
      qc.value = init;
    }
    // optimize path
    return optimize(qc, scp);
  }
Пример #8
0
 @Override
 public boolean accept(final ASTVisitor visitor) {
   if (!visitAll(visitor, specs)) return false;
   for (final Expr ng : preExpr) if (!ng.accept(visitor)) return false;
   for (final Var ng : post) if (!visitor.declared(ng)) return false;
   return true;
 }
Пример #9
0
 /**
  * Ensures that none of the specified expressions performs an update. Otherwise, throws an
  * exception.
  *
  * @param exprs expressions (may be {@code null}, and may contain {@code null} references)
  * @throws QueryException query exception
  */
 protected final void checkNoneUp(final Expr... exprs) throws QueryException {
   if (exprs == null) return;
   checkAllUp(exprs);
   for (final Expr expr : exprs) {
     if (expr != null && expr.has(Flag.UPD)) throw UPNOT_X.get(info, description());
   }
 }
Пример #10
0
 @Override
 public final boolean has(final Flag flag) {
   // first step or root expression will be used as context
   if (flag == Flag.CTX) return root == null || root.has(flag);
   for (final Expr s : steps) if (s.has(flag)) return true;
   return root != null && root.has(flag);
 }
Пример #11
0
  /**
   * Checks if the predicates are successful for the specified item.
   *
   * @param it item to be checked
   * @param qc query context
   * @return result of check
   * @throws QueryException query exception
   */
  protected final boolean preds(final Item it, final QueryContext qc) throws QueryException {
    if (preds.length == 0) return true;

    // set context value and position
    final Value cv = qc.value;
    try {
      if (qc.scoring) {
        double s = 0;
        for (final Expr p : preds) {
          qc.value = it;
          final Item i = p.test(qc, info);
          if (i == null) return false;
          s += i.score();
        }
        it.score(Scoring.avg(s, preds.length));
      } else {
        for (final Expr p : preds) {
          qc.value = it;
          if (p.test(qc, info) == null) return false;
        }
      }
      return true;
    } finally {
      qc.value = cv;
    }
  }
Пример #12
0
 @Override
 public void checkUp() throws QueryException {
   for (final Let c : copies) c.checkUp();
   final Expr m = expr[0];
   m.checkUp();
   if (!m.isVacuous() && !m.has(Flag.UPD)) throw UPMODIFY.get(info);
   checkNoUp(expr[1]);
 }
Пример #13
0
 @Override
 public boolean accept(final ASTVisitor visitor) {
   for (final Expr e : preds) {
     visitor.enterFocus();
     if (!e.accept(visitor)) return false;
     visitor.exitFocus();
   }
   return root.accept(visitor);
 }
Пример #14
0
 @Override
 public VarUsage count(final Var v) {
   final VarUsage inPreds = super.count(v), inRoot = root.count(v);
   if (inPreds == VarUsage.NEVER) return inRoot;
   final long sz = root.size();
   return sz >= 0 && sz <= 1 || root.type().zeroOrOne()
       ? inRoot.plus(inPreds)
       : VarUsage.MORE_THAN_ONCE;
 }
Пример #15
0
  @Override
  public Expr optimize(final QueryContext qc, final VarScope scp) throws QueryException {
    final Expr c = super.optimize(qc, scp);
    if (c != this) return c;

    final int es = exprs.length;
    final ExprList list = new ExprList(es);
    for (int i = 0; i < es; i++) {
      Expr e = exprs[i];
      if (e instanceof CmpG) {
        // merge adjacent comparisons
        while (i + 1 < es && exprs[i + 1] instanceof CmpG) {
          final Expr tmp = ((CmpG) e).union((CmpG) exprs[i + 1], qc, scp);
          if (tmp != null) {
            e = tmp;
            i++;
          } else {
            break;
          }
        }
      }
      // expression will always return true
      if (e == Bln.TRUE) return optPre(Bln.TRUE, qc);
      // skip expression yielding false
      if (e != Bln.FALSE) list.add(e);
    }

    // all arguments return false
    if (list.isEmpty()) return optPre(Bln.FALSE, qc);

    if (es != list.size()) {
      qc.compInfo(OPTREWRITE_X, this);
      exprs = list.finish();
    }
    compFlatten(qc);

    boolean not = true;
    for (final Expr expr : exprs) {
      if (!expr.isFunction(Function.NOT)) {
        not = false;
        break;
      }
    }

    if (not) {
      qc.compInfo(OPTREWRITE_X, this);
      final int el = exprs.length;
      final Expr[] inner = new Expr[el];
      for (int e = 0; e < el; e++) inner[e] = ((Arr) exprs[e]).exprs[0];
      final Expr ex = new And(info, inner).optimize(qc, scp);
      return Function.NOT.get(null, info, ex).optimize(qc, scp);
    }

    // return single expression if it yields a boolean
    return exprs.length == 1 ? compBln(exprs[0], info) : this;
  }
Пример #16
0
 @Override
 public String toString() {
   final TokenBuilder tb = new TokenBuilder("map { ");
   boolean key = true;
   for (final Expr e : expr) {
     tb.add(key ? tb.size() > 6 ? ", " : "" : ":=").add(e.toString());
     key ^= true;
   }
   return tb.add(" }").toString();
 }
Пример #17
0
 /**
  * Ensures that all specified expressions are vacuous or either updating or non-updating.
  * Otherwise, throws an exception.
  *
  * @param exprs expressions to be checked
  * @throws QueryException query exception
  */
 void checkAllUp(final Expr... exprs) throws QueryException {
   // updating state: 0 = initial state, 1 = updating, -1 = non-updating
   int s = 0;
   for (final Expr expr : exprs) {
     expr.checkUp();
     if (expr.isVacuous()) continue;
     final boolean u = expr.has(Flag.UPD);
     if (u && s == -1 || !u && s == 1) throw UPALL.get(info, description());
     s = u ? 1 : -1;
   }
 }
Пример #18
0
 /**
  * Prepares this expression for iterative evaluation. The expression can be iteratively evaluated
  * if no predicate or only the first is positional.
  *
  * @return result of check
  */
 protected final boolean posIterator() {
   // check if first predicate is numeric
   if (preds.length == 1) {
     Expr p = preds[0];
     if (p instanceof Int) p = Pos.get(((Int) p).itr(), info);
     pos = p instanceof Pos ? (Pos) p : null;
     last = p.isFunction(Function.LAST);
     preds[0] = p;
   }
   return pos != null || last;
 }
Пример #19
0
  @Override
  public Expr optimize(final QueryContext ctx, final VarScope scp) throws QueryException {
    if (root instanceof Context) {
      ctx.compInfo(OPTREMCTX);
      root = null;
    }

    for (final Expr e : steps) {
      // check for empty steps
      if (e.isEmpty()) return optPre(null, ctx);
    }

    return this;
  }
Пример #20
0
  @Override
  public Item item(final QueryContext qc, final InputInfo ii) throws QueryException {
    final QNm name = toQNm(exprs[0], qc, sc, false);
    final long arity = toLong(exprs[1], qc);
    if (arity < 0 || arity > Integer.MAX_VALUE) throw FUNCUNKNOWN_X.get(ii, name);

    try {
      final Expr lit = Functions.getLiteral(name, (int) arity, qc, sc, ii);
      return lit == null ? null : lit.item(qc, ii);
    } catch (final QueryException e) {
      // function not found (in most cases: XPST0017)
      return null;
    }
  }
Пример #21
0
 /**
  * Returns the initial context value of a path or {@code null}.
  *
  * @param qc query context (may be @code null)
  * @return root
  */
 private Value initial(final QueryContext qc) {
   // current context value
   final Value v = qc != null ? qc.value : null;
   // no root or context expression: return context
   if (root == null || root instanceof Context) return v;
   // root reference
   if (root instanceof Root) return v != null && v instanceof Item ? Root.root(v) : v;
   // root is value: return root
   if (root.isValue()) return (Value) root;
   // data reference
   final Data d = root.data();
   if (d != null) return new DBNode(d, 0, Data.ELEM);
   // otherwise, return null
   return null;
 }
Пример #22
0
  @Override
  public Expr compile(final QueryContext qc, final VarScope scp) throws QueryException {
    ts = ts.compile(qc, scp);
    // static condition: return branch in question
    if (ts.isValue()) {
      final Value val = ts.value(qc);
      for (final TypeCase tc : cases) {
        if (tc.matches(val)) return optPre(tc.compile(qc, scp, (Value) ts).expr, qc);
      }
    }
    // compile branches
    for (final TypeCase tc : cases) tc.compile(qc, scp);

    return optimize(qc, scp);
  }
Пример #23
0
  /**
   * Checks if the path can be rewritten for iterative evaluation.
   *
   * @param root root expression; can be a {@code null} reference
   * @param steps path steps
   * @return result of check
   */
  private static boolean iterative(final Expr root, final Expr... steps) {
    if (root == null || !root.iterable()) return false;

    final int sl = steps.length;
    for (int s = 0; s < sl; ++s) {
      switch (((Step) steps[s]).axis) {
          // reverse axes - don't iterate
        case ANC:
        case ANCORSELF:
        case PREC:
        case PRECSIBL:
          return false;
          // multiple, unsorted results - only iterate at last step,
          // or if last step uses attribute axis
        case DESC:
        case DESCORSELF:
        case FOLL:
        case FOLLSIBL:
          return s + 1 == sl || s + 2 == sl && ((Step) steps[s + 1]).axis == Axis.ATTR;
          // allow iteration for CHILD, ATTR, PARENT and SELF axes
        default:
      }
    }
    return true;
  }
Пример #24
0
  @Override
  public final Expr inline(final QueryContext ctx, final VarScope scp, final Var v, final Expr e)
      throws QueryException {

    final Value oldVal = ctx.value;
    try {
      ctx.value = root(ctx);
      final Expr rt = root == null ? null : root.inline(ctx, scp, v, e);
      if (rt != null) {
        setRoot(ctx, rt);
        ctx.value = oldVal;
        ctx.value = root(ctx);
      }

      boolean change = rt != null;
      for (int i = 0; i < steps.length; i++) {
        final Expr nw = steps[i].inline(ctx, scp, v, e);
        if (nw != null) {
          steps[i] = nw;
          change = true;
        }
      }
      return change ? optimize(ctx, scp) : null;
    } finally {
      ctx.value = oldVal;
    }
  }
Пример #25
0
  @Override
  public final Expr optimize(final QueryContext ctx, final VarScope scp) throws QueryException {
    // invalidate current context value (will be overwritten by filter)
    final Value cv = ctx.value;
    try {
      // return empty root
      if (root.isEmpty()) return optPre(null, ctx);
      // convert filters without numeric predicates to axis paths
      if (root instanceof AxisPath && !super.has(Flag.FCS))
        return ((AxisPath) root.copy(ctx, scp)).addPreds(ctx, scp, preds);

      // no predicates.. return root; otherwise, do some advanced compilations
      return preds.length == 0 ? root : opt(ctx);
    } finally {
      ctx.value = cv;
    }
  }
Пример #26
0
  @Override
  public FTWords compile(final QueryContext qc, final VarScope scp) throws QueryException {
    if (occ != null) {
      final int ol = occ.length;
      for (int o = 0; o < ol; ++o) occ[o] = occ[o].compile(qc, scp);
    }

    // compile only once
    if (tokens == null) {
      query = query.compile(qc, scp);
      if (query.isValue()) tokens = tokens(qc);
      // choose fast evaluation for default settings
      fast = mode == FTMode.ANY && tokens != null && occ == null;
      if (ftt == null) ftt = new FTTokenizer(this, qc);
    }
    return this;
  }
Пример #27
0
 @Override
 public Expr inline(final QueryContext ctx, final VarScope scp, final Var v, final Expr e)
     throws QueryException {
   final boolean pr = super.inline(ctx, scp, v, e) != null;
   final Expr rt = root == null ? null : root.inline(ctx, scp, v, e);
   if (rt != null) root = rt;
   return pr || rt != null ? optimize(ctx, scp) : null;
 }
Пример #28
0
  /**
   * Merges expensive descendant-or-self::node() steps.
   *
   * @param qc query context
   * @return original or new expression
   */
  private Expr mergeSteps(final QueryContext qc) {
    boolean opt = false;
    final int sl = steps.length;
    final ExprList stps = new ExprList(sl);
    for (int s = 0; s < sl; s++) {
      final Expr step = steps[s];
      // check for simple descendants-or-self step with succeeding step
      if (s < sl - 1 && step instanceof Step) {
        final Step curr = (Step) step;
        if (curr.simple(DESCORSELF, false)) {
          // check succeeding step
          final Expr next = steps[s + 1];
          // descendant-or-self::node()/child::X -> descendant::X
          if (simpleChild(next)) {
            ((Step) next).axis = DESC;
            opt = true;
            continue;
          }
          // descendant-or-self::node()/(X, Y) -> (descendant::X | descendant::Y)
          Expr e = mergeList(next);
          if (e != null) {
            steps[s + 1] = e;
            opt = true;
            continue;
          }
          // //(X, Y)[text()] -> (/descendant::X | /descendant::Y)[text()]
          if (next instanceof Filter && !next.has(Flag.FCS)) {
            final Filter f = (Filter) next;
            e = mergeList(f.root);
            if (e != null) {
              f.root = e;
              opt = true;
              continue;
            }
          }
        }
      }
      stps.add(step);
    }

    if (opt) {
      qc.compInfo(OPTDESC);
      return get(info, root, stps.finish());
    }
    return this;
  }
Пример #29
0
  /**
   * Merges a single predicate with the root expression and returns the resulting expression, or
   * returns a self reference if the expression cannot be merged. This function is e.g. called by
   * {@link Where#optimize}.
   *
   * @param qc query context
   * @param scp variable scope
   * @param root root expression
   * @return expression
   * @throws QueryException query exception
   */
  public Expr merge(final Expr root, final QueryContext qc, final VarScope scp)
      throws QueryException {

    // only one predicate can be rewritten; root expression must yield nodes
    if (preds.length != 1 || !(root.seqType().type instanceof NodeType)) return this;

    final Expr pred = preds[0];
    // a[.] -> a
    if (pred instanceof Context) return root;

    if (!pred.seqType().mayBeNumber()) {
      // a[b] -> a/b
      if (pred instanceof Path) return Path.get(info, root, pred).optimize(qc, scp);

      if (pred instanceof CmpG) {
        final CmpG cmp = (CmpG) pred;
        final Expr expr1 = cmp.exprs[0], expr2 = cmp.exprs[1];
        // only first operand can depend on context
        if (!expr2.has(Flag.CTX)) {
          Expr path = null;
          // a[. = 'x'] -> a = 'x'
          if (expr1 instanceof Context) path = root;
          // a[text() = 'x'] -> a/text() = 'x'
          if (expr1 instanceof Path) path = Path.get(info, root, expr1).optimize(qc, scp);
          if (path != null) return new CmpG(path, expr2, cmp.op, cmp.coll, cmp.sc, cmp.info);
        }
      }

      if (pred instanceof FTContains) {
        final FTContains cmp = (FTContains) pred;
        final FTExpr ftexpr = cmp.ftexpr;
        // only first operand can depend on context
        if (!ftexpr.has(Flag.CTX)) {
          final Expr expr = cmp.expr;
          Expr path = null;
          // a[. contains text 'x'] -> a contains text 'x'
          if (expr instanceof Context) path = root;
          // [text() contains text 'x'] -> a/text() contains text 'x'
          if (expr instanceof Path) path = Path.get(info, root, expr).optimize(qc, scp);
          if (path != null) return new FTContains(path, ftexpr, cmp.info);
        }
      }
    }
    return this;
  }
Пример #30
0
 @Override
 public boolean indexAccessible(final IndexInfo ii) throws QueryException {
   int costs = 0;
   final ExprList el = new ExprList(exprs.length);
   for (final Expr expr : exprs) {
     // check if expression can be rewritten, and if access is not sequential
     if (!expr.indexAccessible(ii)) return false;
     // skip expressions without results
     if (ii.costs == 0) continue;
     costs += ii.costs;
     el.add(ii.expr);
   }
   // use summarized costs for estimation
   ii.costs = costs;
   // no expressions means no costs: expression will later be ignored
   ii.expr = el.size() == 1 ? el.get(0) : new Union(info, el.finish());
   return true;
 }