package org.basex.query.flwor; import static org.basex.query.QueryText.*; import static org.basex.util.Token.*; import java.io.IOException; import org.basex.io.serial.Serializer; import org.basex.query.QueryContext; import org.basex.query.QueryException; import org.basex.query.expr.Expr; import org.basex.query.item.Dbl; import org.basex.query.item.Item; import org.basex.query.item.Int; import org.basex.query.item.SeqType; import org.basex.query.item.SeqType.Occ; import org.basex.query.iter.Iter; import org.basex.query.util.Var; import org.basex.util.InputInfo; /** * For clause. * * @author BaseX Team 2005-12, BSD License * @author Christian Gruen */ public final class For extends ForLet { /** Positional variable. */ final Var pos; /** Full-text score. */ final Var score; /** * Constructor. * @param ii input info * @param e variable input * @param v variable */ public For(final InputInfo ii, final Expr e, final Var v) { this(ii, e, v, null, null); } /** * Constructor. * @param ii input info * @param e variable input * @param v variable * @param p positional variable * @param s score variable */ public For(final InputInfo ii, final Expr e, final Var v, final Var p, final Var s) { super(ii, e, v); pos = p; score = s; } @Override public For comp(final QueryContext ctx) throws QueryException { expr = checkUp(expr, ctx).comp(ctx); type = expr.type(); size = expr.size(); if(ctx.grouping) { var.ret = SeqType.get(type.type, Occ.ZM); } else { var.size = Math.min(1, size); var.ret = type.type.seqType(); } ctx.vars.add(var); if(pos != null) ctx.vars.add(pos); if(score != null) ctx.vars.add(score); return this; } @Override public Iter iter(final QueryContext ctx) { final Var v = var.copy(); final Var p = pos != null ? pos.copy() : null; final Var s = score != null ? score.copy() : null; return new Iter() { /** Variable stack size. */ private int vs; /** Iterator flag. */ private Iter ir; /** Counter. */ private int c; @Override public Item next() throws QueryException { init(); final Item it = ir.next(); if(it != null) return bind(it, ++c); reset(); return null; } @Override public long size() { return expr.size(); } @Override public Item get(final long i) throws QueryException { init(); return bind(ir.get(i), i + 1); } @Override public boolean reset() { if(ir != null) { ctx.vars.size(vs); ir.reset(); ir = null; c = 0; } return true; } /** * Initializes the iterator. * @throws QueryException query exception */ private void init() throws QueryException { if(ir == null) { vs = ctx.vars.size(); ir = ctx.iter(expr); ctx.vars.add(v); if(p != null) ctx.vars.add(p); if(s != null) ctx.vars.add(s); } } /** * Binds an item to the loop variables. * @param it item * @param i position counter * @return specified item * @throws QueryException query exception */ private Item bind(final Item it, final long i) throws QueryException { v.bind(it, ctx); if(p != null) p.bind(Int.get(i), ctx); if(s != null) s.bind(Dbl.get(it.score()), ctx); return it; } }; } @Override boolean simple(final boolean one) { return pos == null && score == null && (!one || type.one() || size == 1); } @Override public void plan(final Serializer ser) throws IOException { ser.openElement(this, VAR, token(var.toString())); if(pos != null) ser.attribute(POS, token(pos.toString())); if(score != null) ser.attribute(token(SCORE), token(score.toString())); expr.plan(ser); ser.closeElement(); } @Override public String toString() { final StringBuilder sb = new StringBuilder(FOR + ' ' + var + ' '); if(pos != null) sb.append(AT + ' ' + pos + ' '); if(score != null) sb.append(SCORE + ' ' + score + ' '); return sb.append(IN + ' ' + expr).toString(); } @Override public boolean declares(final Var v) { return var.is(v) || pos != null && pos.is(v) || score != null && score.is(v); } @Override public Var[] vars() { if(pos != null) { if(score != null) return new Var[]{ var, pos, score }; return new Var[]{ var, pos }; } if(score != null) return new Var[]{ var, score }; return new Var[]{ var }; } }