Beispiel #1
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;
 }
Beispiel #2
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());
   }
 }
Beispiel #3
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;
    }
  }
Beispiel #4
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;
  }
Beispiel #5
0
 @Override
 protected Expr opt(final QueryContext qc, final VarScope scp) {
   final Expr e = exprs[0];
   final SeqType st = e.seqType();
   if (!st.mayBeZero()) return e;
   seqType = SeqType.get(st.type, seqType.occ);
   return this;
 }
Beispiel #6
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;
  }
Beispiel #7
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;
   }
 }
Beispiel #8
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;
 }
Beispiel #9
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;
    }
  }
Beispiel #10
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;
  }
Beispiel #11
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;
 }
Beispiel #12
0
 @Override
 public Expr optimize(final QueryContext qc, final VarScope scp) throws QueryException {
   // number of predicates may change in loop
   for (int p = 0; p < preds.length; p++) {
     final Expr pred = preds[p];
     if (pred instanceof CmpG || pred instanceof CmpV) {
       final Cmp cmp = (Cmp) pred;
       if (cmp.exprs[0].isFunction(Function.POSITION)) {
         final Expr e2 = cmp.exprs[1];
         final SeqType st2 = e2.seqType();
         // position() = last() -> last()
         // position() = $n (numeric) -> $n
         if (e2.isFunction(Function.LAST) || st2.one() && st2.type.isNumber()) {
           if (cmp instanceof CmpG && ((CmpG) cmp).op == OpG.EQ
               || cmp instanceof CmpV && ((CmpV) cmp).op == OpV.EQ) {
             qc.compInfo(OPTWRITE, pred);
             preds[p] = e2;
           }
         }
       }
     } else if (pred instanceof And) {
       if (!pred.has(Flag.FCS)) {
         // replace AND expression with predicates (don't swap position tests)
         qc.compInfo(OPTPRED, pred);
         final Expr[] and = ((Arr) pred).exprs;
         final int m = and.length - 1;
         final ExprList el = new ExprList(preds.length + m);
         for (final Expr e : Arrays.asList(preds).subList(0, p)) el.add(e);
         for (final Expr a : and) {
           // wrap test with boolean() if the result is numeric
           el.add(Function.BOOLEAN.get(null, info, a).optimizeEbv(qc, scp));
         }
         for (final Expr e : Arrays.asList(preds).subList(p + 1, preds.length)) el.add(e);
         preds = el.finish();
       }
     } else if (pred instanceof ANum) {
       final ANum it = (ANum) pred;
       final long i = it.itr();
       if (i == it.dbl()) {
         preds[p] = Pos.get(i, info);
       } else {
         qc.compInfo(OPTREMOVE, this, pred);
         return Empty.SEQ;
       }
     } else if (pred.isValue()) {
       if (pred.ebv(qc, info).bool(info)) {
         qc.compInfo(OPTREMOVE, this, pred);
         preds = Array.delete(preds, p--);
       } else {
         // handle statically known predicates
         qc.compInfo(OPTREMOVE, this, pred);
         return Empty.SEQ;
       }
     }
   }
   return this;
 }
Beispiel #13
0
  @Override
  public Item item(final QueryContext qc, final InputInfo ii) throws QueryException {
    // compute scoring
    if (qc.scoring) {
      double s = 0;
      boolean f = false;
      for (final Expr expr : exprs) {
        final Item it = expr.ebv(qc, info);
        f |= it.bool(ii);
        s += it.score();
      }
      return Bln.get(f, Scoring.avg(s, exprs.length));
    }

    // standard evaluation
    for (final Expr expr : exprs) {
      if (expr.ebv(qc, info).bool(ii)) return Bln.TRUE;
    }
    return Bln.FALSE;
  }
Beispiel #14
0
 /**
  * Ensures that the specified expression performs no updates. Otherwise, throws an exception.
  *
  * @param expr expression (may be {@code null})
  * @throws QueryException query exception
  */
 protected void checkNoUp(final Expr expr) throws QueryException {
   if (expr == null) return;
   expr.checkUp();
   if (expr.has(Flag.UPD)) throw UPNOT_X.get(info, description());
 }
Beispiel #15
0
 /**
  * Returns a boolean equivalent for the specified expression. If the specified expression yields a
  * boolean value anyway, it will be returned as is. Otherwise, it will be wrapped into a boolean
  * function.
  *
  * @param ex expression to be rewritten
  * @param info input info
  * @param sc static context
  * @return expression
  */
 protected static Expr compBln(final Expr ex, final InputInfo info, final StaticContext sc) {
   return ex.seqType().eq(SeqType.BLN) ? ex : Function.BOOLEAN.get(sc, info, ex);
 }
Beispiel #16
0
 /**
  * Checks if the specified expression yields a QName. Returns the item or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @param empty allow empty result
  * @return QNm item
  * @throws QueryException query exception
  */
 protected final QNm toQNm(final Expr ex, final QueryContext qc, final boolean empty)
     throws QueryException {
   return toQNm(ex.atomItem(qc, info), empty);
 }
Beispiel #17
0
 /**
  * Checks if the specified expression yields an item of the specified atomic type. Returns the
  * item or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @param type type to be checked
  * @return item
  * @throws QueryException query exception
  */
 protected Item checkAtomic(final Expr ex, final QueryContext qc, final Type type)
     throws QueryException {
   return checkType(ex.atomItem(qc, info), type);
 }
Beispiel #18
0
 /**
  * Checks if the specified expression yields a binary item. Returns the binary item or throws an
  * exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return binary item
  * @throws QueryException query exception
  */
 protected final Bin toBin(final Expr ex, final QueryContext qc) throws QueryException {
   return toBin(ex.atomItem(qc, info));
 }
Beispiel #19
0
 /**
  * Checks if the specified expression yields a string or binary item.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return byte array
  * @throws QueryException query exception
  */
 protected final byte[] toBytes(final Expr ex, final QueryContext qc) throws QueryException {
   return toBytes(ex.atomItem(qc, info));
 }
Beispiel #20
0
 /**
  * Checks if the evaluated expression yields a non-empty item. Returns the atomized item or throws
  * an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return atomized item
  * @throws QueryException query exception
  */
 protected final Item toAtomItem(final Expr ex, final QueryContext qc) throws QueryException {
   return checkNoEmpty(ex.atomItem(qc, info));
 }
Beispiel #21
0
 /**
  * Checks if the specified expression yields a double. Returns the double or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return double
  * @throws QueryException query exception
  */
 protected final double toDouble(final Expr ex, final QueryContext qc) throws QueryException {
   return toDouble(ex.atomItem(qc, info));
 }
Beispiel #22
0
 /**
  * Checks if the specified expression yields a node or {@code null}. Returns the node, {@code
  * null}, or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return node or {@code null}
  * @throws QueryException query exception
  */
 protected final ANode toEmptyNode(final Expr ex, final QueryContext qc) throws QueryException {
   final Item it = ex.item(qc, info);
   return it == null ? null : toNode(it);
 }
Beispiel #23
0
 /**
  * Checks if the specified expression yields a non-empty item. Returns the item or throws an
  * exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @param type expected type
  * @return item
  * @throws QueryException query exception
  */
 private Item toItem(final Expr ex, final QueryContext qc, final Type type) throws QueryException {
   return checkNoEmpty(ex.item(qc, info), type);
 }
Beispiel #24
0
 /**
  * Checks if the specified expression yields a node. Returns the boolean or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return node
  * @throws QueryException query exception
  */
 protected final ANode toNode(final Expr ex, final QueryContext qc) throws QueryException {
   return toNode(checkNoEmpty(ex.item(qc, info), NodeType.NOD));
 }
Beispiel #25
0
 /**
  * Checks if the specified expression yields a float. Returns the float or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return float
  * @throws QueryException query exception
  */
 protected final float toFloat(final Expr ex, final QueryContext qc) throws QueryException {
   final Item it = ex.atomItem(qc, info);
   if (checkNoEmpty(it, AtomType.FLT).type.isNumberOrUntyped()) return it.flt(info);
   throw numberError(this, it);
 }
Beispiel #26
0
 /**
  * Checks if the specified expression yields a string. Returns a value as token or throws an
  * exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return token
  * @throws QueryException query exception
  */
 protected final byte[] toToken(final Expr ex, final QueryContext qc) throws QueryException {
   final Item it = ex.atomItem(qc, info);
   if (it == null) throw EMPTYFOUND_X.get(info, AtomType.STR);
   return toToken(it);
 }
Beispiel #27
0
 @Override
 public void plan(final FElem plan) {
   for (final Expr p : preds) p.plan(plan);
 }
Beispiel #28
0
 /**
  * Checks if the specified expression yields an element. Returns the element or throws an
  * exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return binary item
  * @throws QueryException query exception
  */
 protected final ANode toElem(final Expr ex, final QueryContext qc) throws QueryException {
   return (ANode) checkType(ex.item(qc, info), NodeType.ELM);
 }
Beispiel #29
0
 /**
  * Checks if the specified expression yields a number or {@code null}. Returns the number, {@code
  * null}, or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return double
  * @throws QueryException query exception
  */
 protected final ANum toNumber(final Expr ex, final QueryContext qc) throws QueryException {
   final Item it = ex.atomItem(qc, info);
   return it == null ? null : toNumber(it);
 }
Beispiel #30
0
 /**
  * Checks if the specified expression yields a string or an empty sequence. Returns a value as
  * token or throws an exception.
  *
  * @param ex expression to be evaluated
  * @param qc query context
  * @return token (empty string if result is an empty sequence)
  * @throws QueryException query exception
  */
 protected final byte[] toEmptyToken(final Expr ex, final QueryContext qc) throws QueryException {
   final Item it = ex.atomItem(qc, info);
   return it == null ? EMPTY : toToken(it);
 }