1 33 package smallsql.database; 34 35 import java.sql.*; 36 37 40 class IndexNode { 41 final private boolean unique; 42 final private char digit; 44 static final private IndexNode[] EMPTY_NODES = new IndexNode[0]; 45 48 private IndexNode[] nodes = EMPTY_NODES; 49 50 56 private char[] remainderKey; 57 58 61 private Object value; 62 63 78 79 85 protected IndexNode(boolean unique, char digit){ 86 this.unique = unique; 87 this.digit = digit; 88 } 89 90 91 96 protected IndexNode createIndexNode(boolean unique, char digit){ 97 return new IndexNode(unique, digit); 98 } 99 100 101 final char getDigit(){ 102 return digit; 103 } 104 105 106 final boolean getUnique(){ 107 return unique; 108 } 109 110 111 115 final boolean isEmpty(){ 116 return nodes == EMPTY_NODES && value == null; 117 } 118 119 120 final void clear(){ 121 nodes = EMPTY_NODES; 122 value = null; 123 remainderKey = null; 124 } 125 126 127 final void clearValue(){ 128 value = null; 129 } 130 131 132 136 final Object getValue(){ 137 return value; 138 } 139 140 141 final IndexNode[] getChildNodes(){ 142 return nodes; 143 } 144 145 146 150 final IndexNode getChildNode(char digit){ 151 int pos = findNodePos(digit); 152 if(pos >=0) return nodes[pos]; 153 return null; 154 } 155 156 157 final char[] getRemainderValue(){ 158 return remainderKey; 159 } 160 161 162 166 final IndexNode addNode(char digit) throws SQLException{ 167 if(remainderKey != null) moveRemainderValue(); 168 int pos = findNodePos( digit ); 169 if(pos == -1){ 170 IndexNode node = createIndexNode(unique, digit); 171 saveNode( node ); 172 return node; 173 }else{ 174 return nodes[pos]; 175 } 176 } 177 178 179 183 final void removeNode(char digit){ 184 int pos = findNodePos( digit ); 185 if(pos != -1){ 186 int length = nodes.length-1; 187 IndexNode[] temp = new IndexNode[length]; 188 System.arraycopy(nodes, 0, temp, 0, pos); 189 System.arraycopy(nodes, pos+1, temp, pos, length-pos); 190 nodes = temp; 191 } 192 } 193 194 195 200 final void addNode(char digit, long rowOffset) throws SQLException{ 201 IndexNode node = addNode(digit); 202 if(node.remainderKey != null) node.moveRemainderValue(); 203 node.saveValue(rowOffset); 204 } 205 206 207 214 final void saveValue(long rowOffset) throws SQLException{ 215 if(unique){ 216 if(value != null) throw Utils.createSQLException("Duplikate Key"); 217 value = new Long (rowOffset); 218 }else{ 219 LongTreeList list = (LongTreeList)value; 220 if(list == null){ 221 value = list = new LongTreeList(); 222 } 223 list.add(rowOffset); 224 } 225 } 226 227 228 240 final void addRemainderKey(long rowOffset, long remainderValue, int charCount) throws SQLException{ 241 saveRemainderValue(remainderValue, charCount); 242 value = (unique) ? (Object )new Long (rowOffset) : new LongTreeList(rowOffset); 243 } 244 245 246 final void addRemainderKey(long rowOffset, char[] remainderValue, int offset) throws SQLException{ 247 saveRemainderValue(remainderValue, offset); 248 value = (unique) ? (Object )new Long (rowOffset) : new LongTreeList(rowOffset); 249 } 250 251 252 258 final IndexNode addRoot(char digit) throws SQLException{ 259 IndexNode node = addNode(digit); 260 if(node.remainderKey != null) node.moveRemainderValue(); 261 return node.addRoot(); 262 } 263 264 265 final IndexNode addRootValue(char[] remainderValue, int offset) throws SQLException{ 266 saveRemainderValue(remainderValue, offset); 267 return addRoot(); 268 } 269 270 271 final IndexNode addRootValue( long remainderValue, int digitCount) throws SQLException{ 272 saveRemainderValue(remainderValue, digitCount); 273 return addRoot(); 274 } 275 276 277 282 private final void moveRemainderValue() throws SQLException{ 283 Object rowOffset = value; 284 char[] puffer = remainderKey; 285 value = null; 286 remainderKey = null; 287 IndexNode newNode = addNode(puffer[0]); 288 if(puffer.length == 1){ 289 newNode.value = rowOffset; 290 }else{ 291 newNode.moveRemainderValueSub( rowOffset, puffer); 292 } 293 } 294 295 296 private final void moveRemainderValueSub( Object rowOffset, char[] remainderValue){ 297 int length = remainderValue.length-1; 298 this.remainderKey = new char[length]; 299 value = rowOffset; 300 System.arraycopy( remainderValue, 1, this.remainderKey, 0, length); 301 } 302 303 304 private final void saveRemainderValue(char[] remainderValue, int offset){ 305 int length = remainderValue.length-offset; 306 this.remainderKey = new char[length]; 307 System.arraycopy( remainderValue, offset, this.remainderKey, 0, length); 308 } 309 310 311 private final void saveRemainderValue( long remainderValue, int charCount){ 312 this.remainderKey = new char[charCount]; 313 for(int i=charCount-1, d=0; i>=0; i--){ 314 this.remainderKey[d++] = (char)(remainderValue >> (i<<4)); 315 } 316 } 317 318 322 final IndexNode addRoot() throws SQLException{ 323 IndexNode root = (IndexNode)value; 324 if(root == null){ 325 value = root = createIndexNode(unique, (char)-1); 326 } 327 return root; 328 } 329 330 331 private final void saveNode(IndexNode node){ 332 int length = nodes.length; 333 IndexNode[] temp = new IndexNode[length+1]; 334 if(length == 0){ 335 temp[0] = node; 336 }else{ 337 int pos = findNodeInsertPos( node.digit, 0, length); 338 System.arraycopy(nodes, 0, temp, 0, pos); 339 System.arraycopy(nodes, pos, temp, pos+1, length-pos); 340 temp[pos] = node; 341 } 342 nodes = temp; 343 } 344 345 346 private final int findNodeInsertPos(char digit, int start, int end){ 347 if(start == end) return start; 348 int mid = start + (end - start)/2; 349 char nodeDigit = nodes[mid].digit; 350 if(nodeDigit == digit) return mid; 351 if(nodeDigit < digit){ 352 return findNodeInsertPos( digit, mid+1, end ); 353 }else{ 354 if(start == mid) return start; 355 return findNodeInsertPos( digit, start, mid ); 356 } 357 } 358 359 360 private final int findNodePos(char digit){ 361 return findNodePos(digit, 0, nodes.length); 362 } 363 364 365 private final int findNodePos(char digit, int start, int end){ 366 if(start == nodes.length) return -1; 367 int mid = start + (end - start)/2; 368 char nodeDigit = nodes[mid].digit; 369 if(nodeDigit == digit) return mid; 370 if(nodeDigit < digit){ 371 return findNodePos( digit, mid+1, end ); 372 }else{ 373 if(start == mid) return -1; 374 return findNodePos( digit, start, mid-1 ); 375 } 376 } 377 378 379 void save(MemoryStream output){ 380 output.writeShort(digit); 381 382 int length = remainderKey == null ? 0 : remainderKey.length; 383 output.writeInt(length); 384 if(length>0) output.writeChars(remainderKey); 385 386 if(value == null){ 387 output.writeByte(0); 388 }else 389 if(value instanceof Long ){ 390 output.writeByte(1); 391 output.writeLong( ((Long )value).longValue() ); 392 }else 393 if(value instanceof LongTreeList){ 394 output.writeByte(2); 395 ((LongTreeList)value).save(output); 396 }else 397 if(value instanceof IndexNode){ 398 output.writeByte(3); 399 ((IndexNode)value).saveRef(output); 400 } 401 402 output.writeShort(nodes.length); 403 for(int i=0; i<nodes.length; i++){ 404 nodes[i].saveRef( output ); 405 } 406 407 } 408 409 410 411 void saveRef(MemoryStream output){ 412 413 } 414 415 416 static IndexNode loadRef( long offset ){ 417 throw new Error (); 418 } 419 420 421 void load(MemoryStream input) throws SQLException{ 422 int length = input.readInt(); 423 remainderKey = (length>0) ? input.readChars(length) : null; 424 425 int valueType = input.readByte(); 426 switch(valueType){ 427 case 0: 428 value = null; 429 break; 430 case 1: 431 value = new Long (input.readLong()); 432 break; 433 case 2: 434 value = new LongTreeList(input); 435 break; 436 case 3: 437 value = IndexNode.loadRef( input.readLong()); 438 break; 439 default: throw Utils.createSQLException("Error in loading Index. Index fils is corrupt. ("+valueType+")"); 440 } 441 442 nodes = new IndexNode[input.readShort()]; 443 for(int i=0; i<nodes.length; i++){ 444 nodes[i] = loadRef( input.readLong() ); 445 } 446 } 447 448 449 } 450 | Popular Tags |