@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; }
@Override public GroupBy optimize(final QueryContext qc, final VarScope scp) throws QueryException { final int pl = preExpr.length; for (int p = 0; p < pl; p++) { final SeqType it = preExpr[p].seqType(); post[p].refineType(it.withOcc(it.mayBeZero() ? Occ.ZERO_MORE : Occ.ONE_MORE), qc); } return this; }
@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; }
@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; }
@Override public Expr optimize(final QueryContext ctx, final VarScope scp) throws QueryException { final SeqType s0 = expr[0].type(); final SeqType s1 = expr[1].type(); final Type t0 = s0.type; final Type t1 = s1.type; if (t0.isNumberOrUntyped() && t1.isNumberOrUntyped()) { final Occ occ = s0.one() && s1.one() ? Occ.ONE : Occ.ZERO_ONE; type = SeqType.get(Calc.type(t0, t1), occ); } else if (s0.one() && s1.one()) { type = SeqType.ITEM; } return optPre(oneIsEmpty() ? null : allAreValues() ? item(ctx, info) : this, ctx); }
/** * Compiles the filter expression, excluding the root node. * * @param ctx query context * @return compiled expression */ private Expr opt(final QueryContext ctx) { // evaluate return type final SeqType t = root.type(); // determine number of results and type final long s = root.size(); if (s != -1) { if (pos != null) { size = Math.max(0, s + 1 - pos.min) - Math.max(0, s - pos.max); } else if (last) { size = s > 0 ? 1 : 0; } // no results will remain: return empty sequence if (size == 0) return optPre(null, ctx); type = SeqType.get(t.type, size); } else { type = SeqType.get(t.type, t.zeroOrOne() ? Occ.ZERO_ONE : Occ.ZERO_MORE); } // no numeric predicates.. use simple iterator if (!super.has(Flag.FCS)) return new IterFilter(this); // one single position() or last() function specified: return single value if (preds.length == 1 && (last || pos != null) && root.isValue() && t.one() && (last || pos.min == 1 && pos.max == 1)) return optPre(root, ctx); // only choose deterministic and context-independent offsets; e.g., skip: // (1 to 10)[random:integer(10)] or (1 to 10)[.] boolean off = false; if (preds.length == 1) { final Expr p = preds[0]; final SeqType st = p.type(); off = st.type.isNumber() && st.zeroOrOne() && !p.has(Flag.CTX) && !p.has(Flag.NDT); if (off) type = SeqType.get(type.type, Occ.ZERO_ONE); } // iterator for simple numeric predicate return off || useIterator() ? new IterPosFilter(this, off) : this; }