/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.foundationdb.qp.operator;
/**
* The third of the three complete implementations of the CursorBase
* interface.
*
* The MultiChainedCursor works in the middle of the operator tree, taking
* input from two input operators and passing the resulting aggregation
* through next()
*
* The MultiChainedCursor assumes nothing about the QueryBindings,
* in general does not use them, and only passes them along to either
* parent or child.
*
* @See LeafCursor
* @see ChainedCursor
*
* Used by:
* @see Except_Ordered$Execution
* @see HKeyUnion_Ordered$Execution
* @see Intersect_Ordered$Execution
* @see Union_Ordered$Execution
* @see UnionAll_Default$Execution
*/
public abstract class MultiChainedCursor extends OperatorCursor {
protected Cursor leftInput;
protected Cursor rightInput;
protected final QueryBindingsCursor bindingsCursor;
protected MultiChainedCursor(QueryContext context, QueryBindingsCursor bindingsCursor) {
super(context);
MultipleQueryBindingsCursor multiple = new MultipleQueryBindingsCursor(bindingsCursor);
this.bindingsCursor = multiple;
this.leftInput = left().cursor(context, multiple.newCursor());
this.rightInput = right().cursor(context, multiple.newCursor());
}
protected abstract Operator left();
protected abstract Operator right();
@Override
public void open() {
CursorLifecycle.checkClosed(leftInput);
CursorLifecycle.checkClosed(rightInput);
leftInput.open();
rightInput.open();
super.open();
}
@Override
public void close() {
try {
if (CURSOR_LIFECYCLE_ENABLED) {
CursorLifecycle.checkIdleOrActive(leftInput);
CursorLifecycle.checkIdleOrActive(rightInput);
}
leftInput.close();
rightInput.close();
} finally {
super.close();
}
}
@Override
public void openBindings() {
bindingsCursor.openBindings();
leftInput.openBindings();
rightInput.openBindings();
}
@Override
public QueryBindings nextBindings() {
CursorLifecycle.checkClosed(this);
QueryBindings bindings = bindingsCursor.nextBindings();
QueryBindings other = leftInput.nextBindings();
assert (bindings == other);
other = rightInput.nextBindings();
assert (bindings == other);
return bindings;
}
@Override
public void closeBindings() {
bindingsCursor.closeBindings();
leftInput.closeBindings();
rightInput.closeBindings();
}
@Override
public void cancelBindings(QueryBindings bindings) {
CursorLifecycle.checkClosed(this);
//close(); // In case override maintains some additional state.
leftInput.cancelBindings(bindings);
rightInput.cancelBindings(bindings);
bindingsCursor.cancelBindings(bindings);
}
}