package org.openanzo.glitter.query.validator; import java.util.Iterator; import java.util.List; import org.openanzo.glitter.expression.AggregateFunction; import org.openanzo.glitter.query.Projection; import org.openanzo.glitter.query.QueryInformation; import org.openanzo.glitter.query.QueryValidator; import org.openanzo.glitter.syntax.abstrakt.Expression; import org.openanzo.glitter.syntax.abstrakt.FunctionCall; import org.openanzo.glitter.syntax.abstrakt.SimpleExpression; import org.openanzo.rdf.Variable; /** * Checks that variables projected outside an aggregate function in an aggregated query occur in the query's GROUP BY clause * @author lee <lee@cambridgesemantics.com> * */ public class AggregateVariableValidator implements QueryValidator { private Variable invalidVariable = null; public String getValidationError() { return invalidVariable + " is used outside an aggregate function and is not in the GROUP BY clause"; } public String getValidatorDescription() { return "Checks that variables projected outside an aggregate function in an aggregated query occur in the query's GROUP BY clause"; } public boolean validateQuery(QueryInformation query) { if (query.getQueryResultForm() instanceof Projection) { Projection p = (Projection) query.getQueryResultForm(); List<Variable> groupByVariables = p.getGroupByVariables(); if (p.isAggregateProjection()) { Iterator<Variable> aliases = p.getResultVariables().iterator(); for (Expression e : p.getProjectedExpressions()) { Variable alias = aliases.next(); if ((this.invalidVariable = checkProjectedExpressionInAggregate(e, null, alias, groupByVariables)) != null) return false; } } } return true; } // returns the failing variable, if any private Variable checkProjectedExpressionInAggregate(Expression e, Expression parent, Variable alias, List<Variable> groupByVariables) { if (e instanceof SimpleExpression) { SimpleExpression se = (SimpleExpression) e; boolean parentIsAggregate = parent != null && parent instanceof FunctionCall && ((FunctionCall) parent).getFunction() instanceof AggregateFunction; if (!parentIsAggregate && se.getTerm() instanceof Variable && !groupByVariables.contains(se.getTerm()) && !groupByVariables.contains(alias)) return (Variable) se.getTerm(); } else if (e instanceof FunctionCall) { FunctionCall fc = (FunctionCall) e; Variable v; for (Expression arg : fc.getArguments()) if ((v = checkProjectedExpressionInAggregate(arg, e, alias, groupByVariables)) != null) return v; } return null; } }