// LCOV_EXCL_START // Used for other RelExpr but not MultiJoin void MultiJoin::synthEstLogProp(const EstLogPropSharedPtr& inputEstLogProp) { CMPASSERT(inputEstLogProp->getNodeSet()); Join * preferredJoin = jbbSubset_.getPreferredJoin(); CMPASSERT(preferredJoin->isJoinFromMJSynthLogProp()); EstLogPropSharedPtr myEstLogProp = preferredJoin->getGroupAttr()->outputLogProp(inputEstLogProp); getGroupAttr()->addInputOutputLogProp (inputEstLogProp, myEstLogProp, NULL); } // MultiJoin::synthEstLogProp
EstLogPropSharedPtr AppliedStatMan::synthesizeLogProp( const CANodeIdSet * nodeSet, EstLogPropSharedPtr &inLP) { EstLogPropSharedPtr outputEstLogProp; CANodeIdSet combinedNodeSetWithInput = *nodeSet; if (inLP->isCacheable()) { CANodeIdSet * inNodeSet = inLP->getNodeSet(); // if inLP are cacheable these should have a nodeSet attached // if not, assert in debug mode. In release mode, set the properties // as not cacheable. These will then be looked into group attr cache if (inNodeSet == NULL) { CCMPASSERT(inNodeSet != NULL); inLP->setCacheableFlag(FALSE); } else { // check ASM cache for the estLogProps of nodeSet for the given // inLP combinedNodeSetWithInput.insert(*inNodeSet); if ((outputEstLogProp =\ getCachedStatistics(&combinedNodeSetWithInput)) != NULL) return outputEstLogProp; } } if(nodeSet->entries() == 1) return getStatsForCANodeId(nodeSet->getFirst(), inLP); JBBSubset * jbbSubset = nodeSet->jbbcsToJBBSubset(); Join * preferredJoin = jbbSubset->getPreferredJoin(); //CMPASSERT(preferredJoin->isJoinFromMJSynthLogProp()); outputEstLogProp = preferredJoin->getGroupAttr()->outputLogProp(inLP); return outputEstLogProp; } // AppliedStatMan::synthesizeLogProp
// get Stats after applying given join predicates on the JBBC EstLogPropSharedPtr AppliedStatMan::getStatsForGivenJoinPredsOnJBBC( const CANodeIdSet jbbSubset, CANodeId jbbc, const ValueIdSet joinPreds, const ValueIdSet localPreds, EstLogPropSharedPtr &inLP) { EstLogPropSharedPtr inputLP = inLP; if(inputLP == (*GLOBAL_EMPTY_INPUT_LOGPROP)) inputLP = jbbc.getJBBInput(); EstLogPropSharedPtr outputEstLogProp; // form a Join expression with the given join predicates, and compute // output estimated logical properties. These properties should not be cached // in the ASM cache, hence set the "cacheable" flag to FALSE in inLP. // We do not want to modify the "cacheable" flag in the inLP, hence make a // copy of these logical properties. EstLogPropSharedPtr nonCacheableInLP(new (HISTHEAP) EstLogProp (*inputLP)); nonCacheableInLP->setCacheableFlag(FALSE); Join * joinExpr = formJoinExprForJoinOnJBBC(jbbSubset, jbbc, &localPreds, &joinPreds, nonCacheableInLP, FALSE); // synthesize estimate logical properties for the join outputEstLogProp = joinExpr->getGroupAttr()->outputLogProp(nonCacheableInLP); return outputEstLogProp; } // AppliedStatMan::getStatsForGivenJoinPreds
Join* MultiJoin::splitSubset(const JBBSubset & leftSet, const JBBSubset & rightSet, NABoolean reUseMJ) const { // At this point assert that none of the subsets has a group by member CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID) && (leftSet.getGB() == NULL_CA_ID) && (rightSet.getGB() == NULL_CA_ID) ); #ifndef NDEBUG // assert that left + right == subSet_ // and left intersect right = phi CANodeIdSet unionSet(leftSet.getJBBCs()); CANodeIdSet intersectSet(leftSet.getJBBCs()); unionSet += rightSet.getJBBCs(); intersectSet.intersectSet(rightSet.getJBBCs()); CMPASSERT ( (unionSet == jbbSubset_.getJBBCs()) && (intersectSet.entries() == 0 )); #endif // Note: Joins including left, semi, anti semi are only created when // a single jbbc connected via one of them is split as a single right // child. InnerNonSemi joins can be created for any split i.e. any // number of jbbcs on the left and the right of the join, but special // joins (i.e. left, semi and anti semi joins) are only created when // there is a single right child i.e. the rightSet contains only one // jbbc that is connected via a special join. This is enforced as follows // // * The leftSet should be legal: This means that for every jbbc in the // leftSet any predecessor jbbcs should be present in the leftSet. // * The rightSet is either a single jbbc or if the rightSet has more // than one jbbc then it should be legal, note that a jbbc connected // via a special join is not a legal set by itself but we allow // creation of special joins assuming the predecessors are present // in the leftSet. // // An implicit assumption here is that 'this' MultiJoin is legal, which // is fair since apart from the top level multijoin, rest of the multijoins // are produced by splitting the top level multijoin. This method should // not produce illegal multijoins, since we check both leftSet and rightSet // for legality. Only time we don't check for legality is when the rightChild // is a single jbbc, and a single jbbc does not result in a multijoin. if(!leftSet.legal()) return NULL; if((rightSet.getJBBCs().entries() > 1) && (!rightSet.legal())) return NULL; // everything here goes to statement heap CollHeap* outHeap = CmpCommon::statementHeap(); RelExpr* child0 = generateSubsetExpr(leftSet, reUseMJ); RelExpr* child1 = generateSubsetExpr(rightSet, reUseMJ); // Flag to remember to pass on the derivedFromRoutineJoin flag if needed. NABoolean derivedFromRoutineJoin(FALSE); // now form a JoinExpr with these left and right children. Join * result = NULL; // if the rightSet is a single jbbc, then it could be connected via // a special join. In such a case we have to create the appropriate // join operator if(rightSet.getJBBCs().entries() == 1){ JBBC * rightChild = rightSet.getJBBCs().getFirst().getNodeAnalysis() ->getJBBC(); Join * rightChildParentJoin = rightChild->getOriginalParentJoin(); // If rightChildParentJoin is NULL, then the child is the left // child of the left most join and is considered to be connected // via a InnerNonSemi join. if(rightChildParentJoin) { if(rightChildParentJoin->derivedFromRoutineJoin()) derivedFromRoutineJoin = TRUE; if(rightChildParentJoin->isSemiJoin()) result = new (outHeap) Join(child0, child1, REL_SEMIJOIN, NULL); if(rightChildParentJoin->isAntiSemiJoin()) result = new (outHeap) Join(child0, child1, REL_ANTI_SEMIJOIN, NULL); if(rightChildParentJoin->isLeftJoin()) { // left joins can have filter preds, i.e. predicates that // are applied as filters after applying the join predicate. // We need to set them here. result = new (outHeap) Join(child0, child1, REL_LEFT_JOIN, NULL); result->setSelectionPredicates(rightChild->getLeftJoinFilterPreds()); } if(rightChildParentJoin->isRoutineJoin()) { derivedFromRoutineJoin = TRUE; result = new (outHeap) Join(child0, child1, REL_ROUTINE_JOIN, NULL); ValueIdSet routineJoinFilterPreds = rightChild->getRoutineJoinFilterPreds(); ValueIdSet predsToAddToRoutineJoin; // add covered filter preds for (ValueId filterPred= routineJoinFilterPreds.init(); routineJoinFilterPreds.next(filterPred); routineJoinFilterPreds.advance(filterPred) ) { if(jbbSubset_.coversExpr(filterPred)) predsToAddToRoutineJoin += filterPred; } result->setSelectionPredicates(predsToAddToRoutineJoin); } if(result) { // set the join predicate for special joins, note predicates // for regular InnerNonSemi joins are set as selection predicates // in the join relexpr. result->setJoinPred(rightChild->getPredsWithPredecessors()); result->nullInstantiatedOutput().insert(rightChild-> nullInstantiatedOutput()); } } } // The join to be created is a regular InnerNonSemi join if (!result) result = new (outHeap) Join(child0, child1, REL_JOIN, NULL); // Make sure we carry the derivedFromRoutineJoin flag with us if (derivedFromRoutineJoin) result->setDerivedFromRoutineJoin(); // Share my groupAttr with result result->setGroupAttr(getGroupAttr()); // get inner join predicates ValueIdSet selPreds = rightSet.joinPredsWithOther(leftSet); // get left join filter preds if any selPreds += result->getSelectionPredicates(); result->setSelectionPredicates(selPreds); result->findEquiJoinPredicates(); // May be I could save a little if i pushdown only to the child(ren) // that are not already JBBCs, i.e. multijoins result->pushdownCoveredExpr (result->getGroupAttr()->getCharacteristicOutputs(), result->getGroupAttr()->getCharacteristicInputs(), result->selectionPred()); // We used CutOp as children, to avoid pushing predicates to JBBCs. // Now put the actual expression back in case the child is a JBBCs if(leftSet.getJBBCs().entries() == 1) result->setChild(0, getJBBCRelExpr(leftSet.getJBBCs().getFirst())); // We used CutOp as children, to avoid pushing predicates to JBBCs. // Now put the actual expression back in case the child is a JBBCs if(rightSet.getJBBCs().entries() == 1) result->setChild(1, getJBBCRelExpr(rightSet.getJBBCs().getFirst())); // Temp fixup. We need to take the selectionPred out of MultiJoin // for now to prevent that pushed expr from being there. selectionPred // is not being used now in MultiJoin xxx. if (leftSet.getJBBCs().entries() > 1) result->child(0)->selectionPred().clear(); if (rightSet.getJBBCs().entries() > 1) result->child(1)->selectionPred().clear(); return result; }
// LCOV_EXCL_START :cnu EstLogPropSharedPtr AppliedStatMan::joinEstLogProps ( const EstLogPropSharedPtr& leftEstLogProp, const EstLogPropSharedPtr& rightEstLogProp, const EstLogPropSharedPtr& inLP) { EstLogPropSharedPtr outputEstLogProp; NABoolean cacheable = FALSE; CANodeIdSet * inputNodeSet = inLP->getNodeSet(); // These nodesets could be NULL, if the estLogProps to which they // belong are not cacheable CANodeIdSet * leftNodeSet = leftEstLogProp->getNodeSet(); CANodeIdSet * rightNodeSet = rightEstLogProp->getNodeSet(); if ((leftEstLogProp->isCacheable()) && (rightEstLogProp->isCacheable()) && (inLP->isCacheable()) ) { CCMPASSERT(leftNodeSet != NULL); CCMPASSERT(rightNodeSet != NULL); CCMPASSERT(inputNodeSet != NULL); if (leftNodeSet && rightNodeSet && inputNodeSet) { cacheable = TRUE; } } if (cacheable) { // check the ASM cache to see if outputEstLogProp for these // NodeSets appear for the given inputEstLogProp CANodeIdSet combineNodeSet = *leftNodeSet; combineNodeSet.insert(*rightNodeSet); CANodeIdSet combinedWithInputNodeSet = combineNodeSet; combinedWithInputNodeSet.insert(*inputNodeSet); outputEstLogProp = getCachedStatistics(&combinedWithInputNodeSet); if (outputEstLogProp != NULL) return outputEstLogProp; } JBBSubset * newJBBSubset = NULL; ValueIdSet setOfPredicates; if (leftNodeSet && rightNodeSet) { // join predicates can be obtained from EstLogProp, only // if these corresponded to complete set of predicates - // all local or complete join. Also, we need a // combinedJBBSubset to set in the fake join expression // that we will be creating. newJBBSubset = leftNodeSet->computeJBBSubset(); JBBSubset rightJBBSubset = *(rightNodeSet->computeJBBSubset()); setOfPredicates = newJBBSubset->joinPredsWithOther(rightJBBSubset); // Since the properties from this group are cacheable, hence the // group attributes for the new join expression should contain // the combined JBBsubset of the left and the right children newJBBSubset->addSubset(rightJBBSubset); } // inputEstLogProp would be either empty input estLogProp or from the // outer child. If cacheable is TRUE, then newJBBsubset should // contain the combined left and the right JBB subset. But if // cacheable is FALSE, newJBBsubset should be NULL Join * joinExpr = formJoinExprWithEstLogProps( leftEstLogProp, rightEstLogProp, inLP, &setOfPredicates, cacheable, newJBBSubset); // Now do the actual synthesis and cache statistics in the cache outputEstLogProp = joinExpr->getGroupAttr()->outputLogProp(inLP); return outputEstLogProp; }