00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.ByteArrayOutputStream;
00042
import java.io.IOException;
00043
import java.io.OutputStream;
00044
00045
import java.sql.SQLException;
00046
00047
import com.quadcap.sql.io.ObjectOutputStream;
00048
00049
import com.quadcap.sql.file.ByteUtil;
00050
import com.quadcap.sql.file.SubPageManager;
00051
00052
import com.quadcap.sql.index.Comparator;
00053
00054
import com.quadcap.sql.types.KeyStream;
00055
import com.quadcap.sql.types.Type;
00056
import com.quadcap.sql.types.Value;
00057
import com.quadcap.sql.types.ValueInteger;
00058
00059
import com.quadcap.util.Debug;
00060
import com.quadcap.util.Util;
00061
00062
00063
00064
00065
00066
00067
00068
00069 public class Key extends Comparator {
00070
00071 static final boolean paranoid =
false;
00072
00073
00074 boolean[]
asc;
00075
00076 public Key(
int cnt) {
00077
asc =
new boolean[cnt];
00078
for (
int i = 0; i < cnt; i++)
asc[i] =
true;
00079 }
00080
00081 public Key(
boolean[] asc) {
00082
this.asc = asc;
00083 }
00084
00085 public static byte[]
makeKey(
Tuple tuple,
Row row,
int[] map,
long rowNum,
00086
boolean doRowNum)
00087
throws SQLException
00088 {
00089
00090
if (
false) {
00091 StringBuffer sb =
new StringBuffer(
"makeKey(");
00092 sb.append(row.toString());
00093 sb.append(
" (" + ((Object)row).
toString());
00094 sb.append(
", [");
00095
for (
int i = 0; i < map.length; i++) {
00096
if (i>0) sb.append(
',');
00097 sb.append(map[i]);
00098 }
00099 sb.append(
"], ");
00100 sb.append(
SubPageManager.toString(rowNum));
00101 sb.append(
", ");
00102 sb.append(doRowNum);
00103 sb.append(
")");
00104 sb.append(
"\nFROM:\n");
00105 sb.append(
Util.stackTrace());
00106
Debug.println(sb.toString());
00107 }
00108
00109
try {
00110 ByteArrayOutputStream bos =
new ByteArrayOutputStream();
00111
KeyStream out =
new KeyStream(bos,
Database.isCaseSensitive);
00112
00113
int cnt = 0;
00114
00115
if (map != null) {
00116
00117 cnt = map.length;
00118
00119
for (
int i = 0; i < map.length; i++) {
00120
int col = map[i];
00121
Value v = row.item(col);
00122
if (tuple != null) {
00123
Column c = tuple.getColumn(col);
00124
Type t = c.
getType();
00125 v = c.
getType().
convert(v);
00126 }
00127 v.
serializeKey(out);
00128 }
00129 }
else {
00130
00131 cnt = row.size();
00132
00133
for (
int i = 1; i <= row.size(); i++) {
00134
Value v = row.item(i);
00135 v.
serializeKey(out);
00136 }
00137 }
00138
if (doRowNum) {
00139 out.
writeLong(rowNum);
00140
00141 cnt++;
00142
00143 }
00144 byte[] ret = bos.toByteArray();
00145
00146
if (
paranoid) {
00147
Key k =
new Key(cnt);
00148 k.
checkKey(ret, 0, ret.length);
00149 }
00150
00151
return ret;
00152 }
catch (IOException e) {
00153
throw DbException.wrapThrowable(e);
00154 }
00155 }
00156
00157 public static byte[] makeKey(
Row row)
throws SQLException {
00158
return makeKey(null, row, null, 0,
false);
00159 }
00160
00161
00162
00163
00164 public boolean compareNulls(byte[] a, byte[] b) {
00165
00166
return compare(a, b) == 0;
00167 }
00168
00169 public static final int COMPOUND =
KeyStream.COMPOUND;
00170 public static final int INTEGER =
KeyStream.INTEGER;
00171 public static final int STRING =
KeyStream.STRING;
00172 public static final int NULL =
KeyStream.NULL;
00173
00174 public int compare(byte[] a, byte[] b) {
00175
return compare(a, 0, a.length, b, 0, b.length);
00176 }
00177
00178
00179 public final int compare(byte[] a,
int aoff,
int alen,
00180 byte[] b,
int boff,
int blen) {
00181
try {
00182
if (
paranoid) {
00183
checkKey(a, aoff, alen);
00184
checkKey(b, boff, blen);
00185 }
00186
int ret =
compare2(a, aoff, alen, b, boff, blen);
00187
if (
Trace.bit(6)) {
00188
Debug.println(
"Compare " +
asc.length +
" fields, ret=" + ret +
": " +
00189
toString(a, aoff, alen) +
00190
"(" +
Util.hexBytes(a, aoff, alen) +
") " +
00191
" vs " +
00192
toString(b, boff, blen) +
00193
"(" +
Util.hexBytes(b, boff, blen) +
") ");
00194
00195 }
00196
return ret;
00197 }
catch (
RuntimeException t) {
00198
Debug.print(t);
00199
Debug.println(
"asc.len = " +
asc.length);
00200
Debug.println(
"a = " +
toString(a, aoff, alen));
00201
Debug.println(
"a = " +
Util.hexBytes(a, aoff, alen));
00202
Debug.println(
"b = " +
toString(b, boff, blen));
00203
Debug.println(
"b = " +
Util.hexBytes(b, boff, blen));
00204
throw t;
00205 }
00206 }
00207
00208 public void checkKey(byte[] buf,
int off,
int len) {
00209
if (
getKeyLen(buf, off) != len) {
00210
Debug.println(
Util.strBytes(buf, off, len));
00211
Debug.println(
toString(buf, off, len));
00212
throw new RuntimeException(
"bad key len: " +
00213
getKeyLen(buf, off) +
" vs " +
00214 len);
00215 }
00216 }
00217
00218
final int compare2
00219
00220
00221
00222 (byte[] a,
int aoff,
int alen,
00223 byte[] b,
int boff,
int blen)
00224 {
00225
int i = 0;
00226
int askip = 0;
00227
int bskip = 0;
00228
int scalar = 0;
00229
while (i <
asc.length) {
00230
int ac = a[aoff++] & 0xff;
00231
int bc = b[boff++] & 0xff;
00232
final int atype = ac & 3;
00233
final int btype = bc & 3;
00234
int al = (ac >> 2) & 0x1f;
00235
int bl = (bc >> 2) & 0x1f;
00236
if ((ac & 0x80) != 0) {
00237 al <<= 8;
00238 al |= (a[aoff++] & 0xff);
00239 }
00240
if ((bc & 0x80) != 0) {
00241 bl <<= 8;
00242 bl |= (b[boff++] & 0xff);
00243 }
00244
00245
00246
switch ((atype << 2) | btype) {
00247
case (
COMPOUND << 2) |
COMPOUND:
00248 askip = al;
00249 bskip = bl;
00250
break;
00251
case (
INTEGER << 2) |
INTEGER:
00252
int signMask = 0xffffffff;
00253
if (al > bl) {
00254
int ab = a[aoff++];
00255
if (ab != 0)
return (ab < 0 ? -1 : 1) * (
asc[i] ? 1 : -1);
00256
while (--al > bl) {
00257
if (a[aoff++] != 0) {
00258
return asc[i] ? 1 : -1;
00259 }
00260 }
00261 signMask = 0xff;
00262 }
00263
00264
if (bl > al) {
00265
int bb = b[boff++];
00266
if (bb != 0)
return (bb < 0 ? 1 : -1) * (
asc[i] ? 1 : -1);
00267
while (--bl > al) {
00268
if (b[boff++] != 0) {
00269
return asc[i] ? -1 : 1;
00270 }
00271 }
00272 signMask = 0xff;
00273 }
00274
00275
int neg = (a[aoff] < 0) ? -1 : 1;
00276
int rneg = 1;
00277
while (al-- > 0) {
00278
int ab = a[aoff++] & signMask;
00279
int bb = b[boff++] & signMask;
00280
if (ab != bb) {
00281
int xa = a[aoff-1];
00282
return (ab < bb ? 1 : -1) * (
asc[i] ? -1 : 1) * rneg;
00283 }
00284 rneg = neg;
00285 signMask = 0xff;
00286 }
00287
break;
00288
case (
STRING << 2) |
STRING:
00289
while (al > 0 && bl > 0) {
00290
int ab = a[aoff++] & 0xff;
00291
int bb = b[boff++] & 0xff;
00292
if (ab != bb) {
00293
return (ab < bb ? 1 : -1) * (
asc[i] ? -1 : 1);
00294 }
00295 al--;
00296 bl--;
00297 }
00298
while (al-- > 0) {
00299
if (a[aoff++] != 0)
return asc[i] ? 1 : -1;
00300 }
00301
while (bl-- > 0) {
00302
if (b[boff++] != 0)
return asc[i] ? -1 : 1;
00303 }
00304
break;
00305
case (
NULL << 2) |
NULL:
00306
00307
if (al == 0) {
00308
if (bl != 0)
return -1;
00309 }
else {
00310
if (bl == 0)
return 1;
00311 }
00312
break;
00313
case (
NULL << 2) |
COMPOUND:
00314
case (
NULL << 2) |
INTEGER:
00315
case (
NULL << 2) |
STRING:
00316
return al == 0 ? -1 : 1;
00317
case (
COMPOUND << 2) |
NULL:
00318
case (
INTEGER << 2) |
NULL:
00319
case (
STRING << 2) |
NULL:
00320
return bl == 0 ? 1 : -1;
00321
00322
case (
COMPOUND << 2) |
INTEGER:
00323 askip = al;
00324 bskip = 1;
00325 boff--;
00326
break;
00327
case (
INTEGER << 2) |
COMPOUND:
00328 bskip = bl;
00329 askip = 1;
00330 aoff--;
00331
break;
00332
00333
case (
STRING << 2) |
INTEGER:
00334
return 1;
00335
case (
INTEGER << 2) |
STRING:
00336
return -1;
00337
00338
default:
00339
throw new RuntimeException(
"Cardinality error");
00340 }
00341 askip--;
00342 bskip--;
00343
if (askip < 0) {
00344
if (bskip < 0) {
00345
00346 i++;
00347 }
else {
00348
00349
while (bskip-- >= 0) {
00350 bc = b[boff++] & 0xff;
00351 bl = (bc >> 2) & 0x1f;
00352
if ((bc & 0x80) != 0) {
00353 bc <<= 8;
00354 bc |= (b[boff++] & 0xff);
00355 }
00356
for (
int j = 0; j < bl; j++) {
00357
if (b[boff++] != 0)
return -1;
00358 }
00359 i++;
00360 }
00361 }
00362 }
else {
00363
if (bskip < 0) {
00364
00365
while (askip-- >= 0) {
00366 ac = a[aoff++] & 0xff;
00367 al = (ac >> 2) & 0x1f;
00368
if ((ac & 0x80) != 0) {
00369 ac <<= 8;
00370 ac |= (a[aoff++] & 0xff);
00371 }
00372
for (
int j = 0; j < al; j++) {
00373
if (a[aoff++] != 0)
return 1;
00374 }
00375 i++;
00376 }
00377 }
else {
00378
00379 }
00380 }
00381 }
00382
return 0;
00383 }
00384
00385 public int getKeyLen(byte[] a,
int aoff) {
00386
int start = aoff;
00387
int i = 0;
00388
int skip = 0;
00389
while (i <
asc.length) {
00390
int ac = a[aoff++] & 0xff;
00391
final int atype = ac & 3;
00392
int al = (ac >> 2) & 0x1f;
00393
if ((ac & 0x80) != 0) {
00394 al <<= 8;
00395 al |= (a[aoff++] & 0xff);
00396 }
00397
switch (atype) {
00398
case NULL:
00399
break;
00400
case INTEGER:
00401
case STRING:
00402 aoff += al;
00403
break;
00404
case COMPOUND:
00405 skip = al;
00406
break;
00407 }
00408 skip--;
00409
if (skip < 0) i++;
00410 }
00411
return aoff - start;
00412 }
00413
00414
00415 public static String
toStringHelper(byte[] key) {
00416
return toStringHelper(key, 0, key.length);
00417 }
00418
00419 public String
toString(byte[] key,
int off,
int xlen) {
00420
return toStringHelper(key, off, xlen);
00421 }
00422
00423 public static String toStringHelper(byte[] key,
int off,
int xlen) {
00424 StringBuffer sb =
new StringBuffer();
00425
int lim = off + xlen;
00426 String delim =
"";
00427 String sdelim =
"";
00428
int clen = -1;
00429
while (off < lim) {
00430 clen--;
00431 sb.append(delim);
00432 sb.append(sdelim);
00433
if (clen > 0) sdelim =
",";
00434 delim =
", ";
00435
int c = key[off++] & 0xff;
00436
int type = c & 3;
00437
int len = (c >> 2) & 0x1f;
00438
if ((c & 0x80) != 0) {
00439 len <<= 8;
00440 len |= key[off++];
00441 }
00442
00443
00444
switch (type) {
00445
case COMPOUND:
00446 sb.append(
"{");
00447 sdelim =
"";
00448 clen = len;
00449
break;
00450
case INTEGER:
00451 sb.append(
"I(");
00452 sb.append(
Util.hexBytes(key, off, len));
00453 sb.append(
")");
00454 off += len;
00455
break;
00456
case STRING:
00457 sb.append(
"S(");
00458
00459
try {
00460 sb.append(
new String(key, off, len));
00461 }
catch (Throwable t) {
00462 sb.append(
"key[" + off +
":" + len +
"]:*****(" +
new String(key) +
")");
00463 }
00464 sb.append(
")");
00465 off += len;
00466
break;
00467
case NULL:
00468 sb.append(
"NULL");
00469
break;
00470 }
00471
if (clen == 0) {
00472 sb.append(
"}");
00473 sdelim =
"";
00474 }
00475 }
00476
return sb.toString();
00477 }
00478
00479 public static void test1() throws IOException {
00480 com.quadcap.sql.file.BlockFile f =
00481
new com.quadcap.sql.file.BlockFile(
"test1.bf",
"rw",
00482
new java.util.Properties(),
00483 4096, 256);
00484
long root = f.newPage();
00485
Key key =
new Key(1);
00486 com.quadcap.sql.index.Btree tree =
new com.quadcap.sql.index.Btree(f, key, root,
true);
00487 byte[] vk =
new byte[5];
00488
for (
int i = 0; i < 40000; i++) {
00489 byte[] r =
makeRandomKey();
00490
ByteUtil.putInt(vk, 0, i);
00491 tree.set(r, vk);
00492
if ((i % 1000) == 0) System.out.print(
".");
00493 }
00494 }
00495
00496 static java.util.Random
random =
new java.util.Random(666);
00497
00498 public static byte[]
makeRandomKey() throws IOException {
00499 ByteArrayOutputStream bos =
new ByteArrayOutputStream();
00500
KeyStream k =
new KeyStream(bos,
true);
00501 StringBuffer sb =
new StringBuffer();
00502
int lim = 40 +
random.nextInt(50);
00503
for (
int i = 0; i < lim; i++) {
00504 sb.append((
char)
random.nextInt(255));
00505 }
00506 k.
writeChars(sb.toString());
00507
return bos.toByteArray();
00508 }
00509
00510 public static void main(String[] args) {
00511
try {
00512
test1();
00513 }
catch (Exception e) {
00514
Debug.print(e);
00515 }
00516 }
00517
00518 }