001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007.
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.query.algebra.evaluation.iterator;
007:
008: import java.util.Set;
009:
010: import info.aduna.iteration.CloseableIteration;
011: import info.aduna.iteration.LookAheadIteration;
012:
013: import org.openrdf.query.BindingSet;
014: import org.openrdf.query.QueryEvaluationException;
015: import org.openrdf.query.algebra.LeftJoin;
016: import org.openrdf.query.algebra.evaluation.QueryBindingSet;
017: import org.openrdf.query.algebra.evaluation.ValueExprEvaluationException;
018: import org.openrdf.query.algebra.evaluation.EvaluationStrategy;
019:
020: public class LeftJoinIterator extends
021: LookAheadIteration<BindingSet, QueryEvaluationException> {
022:
023: /*-----------*
024: * Constants *
025: *-----------*/
026:
027: private EvaluationStrategy strategy;
028:
029: private final LeftJoin join;
030:
031: /**
032: * The set of binding names that are "in scope" for the filter. The filter
033: * must not include bindings that are (only) included because of the
034: * depth-first evaluation strategy in the evaluation of the constraint.
035: */
036: private final Set<String> scopeBindingNames;
037:
038: /*-----------*
039: * Variables *
040: *-----------*/
041:
042: private CloseableIteration<BindingSet, QueryEvaluationException> leftIter;
043:
044: private CloseableIteration<BindingSet, QueryEvaluationException> rightIter;
045:
046: /*--------------*
047: * Constructors *
048: *--------------*/
049:
050: public LeftJoinIterator(EvaluationStrategy strategy, LeftJoin join,
051: BindingSet bindings) throws QueryEvaluationException {
052: this .strategy = strategy;
053: this .join = join;
054: this .scopeBindingNames = join.getBindingNames();
055:
056: leftIter = strategy.evaluate(join.getLeftArg(), bindings);
057: }
058:
059: /*---------*
060: * Methods *
061: *---------*/
062:
063: @Override
064: protected BindingSet getNextElement()
065: throws QueryEvaluationException {
066: while (rightIter != null || leftIter.hasNext()) {
067: BindingSet leftBindings = null;
068:
069: if (rightIter == null) {
070: // Use left arg's bindings in case join fails
071: leftBindings = leftIter.next();
072: rightIter = strategy.evaluate(join.getRightArg(),
073: leftBindings);
074: }
075:
076: while (rightIter.hasNext()) {
077: BindingSet rightBindings = rightIter.next();
078:
079: try {
080: if (join.getCondition() == null) {
081: return rightBindings;
082: } else {
083: // Limit the bindings to the ones that are in scope for this
084: // filter
085: QueryBindingSet scopeBindings = new QueryBindingSet(
086: rightBindings);
087: scopeBindings.retainAll(scopeBindingNames);
088:
089: if (strategy.isTrue(join.getCondition(),
090: scopeBindings)) {
091: return rightBindings;
092: }
093: }
094: } catch (ValueExprEvaluationException e) {
095: // Ignore, condition not evaluated successfully
096: }
097: }
098:
099: rightIter.close();
100: rightIter = null;
101:
102: if (leftBindings != null) {
103: // Join failed, return left arg's bindings
104: return leftBindings;
105: }
106: }
107:
108: return null;
109: }
110:
111: @Override
112: protected void handleClose() throws QueryEvaluationException {
113: if (rightIter != null) {
114: rightIter.close();
115: rightIter = null;
116: }
117:
118: leftIter.close();
119:
120: super.handleClose();
121: }
122: }
|