package org.basex.query.flwor; import static org.basex.query.QueryText.*; 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.expr.ParseExpr; import org.basex.query.item.SeqType; import org.basex.query.iter.Iter; import org.basex.query.util.Var; import org.basex.util.InputInfo; import org.basex.util.TokenBuilder; import org.basex.util.Util; /** * Implementation of the group by clause. * * @author BaseX Team 2005-12, BSD License * @author Michael Seiferle */ public final class Group extends ParseExpr { /** Group by specification. */ private final Var[] groupby; /** Non-grouping variables. */ private final Var[][] nongroup; /** Grouping partition. **/ GroupPartition gp; /** * Constructor. * @param ii input info * @param gb group by expression * @param ng non-grouping variables * @param ngc copies of non-grouping variables */ public Group(final InputInfo ii, final Var[] gb, final Var[] ng, final Var[] ngc) { super(ii); groupby = gb; nongroup = new Var[][]{ ng, ngc }; } /** * Initializes the grouping partition. * @param ob order by specifier */ void init(final Order ob) { gp = new GroupPartition(groupby, nongroup, ob, input); } @Override public Expr comp(final QueryContext ctx) throws QueryException { for(final Var g : groupby) { g.comp(ctx); if(g.ret != null) g.ret = SeqType.get(g.ret.type, 1); } for(final Var v : nongroup[1]) ctx.vars.add(v); return this; } @Override public Iter iter(final QueryContext ctx) { throw Util.notexpected(this); } @Override public boolean uses(final Use use) { for(final Var v : groupby) if(v.uses(use)) return true; return false; } @Override public int count(final Var v) { // non-grouping variables must be counted here (not in the return clause) int c = 0; for(final Var g : groupby) c += g.count(v); for(final Var g : nongroup[0]) c += g.count(v); return c; } @Override public boolean removable(final Var v) { // don't allow removal if variable is used for(final Var g : groupby) if(g.count(v) != 0) return false; for(final Var g : nongroup[0]) if(g.count(v) != 0) return false; return true; } @Override public Expr remove(final Var v) { return this; } @Override public void plan(final Serializer ser) throws IOException { ser.openElement(this); for(int o = 0; o != groupby.length; ++o) groupby[o].plan(ser); ser.closeElement(); } @Override public String toString() { return new TokenBuilder(' ' + GROUP + ' ' + BY + ' '). addSep(groupby, SEP).toString(); } }