/** * 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; }
@Override public boolean has(final Flag flag) { for (final FTExpr e : exprs) if (e.has(flag)) return true; return false; }