/**
* 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;
import com.foundationdb.qp.row.Row;
import com.foundationdb.qp.rowtype.RowType;
import com.foundationdb.server.explain.CompoundExplainer;
import com.foundationdb.server.explain.ExplainContext;
import com.foundationdb.server.explain.std.SortOperatorExplainer;
import com.foundationdb.util.ArgumentValidation;
import com.foundationdb.util.tap.InOutTap;
import com.foundationdb.qp.storeadapter.Sorter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
<h1>Overview</h1>
Sort_General generates an output stream containing all the rows of the input stream, sorted according to an
ordering specification. The "General" in the name refers to the flexible implementation which is provided by
the underlying {@link StoreAdapter}.
<h1>Arguments</h1>
<li><b>Operator inputOperator:</b> Operator providing the input stream.
<li><b>RowType sortType:</b> Type of rows to be sorted.
<li><b>API.Ordering ordering:</b> Specification of ordering, comprising a list of expressions and ascending/descending
specifications.
<li><b>API.SortOption sortOption:</b> Specifies whether duplicates should be kept (PRESERVE_DUPLICATES) or eliminated
(SUPPRESS_DUPLICATES)
<h1>Behavior</h1>
Refer to specific implementations of {@link Sorter} for details.
<h1>Output</h1>
The rows of the input stream, sorted according to the ordering specification. Duplicates are eliminated if
and only if the sortOption is SUPPRESS_DUPLICATES.
<h1>Assumptions</h1>
None.
<h1>Performance</h1>
Refer to specific implementations of {@link Sorter} for details.
<h1>Memory Requirements</h1>
Refer to specific implementations of {@link Sorter} for details.
*/
class Sort_General extends Operator
{
// Object interface
@Override
public String toString()
{
if (sortOption == API.SortOption.PRESERVE_DUPLICATES)
return String.format("%s(%s)", getClass().getSimpleName(), sortType);
else
return String.format("%s(%s, %s)", getClass().getSimpleName(), sortType, sortOption.name());
}
// Operator interface
@Override
public List<Operator> getInputOperators()
{
return Collections.singletonList(inputOperator);
}
@Override
protected Cursor cursor(QueryContext context, QueryBindingsCursor bindingsCursor)
{
return new Execution(context, inputOperator.cursor(context, bindingsCursor));
}
@Override
public RowType rowType()
{
return sortType;
}
@Override
public void findDerivedTypes(Set<RowType> derivedTypes)
{
inputOperator.findDerivedTypes(derivedTypes);
derivedTypes.add(sortType);
}
@Override
public String describePlan()
{
return describePlan(inputOperator);
}
// Sort_General interface
public Sort_General(Operator inputOperator,
RowType sortType,
API.Ordering ordering,
API.SortOption sortOption)
{
ArgumentValidation.notNull("sortType", sortType);
ArgumentValidation.isGT("ordering.columns()", ordering.sortColumns(), 0);
this.inputOperator = inputOperator;
this.sortType = sortType;
this.ordering = ordering;
this.sortOption = sortOption;
}
// Class state
private static final InOutTap TAP_OPEN = OPERATOR_TAP.createSubsidiaryTap("operator: Sort_General open");
private static final InOutTap TAP_NEXT = OPERATOR_TAP.createSubsidiaryTap("operator: Sort_General next");
private static final InOutTap TAP_LOAD = OPERATOR_TAP.createSubsidiaryTap("operator: Sort_General load");
private static final Logger LOG = LoggerFactory.getLogger(Sort_General.class);
// Object state
private final Operator inputOperator;
private final RowType sortType;
private final API.Ordering ordering;
private final API.SortOption sortOption;
@Override
public CompoundExplainer getExplainer(ExplainContext context)
{
return new SortOperatorExplainer(getName(), sortOption, sortType, inputOperator, ordering, context);
}
// Inner classes
private class Execution extends ChainedCursor
{
// Cursor interface
@Override
public void open()
{
TAP_OPEN.in();
try {
super.open();
output = new SorterToCursorAdapter(adapter(), context, bindings, input, sortType, ordering, sortOption, TAP_LOAD);
output.open();
} finally {
TAP_OPEN.out();
}
}
@Override
public Row next()
{
Row row = null;
if (TAP_NEXT_ENABLED) {
TAP_NEXT.in();
}
try {
if (CURSOR_LIFECYCLE_ENABLED) {
CursorLifecycle.checkIdleOrActive(this);
}
checkQueryCancelation();
row = output.next();
if (row == null) {
setIdle();
}
} finally {
if (TAP_NEXT_ENABLED) {
TAP_NEXT.out();
}
}
if (LOG_EXECUTION) {
LOG.debug("Sort_General: yield {}", row);
}
return row;
}
@Override
public void close()
{
super.close();
output.close();
}
// Execution interface
Execution(QueryContext context, Cursor input)
{
super(context, input);
}
// Object state
private RowCursor output;
}
}