KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > quadcap > sql > JoinInnerCursor


1 package com.quadcap.sql;
2
3 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved.
4  *
5  * This software is distributed under the Quadcap Free Software License.
6  * This software may be used or modified for any purpose, personal or
7  * commercial. Open Source redistributions are permitted. Commercial
8  * redistribution of larger works derived from, or works which bundle
9  * this software requires a "Commercial Redistribution License"; see
10  * http://www.quadcap.com/purchase.
11  *
12  * Redistributions qualify as "Open Source" under one of the following terms:
13  *
14  * Redistributions are made at no charge beyond the reasonable cost of
15  * materials and delivery.
16  *
17  * Redistributions are accompanied by a copy of the Source Code or by an
18  * irrevocable offer to provide a copy of the Source Code for up to three
19  * years at the cost of materials and delivery. Such redistributions
20  * must allow further use, modification, and redistribution of the Source
21  * Code under substantially the same terms as this license.
22  *
23  * Redistributions of source code must retain the copyright notices as they
24  * appear in each source code file, these license terms, and the
25  * disclaimer/limitation of liability set forth as paragraph 6 below.
26  *
27  * Redistributions in binary form must reproduce this Copyright Notice,
28  * these license terms, and the disclaimer/limitation of liability set
29  * forth as paragraph 6 below, in the documentation and/or other materials
30  * provided with the distribution.
31  *
32  * The Software is provided on an "AS IS" basis. No warranty is
33  * provided that the Software is free of defects, or fit for a
34  * particular purpose.
35  *
36  * Limitation of Liability. Quadcap Software shall not be liable
37  * for any damages suffered by the Licensee or any third party resulting
38  * from use of the Software.
39  */

40
41 import java.io.ByteArrayOutputStream JavaDoc;
42 import java.io.Externalizable JavaDoc;
43 import java.io.IOException JavaDoc;
44 import java.io.ObjectInput JavaDoc;
45 import java.io.ObjectOutput JavaDoc;
46
47 import java.util.BitSet JavaDoc;
48 import java.util.Enumeration JavaDoc;
49 import java.util.Hashtable JavaDoc;
50 import java.util.Vector JavaDoc;
51
52 import java.sql.SQLException JavaDoc;
53
54 import com.quadcap.sql.file.BlockFile;
55 import com.quadcap.sql.file.ByteUtil;
56 import com.quadcap.sql.file.PageManager;
57 import com.quadcap.sql.file.RandomAccess;
58
59 import com.quadcap.sql.io.ObjectOutputStream;
60
61 import com.quadcap.sql.index.BCursor;
62 import com.quadcap.sql.index.Btree;
63 import com.quadcap.sql.index.Comparator;
64
65 import com.quadcap.sql.types.Value;
66 import com.quadcap.sql.types.ValueBoolean;
67 import com.quadcap.sql.types.ValueInteger;
68 import com.quadcap.sql.types.Type;
69
70 import com.quadcap.util.Debug;
71 import com.quadcap.util.Util;
72
73 /**
74  * Cursor implementing <b>INNER JOIN</b> using nested loops (optimized using
75  * the inner index)
76  *
77  * @author Stan Bailes
78  */

79 public class JoinInnerCursor extends JoinCursor {
80     Database db;
81     BlockFile file;
82     BlockFile tempFile;
83
84     /** The join columns in the outer table. */
85     int[] caCols;
86
87     /** The current join key. */
88     byte[] caKey;
89
90     /** Cache number of columns in inner table. */
91     int cbCnt;
92
93     /** The join columns in the inner table. */
94     int[] cbCols;
95
96     /** Map inner, non-join-key columns from join cursor to inner cursor pos */
97     int[] cbMap;
98
99     /** Map outer columns from join cursor to outer cursor pos */
100     int[] caMap;
101
102     /** If the inner is really a table, or null if it's a view. */
103     Table cbTable;
104
105     /** If there's an index on the join columns of the inner table */
106     IndexConstraint cbIndex;
107
108     /** Either the index from above, or a temporary one we create. */
109     Btree index;
110
111     /** Did we make 'index', or were the columns already indexed? */
112     boolean tempIndex;
113
114     /** Did we make create new (temporary) rows for the inner index? */
115     boolean mustFreeRows = false;
116
117     BCursor cbKeys;
118
119     /** Used to compare the inner and outer join keys. */
120     Comparator compare;
121
122     /** Temporary used to build keys for inner table index */
123     MapRow mapRow;
124
125     /**
126      * Constructor takes a whole shitload of parameters.
127      *
128      * @param session my execution session context (transaction, etc)
129      * @param ca the outer join cursor
130      * @param caCols the join columns in the outer cursor
131      * @param cb the inner join cursor
132      * @param cbCols the join columns in the inner cursor
133      * @param where the ON/WHERE predicate expression
134      * @param tuple the format we're supposed to return
135      * @param row A mapping between the inner/outer rows and the join row
136      * @param left Include non-matching outer rows with nulls for inner
137      * @param inner Include matching rows
138      * @param flip Left is Right, Right is Left
139      */

140     public JoinInnerCursor(Session session, Cursor outer, Cursor ca, int[] caCols,
141                Cursor cb, int[] cbCols,
142                Expression where, Tuple tuple, JoinMapRow row,
143                            boolean left, boolean inner)
144     throws SQLException JavaDoc
145     {
146     super(session, outer, ca, cb, where, tuple, row, left, inner);
147     this.db = session.getDatabase();
148     this.file = db.getFile();
149     try {
150         this.tempFile = db.getTempFile();
151     } catch (IOException JavaDoc e) {
152         throw DbException.wrapThrowable(e);
153     }
154     this.caCols = caCols;
155     this.cbCnt = cb.getColumnCount();
156     this.cbCols = cbCols;
157     this.cbIndex = findIndex(cb, cbCols);
158     this.compare = new Key(cbCols.length);
159     
160     int joinCnt = cbCols.length;
161
162     }
163         
164     final IndexConstraint findIndex(Cursor r, int[] cols)
165     throws SQLException JavaDoc
166     {
167     IndexConstraint ret = null;
168     BitSet JavaDoc b = null;
169     this.cbTable = r.getTable();
170     if (this.cbTable == null) {
171             return null;
172         }
173         final int num = cbTable.getNumConstraints();
174         for (int ci = 0; ci < num; ci++) {
175         Constraint c = cbTable.getConstraint(ci);
176         if (!(c instanceof IndexConstraint)) continue;
177         int[] ccols = c.getColumns();
178         if (cols.length != ccols.length) continue;
179         if (b == null) b = intArrayToBitSet(cols);
180         boolean match = true;
181         for (int i = 0; i < ccols.length; i++) {
182         if (!b.get(ccols[i])) {
183             match = false;
184             break;
185         }
186         }
187         if (match) ret = (IndexConstraint)c;
188     }
189     return ret;
190     }
191
192     final static BitSet JavaDoc intArrayToBitSet(int[] a) {
193     BitSet JavaDoc b = new BitSet JavaDoc();
194     for (int i = 0; i < a.length; i++) {
195         b.set(a[i]);
196     }
197     return b;
198     }
199     
200     final byte[] makeInnerKey(Cursor cursor, Row row, long rowId)
201     throws IOException JavaDoc, SQLException JavaDoc
202     {
203     return Key.makeKey(cursor, row, cbCols, rowId, true);
204     }
205
206     final byte[] makeOuterKey(Cursor cursor, Row row)
207     throws IOException JavaDoc, SQLException JavaDoc
208     {
209     if (cbIndex != null) {
210         mapRow.setRow(row);
211         return cbIndex.makeKey(session, mapRow, Long.MIN_VALUE);
212     }
213     return Key.makeKey(cursor, row, caCols, Long.MIN_VALUE,
214                true);
215     }
216
217
218     protected void bfirst() throws SQLException JavaDoc {
219         try {
220             row.setB(null);
221             if (index == null) {
222                 this.index = makeInnerIndex();
223                 this.rb = new LazyRow(cbCnt);
224             }
225             caKey = makeOuterKey(ca, ra);
226             if (cbKeys == null) cbKeys = index.getCursor(false);
227             cbKeys.seek(caKey);
228         } catch (IOException JavaDoc e) {
229             throw DbException.wrapThrowable(e);
230         }
231     }
232
233     final protected boolean bnext() throws SQLException JavaDoc {
234         try {
235             boolean ret = false;
236         
237             while (!ret && cbKeys.next()) {
238                 byte[] cbKey = cbKeys.getKeyBuf();
239                 int len = cbKeys.getKeyLen();
240                 if (compare.compare(caKey, 0, caKey.length,
241                                     cbKey, 0, len) != 0) {
242                     break;
243                 }
244                 long rowId = cbKeys.getValAsLong();
245                 boolean isTemp = cbTable == null;
246                 db.getRow(rowId, (LazyRow)rb, isTemp);
247                 row.setB(rb);
248                 //Debug.println("bnext: rb = " + rb + ", row = " + row);
249
ret = true;
250             }
251             if (!ret) row.setB(null);
252             return ret;
253         } catch (IOException JavaDoc ex) {
254             throw DbException.wrapThrowable(ex);
255         }
256     }
257
258     final void makeTemporaryIndexForTable() throws IOException JavaDoc, SQLException JavaDoc {
259         //#ifdef DEBUG
260
if (Trace.bit(17)) {
261             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
262             for (int i = 0; i < cbCols.length; i++) {
263                 if (i > 0) sb.append(", ");
264                 sb.append(cb.getColumn(cbCols[i]).getName());
265             }
266             Debug.println("Make Temporary Index for " + cb.getName() +
267                           " (" + sb + ")");
268         }
269         //#endif
270
Comparator tempCompare = new Key(cbCols.length + 1);
271     index = session.makeTempTree(tempCompare);
272         while (cb.next()) {
273         long rowId = cb.getRowId();
274         Row r = cb.getRow();
275         byte[] key = makeInnerKey(cb, r, rowId);
276         index.set(key, session.getBuf8(rowId));
277     }
278     }
279
280     final void makeTemporaryIndexForView() throws IOException JavaDoc, SQLException JavaDoc {
281     Comparator tempCompare = new Key(cbCols.length + 1);
282     index = session.makeTempTree(tempCompare);
283     int cnt = 0;
284         mustFreeRows = true;
285         while (cb.next()) {
286         Row r = cb.getRow();
287         byte[] key = makeInnerKey(cb, r, cnt++);
288             long rowId = session.getDatabase().putRow(session, tempFile, cb, r);
289         index.set(key, session.getBuf8(rowId));
290     }
291     }
292
293     final Btree makeInnerIndex() throws IOException JavaDoc, SQLException JavaDoc {
294     if (cbTable != null) {
295         if (cbIndex != null) {
296         int[] map = new int[cb.getColumnCount() + 1];
297         for (int i = 0; i < cbCols.length; i++) {
298             int ic = cbCols[i];
299             int oc = caCols[i];
300             map[ic] = oc;
301         }
302         mapRow = new MapRow(map, 1);
303         index = cbIndex.getIndex(db);
304         } else {
305         makeTemporaryIndexForTable();
306         tempIndex = true;
307         }
308     } else {
309             makeTemporaryIndexForView();
310         tempIndex = true;
311     }
312     return index;
313     }
314
315     public void freeRows(Btree index, BlockFile file)
316     throws IOException JavaDoc
317     {
318         BCursor c = index.getCursor();
319         try {
320             while (c.next()) {
321                 long rowId = c.getValAsLong();
322                 db.removeRow(file, rowId);
323             }
324         } finally {
325             c.release();
326         }
327     }
328
329     public void close() throws SQLException JavaDoc {
330         try {
331             super.close();
332         } finally {
333             try {
334                 if (cbKeys != null) cbKeys.release();
335             } finally {
336                 try {
337                     cbKeys = null;
338                     if (tempIndex && mustFreeRows) {
339                         freeRows(index, tempFile);
340                     }
341                 } catch (IOException JavaDoc e2) {
342                     throw DbException.wrapThrowable(e2);
343                 } finally {
344                     try {
345                         mustFreeRows = false;
346                         if (tempIndex) {
347                             index.free();
348                             session.getDatabase().releaseTempFile();
349                         }
350                     } catch (IOException JavaDoc e3) {
351                         throw DbException.wrapThrowable(e3);
352                     } finally {
353                         index = null;
354                         if (tempFile != null) {
355                             session.getDatabase().releaseTempFile();
356                             tempFile = null;
357                         }
358                         tempIndex = false;
359                     }
360                 }
361             }
362         }
363     }
364 }
365
Popular Tags