KickJava   Java API By Example, From Geeks To Geeks.

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


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.IOException JavaDoc;
43 import java.io.ObjectInput JavaDoc;
44 import java.io.ObjectOutput JavaDoc;
45
46 import java.util.Enumeration JavaDoc;
47 import java.util.Hashtable JavaDoc;
48 import java.util.Vector JavaDoc;
49
50 import java.sql.SQLException JavaDoc;
51
52 import com.quadcap.sql.io.ObjectOutputStream;
53
54 import com.quadcap.sql.file.ByteUtil;
55
56 import com.quadcap.sql.index.Btree;
57 import com.quadcap.sql.index.Comparator;
58
59 import com.quadcap.sql.types.Op;
60 import com.quadcap.sql.types.Value;
61 import com.quadcap.sql.types.ValueException;
62 import com.quadcap.sql.types.ValueInteger;
63 import com.quadcap.sql.types.ValueNull;
64
65 import com.quadcap.util.Debug;
66 import com.quadcap.util.Util;
67
68 /**
69  * Cursor for iterating an index.
70  *
71  * @author Stan Bailes
72  */

73 public class IndexCursor extends BC_Cursor {
74     Table table;
75     IndexConstraint constraint;
76     Btree index;
77     Comparator compare;
78     Vector JavaDoc indexNames = null;
79     StaticCursor startVals = null;
80     StaticCursor stopVals = null;
81
82     byte[] startVal;
83     byte[] stopVal;
84
85     
86     /**
87      * IndexCursor construtor for the specified table (with optional
88      * where clause)
89      */

90     public IndexCursor(Table table, Session session,
91                IndexConstraint constraint, Expression where,
92                String JavaDoc qualifier, Cursor outerCursor)
93     throws SQLException JavaDoc, IOException JavaDoc
94     {
95     super(session, qualifier, outerCursor);
96     this.table = table;
97     this.constraint = constraint;
98     this.index = constraint.getIndex(session.getDatabase());
99     this.compare = index.getComparator();
100     
101     addColumns(session, table);
102
103     this.indexNames = constraint.getColumnNames();
104         reset(where, outerCursor);
105     }
106     public void checkCursor() throws SQLException JavaDoc {
107         if (bc == null) {
108             throw new SQLException JavaDoc("Cursor closed");
109         }
110     }
111
112     public long getCurrentRowId() throws SQLException JavaDoc {
113         checkCursor();
114         return ByteUtil.getLong(bc.getValBuf(), 0);
115     }
116
117     public void fetchCurrentRow() throws SQLException JavaDoc, IOException JavaDoc {
118         session.getDatabase().getRow(rowId, row, false);
119         rowValid = true;
120     }
121
122     public IndexConstraint getConstraint() {
123         return constraint;
124     }
125
126     public void reset(Expression where, Cursor outer)
127         throws SQLException JavaDoc
128     {
129         try {
130             this.setOuterCursor(outer);
131             startVal = null;
132             stopVal = null;
133             if (indexNames != null && indexNames.size() > 0) {
134                 startVals = makeValues(session, table, ValueNull.valueNull);
135                 stopVals = makeValues(session, table, ValueNull.valueLastNull);
136                 getCursorRange(session, where, startVals, stopVals);
137                 startVal = constraint.makeKey(session, startVals.getRow(),
138                                               Long.MIN_VALUE);
139                 stopVal = constraint.makeKey(session, stopVals.getRow(),
140                                              Long.MAX_VALUE);
141                 //Debug.println("startVal = " + Util.hexBytes(startVal));
142
//Debug.println("stopVal = " + Util.hexBytes(stopVal));
143
}
144             
145             this.row = new LazyRow(table.getColumnCount());
146             bc = index.getCursor(false);
147             if (startVal != null) {
148                 bc.seek(startVal);
149             } else {
150                 bc.beforeFirst();
151             }
152         } catch (IOException JavaDoc e) {
153             throw DbException.wrapThrowable(e);
154         }
155     }
156
157     /**
158      * Make a row for the specified table and fill it with the specified
159      * value
160      */

161     StaticCursor makeValues(Session session, Table table, Value v)
162         throws SQLException JavaDoc
163     {
164     Row r = new Row(table.getColumnCount());
165     for (int i = 1; i <= r.size(); i++) {
166         r.set(i, v);
167     }
168     StaticCursor s = new StaticCursor(session, table, r);
169     s.absolute(1);
170     return s;
171     }
172
173     //#ifdef DEBUG
174
static String JavaDoc isa(Object JavaDoc x) {
175         return x == null ? "null" :
176             x.getClass().getName() + ":" + x;
177     }
178     //#endif
179

180     /**
181      * Determine if an expression in the where clause can supply a lower
182      * or upper bound on the value of the index key
183      */

184     void getCursorRange(Session session, Expression e,
185                         StaticCursor startVals, StaticCursor stopVals)
186     throws SQLException JavaDoc
187     {
188     if (e instanceof BinaryExpression) {
189         BinaryExpression b = (BinaryExpression)e;
190         switch (b.op) {
191         case Op.EQ:
192                 //Debug.println("b.e = " + b.e);
193
//Debug.println("b.f = " + b.f);
194
//Debug.println("startVals = " + startVals);
195
if (b.e instanceof NameExpression) {
196             NameExpression ne = (NameExpression)b.e;
197             String JavaDoc name = session.getConnection().resolveColname(ne.getName(), table);
198                     String JavaDoc tname = table.getName();
199                     if (name.startsWith(tname)) name = name.substring(tname.length() + 1);
200                     //Debug.println(" name = " + name + ", tablename = " + table.getName());
201
if (startVals.get(name) != null) {
202             try {
203                 Value v = b.f.getValue(session, outer);
204                             //Debug.println(" v = " + v);
205
startVals.put(name, v);
206                 stopVals.put(name, v);
207                             return;
208             } catch (SQLException JavaDoc se) {}
209             }
210                 }
211                 if (b.f instanceof NameExpression) {
212             NameExpression nf = (NameExpression)b.f;
213             String JavaDoc name = session.getConnection().resolveColname(nf.getName(), table);
214             if (startVals.get(name) != null) {
215             try {
216                 Value v = b.e.getValue(session, outer);
217                 startVals.put(name, v);
218                 stopVals.put(name, v);
219             } catch (SQLException JavaDoc se) {}
220             }
221         }
222         break;
223         case Op.AND:
224         getCursorRange(session, b.e, startVals, stopVals);
225         getCursorRange(session, b.f, startVals, stopVals);
226         break;
227         case Op.LT:
228         case Op.LE:
229         doOneBound(session, b.e, b.f, startVals, stopVals);
230         break;
231         case Op.GT:
232         case Op.GE:
233         doOneBound(session, b.f, b.e, startVals, stopVals);
234         break;
235         }
236     } else if (e instanceof TernaryExpression) {
237         TernaryExpression t = (TernaryExpression)e;
238         if (t.op == Op.BETWEEN) {
239         if (!t.not) {
240             doOneBound(session, t.f, t.e, startVals, stopVals);
241             doOneBound(session, t.e, t.g, startVals, stopVals);
242         }
243         }
244     }
245     }
246
247     /**
248      * Compare a single element to a bound to determine a possible
249      * limit
250      */

251     void doOneBound(Session session, Expression a, Expression b,
252             StaticCursor startVals, StaticCursor stopVals)
253     throws SQLException JavaDoc
254     {
255     if (a instanceof NameExpression) {
256         NameExpression na = (NameExpression)a;
257         String JavaDoc name = na.getName();
258         Value s = (Value)stopVals.get(name);
259         if (s != null) {
260         Value v = b.getValue(session, null); // XXX outer?
261
Value cmp = Value.binop(Op.COMPARE, v, s);
262         ValueInteger vi = (ValueInteger)cmp;
263         int ret = vi.intValue();
264         if (ret < 0) {
265             stopVals.put(name, v);
266         }
267         }
268     } else if (b instanceof NameExpression) {
269         NameExpression nb = (NameExpression)b;
270         String JavaDoc name = nb.getName();
271         Value s = (Value)startVals.get(name);
272         if (s != null) {
273         Value v = a.getValue(session, null); // XXX outer?
274
Value cmp = Value.binop(Op.COMPARE, v, s);
275         ValueInteger vi = (ValueInteger)cmp;
276         int ret = vi.intValue();
277         if (ret > 0) {
278             startVals.put(name, v);
279         }
280         }
281     }
282     }
283
284     /**
285      * Cursor.next():
286      */

287     public boolean next() throws SQLException JavaDoc {
288         boolean ret = super.next();
289         if (ret) {
290             if (stopVal != null) {
291                 if (compare.compare(bc.getKeyBuf(), 0, bc.getKeyLen(),
292                                     stopVal, 0, stopVal.length) > 0) {
293                     ret = false;
294                 }
295             }
296     }
297         return ret;
298     }
299
300     /**
301      * Cursor.prev()
302      */

303     public boolean prev() throws SQLException JavaDoc {
304         boolean ret = super.prev();
305         if (ret) {
306             if (startVal != null) {
307                 if (compare.compare(bc.getKeyBuf(), 0, bc.getKeyLen(),
308                                     startVal, 0, startVal.length) < 0) {
309                     ret = false;
310                 }
311             }
312     }
313         return ret;
314     }
315
316     /**
317      * Update the current row with the specified new values
318      */

319     public void updateRow(Row row) throws SQLException JavaDoc {
320     try {
321         TableOps.updateRow(session, table,
322                                bc.getKey(), rowId,
323                                row, constraint);
324     } catch (IOException JavaDoc e) {
325         throw DbException.wrapThrowable(e);
326     }
327     }
328
329     /**
330      * Insert the specified row into the table referenced by this cursor
331      */

332     public void insertRow(Row row) throws SQLException JavaDoc {
333     try {
334         TableOps.insertRow(session, table, row);
335     } catch (IOException JavaDoc e) {
336         throw DbException.wrapThrowable(e);
337     }
338     }
339
340     /**
341      * Delete the current cursor row
342      */

343     public void deleteRow() throws SQLException JavaDoc {
344     try {
345         TableOps.deleteRow(session, table,
346                                rowId, getRow(), constraint);
347     } catch (IOException JavaDoc e) {
348         throw DbException.wrapThrowable(e);
349     }
350     }
351
352     /**
353      * Move the cursor to the beginning; before the first row
354      */

355     public void beforeFirst() throws SQLException JavaDoc {
356         try {
357             rowValid = false;
358             rowId = 0;
359             checkCursor();
360             if (startVal != null) bc.seek(startVal);
361             else bc.beforeFirst();
362         } catch (IOException JavaDoc e) {
363             throw DbException.wrapThrowable(e);
364         }
365     }
366     
367     /**
368      * Move the cursor to the beginning; before the first row
369      */

370     public void afterLast() throws SQLException JavaDoc {
371         try {
372             rowValid = false;
373             rowId = 0;
374             checkCursor();
375             if (stopVal != null) bc.seek(stopVal);
376             else bc.afterLast();
377         } catch (IOException JavaDoc e) {
378             throw DbException.wrapThrowable(e);
379         }
380     }
381     
382 // /**
383
// * Absolute cursor positioning
384
// */
385
// public boolean absolute(int row) throws SQLException {
386
// return ((CursorImpl)this).absolute(row);
387
// }
388

389     /**
390      * All columns in an index cursor are writable.
391      */

392     public boolean isWritable(int col) {
393     return true;
394     }
395
396     /**
397      * Return the underlying table for this cursor. Apparently, some poor
398      * cursors don't have tables! Can you imagine!
399      */

400     public Table getTable() { return table; }
401
402     //#ifdef DEBUG
403
public String JavaDoc toString() {
404     try {
405         StringBuffer JavaDoc sb =
406                 new StringBuffer JavaDoc(Table.strip(getClass().getName()));
407         sb.append(": ");
408         sb.append(constraint.getName());
409         if (outer != null) {
410         sb.append(" (outer ");
411         sb.append(outer.toString()); // Table.strip(outer.getClass().getName()));
412
sb.append(")");
413         }
414             sb.append(" {");
415         for (int i = 1; i <= getColumnCount(); i++) {
416         Column c = getColumn(i);
417                 if (i > 1) sb.append(',');
418                 sb.append(c.getName());
419             }
420             sb.append('}');
421         return sb.toString();
422     } catch (Exception JavaDoc e) {
423         Debug.print(e);
424         return this.getClass().getName();
425     }
426     }
427     //#endif
428
}
429
Popular Tags