001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.db.table;
031:
032: import com.caucho.db.sql.QueryContext;
033: import com.caucho.db.sql.SelectResult;
034: import com.caucho.db.store.Block;
035: import com.caucho.db.store.Store;
036: import com.caucho.db.store.Transaction;
037: import com.caucho.util.L10N;
038:
039: import java.io.IOException;
040: import java.sql.SQLException;
041:
042: /**
043: * Iterates over a table's rows.
044: */
045: public class TableIterator {
046: private static final L10N L = new L10N(TableIterator.class);
047:
048: private final static byte[] _nullBuffer = new byte[256];
049:
050: private Table _table;
051: private Column[] _columns;
052:
053: private Transaction _xa;
054: private QueryContext _queryContext;
055:
056: private long _blockId;
057: private int _rowLength;
058: private int _rowEnd;
059: private int _rowOffset;
060:
061: private Block _block;
062: private byte[] _buffer;
063:
064: public TableIterator() {
065: }
066:
067: TableIterator(Table table) {
068: init(table);
069: }
070:
071: public void init(Table table) {
072: _table = table;
073:
074: if (table.getId() == 0) {
075: throw new IllegalStateException(L
076: .l("iterating with closed table."));
077: }
078:
079: _columns = table.getColumns();
080:
081: _rowLength = table.getRowLength();
082: _rowEnd = table.getRowEnd();
083: _rowOffset = _rowEnd;
084: _blockId = 0;
085: }
086:
087: /**
088: * Returns the table of the iterator.
089: */
090: public Table getTable() {
091: return _table;
092: }
093:
094: /**
095: * Returns the current block id of the iterator.
096: */
097: public final long getBlockId() {
098: return _blockId;
099: }
100:
101: /**
102: * Sets the current block id of the iterator.
103: */
104: public final void setBlockId(long blockId) {
105: _blockId = blockId;
106: }
107:
108: /**
109: * Returns the current address.
110: */
111: public final long getRowAddress() {
112: return _table.blockIdToAddress(_blockId) + _rowOffset;
113: }
114:
115: /**
116: * Returns the current row offset of the iterator.
117: */
118: public final int getRowOffset() {
119: return _rowOffset;
120: }
121:
122: /**
123: * Sets the current row offset of the iterator.
124: */
125: public final void setRowOffset(int rowOffset) {
126: _rowOffset = rowOffset;
127: }
128:
129: /**
130: * Gets the current block.
131: */
132: public final byte[] getBuffer() {
133: return _buffer;
134: }
135:
136: /**
137: * Returns the transaction for the iterator.
138: */
139: public Transaction getTransaction() {
140: return _xa;
141: }
142:
143: /**
144: * Returns the query context for the iterator.
145: */
146: public QueryContext getQueryContext() {
147: return _queryContext;
148: }
149:
150: public void init(QueryContext queryContext) throws SQLException {
151: init(queryContext.getTransaction());
152:
153: _queryContext = queryContext;
154: }
155:
156: public void init(Transaction xa) throws SQLException {
157: Block block = _block;
158: _block = null;
159: _buffer = null;
160:
161: if (block != null)
162: block.free();
163:
164: _blockId = 0;
165: _rowOffset = Integer.MAX_VALUE / 2;
166: _queryContext = null;
167: _xa = xa;
168:
169: // XXX:
170: /*
171: if (! _xa.isAutoCommit())
172: _xa.lockRead(_table.getLock());
173: */
174: }
175:
176: public void initRow() throws IOException {
177: _rowOffset = -_rowLength;
178: }
179:
180: public void prevRow() {
181: _rowOffset -= _rowLength;
182: }
183:
184: /**
185: * Sets the row.
186: */
187: void setRow(Block block, int rowOffset) {
188: _block = block;
189: _buffer = block.getBuffer();
190: _blockId = block.getBlockId();
191: _rowOffset = rowOffset;
192: }
193:
194: public Block getBlock() {
195: return _block;
196: }
197:
198: /**
199: * Returns the next tuple in the current row.
200: *
201: * @return true if a tuple is found,
202: * or false if the block has no more tuples
203: */
204: public boolean nextRow() throws IOException {
205: int rowOffset = _rowOffset;
206: int rowLength = _rowLength;
207: int rowEnd = _rowEnd;
208: byte[] buffer = _buffer;
209:
210: rowOffset += rowLength;
211: for (; rowOffset < rowEnd; rowOffset += rowLength) {
212: if ((buffer[rowOffset] & Table.ROW_VALID) != 0) {
213: _rowOffset = rowOffset;
214: return true;
215: }
216: }
217:
218: _rowOffset = rowOffset;
219:
220: return false;
221: }
222:
223: /**
224: * Returns the next row.
225: */
226: public boolean next() throws IOException {
227: do {
228: if (nextRow())
229: return true;
230: } while (nextBlock());
231:
232: return false;
233: }
234:
235: /**
236: * Returns the following block.
237: */
238: public boolean nextBlock() throws IOException {
239: byte[] buffer = _buffer;
240:
241: Block block = _block;
242: _block = null;
243: _buffer = null;
244:
245: if (block != null)
246: block.free();
247:
248: _blockId = _table.firstRow(_blockId + Table.BLOCK_SIZE);
249:
250: if (_blockId < 0) {
251: return false;
252: }
253:
254: block = _xa.readBlock(_table, _blockId);
255:
256: buffer = block.getBuffer();
257: _block = block;
258: _buffer = buffer;
259: _rowOffset = 0;
260:
261: return true;
262: }
263:
264: /**
265: * Sets the next row.
266: */
267: public void setRow(long rowAddr) throws IOException {
268: long blockId = _table.addressToBlockId(rowAddr);
269:
270: if (blockId != _blockId) {
271: _blockId = blockId;
272:
273: Block block = _block;
274: _block = null;
275: _buffer = null;
276:
277: if (block != null)
278: block.free();
279:
280: _block = _xa.readBlock(_table, _blockId);
281: _buffer = _block.getBuffer();
282: }
283:
284: _rowOffset = (int) (rowAddr & Store.BLOCK_OFFSET_MASK);
285: }
286:
287: /**
288: * Sets the next row.
289: */
290: public void initNullRow() throws IOException {
291: Block block = _block;
292: _block = null;
293: _buffer = null;
294:
295: if (block != null)
296: block.free();
297:
298: _rowOffset = 0;
299: _buffer = _nullBuffer;
300: }
301:
302: /**
303: * Returns true for the null for (for OUTER JOINs)
304: */
305: public boolean isNullRow() {
306: return _buffer == _nullBuffer;
307: }
308:
309: /**
310: * Returns true if the column is null.
311: */
312: public boolean isNull(Column column) throws SQLException {
313: return column.isNull(_buffer, _rowOffset);
314: }
315:
316: /**
317: * Returns the string for the column at the given index.
318: */
319: public String getString(Column column) throws SQLException {
320: return column.getString(_buffer, _rowOffset);
321: }
322:
323: /**
324: * Returns the column's value as an integer
325: *
326: * @param index column index in the row
327: *
328: * @return the integer value
329: */
330: public int getInteger(Column column) throws SQLException {
331: return column.getInteger(_buffer, _rowOffset);
332: }
333:
334: /**
335: * Returns the column's long value.
336: *
337: * @param index column index in the row
338: *
339: * @return the long value
340: */
341: public long getLong(Column column) throws SQLException {
342: return column.getLong(_buffer, _rowOffset);
343: }
344:
345: /**
346: * Returns the column's double value.
347: *
348: * @param index column index in the row
349: *
350: * @return the double value
351: */
352: public double getDouble(Column column) throws SQLException {
353: return column.getDouble(_buffer, _rowOffset);
354: }
355:
356: public boolean isEqual(Column column, byte[] matchBuffer)
357: throws SQLException {
358: return column.isEqual(_buffer, _rowOffset, matchBuffer, 0,
359: matchBuffer.length);
360: }
361:
362: public boolean isEqual(Column column, byte[] matchBuffer,
363: int matchLength) throws SQLException {
364: return column.isEqual(_buffer, _rowOffset, matchBuffer, 0,
365: matchLength);
366: }
367:
368: public boolean isEqual(Column column, String string)
369: throws SQLException {
370: return column.isEqual(_buffer, _rowOffset, string);
371: }
372:
373: /**
374: * Evaluates the row to the result.
375: */
376: public void evalToResult(Column column, SelectResult result)
377: throws SQLException {
378: column.evalToResult(_buffer, _rowOffset, result);
379: }
380:
381: public void delete() throws SQLException {
382: setDirty();
383: _table.delete(_xa, _block, _buffer, _rowOffset);
384: }
385:
386: public void setDirty() throws SQLException {
387: _xa.addUpdateBlock(_block);
388:
389: _block.setDirty(getRowOffset(), getRowOffset() + _rowLength);
390: }
391:
392: public void free() {
393: Block block = _block;
394: _block = null;
395:
396: if (block != null)
397: block.free();
398: }
399: }
|