1 21 22 package org.apache.derby.impl.sql.compile; 23 24 import org.apache.derby.iapi.sql.compile.CostEstimate; 25 import org.apache.derby.iapi.sql.compile.ExpressionClassBuilderInterface; 26 import org.apache.derby.iapi.sql.compile.JoinStrategy; 27 import org.apache.derby.iapi.sql.compile.Optimizable; 28 import org.apache.derby.iapi.sql.compile.Optimizer; 29 import org.apache.derby.iapi.sql.compile.OptimizablePredicate; 30 import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; 31 32 import org.apache.derby.iapi.sql.dictionary.DataDictionary; 33 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; 34 35 import org.apache.derby.iapi.store.access.StoreCostController; 36 import org.apache.derby.iapi.store.access.TransactionController; 37 38 import org.apache.derby.iapi.services.compiler.MethodBuilder; 39 40 import org.apache.derby.impl.sql.compile.ExpressionClassBuilder; 41 import org.apache.derby.impl.sql.compile.ProjectRestrictNode; 42 import org.apache.derby.impl.sql.compile.Predicate; 43 44 import org.apache.derby.iapi.error.StandardException; 45 46 import org.apache.derby.iapi.reference.SQLState; 47 48 import org.apache.derby.iapi.services.cache.ClassSize; 49 50 import org.apache.derby.iapi.services.sanity.SanityManager; 51 52 import org.apache.derby.iapi.services.io.FormatableArrayHolder; 53 import org.apache.derby.iapi.services.io.FormatableIntHolder; 54 55 import org.apache.derby.iapi.util.JBitSet; 56 57 import java.util.Vector ; 58 59 public class HashJoinStrategy extends BaseJoinStrategy { 60 public HashJoinStrategy() { 61 } 62 63 68 public boolean feasible(Optimizable innerTable, 69 OptimizablePredicateList predList, 70 Optimizer optimizer 71 ) 72 throws StandardException 73 { 74 int[] hashKeyColumns = null; 75 76 ConglomerateDescriptor cd = null; 77 78 83 if (! innerTable.isMaterializable()) 84 { 85 86 optimizer.trace(Optimizer.HJ_SKIP_NOT_MATERIALIZABLE, 0, 0, 0.0, 87 null); 88 return false; 89 } 90 91 96 if (innerTable.isTargetTable()) 97 { 98 return false; 99 } 100 101 123 if ((predList != null) && (predList.size() > 0) && 124 !(innerTable instanceof FromBaseTable)) 125 { 126 FromTable ft = (FromTable)innerTable; 127 128 JBitSet tNums = new JBitSet(ft.getReferencedTableMap().size()); 131 BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tNums); 132 ft.accept(btnVis); 133 134 JBitSet pNums = new JBitSet(tNums.size()); 137 Predicate pred = null; 138 for (int i = 0; i < predList.size(); i++) 139 { 140 pred = (Predicate)predList.getOptPredicate(i); 141 if (pred.isJoinPredicate()) 142 pNums.or(pred.getReferencedSet()); 143 } 144 145 tNums.and(pNums); 151 if (tNums.getFirstSetBit() != -1) 152 return false; 153 } 154 155 if (innerTable.isBaseTable()) 156 { 157 158 cd = innerTable.getCurrentAccessPath().getConglomerateDescriptor(); 159 } 160 161 162 hashKeyColumns = findHashKeyColumns( 163 innerTable, 164 cd, 165 predList); 166 167 if (SanityManager.DEBUG) 168 { 169 if (hashKeyColumns == null) 170 { 171 optimizer.trace(Optimizer.HJ_SKIP_NO_JOIN_COLUMNS, 0, 0, 0.0, null); 172 } 173 else 174 { 175 optimizer.trace(Optimizer.HJ_HASH_KEY_COLUMNS, 0, 0, 0.0, hashKeyColumns); 176 } 177 } 178 179 if (hashKeyColumns == null) 180 { 181 return false; 182 } 183 184 return true; 185 } 186 187 188 public boolean ignoreBulkFetch() { 189 return true; 190 } 191 192 193 public boolean multiplyBaseCostByOuterRows() { 194 return false; 195 } 196 197 202 public OptimizablePredicateList getBasePredicates( 203 OptimizablePredicateList predList, 204 OptimizablePredicateList basePredicates, 205 Optimizable innerTable) 206 throws StandardException { 207 if (SanityManager.DEBUG) { 208 SanityManager.ASSERT(basePredicates.size() == 0, 209 "The base predicate list should be empty."); 210 } 211 212 for (int i = predList.size() - 1; i >= 0; i--) { 213 OptimizablePredicate pred = predList.getOptPredicate(i); 214 215 if (innerTable.getReferencedTableMap().contains(pred.getReferencedMap())) 216 { 217 basePredicates.addOptPredicate(pred); 218 predList.removeOptPredicate(i); 219 } 220 } 221 222 basePredicates.classify( 223 innerTable, 224 innerTable.getCurrentAccessPath().getConglomerateDescriptor()); 225 226 return basePredicates; 227 } 228 229 230 public double nonBasePredicateSelectivity( 231 Optimizable innerTable, 232 OptimizablePredicateList predList) 233 throws StandardException { 234 double retval = 1.0; 235 236 if (predList != null) { 237 for (int i = 0; i < predList.size(); i++) { 238 if (predList.isRedundantPredicate(i)) 240 { 241 continue; 242 } 243 244 retval *= predList.getOptPredicate(i).selectivity(innerTable); 245 } 246 } 247 248 return retval; 249 } 250 251 256 public void putBasePredicates(OptimizablePredicateList predList, 257 OptimizablePredicateList basePredicates) 258 throws StandardException { 259 for (int i = basePredicates.size() - 1; i >= 0; i--) { 260 OptimizablePredicate pred = basePredicates.getOptPredicate(i); 261 262 predList.addOptPredicate(pred); 263 basePredicates.removeOptPredicate(i); 264 } 265 } 266 267 268 public void estimateCost(Optimizable innerTable, 269 OptimizablePredicateList predList, 270 ConglomerateDescriptor cd, 271 CostEstimate outerCost, 272 Optimizer optimizer, 273 CostEstimate costEstimate) { 274 278 } 279 280 281 public int maxCapacity( int userSpecifiedCapacity, 282 int maxMemoryPerTable, 283 double perRowUsage) { 284 if( userSpecifiedCapacity >= 0) 285 return userSpecifiedCapacity; 286 perRowUsage += ClassSize.estimateHashEntrySize(); 287 if( perRowUsage <= 1) 288 return maxMemoryPerTable; 289 return (int)(maxMemoryPerTable/perRowUsage); 290 } 291 292 293 public String getName() { 294 return "HASH"; 295 } 296 297 298 public int scanCostType() { 299 return StoreCostController.STORECOST_SCAN_SET; 300 } 301 302 303 public String resultSetMethodName(boolean bulkFetch) { 304 return "getHashScanResultSet"; 305 } 306 307 308 public String joinResultSetMethodName() { 309 return "getHashJoinResultSet"; 310 } 311 312 313 public String halfOuterJoinResultSetMethodName() { 314 return "getHashLeftOuterJoinResultSet"; 315 } 316 317 322 public int getScanArgs( 323 TransactionController tc, 324 MethodBuilder mb, 325 Optimizable innerTable, 326 OptimizablePredicateList storeRestrictionList, 327 OptimizablePredicateList nonStoreRestrictionList, 328 ExpressionClassBuilderInterface acbi, 329 int bulkFetch, 330 MethodBuilder resultRowAllocator, 331 int colRefItem, 332 int indexColItem, 333 int lockMode, 334 boolean tableLocked, 335 int isolationLevel, 336 int maxMemoryPerTable 337 ) 338 throws StandardException { 339 ExpressionClassBuilder acb = (ExpressionClassBuilder) acbi; 340 341 fillInScanArgs1(tc, 342 mb, 343 innerTable, 344 storeRestrictionList, 345 acb, 346 resultRowAllocator); 347 348 nonStoreRestrictionList.generateQualifiers(acb, mb, innerTable, true); 349 mb.push(innerTable.initialCapacity()); 350 mb.push(innerTable.loadFactor()); 351 mb.push(innerTable.maxCapacity( (JoinStrategy) this, maxMemoryPerTable)); 352 353 int[] hashKeyColumns = innerTable.hashKeyColumns(); 354 FormatableIntHolder[] fihArray = 355 FormatableIntHolder.getFormatableIntHolders(hashKeyColumns); 356 FormatableArrayHolder hashKeyHolder = new FormatableArrayHolder(fihArray); 357 int hashKeyItem = acb.addItem(hashKeyHolder); 358 mb.push(hashKeyItem); 359 360 fillInScanArgs2(mb, 361 innerTable, 362 bulkFetch, 363 colRefItem, 364 indexColItem, 365 lockMode, 366 tableLocked, 367 isolationLevel); 368 369 return 28; 370 } 371 372 377 public void divideUpPredicateLists( 378 Optimizable innerTable, 379 OptimizablePredicateList originalRestrictionList, 380 OptimizablePredicateList storeRestrictionList, 381 OptimizablePredicateList nonStoreRestrictionList, 382 OptimizablePredicateList requalificationRestrictionList, 383 DataDictionary dd 384 ) throws StandardException 385 { 386 396 originalRestrictionList.copyPredicatesToOtherList( 397 requalificationRestrictionList); 398 399 ConglomerateDescriptor cd = 400 innerTable.getTrulyTheBestAccessPath().getConglomerateDescriptor(); 401 402 420 421 originalRestrictionList.transferPredicates( 423 storeRestrictionList, 424 innerTable.getReferencedTableMap(), 425 innerTable); 426 427 441 for (int i = storeRestrictionList.size() - 1; i >= 0; i--) 442 { 443 Predicate p1 = (Predicate) storeRestrictionList.getOptPredicate(i); 444 445 446 if (!p1.isStoreQualifier() && !p1.isStartKey() && !p1.isStopKey()) 447 { 448 storeRestrictionList.removeOptPredicate(i); 449 } 450 } 451 452 for (int i = originalRestrictionList.size() - 1; i >= 0; i--) 453 { 454 Predicate p1 = 455 (Predicate) originalRestrictionList.getOptPredicate(i); 456 457 if (!p1.isStoreQualifier()) 458 originalRestrictionList.removeOptPredicate(i); 459 } 460 461 462 originalRestrictionList.copyPredicatesToOtherList( 463 nonStoreRestrictionList); 464 465 476 Optimizable hashTableFor = innerTable; 477 if (innerTable instanceof ProjectRestrictNode) 478 { 479 ProjectRestrictNode prn = (ProjectRestrictNode) innerTable; 480 if (prn.getChildResult() instanceof Optimizable) 481 hashTableFor = (Optimizable) (prn.getChildResult()); 482 } 483 int[] hashKeyColumns = findHashKeyColumns(hashTableFor, 484 cd, 485 nonStoreRestrictionList); 486 if (hashKeyColumns != null) 487 { 488 innerTable.setHashKeyColumns(hashKeyColumns); 489 } 490 else 491 { 492 String name; 493 if (cd != null && cd.isIndex()) 494 { 495 name = cd.getConglomerateName(); 496 } 497 else 498 { 499 name = innerTable.getBaseTableName(); 500 } 501 502 throw StandardException.newException(SQLState.LANG_HASH_NO_EQUIJOIN_FOUND, 503 name, 504 innerTable.getBaseTableName()); 505 } 506 507 nonStoreRestrictionList.markAllPredicatesQualifiers(); 509 510 int[] conglomColumn = new int[hashKeyColumns.length]; 511 if (cd != null && cd.isIndex()) 512 { 513 517 for (int index = 0; index < hashKeyColumns.length; index++) 518 { 519 conglomColumn[index] = 520 cd.getIndexDescriptor().baseColumnPositions()[hashKeyColumns[index]]; 521 } 522 } 523 else 524 { 525 531 for (int index = 0; index < hashKeyColumns.length; index++) 532 { 533 conglomColumn[index] = hashKeyColumns[index] + 1; 534 } 535 } 536 537 540 for (int index = hashKeyColumns.length - 1; index >= 0; index--) 541 { 542 nonStoreRestrictionList.putOptimizableEqualityPredicateFirst( 543 innerTable, 544 conglomColumn[index]); 545 } 546 } 547 548 551 public boolean isHashJoin() 552 { 553 return true; 554 } 555 556 559 public boolean doesMaterialization() 560 { 561 return true; 562 } 563 564 575 private int[] findHashKeyColumns(Optimizable innerTable, 576 ConglomerateDescriptor cd, 577 OptimizablePredicateList predList) 578 throws StandardException 579 { 580 if (predList == null) 581 return (int[]) null; 582 583 591 int[] columns = null; 592 if (cd == null) 593 { 594 columns = new int[innerTable.getNumColumnsReturned()]; 595 for (int j = 0; j < columns.length; j++) 596 { 597 columns[j] = j + 1; 598 } 599 } 600 else if (cd.isIndex()) 601 { 602 columns = cd.getIndexDescriptor().baseColumnPositions(); 603 } 604 else 605 { 606 columns = 607 new int[innerTable.getTableDescriptor().getNumberOfColumns()]; 608 for (int j = 0; j < columns.length; j++) 609 { 610 columns[j] = j + 1; 611 } 612 } 613 614 int colCtr; 616 Vector hashKeyVector = new Vector (); 617 for (colCtr = 0; colCtr < columns.length; colCtr++) 618 { 619 if (predList.hasOptimizableEquijoin(innerTable, columns[colCtr])) 621 { 622 hashKeyVector.addElement(new Integer (colCtr)); 623 } 624 } 625 626 if (hashKeyVector.size() > 0) 628 { 629 int[] keyCols = new int[hashKeyVector.size()]; 630 for (int index = 0; index < keyCols.length; index++) 631 { 632 keyCols[index] = ((Integer ) hashKeyVector.elementAt(index)).intValue(); 633 } 634 return keyCols; 635 } 636 else 637 return (int[]) null; 638 } 639 640 public String toString() { 641 return getName(); 642 } 643 } 644 | Popular Tags |