/** * 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.storeadapter.indexcursor; import com.foundationdb.qp.expression.IndexKeyRange; import com.foundationdb.qp.operator.API; import com.foundationdb.qp.operator.BindingsAwareCursor; import com.foundationdb.qp.operator.CursorLifecycle; import com.foundationdb.qp.operator.QueryBindings; import com.foundationdb.qp.operator.QueryContext; import com.foundationdb.qp.operator.RowCursorImpl; import com.foundationdb.qp.operator.StoreAdapter; import com.foundationdb.qp.row.Row; import com.foundationdb.util.tap.PointTap; import com.foundationdb.util.tap.Tap; import com.persistit.Key; import com.persistit.Key.Direction; public abstract class IndexCursor extends RowCursorImpl implements BindingsAwareCursor { // Cursor interface @Override public void open() { super.open(); iterationHelper.openIteration(); } @Override public Row next() { CursorLifecycle.checkIdleOrActive(this); return null; } @Override public void close() { try { iterationHelper.closeIteration(); } finally { super.close(); } } @Override public void rebind(QueryBindings bindings) { this.bindings = bindings; } // For use by subclasses protected boolean traverse(Direction dir) { return iterationHelper.traverse(dir); } protected void clear() { iterationHelper.clear(); } protected Key key() { return iterationHelper.key(); } protected Key endKey() { return iterationHelper.endKey(); } // IndexCursor interface public static IndexCursor create(QueryContext context, IndexKeyRange keyRange, API.Ordering ordering, IterationHelper iterationHelper, boolean openAllSubCursors) { IndexCursor indexCursor; if (keyRange != null && keyRange.spatialCoordsIndex()) { if (keyRange.hi() == null) { indexCursor = IndexCursorSpatial_NearPoint.create(context, iterationHelper, keyRange); } else { indexCursor = IndexCursorSpatial_InBox.create(context, iterationHelper, keyRange, openAllSubCursors); } } else if (keyRange != null && keyRange.spatialObjectIndex()) { indexCursor = IndexCursorSpatial_InBox.create(context, iterationHelper, keyRange, openAllSubCursors); } else { SortKeyAdapter<?, ?> adapter = ValueSortKeyAdapter.INSTANCE; assert ordering.allAscending() || ordering.allDescending() : "Index API.ordering not all ascending/descending"; indexCursor = IndexCursorUnidirectional.create(context, iterationHelper, keyRange, ordering, adapter); } return indexCursor; } // For use by subclasses protected IndexCursor(QueryContext context, IterationHelper iterationHelper) { this.context = context; this.adapter = context.getStore(); this.iterationHelper = iterationHelper; } protected Row row() { return iterationHelper.row(); } // Object state protected final QueryContext context; protected final StoreAdapter adapter; protected final IterationHelper iterationHelper; protected QueryBindings bindings; static final PointTap INDEX_TRAVERSE = Tap.createCount("traverse: index cursor"); }