001: /* Copyright (c) 1995-2000, The Hypersonic SQL Group.
002: * All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * Redistributions of source code must retain the above copyright notice, this
008: * list of conditions and the following disclaimer.
009: *
010: * Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * Neither the name of the Hypersonic SQL Group nor the names of its
015: * contributors may be used to endorse or promote products derived from this
016: * software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021: * ARE DISCLAIMED. IN NO EVENT SHALL THE HYPERSONIC SQL GROUP,
022: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
026: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: *
030: * This software consists of voluntary contributions made by many individuals
031: * on behalf of the Hypersonic SQL Group.
032: *
033: *
034: * For work added by the HSQL Development Group:
035: *
036: * Copyright (c) 2001-2005, The HSQL Development Group
037: * All rights reserved.
038: *
039: * Redistribution and use in source and binary forms, with or without
040: * modification, are permitted provided that the following conditions are met:
041: *
042: * Redistributions of source code must retain the above copyright notice, this
043: * list of conditions and the following disclaimer.
044: *
045: * Redistributions in binary form must reproduce the above copyright notice,
046: * this list of conditions and the following disclaimer in the documentation
047: * and/or other materials provided with the distribution.
048: *
049: * Neither the name of the HSQL Development Group nor the names of its
050: * contributors may be used to endorse or promote products derived from this
051: * software without specific prior written permission.
052: *
053: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
054: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
055: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
056: * ARE DISCLAIMED. IN NO EVENT SHALL HSQL DEVELOPMENT GROUP, HSQLDB.ORG,
057: * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
058: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
059: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
060: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
061: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
062: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
063: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
064: */
065:
066: package org.hsqldb;
067:
068: import java.io.IOException;
069:
070: import org.hsqldb.lib.IntLookup;
071: import org.hsqldb.lib.java.JavaSystem;
072: import org.hsqldb.rowio.RowInputInterface;
073: import org.hsqldb.rowio.RowOutputInterface;
074:
075: // fredt@users 20020221 - patch 513005 by sqlbob@users (RMP)
076: // fredt@users 20020920 - patch 1.7.1 - refactoring to cut memory footprint
077: // fredt@users 20021205 - patch 1.7.2 - enhancements
078: // fredt@users 20021215 - doc 1.7.2 - javadoc comments
079: // boucherb@users - 20040411 - doc 1.7.2 - javadoc comments
080:
081: /**
082: * In-memory representation of a disk-based database row object with methods
083: * for serialization and de-serialization. <p>
084: *
085: * A CachedRow is normally part of a circular double linked list which
086: * contains all of the Rows currently in the Cache for the database. It is
087: * unlinked from this list when it is freed from the Cache to make way for
088: * other rows.
089: *
090: * New class from the Hypersonic Original
091: *
092: * @author Thomas Mueller (Hypersonic SQL Group)
093: * @version 1.7.2
094: * @since Hypersonic SQL
095: */
096: public class CachedRow extends Row {
097:
098: static final int NO_POS = -1;
099:
100: //
101: protected Table tTable;
102: int storageSize;
103:
104: /**
105: * Flag indicating unwritten data.
106: */
107: protected boolean hasDataChanged;
108:
109: /**
110: * Flag indicating Node data has changed.
111: */
112: boolean hasNodesChanged;
113:
114: /**
115: * Default constructor used only in subclasses.
116: */
117: CachedRow() {
118: }
119:
120: public static CachedRow newCachedRow(Table t, Object[] o)
121: throws HsqlException {
122:
123: if (t.isText) {
124: return new CachedDataRow(t, o);
125: } else {
126: return new CachedRow(t, o);
127: }
128: }
129:
130: /**
131: * Constructor for new Rows. Variable hasDataChanged is set to true in
132: * order to indicate the data needs saving.
133: *
134: * @param t table
135: * @param o row data
136: * @throws HsqlException if a database access error occurs
137: */
138: CachedRow(Table t, Object[] o) throws HsqlException {
139:
140: tTable = t;
141:
142: int indexcount = t.getIndexCount();
143:
144: nPrimaryNode = Node.newNode(this , 0, t);
145:
146: Node n = nPrimaryNode;
147:
148: for (int i = 1; i < indexcount; i++) {
149: n.nNext = Node.newNode(this , i, t);
150: n = n.nNext;
151: }
152:
153: oData = o;
154: hasDataChanged = hasNodesChanged = true;
155: }
156:
157: /**
158: * Constructor when read from the disk into the Cache.
159: *
160: * @param t table
161: * @param in data source
162: * @throws IOException
163: * @throws HsqlException
164: */
165: public CachedRow(Table t, RowInputInterface in) throws IOException,
166: HsqlException {
167:
168: tTable = t;
169: iPos = in.getPos();
170: storageSize = in.getSize();
171:
172: int indexcount = t.getIndexCount();
173:
174: nPrimaryNode = Node.newNode(this , in, 0, t);
175:
176: Node n = nPrimaryNode;
177:
178: for (int i = 1; i < indexcount; i++) {
179: n.nNext = Node.newNode(this , in, i, t);
180: n = n.nNext;
181: }
182:
183: oData = in.readData(tTable.getColumnTypes());
184: }
185:
186: private void readRowInfo(RowInputInterface in) throws IOException,
187: HsqlException {
188:
189: // for use when additional transaction info is attached to rows
190: }
191:
192: /**
193: * This method is called only when the Row is deleted from the database
194: * table. The links with all the other objects apart from the data
195: * are removed.
196: *
197: * @throws HsqlException
198: */
199: public void delete() throws HsqlException {
200:
201: super .delete();
202:
203: hasNodesChanged = hasDataChanged = false;
204: tTable = null;
205: }
206:
207: public int getStorageSize() {
208: return storageSize;
209: }
210:
211: /**
212: * Sets the file position for the row
213: *
214: * @param pos position in data file
215: */
216: public void setPos(int pos) {
217: iPos = pos;
218: }
219:
220: /**
221: * Sets flag for Node data change.
222: */
223: void setChanged() {
224: hasNodesChanged = true;
225: }
226:
227: /**
228: * Returns true if Node data has changed.
229: *
230: * @return boolean
231: */
232: public boolean hasChanged() {
233: return hasNodesChanged;
234: }
235:
236: /**
237: * Returns the Table to which this Row belongs.
238: *
239: * @return Table
240: */
241: public Table getTable() {
242: return tTable;
243: }
244:
245: /**
246: * returned size does not include the row size written at the beginning
247: */
248: public int getRealSize(RowOutputInterface out) {
249: return tTable.getIndexCount() * DiskNode.SIZE_IN_BYTE
250: + out.getSize(this );
251: }
252:
253: public void setStorageSize(int size) {
254: storageSize = size;
255: }
256:
257: /**
258: * Returns true if any of the Nodes for this row is a root node.
259: * Used only in Cache.java to avoid removing the row from the cache.
260: *
261: * @return boolean
262: * @throws HsqlException
263: */
264: synchronized public boolean isKeepInMemory() {
265:
266: Node n = nPrimaryNode;
267:
268: while (n != null) {
269: if (n.isRoot()) {
270: return true;
271: }
272:
273: n = n.nNext;
274: }
275:
276: return false;
277: }
278:
279: /**
280: * Using the internal reference to the Table, returns the current cached
281: * Row. Valid for deleted rows only before any subsequent insert or
282: * update on any cached table.<p>
283: *
284: * Access to tables while performing the internal operations for an
285: * SQL statement result in CachedRow objects to be cleared from the cache.
286: * This method returns the CachedRow, loading it to the cache if it is not
287: * there.
288: * @return the current Row in Cache for this Object
289: * @throws HsqlException
290: */
291: synchronized Row getUpdatedRow() throws HsqlException {
292: return tTable == null ? null : (CachedRow) tTable.rowStore
293: .get(iPos);
294: }
295:
296: /**
297: * used in CachedDataRow
298: */
299: void setNewNodes() {
300: }
301:
302: /**
303: * Used exclusively by Cache to save the row to disk. New implementation
304: * in 1.7.2 writes out only the Node data if the table row data has not
305: * changed. This situation accounts for the majority of invocations as
306: * for each row deleted or inserted, the Nodes for several other rows
307: * will change.
308: *
309: * @param output data source
310: * @throws IOException
311: * @throws HsqlException
312: */
313: public void write(RowOutputInterface out) {
314:
315: try {
316: writeNodes(out);
317:
318: if (hasDataChanged) {
319: out.writeData(oData, tTable);
320: out.writeEnd();
321:
322: hasDataChanged = false;
323: }
324: } catch (IOException e) {
325: }
326: }
327:
328: private void writeRowInfo(RowOutputInterface out) {
329:
330: // for use when additional transaction info is attached to rows
331: }
332:
333: public void write(RowOutputInterface out, IntLookup lookup) {
334:
335: out.writeSize(storageSize);
336:
337: Node rownode = nPrimaryNode;
338:
339: while (rownode != null) {
340: ((DiskNode) rownode).writeTranslate(out, lookup);
341:
342: rownode = rownode.nNext;
343: }
344:
345: out.writeData(getData(), getTable());
346: out.writeEnd();
347: }
348:
349: /**
350: * Writes the Nodes, immediately after the row size.
351: *
352: * @param out
353: *
354: * @throws IOException
355: * @throws HsqlException
356: */
357: private void writeNodes(RowOutputInterface out) throws IOException {
358:
359: out.writeSize(storageSize);
360:
361: Node n = nPrimaryNode;
362:
363: while (n != null) {
364: n.write(out);
365:
366: n = n.nNext;
367: }
368:
369: hasNodesChanged = false;
370: }
371:
372: /**
373: * With CACHED tables there may possibly exist two copies of the row.
374: * All copies will have the same iPos.
375: *
376: * @param obj row to compare
377: * @return boolean
378: */
379: public boolean equals(Object obj) {
380:
381: if (obj == this ) {
382: return true;
383: }
384:
385: if (obj instanceof CachedRow) {
386: return ((CachedRow) obj).iPos == iPos;
387: }
388:
389: return false;
390: }
391:
392: /**
393: * Hash code is valid only until a modification to the cache
394: *
395: * @return file position of row
396: */
397: public int hashCode() {
398: return iPos;
399: }
400: }
|