KickJava   Java API By Example, From Geeks To Geeks.

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


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.OutputStream JavaDoc;
44
45 import java.sql.SQLException JavaDoc;
46
47 import com.quadcap.sql.io.ObjectOutputStream;
48
49 import com.quadcap.sql.file.ByteUtil;
50 import com.quadcap.sql.file.SubPageManager;
51
52 import com.quadcap.sql.index.Comparator;
53
54 import com.quadcap.sql.types.KeyStream;
55 import com.quadcap.sql.types.Type;
56 import com.quadcap.sql.types.Value;
57 import com.quadcap.sql.types.ValueInteger;
58
59 import com.quadcap.util.Debug;
60 import com.quadcap.util.Util;
61
62 /**
63  * Micro-optimized (-;) key serialization and comparison. This class
64  * is designed to eliminate copies and allocations during key comparison
65  * and serialization operations.
66  *
67  * @author Stan Bailes
68  */

69 public class Key extends Comparator {
70     //#ifdef DEBUG
71
static final boolean paranoid = false;
72     //#endif
73

74     boolean[] asc;
75
76     public Key(int cnt) {
77     asc = new boolean[cnt];
78     for (int i = 0; i < cnt; i++) asc[i] = true;
79     }
80
81     public Key(boolean[] asc) {
82     this.asc = asc;
83     }
84
85     public static byte[] makeKey(Tuple tuple, Row row, int[] map, long rowNum,
86                  boolean doRowNum)
87     throws SQLException JavaDoc
88     {
89         //#ifdef DEBUG
90
if (false) {
91             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("makeKey(");
92             sb.append(row.toString());
93             sb.append(" (" + ((Object JavaDoc)row).toString());
94             sb.append(", [");
95             for (int i = 0; i < map.length; i++) {
96                 if (i>0) sb.append(',');
97                 sb.append(map[i]);
98             }
99             sb.append("], ");
100             sb.append(SubPageManager.toString(rowNum));
101             sb.append(", ");
102             sb.append(doRowNum);
103             sb.append(")");
104             sb.append("\nFROM:\n");
105             sb.append(Util.stackTrace());
106             Debug.println(sb.toString());
107         }
108         //#endif
109
try {
110         ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
111         KeyStream out = new KeyStream(bos, Database.isCaseSensitive);
112         //#ifdef DEBUG
113
int cnt = 0;
114         //#endif
115
if (map != null) {
116         //#ifdef DEBUG
117
cnt = map.length;
118         //#endif
119
for (int i = 0; i < map.length; i++) {
120             int col = map[i];
121             Value v = row.item(col);
122             if (tuple != null) {
123             Column c = tuple.getColumn(col);
124                         Type t = c.getType();
125                         v = c.getType().convert(v);
126             }
127             v.serializeKey(out);
128         }
129         } else {
130         //#ifdef DEBUG
131
cnt = row.size();
132         //#endif
133
for (int i = 1; i <= row.size(); i++) {
134                     Value v = row.item(i);
135             v.serializeKey(out);
136         }
137         }
138         if (doRowNum) {
139         out.writeLong(rowNum);
140         //#ifdef DEBUG
141
cnt++;
142         //#endif
143
}
144         byte[] ret = bos.toByteArray();
145         //#ifdef DEBUG
146
if (paranoid) {
147         Key k = new Key(cnt);
148         k.checkKey(ret, 0, ret.length);
149         }
150         //#endif
151
return ret;
152     } catch (IOException JavaDoc e) {
153         throw DbException.wrapThrowable(e);
154     }
155     }
156
157     public static byte[] makeKey(Row row) throws SQLException JavaDoc {
158     return makeKey(null, row, null, 0, false);
159     }
160
161     /**
162      * Null comparison for GROUP BY
163      */

164     public boolean compareNulls(byte[] a, byte[] b) {
165     // XXX hack
166
return compare(a, b) == 0;
167     }
168
169     public static final int COMPOUND = KeyStream.COMPOUND;
170     public static final int INTEGER = KeyStream.INTEGER;
171     public static final int STRING = KeyStream.STRING;
172     public static final int NULL = KeyStream.NULL;
173
174     public int compare(byte[] a, byte[] b) {
175     return compare(a, 0, a.length, b, 0, b.length);
176     }
177
178     //#ifdef DEBUG
179
public final int compare(byte[] a, int aoff, int alen,
180                              byte[] b, int boff, int blen) {
181     try {
182         if (paranoid) {
183         checkKey(a, aoff, alen);
184         checkKey(b, boff, blen);
185         }
186         int ret = compare2(a, aoff, alen, b, boff, blen);
187             if (Trace.bit(6)) {
188                 Debug.println("Compare " + asc.length + " fields, ret=" + ret + ": " +
189                               toString(a, aoff, alen) +
190                               "(" + Util.hexBytes(a, aoff, alen) + ") " +
191                               " vs " +
192                               toString(b, boff, blen) +
193                               "(" + Util.hexBytes(b, boff, blen) + ") ");
194                 //Debug.println(Util.stackTrace());
195
}
196         return ret;
197     } catch (RuntimeException JavaDoc t) {
198         Debug.print(t);
199             Debug.println("asc.len = " + asc.length);
200         Debug.println("a = " + toString(a, aoff, alen));
201             Debug.println("a = " + Util.hexBytes(a, aoff, alen));
202         Debug.println("b = " + toString(b, boff, blen));
203             Debug.println("b = " + Util.hexBytes(b, boff, blen));
204         throw t;
205     }
206     }
207
208     public void checkKey(byte[] buf, int off, int len) {
209     if (getKeyLen(buf, off) != len) {
210         Debug.println(Util.strBytes(buf, off, len));
211         Debug.println(toString(buf, off, len));
212         throw new RuntimeException JavaDoc("bad key len: " +
213                        getKeyLen(buf, off) + " vs " +
214                        len);
215     }
216     }
217
218     final int compare2
219     //#else
220
//- public final int compare
221
//#endif
222
(byte[] a, int aoff, int alen,
223      byte[] b, int boff, int blen)
224     {
225     int i = 0;
226     int askip = 0;
227     int bskip = 0;
228     int scalar = 0;
229     while (i < asc.length) {
230         int ac = a[aoff++] & 0xff;
231         int bc = b[boff++] & 0xff;
232         final int atype = ac & 3;
233         final int btype = bc & 3;
234         int al = (ac >> 2) & 0x1f;
235         int bl = (bc >> 2) & 0x1f;
236         if ((ac & 0x80) != 0) {
237         al <<= 8;
238         al |= (a[aoff++] & 0xff);
239         }
240         if ((bc & 0x80) != 0) {
241         bl <<= 8;
242         bl |= (b[boff++] & 0xff);
243         }
244         //Debug.println("Field " + i + ": " + atype + " - " + btype);
245
//Debug.println("ac/al = " + ac + "/" + al + ", bc/bl = " + bc + "/" + bl);
246
switch ((atype << 2) | btype) {
247         case (COMPOUND << 2) | COMPOUND:
248         askip = al;
249         bskip = bl;
250         break;
251         case (INTEGER << 2) | INTEGER:
252                 int signMask = 0xffffffff;
253                 if (al > bl) {
254                     int ab = a[aoff++];
255                     if (ab != 0) return (ab < 0 ? -1 : 1) * (asc[i] ? 1 : -1);
256                     while (--al > bl) {
257                         if (a[aoff++] != 0) {
258                             return asc[i] ? 1 : -1;
259                         }
260                     }
261                     signMask = 0xff;
262                 }
263
264                 if (bl > al) {
265                     int bb = b[boff++];
266                     if (bb != 0) return (bb < 0 ? 1 : -1) * (asc[i] ? 1 : -1);
267                     while (--bl > al) {
268                         if (b[boff++] != 0) {
269                             return asc[i] ? -1 : 1;
270                         }
271                     }
272                     signMask = 0xff;
273                 }
274
275                 int neg = (a[aoff] < 0) ? -1 : 1;
276                 int rneg = 1;
277                 while (al-- > 0) {
278             int ab = a[aoff++] & signMask;
279             int bb = b[boff++] & signMask;
280             if (ab != bb) {
281                         int xa = a[aoff-1];
282                         return (ab < bb ? 1 : -1) * (asc[i] ? -1 : 1) * rneg;
283                     }
284                     rneg = neg;
285                     signMask = 0xff;
286         }
287         break;
288         case (STRING << 2) | STRING:
289         while (al > 0 && bl > 0) {
290             int ab = a[aoff++] & 0xff;
291             int bb = b[boff++] & 0xff;
292                     if (ab != bb) {
293                         return (ab < bb ? 1 : -1) * (asc[i] ? -1 : 1);
294                     }
295             al--;
296             bl--;
297         }
298                 while (al-- > 0) {
299                     if (a[aoff++] != 0) return asc[i] ? 1 : -1;
300                 }
301                 while (bl-- > 0) {
302                     if (b[boff++] != 0) return asc[i] ? -1 : 1;
303                 }
304         break;
305         case (NULL << 2) | NULL:
306         // length == 0: first null, otherwise last null
307
if (al == 0) {
308             if (bl != 0) return -1;
309         } else {
310             if (bl == 0) return 1;
311         }
312         break;
313         case (NULL << 2) | COMPOUND:
314         case (NULL << 2) | INTEGER:
315         case (NULL << 2) | STRING:
316         return al == 0 ? -1 : 1;
317         case (COMPOUND << 2) | NULL:
318         case (INTEGER << 2) | NULL:
319         case (STRING << 2) | NULL:
320         return bl == 0 ? 1 : -1;
321
322         case (COMPOUND << 2) | INTEGER:
323         askip = al;
324         bskip = 1;
325         boff--;
326         break;
327         case (INTEGER << 2) | COMPOUND:
328         bskip = bl;
329         askip = 1;
330         aoff--;
331         break;
332
333         case (STRING << 2) | INTEGER:
334                 return 1;
335             case (INTEGER << 2) | STRING:
336                 return -1;
337
338         default:
339         throw new RuntimeException JavaDoc("Cardinality error");
340         }
341         askip--;
342         bskip--;
343         if (askip < 0) {
344         if (bskip < 0) {
345             // end of both compound fields
346
i++;
347         } else {
348             // end of a, more fields left in b
349
while (bskip-- >= 0) {
350             bc = b[boff++] & 0xff;
351             bl = (bc >> 2) & 0x1f;
352             if ((bc & 0x80) != 0) {
353                 bc <<= 8;
354                 bc |= (b[boff++] & 0xff);
355             }
356             for (int j = 0; j < bl; j++) {
357                 if (b[boff++] != 0) return -1;
358             }
359             i++;
360             }
361         }
362         } else {
363         if (bskip < 0) {
364             // end of b, more fields left in a
365
while (askip-- >= 0) {
366             ac = a[aoff++] & 0xff;
367             al = (ac >> 2) & 0x1f;
368             if ((ac & 0x80) != 0) {
369                 ac <<= 8;
370                 ac |= (a[aoff++] & 0xff);
371             }
372             for (int j = 0; j < al; j++) {
373                 if (a[aoff++] != 0) return 1;
374             }
375             i++;
376             }
377         } else {
378             // next compound field
379
}
380         }
381     }
382     return 0;
383     }
384
385     public int getKeyLen(byte[] a, int aoff) {
386     int start = aoff;
387     int i = 0;
388     int skip = 0;
389     while (i < asc.length) {
390         int ac = a[aoff++] & 0xff;
391         final int atype = ac & 3;
392         int al = (ac >> 2) & 0x1f;
393         if ((ac & 0x80) != 0) {
394         al <<= 8;
395         al |= (a[aoff++] & 0xff);
396         }
397         switch (atype) {
398         case NULL:
399         break;
400         case INTEGER:
401         case STRING:
402         aoff += al;
403         break;
404         case COMPOUND:
405         skip = al;
406         break;
407         }
408         skip--;
409         if (skip < 0) i++;
410     }
411     return aoff - start;
412     }
413
414     //#ifdef DEBUG
415
public static String JavaDoc toStringHelper(byte[] key) {
416         return toStringHelper(key, 0, key.length);
417     }
418     
419     public String JavaDoc toString(byte[] key, int off, int xlen) {
420         return toStringHelper(key, off, xlen);
421     }
422     
423     public static String JavaDoc toStringHelper(byte[] key, int off, int xlen) {
424     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
425     int lim = off + xlen;
426     String JavaDoc delim = "";
427     String JavaDoc sdelim = "";
428     int clen = -1;
429     while (off < lim) {
430         clen--;
431         sb.append(delim);
432         sb.append(sdelim);
433         if (clen > 0) sdelim =",";
434         delim = ", ";
435         int c = key[off++] & 0xff;
436         int type = c & 3;
437         int len = (c >> 2) & 0x1f;
438         if ((c & 0x80) != 0) {
439         len <<= 8;
440         len |= key[off++];
441         }
442         //Debug.println("TYPE: " + type + ", off = " + off +
443
// ", len = " + len);
444
switch (type) {
445         case COMPOUND:
446         sb.append("{");
447         sdelim = "";
448         clen = len;
449         break;
450         case INTEGER:
451         sb.append("I(");
452         sb.append(Util.hexBytes(key, off, len));
453         sb.append(")");
454         off += len;
455         break;
456         case STRING:
457         sb.append("S(");
458         //sb.append(Util.hexBytes(key, off, len));
459
try {
460                     sb.append(new String JavaDoc(key, off, len));
461                 } catch (Throwable JavaDoc t) {
462                     sb.append("key[" + off + ":" + len + "]:*****(" + new String JavaDoc(key) + ")");
463                 }
464         sb.append(")");
465         off += len;
466         break;
467         case NULL:
468         sb.append("NULL");
469         break;
470         }
471         if (clen == 0) {
472         sb.append("}");
473         sdelim = "";
474         }
475     }
476     return sb.toString();
477     }
478
479     public static void test1() throws IOException JavaDoc {
480     com.quadcap.sql.file.BlockFile f =
481             new com.quadcap.sql.file.BlockFile("test1.bf", "rw",
482                                                new java.util.Properties JavaDoc(),
483                                                4096, 256);
484     long root = f.newPage();
485     Key key = new Key(1);
486     com.quadcap.sql.index.Btree tree = new com.quadcap.sql.index.Btree(f, key, root, true);
487         byte[] vk = new byte[5];
488     for (int i = 0; i < 40000; i++) {
489         byte[] r = makeRandomKey();
490             ByteUtil.putInt(vk, 0, i);
491         tree.set(r, vk);
492         if ((i % 1000) == 0) System.out.print(".");
493     }
494     }
495
496     static java.util.Random JavaDoc random = new java.util.Random JavaDoc(666);
497
498     public static byte[] makeRandomKey() throws IOException JavaDoc {
499     ByteArrayOutputStream JavaDoc bos = new ByteArrayOutputStream JavaDoc();
500     KeyStream k = new KeyStream(bos, true);
501     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
502     int lim = 40 + random.nextInt(50);
503     for (int i = 0; i < lim; i++) {
504         sb.append((char)random.nextInt(255));
505     }
506     k.writeChars(sb.toString());
507     return bos.toByteArray();
508     }
509
510     public static void main(String JavaDoc[] args) {
511     try {
512         test1();
513     } catch (Exception JavaDoc e) {
514         Debug.print(e);
515     }
516     }
517     //#endif
518
}
519
Popular Tags