1 33 package smallsql.database; 34 35 import java.sql.SQLException ; 36 import java.util.ArrayList ; 37 38 39 63 class Index{ 64 65 final IndexNode rootPage; 66 67 71 Index(boolean unique){ 72 rootPage = new IndexNode(unique, (char)-1); 73 } 74 75 76 Index(IndexNode rootPage){ 77 this.rootPage = rootPage; 78 } 79 80 81 IndexScrollStatus createScrollStatus(Expressions expressions){ 82 return new IndexScrollStatus(rootPage, expressions); 83 } 84 85 90 final Object findRows( Expressions expressions, ArrayList nodeList ) throws Exception { 91 IndexNode page = rootPage; 92 int count = expressions.size(); 93 for(int i=0; i<count; i++){ 94 page = findRows( page, expressions.get(i), nodeList); 95 if(page == null) 96 return null; 97 if(i+1 == count) 98 return page.getValue(); 99 else 100 page = (IndexNode)page.getValue(); 101 } 102 throw new Error (); 103 } 104 105 106 111 final Object findRows( Expression[] expressions, ArrayList nodeList ) throws Exception { 112 IndexNode page = rootPage; 113 int count = expressions.length; 114 for(int i=0; i<count; i++){ 115 page = findRows( page, expressions[i], nodeList); 116 if(page == null) 117 return null; 118 if(i+1 == count) 119 return page.getValue(); 120 else 121 page = (IndexNode)page.getValue(); 122 } 123 throw new Error (); 124 } 125 126 127 128 final private IndexNode findRows(IndexNode page, Expression expr, ArrayList nodeList) throws Exception { 129 if(expr.isNull()){ 130 page = findNull(page); 131 }else{ 132 switch(expr.getDataType()){ 133 case SQLTokenizer.REAL: 134 page = find( page, floatToBinarySortOrder( expr.getFloat()), 2, nodeList ); 135 break; 136 case SQLTokenizer.DOUBLE: 137 case SQLTokenizer.FLOAT: 138 page = find( page, doubleToBinarySortOrder( expr.getDouble()), 4, nodeList ); 139 break; 140 case SQLTokenizer.TINYINT: 141 page = find( page, expr.getInt(), 1, nodeList ); 142 break; 143 case SQLTokenizer.SMALLINT: 144 page = find( page, shortToBinarySortOrder( expr.getInt()), 1, nodeList ); 145 break; 146 case SQLTokenizer.INT: 147 page = find( page, intToBinarySortOrder( expr.getInt()), 2, nodeList ); 148 break; 149 case SQLTokenizer.BIGINT: 150 case SQLTokenizer.DATE: 151 case SQLTokenizer.TIME: 152 case SQLTokenizer.TIMESTAMP: 153 case SQLTokenizer.SMALLDATETIME: 154 case SQLTokenizer.MONEY: 155 case SQLTokenizer.SMALLMONEY: 156 page = find( page, longToBinarySortOrder( expr.getLong()), 4, nodeList ); 157 break; 158 case SQLTokenizer.VARCHAR: 159 case SQLTokenizer.NVARCHAR: 160 case SQLTokenizer.LONGVARCHAR: 161 case SQLTokenizer.LONGNVARCHAR: 162 case SQLTokenizer.CLOB: 163 page = find( page, stringToBinarySortOrder( expr.getString(), false ), nodeList ); 164 break; 165 case SQLTokenizer.NCHAR: 166 case SQLTokenizer.CHAR: 167 page = find( page, stringToBinarySortOrder( expr.getString(), true ), nodeList ); 168 break; 169 case SQLTokenizer.VARBINARY: 170 case SQLTokenizer.BINARY: 171 case SQLTokenizer.LONGVARBINARY: 172 case SQLTokenizer.BLOB: 173 case SQLTokenizer.UNIQUEIDENTIFIER: 174 page = find( page, bytesToBinarySortOrder( expr.getBytes()), nodeList ); 175 break; 176 case SQLTokenizer.BIT: 177 case SQLTokenizer.BOOLEAN: 178 page = find( page, expr.getBoolean() ? 2 : 1, 1, nodeList ); 179 break; 180 case SQLTokenizer.NUMERIC: 181 case SQLTokenizer.DECIMAL: 182 page = find( page, numericToBinarySortOrder( expr.getNumeric() ), nodeList ); 183 break; 184 default: 185 throw new Error (String.valueOf(expr.getDataType())); 187 } 188 } 189 return page; 190 } 191 192 193 198 final void addValues( long rowOffset, Expressions expressions ) throws Exception { 199 IndexNode page = this.rootPage; 200 int count = expressions.size(); 201 for(int i=0; i<count; i++){ 202 Expression expr = expressions.get(i); 203 boolean isLastValues = (i == count-1); 204 if(expr.isNull()){ 205 page = addNull(page, rowOffset, isLastValues); 206 }else{ 207 switch(expr.getDataType()){ 208 case SQLTokenizer.REAL: 209 page = add( page, rowOffset, floatToBinarySortOrder( expr.getFloat()), isLastValues, 2 ); 210 break; 211 case SQLTokenizer.DOUBLE: 212 case SQLTokenizer.FLOAT: 213 page = add( page, rowOffset, doubleToBinarySortOrder( expr.getDouble()), isLastValues, 4 ); 214 break; 215 case SQLTokenizer.TINYINT: 216 page = add( page, rowOffset, expr.getInt(), isLastValues, 1 ); 217 break; 218 case SQLTokenizer.SMALLINT: 219 page = add( page, rowOffset, shortToBinarySortOrder( expr.getInt()), isLastValues, 1 ); 220 break; 221 case SQLTokenizer.INT: 222 page = add( page, rowOffset, intToBinarySortOrder( expr.getInt()), isLastValues, 2 ); 223 break; 224 case SQLTokenizer.BIGINT: 225 case SQLTokenizer.DATE: 226 case SQLTokenizer.TIME: 227 case SQLTokenizer.TIMESTAMP: 228 case SQLTokenizer.SMALLDATETIME: 229 case SQLTokenizer.MONEY: 230 case SQLTokenizer.SMALLMONEY: 231 page = add( page, rowOffset, longToBinarySortOrder( expr.getLong()), isLastValues, 4 ); 232 break; 233 case SQLTokenizer.VARCHAR: 234 case SQLTokenizer.NVARCHAR: 235 case SQLTokenizer.LONGVARCHAR: 236 case SQLTokenizer.LONGNVARCHAR: 237 page = add( page, rowOffset, stringToBinarySortOrder( expr.getString(), false ), isLastValues ); 238 break; 239 case SQLTokenizer.NCHAR: 240 case SQLTokenizer.CHAR: 241 page = add( page, rowOffset, stringToBinarySortOrder( expr.getString(), true ), isLastValues ); 242 break; 243 case SQLTokenizer.VARBINARY: 244 case SQLTokenizer.BINARY: 245 case SQLTokenizer.LONGVARBINARY: 246 case SQLTokenizer.BLOB: 247 case SQLTokenizer.UNIQUEIDENTIFIER: 248 page = add( page, rowOffset, bytesToBinarySortOrder( expr.getBytes()), isLastValues ); 249 break; 250 case SQLTokenizer.BIT: 251 case SQLTokenizer.BOOLEAN: 252 page = add( page, rowOffset, expr.getBoolean() ? 2 : 1, isLastValues, 1 ); 253 break; 254 case SQLTokenizer.NUMERIC: 255 case SQLTokenizer.DECIMAL: 256 page = add( page, rowOffset, numericToBinarySortOrder( expr.getNumeric()), isLastValues ); 257 break; 258 default: 259 throw new Error (String.valueOf(expr.getDataType())); 261 } 262 } 263 } 264 } 265 266 267 final void removeValue( long rowOffset, Expressions expressions ) throws Exception { 268 ArrayList nodeList = new ArrayList (); 269 Object obj = findRows(expressions, nodeList); 270 if(!rootPage.getUnique()){ 271 LongTreeList list = (LongTreeList)obj; 272 list.remove(rowOffset); 273 if(list.getSize() > 0) return; 274 } 275 IndexNode node = (IndexNode)nodeList.get(nodeList.size()-1); 276 node.clearValue(); 277 for(int i = nodeList.size()-2; i >= 0; i--){ 278 if(!node.isEmpty()) 279 break; 280 IndexNode parent = (IndexNode)nodeList.get(i); 281 parent.removeNode( node.getDigit() ); 282 node = parent; 283 } 284 } 285 286 287 final private IndexNode findNull(IndexNode page){ 288 return page.getChildNode( (char)0 ); 289 } 290 291 292 final private IndexNode addNull(IndexNode page, long rowOffset, boolean isLastValue) throws SQLException { 293 if(isLastValue){ 294 page.addNode( (char)0, rowOffset ); 295 return null; 296 }else 297 return page.addRoot((char)0); 298 } 299 300 301 final private IndexNode find(IndexNode node, long key, int digitCount, ArrayList nodeList){ 302 for(int i=digitCount-1; i>=0; i--){ 303 char digit = (char)(key >> (i<<4)); 304 node = node.getChildNode(digit); 305 306 if(node == null) return null; 307 if(nodeList != null) nodeList.add(node); 308 309 if(equals(node.getRemainderValue(), key, i)){ 310 return node; 311 } 312 } 313 return node; 314 } 315 316 317 321 final private IndexNode add(IndexNode node, long rowOffset, long key, boolean isLastValue, int digitCount) throws SQLException { 322 for(int i=digitCount-1; i>=0; i--){ 323 char digit = (char)(key >> (i<<4)); 324 if(i == 0){ 325 if(isLastValue){ 326 node.addNode( digit, rowOffset ); 327 return null; 328 } 329 return node.addRoot(digit); 330 } 331 node = node.addNode(digit); 332 if(node.isEmpty()){ 333 if(isLastValue){ 334 node.addRemainderKey( rowOffset, key, i ); 335 return null; 336 } 337 return node.addRootValue( key, i); 338 }else 339 if(equals(node.getRemainderValue(), key, i)){ 340 if(isLastValue){ 341 node.saveValue( rowOffset); 342 return null; 343 } 344 return node.addRoot(); 345 } 346 } 347 throw new Error (); 348 } 349 350 351 final private IndexNode find(IndexNode node, char[] key, ArrayList nodeList){ 352 int length = key.length; 353 int i=-1; 354 while(true){ 355 char digit = (i<0) ? (length == 0 ? (char)1 : 2) 357 : (key[i]); 358 node = node.getChildNode(digit); 359 360 if(node == null) return null; 361 if(nodeList != null) nodeList.add(node); 362 if(++i == length){ 363 return node; 364 } 365 366 if(equals(node.getRemainderValue(), key, i)){ 367 return node; 368 } 369 } 370 } 371 372 373 376 final private IndexNode add(IndexNode node, long rowOffset, char[] key, boolean isLast) throws SQLException { 377 int length = key.length; 378 int i=-1; 379 while(true){ 380 char digit = (i<0) ? (length == 0 ? (char)1 : 2) 382 : (key[i]); 383 if(++i == length){ 384 if(isLast){ 385 node.addNode( digit, rowOffset ); 386 return null; 387 } 388 return node.addRoot(digit); 389 } 390 node = node.addNode(digit); 391 if(node.isEmpty()){ 392 if(isLast){ 393 node.addRemainderKey( rowOffset, key, i ); 394 return null; 395 } 396 return node.addRootValue( key, i ); 397 }else 398 if(equals(node.getRemainderValue(), key, i)){ 399 if(isLast){ 400 node.saveValue(rowOffset); 401 return null; 402 } 403 return node.addRoot(); 404 } 405 } 406 } 407 408 409 412 final void clear(){ 413 rootPage.clear(); 414 } 415 420 421 422 final static private int floatToBinarySortOrder(float value){ 423 int intValue = Float.floatToIntBits(value); 424 return (intValue<0) ? 425 ~intValue : 426 intValue ^ 0x80000000; 427 } 428 429 final static private long doubleToBinarySortOrder(double value){ 430 long intValue = Double.doubleToLongBits(value); 431 return (intValue<0) ? 432 ~intValue : 433 intValue ^ 0x8000000000000000L; 434 } 435 436 final static private int shortToBinarySortOrder(int value){ 437 return value ^ 0x8000; 438 } 439 440 final static private int intToBinarySortOrder(int value){ 441 return value ^ 0x80000000; 442 } 443 444 final static private long longToBinarySortOrder(long value){ 445 return value ^ 0x8000000000000000L; 446 } 447 448 449 final static private char[] stringToBinarySortOrder(String value, boolean needTrim){ 450 int length = value.length(); 451 if(needTrim){ 452 while(length > 0 && value.charAt(length-1) == ' ') length--; 453 } 454 char[] puffer = new char[length]; 455 for(int i=0; i<length; i++){ 456 puffer[i] = Character.toLowerCase(Character.toUpperCase( value.charAt(i) )); 457 } 458 return puffer; 459 } 460 461 462 final static private char[] bytesToBinarySortOrder(byte[] value){ 463 int length = value.length; 464 char[] puffer = new char[length]; 465 for(int i=0; i<length; i++){ 466 puffer[i] = (char)(value[i] & 0xFF); 467 } 468 return puffer; 469 } 470 471 472 final static private char[] numericToBinarySortOrder(MutableNumeric numeric){ 473 int[] value = numeric.getInternalValue(); 474 int count = 1; 475 int i; 476 for(i=0; i<value.length; i++){ 477 if(value[i] != 0){ 478 count = 2*(value.length - i)+1; 479 break; 480 } 481 } 482 char[] puffer = new char[count]; 483 puffer[0] = (char)count; 484 for(int c=1; c<count;){ 485 puffer[c++] = (char)(value[i] >> 16); 486 puffer[c++] = (char)value[i++]; 487 } 488 return puffer; 489 } 490 491 492 497 498 499 500 private final boolean equals(char[] src1, char[] src2, int offset2){ 501 if(src1 == null) return false; 502 int length = src1.length; 503 if(length != src2.length - offset2) return false; 504 for(int i=0; i<length; i++){ 505 if(src1[i] != src2[i+offset2]) return false; 506 } 507 return true; 508 } 509 510 511 private final boolean equals(char[] src1, long src2, int charCount){ 512 if(src1 == null) return false; 513 int length = src1.length; 514 if(length != charCount) return false; 515 for(int i=0, d = charCount-1; i<length; i++){ 516 if(src1[i] != (char)((src2 >> (d-- << 4)))) return false; 517 } 518 return true; 519 } 520 } 521 | Popular Tags |