/* * JBoss, Home of Professional Open Source. * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. Some portions may be licensed * to Red Hat, Inc. under one or more contributor license agreements. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301 USA. */ package org.teiid.query.processor; import java.util.List; import org.teiid.common.buffer.AbstractTupleSource; import org.teiid.common.buffer.BlockedException; import org.teiid.common.buffer.TupleBatch; import org.teiid.common.buffer.TupleBuffer; import org.teiid.core.TeiidComponentException; import org.teiid.core.TeiidProcessingException; import org.teiid.query.processor.BatchCollector.BatchProducer; /** * A BatchIterator provides an iterator interface to a {@link BatchProducer}. * By setting {@link #setBuffer(TupleBuffer)}, * the iterator can copy on read into a {@link TupleBuffer} for repeated reading. * * Note that the saveOnMark buffering only lasts until the next mark is set. */ public class BatchIterator extends AbstractTupleSource { private final BatchProducer source; private boolean saveOnMark; private TupleBuffer buffer; private boolean done; private boolean mark; public BatchIterator(BatchProducer source) { this.source = source; } @Override protected TupleBatch getBatch(long row) throws TeiidComponentException, TeiidProcessingException { throw new UnsupportedOperationException(); } @Override protected List<?> finalRow() throws TeiidComponentException, TeiidProcessingException { if (this.buffer != null && this.getCurrentIndex() <= this.buffer.getRowCount()) { batch = this.buffer.getBatch(this.getCurrentIndex()); } while (available() < 1) { if (done) { return null; } batch = source.nextBatch(); done = batch.getTerminationFlag(); if (buffer != null && (!saveOnMark || mark) && !buffer.isForwardOnly()) { buffer.addTupleBatch(batch, true); } if (done && buffer != null) { this.buffer.close(); } } return getCurrentTuple(); } @Override protected List<?> getCurrentTuple() throws TeiidComponentException, BlockedException, TeiidProcessingException { List<?> tuple = super.getCurrentTuple(); saveTuple(tuple); return tuple; } private void saveTuple(List<?> tuple) throws TeiidComponentException { if (tuple != null && mark && saveOnMark && this.getCurrentIndex() > this.buffer.getRowCount()) { this.buffer.setRowCount(this.getCurrentIndex() - 1); this.buffer.addTuple(tuple); } } public long available() { if (batch != null && batch.containsRow(getCurrentIndex())) { return batch.getEndRow() - getCurrentIndex() + 1; } return 0; } public void setBuffer(TupleBuffer buffer, boolean saveOnMark) { this.buffer = buffer; this.saveOnMark = saveOnMark; } @Override public void closeSource() { if (this.buffer != null) { this.buffer.remove(); this.buffer = null; } } @Override public void reset() { super.reset(); if (this.buffer != null) { mark = false; return; } } @Override public void mark() throws TeiidComponentException { super.mark(); if (this.buffer != null && saveOnMark && this.getCurrentIndex() > this.buffer.getRowCount()) { this.buffer.purge(); } mark = true; saveTuple(this.currentTuple); } @Override public void setPosition(long position) { if (this.buffer == null && position < getCurrentIndex() && position < (this.batch != null ? batch.getBeginRow() : Long.MAX_VALUE)) { throw new UnsupportedOperationException("Backwards positioning is not allowed"); //$NON-NLS-1$ } super.setPosition(position); } /** * non-destructive method to set the mark * @return true if the mark was set */ public boolean ensureSave() { if (!saveOnMark || mark) { return false; } mark = true; return true; } public void disableSave() { if (buffer != null) { this.saveOnMark = true; this.mark = false; if (batch != null && batch.getEndRow() <= this.buffer.getRowCount()) { this.batch = null; } } } public void readAhead(long limit) throws TeiidComponentException, TeiidProcessingException { if (buffer == null || done) { return; } if (this.buffer.getManagedRowCount() >= limit) { return; } if (this.batch != null && this.buffer.getRowCount() < this.batch.getEndRow() && !this.buffer.isForwardOnly()) { //haven't saved already this.buffer.addTupleBatch(this.batch, true); } TupleBatch tb = source.nextBatch(); done = tb.getTerminationFlag(); this.buffer.addTupleBatch(tb, true); if (done) { this.buffer.close(); } } public TupleBuffer getBuffer() { return buffer; } }