@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; }
/** * Returns the root of the current context or {@code null}. * * @param ctx query context * @return root */ final Value root(final QueryContext ctx) { final Value v = ctx != null ? ctx.value : null; // no root specified: return context, if it does not reference a document // as e.g. happens in //a(b|c) if (root == null) return v == null || v.type != NodeType.DOC ? v : null; // root is value: return root if (root.isValue()) return (Value) root; // no root reference, no context: return null if (!(root instanceof Root) || v == null) return null; // return context sequence or root of current context return v.size() == 1 ? Root.root(v) : v; }
@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); }
/** * 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; }
@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; }
/** * 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; }
/** * Returns true if all arguments are values. * * @return result of check */ protected final boolean allAreValues() { for (final Expr e : exprs) if (!e.isValue()) return false; return true; }