📄 projectrestrictnode.java
字号:
/** @see Optimizable#getBestSortAvoidancePath */ public AccessPath getBestSortAvoidancePath() { if (childResult instanceof Optimizable) return ((Optimizable) childResult).getBestSortAvoidancePath(); return super.getBestSortAvoidancePath(); } /** @see Optimizable#getTrulyTheBestAccessPath */ public AccessPath getTrulyTheBestAccessPath() { /* The childResult will always be an Optimizable * during code generation. If the childResult was * not an Optimizable during optimization, then this node * will have the truly the best access path, so we want to * return it from this node, rather than traversing the tree. * This can happen for non-flattenable derived tables. * Anyway, we note this state when modifying the access paths. */ if (hasTrulyTheBestAccessPath) { return super.getTrulyTheBestAccessPath(); } if (childResult instanceof Optimizable) return ((Optimizable) childResult).getTrulyTheBestAccessPath(); return super.getTrulyTheBestAccessPath(); } /** @see Optimizable#rememberSortAvoidancePath */ public void rememberSortAvoidancePath() { if (childResult instanceof Optimizable) ((Optimizable) childResult).rememberSortAvoidancePath(); else super.rememberSortAvoidancePath(); } /** @see Optimizable#considerSortAvoidancePath */ public boolean considerSortAvoidancePath() { if (childResult instanceof Optimizable) return ((Optimizable) childResult).considerSortAvoidancePath(); return super.considerSortAvoidancePath(); } /** * @see Optimizable#pushOptPredicate * * @exception StandardException Thrown on error */ public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate) throws StandardException { if (SanityManager.DEBUG) { SanityManager.ASSERT(optimizablePredicate instanceof Predicate, "optimizablePredicate expected to be instanceof Predicate"); SanityManager.ASSERT(! optimizablePredicate.hasSubquery() && ! optimizablePredicate.hasMethodCall(), "optimizablePredicate either has a subquery or a method call"); } /* Add the matching predicate to the restrictionList */ if (restrictionList == null) { restrictionList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); } restrictionList.addPredicate((Predicate) optimizablePredicate); /* Remap all of the ColumnReferences to point to the * source of the values. */ RemapCRsVisitor rcrv = new RemapCRsVisitor(true); ((Predicate) optimizablePredicate).getAndNode().accept(rcrv); return true; } /** * @see Optimizable#pullOptPredicates * * @exception StandardException Thrown on error */ public void pullOptPredicates( OptimizablePredicateList optimizablePredicates) throws StandardException { if (restrictionList != null) { // Pull up any predicates that may have been pushed further // down the tree during optimization. if (childResult instanceof UnionNode) ((UnionNode)childResult).pullOptPredicates(restrictionList); RemapCRsVisitor rcrv = new RemapCRsVisitor(false); for (int i = restrictionList.size() - 1; i >= 0; i--) { OptimizablePredicate optPred = restrictionList.getOptPredicate(i); ((Predicate) optPred).getAndNode().accept(rcrv); optimizablePredicates.addOptPredicate(optPred); restrictionList.removeOptPredicate(i); } } } /** * @see Optimizable#modifyAccessPath * * @exception StandardException Thrown on error */ public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException { boolean origChildOptimizable = true; /* It is okay to optimize most nodes multiple times. However, * modifying the access path is something that should only be done * once per node. One reason for this is that the predicate list * will be empty after the 1st call, and we assert that it should * be non-empty. Multiple calls to modify the access path can * occur when there is a non-flattenable FromSubquery (or view). */ if (accessPathModified) { return this; } /* ** Do nothing if the child result set is not optimizable, as there ** can be nothing to modify. */ boolean alreadyPushed = false; if ( ! (childResult instanceof Optimizable)) { // Remember that the original child was not Optimizable origChildOptimizable = false; childResult = childResult.modifyAccessPaths(); /* Mark this node as having the truly ... for * the underlying tree. */ hasTrulyTheBestAccessPath = true; /* Replace this PRN with a HRN if we are doing a hash join */ if (trulyTheBestAccessPath.getJoinStrategy().isHashJoin()) { if (SanityManager.DEBUG) { SanityManager.ASSERT(restrictionList != null, "restrictionList expected to be non-null"); SanityManager.ASSERT(restrictionList.size() != 0, "restrictionList.size() expected to be non-zero"); } /* We're doing a hash join on an arbitary result set. * We need to get the table number from this node when * dividing up the restriction list for a hash join. * We need to explicitly remember this. */ getTableNumberHere = true; } else { /* We consider materialization into a temp table as a last step. * Currently, we only materialize VTIs that are inner tables * and can't be instantiated multiple times. In the future we * will consider materialization as a cost based option. */ return (Optimizable) considerMaterialization(outerTables); } } /* If the child is not a FromBaseTable, then we want to * keep going down the tree. (Nothing to do at this node.) */ else if (!(childResult instanceof FromBaseTable)) { /* Make sure that we have a join strategy */ if (trulyTheBestAccessPath.getJoinStrategy() == null) { trulyTheBestAccessPath = (AccessPathImpl) ((Optimizable) childResult).getTrulyTheBestAccessPath(); } // If the childResult is a SetOperatorNode (esp. a UnionNode), // then it's possible that predicates in our restrictionList are // supposed to be pushed further down the tree (as of DERBY-805). // We passed the restrictionList down when we optimized the child // so that the relevant predicates could be pushed further as part // of the optimization process; so now that we're finalizing the // paths, we need to do the same thing: i.e. pass restrictionList // down so that the predicates that need to be pushed further // _can_ be pushed further. if (childResult instanceof SetOperatorNode) { childResult = (ResultSetNode) ((SetOperatorNode) childResult).modifyAccessPath( outerTables, restrictionList); // Take note of the fact that we already pushed predicates // as part of the modifyAccessPaths call. This is necessary // because there may still be predicates in restrictionList // that we intentionally decided not to push (ex. if we're // going to do hash join then we chose to not push the join // predicates). Whatever the reason for not pushing the // predicates, we have to make sure we don't inadvertenly // push them later (esp. as part of the "pushUsefulPredicates" // call below). alreadyPushed = true; } else { childResult = (ResultSetNode) ((FromTable) childResult). modifyAccessPath(outerTables); } } if ((restrictionList != null) && !alreadyPushed) { restrictionList.pushUsefulPredicates((Optimizable) childResult); } /* ** The optimizer's decision on the access path for the child result ** set may require the generation of extra result sets. For ** example, if it chooses an index, we need an IndexToBaseRowNode ** above the FromBaseTable (and the FromBaseTable has to change ** its column list to match that of the index. */ if (origChildOptimizable) { childResult = childResult.changeAccessPath(); } accessPathModified = true; /* ** Replace this PRN with a HTN if a hash join ** is being done at this node. (Hash join on a scan ** is a special case and is handled at the FBT.) */ if (trulyTheBestAccessPath.getJoinStrategy() != null && trulyTheBestAccessPath.getJoinStrategy().isHashJoin()) { return replaceWithHashTableNode(); } /* We consider materialization into a temp table as a last step. * Currently, we only materialize VTIs that are inner tables * and can't be instantiated multiple times. In the future we * will consider materialization as a cost based option. */ return (Optimizable) considerMaterialization(outerTables); } /** * This method creates a HashTableNode between the PRN and * it's child when the optimizer chooses hash join on an * arbitrary (non-FBT) result set tree. * We divide up the restriction list into 3 parts and * distribute those parts as described below. * * @return The new (same) top of our result set tree. * @exception StandardException Thrown on error */ private Optimizable replaceWithHashTableNode() throws StandardException { /* We want to divide the predicate list into 3 separate lists - * o predicates against the source of the hash table, which will * be applied on the way into the hash table (searchRestrictionList) * o join clauses which are qualifiers and get applied to the * rows in the hash table on a probe (joinRestrictionList) * o non-qualifiers involving both tables which will get * applied after a row gets returned from the HTRS (nonQualifiers) * * We do some unnecessary work when doing this as we want to reuse * as much existing code as possible. The code that we are reusing * was originally built for hash scans, hence the unnecessary * requalification list. */ PredicateList searchRestrictionList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); PredicateList joinQualifierList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); PredicateList requalificationRestrictionList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); trulyTheBestAccessPath.getJoinStrategy().divideUpPredicateLists( this, restrictionList, searchRestrictionList, joinQualifierList, requalificationRestrictionList, getDataDictionary()); /* Break out the non-qualifiers from HTN's join qualifier list and make that * the new restriction list for this PRN. */ restrictionList = (PredicateList) getNodeFactory().getNode( C_NodeTypes.PREDICATE_LIST, getContextManager()); /* For non-base table, we remove first 2 lists from requal list to avoid adding duplicates. */ for (int i = 0; i < searchRestrictionList.size(); i++) requalificationRestrictionList.removeOptPredicate((Predicate) searchRestrictionList.elementAt(i)); for (int i = 0; i < joinQualifierList.size(); i++) requalificationRestrictionList.removeOptPredicate((Predicate) joinQualifierList.elementAt(i)); joinQualifierList.transferNonQualifiers(this, restrictionList); //purify joinQual list requalificationRestrictionList.copyPredicatesToOtherList(restrictionList); //any residual ResultColumnList htRCList; /* We get a shallow copy of the child's ResultColumnList and its * ResultColumns. (Copy maintains ResultColumn.expression for now.) */ htRCList = childResult.getResultColumns(); childResult.setResultColumns(htRCList.copyListAndObjects()); /* Replace ResultColumn.expression with new VirtualColumnNodes * in the HTN's ResultColumnList. (VirtualColumnNodes include * pointers to source ResultSetNode, this, and source ResultColumn.) * NOTE: We don't want to mark the underlying RCs as referenced, otherwise * we won't be able to project out any of them. */ htRCList.genVirtualColumnNodes(childResult, childResult.getResultColumns(), false); /* The CRs for this side of the join in both the searchRestrictionList * the joinQualifierList now point to the HTN's RCL. We need them * to point to the RCL in the child of the HTN. (We skip doing this for * the joinQualifierList as the code to generate the Qualifiers does not * care.) */ RemapCRsVisitor rcrv = new RemapCRsVisitor(true); searchRestrictionList.accept(rcrv); /* We can finally put the HTN between ourself and our old child. */ childResult = (ResultSetNode) getNodeFactory().getNode( C_NodeTypes.HASH_TABLE_NODE, childResult, tableProperties, htRCList, searchRestrictionList, joinQualifierList, trulyTheBestAccessPath, getCostEstimate(), projectSubquerys, restrictSubquerys, hashKeyColumns(), getContextManager()); return this; } /** @see Optimizable#verifyProperties * @exception StandardException Thrown on error */ public void verifyProperties(DataDictionary dDictionary) throws StandardException { /* Table properties can be attached to this node if * its child is not an optimizable, otherwise they * are attached to its child. */ if (childResult instanceof Optimizable) { ((Optimizable) childResult).verifyProperties(dDictionary); } else { super.verifyProperties(dDictionary); } } /** * @see Optimizable#legalJoinOrder */ public boolean legalJoinOrder(JBitSet assignedTableMap) { if (childResult instanceof Optimizable) { return ((Optimizable) childResult).legalJoinOrder(assignedTableMap); } else { return true; } } /** @see Optimizable#isMaterializable * * @exception StandardException Thrown on error */ public boolean isMaterializable() throws StandardException { /* RESOLVE - Disallow arbitrary hash joins on * SELECTS within a derived table for now. * Remove this method once that restriction is removed. */ if (! (childResult instanceof Optimizable)) { return false; } return super.isMaterializable(); } /** * @see Optimizable#uniqueJoin * * @exception StandardException Thrown on error */ public double uniqueJoin(OptimizablePredicateList predList) throws StandardException { if (childResult instanceof Optimizable) { return ((Optimizable) childResult).uniqueJoin(predList); } else { return super.uniqueJoin(predList); } } /** * Return the restriction list from this node. * * @return The restriction list from this node. */ PredicateList getRestrictionList() { return restrictionList; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -