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.ByteArrayOutputStream;
042: import java.io.Externalizable;
043: import java.io.IOException;
044: import java.io.ObjectInput;
045: import java.io.ObjectOutput;
046:
047: import java.util.Enumeration;
048: import java.util.Hashtable;
049:
050: import java.util.Vector;
051:
052: import java.sql.SQLException;
053:
054: import com.quadcap.sql.io.ObjectInputStream;
055: import com.quadcap.sql.io.ObjectOutputStream;
056:
057: import com.quadcap.sql.file.ByteUtil;
058:
059: import com.quadcap.util.Debug;
060: import com.quadcap.util.Util;
061:
062: /**
063: * Cursor that implements the <b>DISTINCT</b> modifier by creating
064: * temporary table, where the entire row is used as the index key.
065: *
066: * @author Stan Bailes
067: */
068: public class DistinctCursor extends BC_Cursor {
069: Cursor sourceCursor;
070: Vector orderBy = null;
071: TempTable tempTable;
072: boolean distinct = true;
073:
074: /**
075: * Constructor on session and cursor
076: */
077: public DistinctCursor(Session session, Cursor cursor)
078: throws SQLException {
079: super (session, null, null);
080: this .sourceCursor = cursor;
081: addColumns(session, cursor);
082: }
083:
084: public final void checkCursor() throws SQLException, IOException {
085: if (bc == null) {
086: try {
087: makeTempTable();
088: } finally {
089: try {
090: sourceCursor.close();
091: } catch (Throwable t) {
092: } finally {
093: sourceCursor = null;
094: }
095: }
096: }
097: }
098:
099: private void makeTempTable() throws IOException, SQLException {
100: int size = getColumnCount();
101: if (orderBy == null) {
102: if (distinct) {
103: tempTable = new TempTable(session, new Key(size), null);
104: } else {
105: tempTable = new TempTable(session, new Key(1),
106: new int[0]);
107: }
108: } else {
109: tempTable = makeObTemp();
110: }
111: tempTable.addRows(sourceCursor);
112: row = new LazyRow(size);
113: bc = tempTable.getCursor();
114: }
115:
116: TempTable makeObTemp() throws SQLException, IOException {
117: int[] map = new int[getColumnCount()];
118: boolean[] rmap = new boolean[map.length + 1];
119: boolean[] asc = new boolean[map.length];
120: for (int i = 0; i < orderBy.size(); i++) {
121: OrderElement elem = (OrderElement) orderBy.elementAt(i);
122: int num = elem.getColumn();
123: if (num < 0) {
124: String name = elem.getColName();
125: Column col = getColumn(name);
126: if (col == null) {
127: throw new SQLException("Bad column name: " + name);
128: }
129: num = col.getColumn();
130: elem.setColumn(num);
131: }
132: map[i] = num;
133: rmap[num] = true;
134: asc[i] = elem.isAscending();
135: }
136: int cnt = orderBy.size();
137: for (int i = 1; i < rmap.length; i++) {
138: if (!rmap[i]) {
139: map[cnt] = i;
140: asc[cnt] = true;
141: cnt++;
142: }
143: }
144: Key compare = new Key(asc);
145: return new TempTable(session, compare, map);
146: }
147:
148: public void setOrder(Vector v) {
149: this .orderBy = v;
150: }
151:
152: public void setDistinct(boolean b) {
153: this .distinct = b;
154: }
155:
156: public long getCurrentRowId() throws SQLException {
157: return ByteUtil.getLong(bc.getValBuf(), 1);
158: }
159:
160: public void fetchCurrentRow() throws SQLException, IOException {
161: tempTable.getRow(bc.getValBuf(), row);
162: rowValid = true;
163: }
164:
165: /**
166: * On close, we release the resources.
167: */
168: public void close() throws SQLException {
169: try {
170: super .close();
171: } finally {
172: try {
173: if (sourceCursor != null)
174: sourceCursor.close();
175: } finally {
176: sourceCursor = null;
177: try {
178: if (tempTable != null)
179: tempTable.release();
180: } catch (IOException ex) {
181: throw DbException.wrapThrowable(ex);
182: } finally {
183: tempTable = null;
184: }
185: }
186: }
187: }
188:
189: //#ifdef DEBUG
190: public String toString() {
191: return super .toString() + "\n\t[source cursor = "
192: + sourceCursor + "]\n";
193: }
194: //#endif
195: }
|