package org.basex.query.expr; import org.basex.query.QueryException; import org.basex.query.expr.CmpV.Op; import org.basex.query.func.StandardFunc; import org.basex.query.func.Function; import org.basex.query.item.Bln; import org.basex.query.item.Item; import org.basex.query.item.Type; import org.basex.query.path.AxisPath; import org.basex.util.InputInfo; /** * Abstract comparison. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public abstract class Cmp extends Arr { /** * Constructor. * @param ii input info * @param e1 first expression * @param e2 second expression */ Cmp(final InputInfo ii, final Expr e1, final Expr e2) { super(ii, e1, e2); } /** * Swaps the operands of the expression, if better performance is expected. * The operator itself needs to be swapped by the calling expression. * @return resulting expression */ final boolean swap() { // move value or path without root to second position final boolean swap = expr[0].isValue() && !expr[1].isValue() || expr[0] instanceof AxisPath && ((AxisPath) expr[0]).root != null && expr[1] instanceof AxisPath && ((AxisPath) expr[1]).root == null; if(swap) { final Expr tmp = expr[0]; expr[0] = expr[1]; expr[1] = tmp; } return swap; } /** * If possible, inverts the operands of the expression. * @return original or modified expression */ public abstract Cmp invert(); /** * This method is called if the first operand of the comparison * expression is a {@code count()} function. * @param o comparison operator * @return resulting expression * @throws QueryException query exception */ final Expr compCount(final Op o) throws QueryException { // evaluate argument final Expr a = expr[1]; if(!a.isItem()) return this; final Item it = (Item) a; final Type ip = it.type; if(!ip.isNumber() && !ip.isUntyped()) return this; final double v = it.dbl(input); // TRUE: c > (v<0), c != (v<0), c >= (v<=0), c != not-int(v) if((o == Op.GT || o == Op.NE) && v < 0 || o == Op.GE && v <= 0 || o == Op.NE && v != (int) v) return Bln.TRUE; // FALSE: c < (v<=0), c <= (v<0), c = (v<0), c = not-int(v) if(o == Op.LT && v <= 0 || (o == Op.LE || o == Op.EQ) && v < 0 || o == Op.EQ && v != (int) v) return Bln.FALSE; // EXISTS: c > (v<1), c >= (v<=1), c != (v=0) if(o == Op.GT && v < 1 || o == Op.GE && v <= 1 || o == Op.NE && v == 0) return Function.EXISTS.get(input, ((StandardFunc) expr[0]).expr); // EMPTY: c < (v<=1), c <= (v<1), c = (v=0) if(o == Op.LT && v <= 1 || o == Op.LE && v < 1 || o == Op.EQ && v == 0) return Function.EMPTY.get(input, ((StandardFunc) expr[0]).expr); return this; } }