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.ByteArrayInputStream;
042: import java.io.ByteArrayOutputStream;
043: import java.io.IOException;
044:
045: import java.util.Vector;
046:
047: import java.sql.SQLException;
048:
049: import com.quadcap.sql.io.ObjectInputStream;
050: import com.quadcap.sql.io.ObjectOutputStream;
051:
052: import com.quadcap.sql.index.BCursor;
053: import com.quadcap.sql.index.Btree;
054:
055: import com.quadcap.sql.file.BlockFile;
056: import com.quadcap.sql.file.PageManager;
057:
058: import com.quadcap.sql.types.Op;
059: import com.quadcap.sql.types.Value;
060:
061: import com.quadcap.util.Debug;
062: import com.quadcap.util.Util;
063:
064: /**
065: * Cursor to support SQL <b>GROUP BY</b>.
066: *
067: * @author Stan Bailes
068: */
069:
070: public class GroupByCursor extends FilterCursor {
071: Vector groupBy = null;
072: int currentRowNum = 0;
073: byte[] prevKey = new byte[32];
074: int prevKeyLen = -1;
075: int[] gMap = null;
076: BCursor bc = null;
077: LazyRow prevRow = null;
078: LazyRow currRow = null;
079: boolean sameGroup = false;
080: boolean prev = false;
081: Key compare = null;
082: TempTable tempTable = null;
083:
084: public GroupByCursor(Session session, Cursor cursor, Vector groupBy)
085: throws SQLException {
086: super (session, cursor);
087:
088: this .currRow = new LazyRow(cursor.getColumnCount());
089: this .prevRow = new LazyRow(cursor.getColumnCount());
090: this .groupBy = groupBy;
091: this .gMap = new int[groupBy.size()];
092: this .compare = new Key(gMap.length);
093: for (int i = 0; i < gMap.length; i++) {
094: Column c = cursor.getColumn((String) groupBy.elementAt(i));
095: gMap[i] = c.getColumn();
096: }
097: try {
098: this .tempTable = new TempTable(session, new Key(
099: gMap.length + 1), gMap);
100: tempTable.addRows(cursor);
101: this .bc = tempTable.getCursor();
102: beforeFirst();
103: } catch (IOException e) {
104: throw DbException.wrapThrowable(e);
105: }
106: }
107:
108: public Row getRow() throws SQLException {
109: //Debug.println("getRow: " + prevRow);
110: return prevRow;
111: }
112:
113: public void updateRow(Row row) throws SQLException {
114: throw new SQLException("GroupBy expressions aren't updateable",
115: "42000");
116: }
117:
118: public void deleteRow() throws SQLException {
119: throw new SQLException("GroupBy expressions aren't updateable",
120: "42000");
121: }
122:
123: public void beforeFirst() throws SQLException {
124: try {
125: bc.beforeFirst();
126: prev = nextRow();
127: } catch (IOException e) {
128: throw DbException.wrapThrowable(e);
129: } catch (ClassNotFoundException e) {
130: throw DbException.wrapThrowable(e);
131: }
132: }
133:
134: public boolean lastRowOfGroup() {
135: //Debug.println("lastRow: " + !sameGroup);
136: return !sameGroup;
137: }
138:
139: public boolean next() throws SQLException {
140: try {
141: boolean ret = prev;
142: prev = nextRow();
143: return ret;
144: } catch (IOException e) {
145: throw DbException.wrapThrowable(e);
146: } catch (ClassNotFoundException e) {
147: throw DbException.wrapThrowable(e);
148: }
149: }
150:
151: public boolean nextRow() throws SQLException, IOException,
152: ClassNotFoundException {
153: swapRows();
154: sameGroup = false;
155: if (!bc.next()) {
156: return false;
157: }
158: final byte[] key = bc.getKeyBuf();
159: final int len = bc.getKeyLen();
160:
161: if (prevKeyLen != -1) {
162: sameGroup = compare.compare(key, 0, len, prevKey, 0,
163: prevKeyLen) == 0;
164: }
165: prevKey = (byte[]) Util.checkCapacity(prevKey, len);
166: prevKeyLen = len;
167:
168: System.arraycopy(key, 0, prevKey, 0, len);
169:
170: tempTable.getRow(bc.getValBuf(), currRow);
171: return true;
172: }
173:
174: final void swapRows() {
175: LazyRow temp = prevRow;
176: prevRow = currRow;
177: currRow = temp;
178:
179: }
180:
181: public boolean isWritable(int col) throws SQLException {
182: return false;
183: }
184:
185: /**
186: * I honestly have no idea.
187: */
188: public long size() {
189: return -1;
190: }
191:
192: public void close() throws SQLException {
193: try {
194: super .close();
195: } finally {
196: try {
197: if (bc != null)
198: bc.release();
199: } finally {
200: bc = null;
201: try {
202: if (tempTable != null)
203: tempTable.release();
204: } catch (IOException e2) {
205: throw DbException.wrapThrowable(e2);
206: } finally {
207: tempTable = null;
208: }
209: }
210: }
211: }
212: }
|