use of org.eclipse.rdf4j.query.algebra.Distinct 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.Distinct in project rdf4j by eclipse.
the class TupleExprBuilder method handlePathModifiers.
private TupleExpr handlePathModifiers(Scope scope, Var subjVar, TupleExpr te, Var endVar, Var contextVar, long lowerBound, long upperBound) throws VisitorException {
TupleExpr result = te;
if (lowerBound >= 0L) {
if (lowerBound < upperBound) {
if (upperBound < Long.MAX_VALUE) {
// upperbound is fixed-length
// create set of unions for all path lengths between lower
// and upper bound.
Union union = new Union();
Union currentUnion = union;
for (long length = lowerBound; length < upperBound; length++) {
TupleExpr path = createPath(scope, subjVar, te, endVar, contextVar, length);
currentUnion.setLeftArg(path);
if (length == upperBound - 1) {
path = createPath(scope, subjVar, te, endVar, contextVar, length + 1);
currentUnion.setRightArg(path);
} else {
Union nextUnion = new Union();
currentUnion.setRightArg(nextUnion);
currentUnion = nextUnion;
}
}
ProjectionElemList pelist = new ProjectionElemList();
for (String name : union.getAssuredBindingNames()) {
ProjectionElem pe = new ProjectionElem(name);
pelist.addElement(pe);
}
result = new Distinct(new Projection(union, pelist, false));
} else {
// upperbound is abitrary-length
result = new ArbitraryLengthPath(scope, subjVar, te, endVar, contextVar, lowerBound);
}
} else {
// create single path of fixed length.
TupleExpr path = createPath(scope, subjVar, te, endVar, contextVar, lowerBound);
result = path;
}
}
return result;
}
use of org.eclipse.rdf4j.query.algebra.Distinct in project rdf4j by eclipse.
the class ConstructorBuilder method buildConstructor.
private TupleExpr buildConstructor(TupleExpr bodyExpr, TupleExpr constructExpr, boolean explicitConstructor, boolean distinct, boolean reduced) {
TupleExpr result = bodyExpr;
// Retrieve all StatementPattern's from the construct expression
List<StatementPattern> statementPatterns = StatementPatternCollector.process(constructExpr);
Set<Var> constructVars = getConstructVars(statementPatterns);
// Finally, the spo-bindings are again filtered for duplicates.
if (distinct || reduced) {
// Create projection that removes all bindings that are not used in the
// constructor
ProjectionElemList projElemList = new ProjectionElemList();
for (Var var : constructVars) {
// the distinct
if (!var.isAnonymous() && !var.hasValue()) {
projElemList.addElement(new ProjectionElem(var.getName()));
}
}
result = new Projection(result, projElemList);
// Filter the duplicates from these projected bindings
if (distinct) {
result = new Distinct(result);
} else {
result = new Reduced(result);
}
}
// Create BNodeGenerator's for all anonymous variables
Map<Var, ExtensionElem> extElemMap = new HashMap<Var, ExtensionElem>();
for (Var var : constructVars) {
if (var.isAnonymous() && !extElemMap.containsKey(var)) {
ValueExpr valueExpr = null;
if (var.hasValue()) {
valueExpr = new ValueConstant(var.getValue());
} else if (explicitConstructor) {
// only generate bnodes in case of an explicit constructor
valueExpr = new BNodeGenerator();
}
if (valueExpr != null) {
extElemMap.put(var, new ExtensionElem(valueExpr, var.getName()));
}
}
}
if (!extElemMap.isEmpty()) {
result = new Extension(result, extElemMap.values());
}
// Create a Projection for each StatementPattern in the constructor
List<ProjectionElemList> projections = new ArrayList<ProjectionElemList>();
for (StatementPattern sp : statementPatterns) {
ProjectionElemList projElemList = new ProjectionElemList();
projElemList.addElement(new ProjectionElem(sp.getSubjectVar().getName(), "subject"));
projElemList.addElement(new ProjectionElem(sp.getPredicateVar().getName(), "predicate"));
projElemList.addElement(new ProjectionElem(sp.getObjectVar().getName(), "object"));
projections.add(projElemList);
}
if (projections.size() == 1) {
result = new Projection(result, projections.get(0));
// Note: no need to apply the second duplicate elimination step if
// there's just one projection
} else if (projections.size() > 1) {
result = new MultiProjection(result, projections);
if (distinct) {
// Add another distinct to filter duplicate statements
result = new Distinct(result);
} else if (reduced) {
result = new Reduced(result);
}
} else {
// Empty constructor
result = new EmptySet();
}
return result;
}
use of org.eclipse.rdf4j.query.algebra.Distinct in project rdf4j by eclipse.
the class QueryModelBuilder method visit.
@Override
public TupleExpr visit(ASTGraphUnion node, Object data) throws VisitorException {
TupleExpr leftArg = (TupleExpr) node.getLeftArg().jjtAccept(this, null);
TupleExpr rightArg = (TupleExpr) node.getRightArg().jjtAccept(this, null);
TupleExpr result = new Union(leftArg, rightArg);
if (node.isDistinct()) {
result = new Distinct(result);
}
return result;
}
use of org.eclipse.rdf4j.query.algebra.Distinct in project rdf4j by eclipse.
the class QueryModelBuilder method visit.
@Override
public TupleExpr visit(ASTTupleUnion node, Object data) throws VisitorException {
TupleExpr leftArg = (TupleExpr) node.getLeftArg().jjtAccept(this, null);
TupleExpr rightArg = (TupleExpr) node.getRightArg().jjtAccept(this, null);
TupleExpr result = new Union(leftArg, rightArg);
if (node.isDistinct()) {
result = new Distinct(result);
}
return result;
}
Aggregations