/** * Computes the number of results. * * @param qc query context (may be @code null) * @return number of results */ private long size(final QueryContext qc) { final Value rt = initial(qc); // skip computation if value is not a document node if (rt == null || rt.type != NodeType.DOC) return -1; final Data data = rt.data(); // skip computation if no database instance is available, is out-of-date or // if context does not contain all database nodes if (data == null || !data.meta.uptodate || data.resources.docs().size() != rt.size()) return -1; ArrayList<PathNode> nodes = data.paths.root(); long m = 1; final int sl = steps.length; for (int s = 0; s < sl; s++) { final Step curr = axisStep(s); if (curr != null) { nodes = curr.nodes(nodes, data); if (nodes == null) return -1; } else if (s + 1 == sl) { m = steps[s].size(); } else { // stop if a non-axis step is not placed last return -1; } } long sz = 0; for (final PathNode pn : nodes) sz += pn.stats.count; return sz * m; }
/** * 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; }
/** * Returns a document test. This test will be called by {@link AxisPath#index} if the context * value only consists of database nodes. * * @param rt root value * @return document test */ static Test get(final Value rt) { // use simple test if database contains only one document final Data data = rt.data(); if (data.meta.ndocs == 1) return Test.DOC; // adopt nodes from existing sequence if (rt instanceof DBNodeSeq) { final DBNodeSeq seq = (DBNodeSeq) rt; return seq.all() ? Test.DOC : new InvDocTest(new IntList(seq.pres()), data); } // loop through all documents and add pre values of documents // not more than 2^31 documents supported final IntList il = new IntList((int) rt.size()); for (final Item it : rt) il.add(((DBNode) it).pre()); return new InvDocTest(il, data); }