use of org.eclipse.rdf4j.query.algebra.AggregateOperator in project rdf4j by eclipse.
the class TupleExprBuilder method visit.
@Override
public TupleExpr visit(ASTSelect node, Object data) throws VisitorException {
TupleExpr result = (TupleExpr) data;
final Order orderClause = result instanceof Order ? (Order) result : null;
Extension extension = new Extension();
ProjectionElemList projElemList = new ProjectionElemList();
GroupFinder groupFinder = new GroupFinder();
result.visit(groupFinder);
Group group = groupFinder.getGroup();
boolean existingGroup = group != null;
List<String> aliasesInProjection = new ArrayList<String>();
for (ASTProjectionElem projElemNode : node.getProjectionElemList()) {
Node child = projElemNode.jjtGetChild(0);
String alias = projElemNode.getAlias();
if (alias != null) {
// aliased projection element
if (aliasesInProjection.contains(alias)) {
throw new VisitorException("duplicate use of alias '" + alias + "' in projection.");
}
// check if alias is not previously used.
if (result.getBindingNames().contains(alias)) {
throw new VisitorException("projection alias '" + alias + "' was previously used");
}
aliasesInProjection.add(alias);
ValueExpr valueExpr = (ValueExpr) child.jjtAccept(this, null);
String targetName = alias;
String sourceName = alias;
if (child instanceof ASTVar) {
sourceName = ((ASTVar) child).getName();
}
ProjectionElem elem = new ProjectionElem(sourceName, targetName);
projElemList.addElement(elem);
AggregateCollector collector = new AggregateCollector();
valueExpr.visit(collector);
if (collector.getOperators().size() > 0) {
elem.setAggregateOperatorInExpression(true);
for (AggregateOperator operator : collector.getOperators()) {
// Apply implicit grouping if necessary
if (group == null) {
group = new Group(result);
}
if (operator.equals(valueExpr)) {
group.addGroupElement(new GroupElem(alias, operator));
extension.setArg(group);
} else {
ValueExpr expr = (ValueExpr) operator.getParentNode();
Extension anonymousExtension = new Extension();
Var anonVar = createAnonVar();
expr.replaceChildNode(operator, anonVar);
anonymousExtension.addElement(new ExtensionElem(operator, anonVar.getName()));
anonymousExtension.setArg(result);
result = anonymousExtension;
group.addGroupElement(new GroupElem(anonVar.getName(), operator));
}
if (!existingGroup) {
result = group;
}
}
}
// add extension element reference to the projection element and
// to
// the extension
ExtensionElem extElem = new ExtensionElem(valueExpr, alias);
extension.addElement(extElem);
elem.setSourceExpression(extElem);
} else if (child instanceof ASTVar) {
Var projVar = (Var) child.jjtAccept(this, null);
ProjectionElem elem = new ProjectionElem(projVar.getName());
projElemList.addElement(elem);
VarCollector whereClauseVarCollector = new VarCollector();
result.visit(whereClauseVarCollector);
if (!whereClauseVarCollector.collectedVars.contains(projVar)) {
ExtensionElem extElem = new ExtensionElem(projVar, projVar.getName());
extension.addElement(extElem);
elem.setSourceExpression(extElem);
}
} else {
throw new IllegalStateException("required alias for non-Var projection elements not found");
}
}
if (!extension.getElements().isEmpty()) {
if (orderClause != null) {
// Extensions produced by SELECT expressions should be nested
// inside
// the ORDER BY clause, to make sure
// sorting can work on the newly introduced variable. See
// SES-892
// and SES-1809.
TupleExpr arg = orderClause.getArg();
extension.setArg(arg);
orderClause.setArg(extension);
result = orderClause;
} else {
extension.setArg(result);
result = extension;
}
}
result = new Projection(result, projElemList);
if (group != null) {
for (ProjectionElem elem : projElemList.getElements()) {
if (!elem.hasAggregateOperatorInExpression()) {
Set<String> groupNames = group.getBindingNames();
ExtensionElem extElem = elem.getSourceExpression();
if (extElem != null) {
ValueExpr expr = extElem.getExpr();
VarCollector collector = new VarCollector();
expr.visit(collector);
for (Var var : collector.getCollectedVars()) {
if (!groupNames.contains(var.getName())) {
throw new VisitorException("variable '" + var.getName() + "' in projection not present in GROUP BY.");
}
}
} else {
if (!groupNames.contains(elem.getTargetName())) {
throw new VisitorException("variable '" + elem.getTargetName() + "' in projection not present in GROUP BY.");
} else if (!groupNames.contains(elem.getSourceName())) {
throw new VisitorException("variable '" + elem.getSourceName() + "' in projection not present in GROUP BY.");
}
}
}
}
}
if (node.isSubSelect()) {
// set context var at the level of the projection. This allows us
// to distinguish named graphs selected in the
// outer query from named graphs selected as part of the sub-select.
((Projection) result).setProjectionContext(graphPattern.getContextVar());
}
if (node.isDistinct()) {
result = new Distinct(result);
} else if (node.isReduced()) {
result = new Reduced(result);
}
return result;
}
use of org.eclipse.rdf4j.query.algebra.AggregateOperator in project rdf4j by eclipse.
the class TupleExprBuilder method processOrderClause.
private TupleExpr processOrderClause(ASTOrderClause orderNode, TupleExpr tupleExpr, Group group) throws VisitorException {
if (orderNode != null) {
@SuppressWarnings("unchecked") List<OrderElem> orderElements = (List<OrderElem>) orderNode.jjtAccept(this, null);
for (OrderElem orderElem : orderElements) {
// retrieve any aggregate operators from the order element.
AggregateCollector collector = new AggregateCollector();
collector.meet(orderElem);
Extension extension = new Extension();
for (AggregateOperator operator : collector.getOperators()) {
Var var = createAnonVar();
// replace occurrence of the operator in the order condition
// with the variable.
AggregateOperatorReplacer replacer = new AggregateOperatorReplacer(operator, var);
replacer.meet(orderElem);
// create an extension linking the operator to the variable
// name.
String alias = var.getName();
ExtensionElem pe = new ExtensionElem(operator, alias);
extension.addElement(pe);
// add the aggregate operator to the group.
GroupElem ge = new GroupElem(alias, operator);
group.addGroupElement(ge);
}
if (!extension.getElements().isEmpty()) {
extension.setArg(tupleExpr);
tupleExpr = extension;
}
}
tupleExpr = new Order(tupleExpr, orderElements);
}
return tupleExpr;
}
use of org.eclipse.rdf4j.query.algebra.AggregateOperator in project rdf4j by eclipse.
the class TupleExprBuilder method processHavingClause.
private TupleExpr processHavingClause(ASTHavingClause havingNode, TupleExpr tupleExpr, Group group) throws VisitorException {
if (havingNode != null) {
// create an implicit group
if (group == null) {
group = new Group(tupleExpr);
}
ValueExpr expr = (ValueExpr) havingNode.jjtGetChild(0).jjtAccept(this, tupleExpr);
// retrieve any aggregate operators from the expression.
AggregateCollector collector = new AggregateCollector();
collector.meetOther(expr);
// replace operator occurrences with an anonymous var, and alias it
// to the group
Extension extension = new Extension();
for (AggregateOperator operator : collector.getOperators()) {
Var var = createAnonVar();
// replace occurrence of the operator in the filter expression
// with the variable.
AggregateOperatorReplacer replacer = new AggregateOperatorReplacer(operator, var);
replacer.meetOther(expr);
String alias = var.getName();
// create an extension linking the operator to the variable
// name.
ExtensionElem pe = new ExtensionElem(operator, alias);
extension.addElement(pe);
// add the aggregate operator to the group.
GroupElem ge = new GroupElem(alias, operator);
// FIXME quite often the aggregate in the HAVING clause will be
// a duplicate of an aggregate in the projection. We could
// perhaps
// optimize for that, to avoid having to evaluate twice.
group.addGroupElement(ge);
}
extension.setArg(group);
tupleExpr = new Filter(extension, expr);
}
return tupleExpr;
}
Aggregations