package org.basex.query.expr; import static org.basex.query.QueryText.*; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.item.Bln; import org.basex.query.item.Item; import org.basex.query.util.IndexContext; import org.basex.util.Array; import org.basex.util.InputInfo; import org.basex.util.ft.Scoring; /** * And expression. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public final class And extends Logical { /** * Constructor. * @param ii input info * @param e expression list */ public And(final InputInfo ii, final Expr[] e) { super(ii, e); } @Override public Expr comp(final QueryContext ctx) throws QueryException { // remove atomic values final Expr c = super.comp(ctx); if(c != this) return c; // merge predicates if possible Expr[] ex = {}; Pos ps = null; CmpR cr = null; for(final Expr e : expr) { Expr tmp = null; if(e instanceof Pos) { // merge numeric predicates tmp = ps == null ? e : ps.intersect((Pos) e, input); if(!(tmp instanceof Pos)) return tmp; ps = (Pos) tmp; } else if(e instanceof CmpR) { // merge comparisons tmp = cr == null ? e : cr.intersect((CmpR) e); if(tmp instanceof CmpR) cr = (CmpR) tmp; else if(tmp != null) return tmp; } // no optimization found; add original expression if(tmp == null) ex = Array.add(ex, e); } expr = ex; if(ps != null) expr = Array.add(expr, ps); if(cr != null) expr = Array.add(expr, cr); if(ex.length != expr.length) ctx.compInfo(OPTWRITE, this); compFlatten(ctx); // return single expression if it yields a boolean return expr.length == 1 ? compBln(expr[0]) : this; } @Override public Bln item(final QueryContext ctx, final InputInfo ii) throws QueryException { double s = 0; for(final Expr e : expr) { final Item it = e.ebv(ctx, input); if(!it.bool(input)) return Bln.FALSE; s = Scoring.and(s, it.score()); } // no scoring - return default boolean return s == 0 ? Bln.TRUE : Bln.get(s); } @Override public boolean indexAccessible(final IndexContext ic) throws QueryException { int is = 0; final double[] ics = new double[expr.length]; boolean ia = true; for(int e = 0; e < expr.length; ++e) { if(expr[e].indexAccessible(ic) && !ic.seq) { // skip queries with no results if(ic.costs() == 0) return true; // summarize costs ics[e] = ic.costs(); if(is == 0 || ic.costs() < is) is = ic.costs(); } else { ia = false; } } if(ia) { // evaluate arguments with high selectivity first final int[] ord = Array.createOrder(ics, true); final Expr[] ex = new Expr[ics.length]; for(int e = 0; e < expr.length; ++e) ex[e] = expr[ord[e]]; expr = ex; } ic.costs(is); return ia; } @Override public Expr indexEquivalent(final IndexContext ic) throws QueryException { super.indexEquivalent(ic); return new InterSect(input, expr); } @Override public String toString() { return toString(' ' + AND + ' '); } }