001: package com.quadcap.sql;
002:
003: /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
004: *
005: * This software is distributed under the Quadcap Free Software License.
006: * This software may be used or modified for any purpose, personal or
007: * commercial. Open Source redistributions are permitted. Commercial
008: * redistribution of larger works derived from, or works which bundle
009: * this software requires a "Commercial Redistribution License"; see
010: * http://www.quadcap.com/purchase.
011: *
012: * Redistributions qualify as "Open Source" under one of the following terms:
013: *
014: * Redistributions are made at no charge beyond the reasonable cost of
015: * materials and delivery.
016: *
017: * Redistributions are accompanied by a copy of the Source Code or by an
018: * irrevocable offer to provide a copy of the Source Code for up to three
019: * years at the cost of materials and delivery. Such redistributions
020: * must allow further use, modification, and redistribution of the Source
021: * Code under substantially the same terms as this license.
022: *
023: * Redistributions of source code must retain the copyright notices as they
024: * appear in each source code file, these license terms, and the
025: * disclaimer/limitation of liability set forth as paragraph 6 below.
026: *
027: * Redistributions in binary form must reproduce this Copyright Notice,
028: * these license terms, and the disclaimer/limitation of liability set
029: * forth as paragraph 6 below, in the documentation and/or other materials
030: * provided with the distribution.
031: *
032: * The Software is provided on an "AS IS" basis. No warranty is
033: * provided that the Software is free of defects, or fit for a
034: * particular purpose.
035: *
036: * Limitation of Liability. Quadcap Software shall not be liable
037: * for any damages suffered by the Licensee or any third party resulting
038: * from use of the Software.
039: */
040:
041: import java.io.IOException;
042:
043: import java.sql.SQLException;
044:
045: import com.quadcap.sql.file.BlockFile;
046: import com.quadcap.sql.file.ByteUtil;
047: import com.quadcap.sql.file.PageManager;
048: import com.quadcap.sql.file.SubPageManager;
049:
050: import com.quadcap.sql.index.Btree;
051: import com.quadcap.sql.index.BCursor;
052:
053: import com.quadcap.sql.types.Value;
054:
055: import com.quadcap.util.Debug;
056: import com.quadcap.util.Util;
057:
058: /**
059: * Temporary tables are Useful for several operations, including
060: * <b>GROUP BY</b>,
061: * <b>DISTINCT</b>,
062: * and <b>ORDER BY</b>.
063: *
064: * Todo: in-memory version of this based on configurable 'max temp' size.
065: *
066: * @author Stan Bailes
067: */
068: public class TempTable {
069: Session session = null;
070: int[] map = null;
071: BlockFile file;
072: BlockFile tempFile = null;
073: Key compare = null;
074: Btree index = null;
075: long keyCount = 0;
076: byte[] data = new byte[9];
077: boolean inMemory = false;
078:
079: //#ifdef DEBUG
080: static int serial = 0;
081: int mySerial = serial++;
082: static final boolean trace = false;
083:
084: //#endif
085:
086: public TempTable(Session session, Key compare, int[] map)
087: throws SQLException, IOException {
088: this .inMemory = session.getDatabase().inMemory();
089: this .session = session;
090: this .compare = compare;
091: this .map = map;
092: this .index = session.makeTempTree(compare);
093: this .file = session.getDatabase().getFile();
094: this .tempFile = session.getDatabase().getTempFile(false);
095: }
096:
097: public int addRows(Cursor cursor) throws SQLException, IOException {
098: int count = 0;
099: //#ifdef DEBUG
100: if (trace) {
101: Debug
102: .println("TempTable[" + mySerial
103: + "].addRows() begin");
104: Debug.println("cursor = " + cursor);
105: }
106: //#endif
107: cursor.beforeFirst();
108: Database db = session.getDatabase();
109: while (cursor.next()) {
110: Row row = cursor.getRow();
111: byte[] key = makeKey(row);
112: long rowId = cursor.getRowId();
113: if (rowId == 0) {
114: rowId = db.putRow(session, tempFile, null, row);
115: count++;
116: //#ifdef DEBUG
117: if (trace) {
118: Debug.println("TempTable[" + mySerial
119: + "].putRow: " + toString(rowId) + " "
120: + row);
121: }
122: //#endif
123: data[0] = 1;
124: } else {
125: data[0] = 0;
126: //#ifdef DEBUG
127: if (trace) {
128: Debug.println("TempTable[" + mySerial
129: + "] refersTo row " + toString(rowId) + " "
130: + row);
131: }
132: //#endif
133: }
134: ByteUtil.putLong(data, 1, rowId);
135: index.set(key, data);
136: }
137: //#ifdef DEBUG
138: if (trace) {
139: Debug.println("TempTable[" + mySerial
140: + "].addRows() complete");
141: }
142: //#endif
143: return count;
144: }
145:
146: public byte[] makeKey(Row row) throws SQLException {
147: return Key.makeKey(null, row, map, keyCount++, true);
148: }
149:
150: public BCursor getCursor() throws IOException {
151: return index.getCursor(false);
152: }
153:
154: public void getRow(byte[] rowIdBuf, LazyRow row)
155: throws SQLException, IOException {
156: long rowId = ByteUtil.getLong(rowIdBuf, 1);
157: boolean isTemp = rowIdBuf[0] != 0;
158: //#ifdef DEBUG
159: if (trace) {
160: Debug.println("TempTable[" + mySerial + "].getRow("
161: + toString(rowId) + ", " + isTemp + ")");
162: }
163: //#endif
164: session.getDatabase().getRow(rowId, row, isTemp);
165: }
166:
167: public void release() throws IOException {
168: //#ifdef DEBUG
169: if (trace) {
170: Debug.println("TempTable[" + mySerial + "].release()");
171: }
172: //#endif
173: try {
174: try {
175: BCursor c = index.getCursor(false);
176: try {
177: while (c.next()) {
178: byte[] dataBuf = c.getValBuf();
179: if (dataBuf[0] == 1) {
180: long ref = ByteUtil.getLong(dataBuf, 1);
181: if (inMemory) {
182: tempFile.removeObject(ref);
183: } else {
184: // We don't bother freeing the stream, to
185: // save time. Ultimately, we can just toss
186: // the entire temp file....
187: //tempFile.freeStream(ref);
188: }
189: }
190: }
191: } finally {
192: c.release();
193: }
194: } finally {
195: index.free();
196: }
197: } finally {
198: session.getDatabase().releaseTempFile();
199: }
200: }
201:
202: //#ifdef DEBUG
203: public String toString(long rowId) {
204: //return SubPageManager.toString(rowId);
205: return String.valueOf(rowId);
206: }
207: //#endif
208:
209: }
|