void MultiJoin::synthLogPropWithMJReuse(NormWA * normWAPtr) { // Check to see whether this GA has already been associated // with a logExpr for synthesis. If so, no need to resynthesize // for this equivalent log. expression. if (getGroupAttr()->existsLogExprForSynthesis()) { Join * joinExprForSynth = (Join *) getGroupAttr()->getLogExprForSynthesis(); if(joinExprForSynth->isJoinFromMJSynthLogProp()) return; } NABoolean reUseMJ = TRUE; CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID)); const CANodeIdSet & jbbcs = jbbSubset_.getJBBCs(); // Instead of always picking the first JBBC as the right child // pick the one with minimum JBBC connections. This will avoid // all unnecessary crossproducts CANodeId jbbcRight; jbbcRight = jbbcs.getJBBCwithMinConnectionsToThisJBBSubset(); CANodeIdSet right(jbbcRight); CANodeIdSet left(jbbcs); left -= jbbcRight; Join* join = splitSubset(*(left.jbbcsToJBBSubset()), *(right.jbbcsToJBBSubset()), reUseMJ); //if the left is a MultiJoin, synthesize it using reUse //this has to be done before join->synthLogProp to avoid //calling MultiJoin::synthLogProp on the left MultiJoin //because that does not reUse if(left.entries() > 1) { RelExpr * leftRelExpr = join->child(0)->castToRelExpr(); if(leftRelExpr && leftRelExpr->getOperator() == REL_MULTI_JOIN) ((MultiJoin *) leftRelExpr)->synthLogPropWithMJReuse(normWAPtr); } join->synthLogProp(normWAPtr); join->setJoinFromMJSynthLogProp(); getGroupAttr()->setLogExprForSynthesis(join); jbbSubset_.setSubsetMJ(this); CMPASSERT ( getGroupAttr()->getNumJoinedTables() >= getArity()); }
void MultiJoin::synthLogProp(NormWA * normWAPtr) { // Check to see whether this GA has already been associated // with a logExpr for synthesis. If so, no need to resynthesize // for this equivalent log. expression. if (getGroupAttr()->existsLogExprForSynthesis()) return; CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID)); const CANodeIdSet & jbbcs = jbbSubset_.getJBBCs(); // Instead of always picking the first JBBC as the right child // pick the one with minimum JBBC connections. This will avoid // all unnecessary crossproducts CANodeId jbbcRight; jbbcRight = jbbcs.getJBBCwithMinConnectionsToThisJBBSubset(); CANodeIdSet right(jbbcRight); CANodeIdSet left(jbbcs); left -= jbbcRight; Join* join = splitSubset(*(left.jbbcsToJBBSubset()), *(right.jbbcsToJBBSubset())); join->synthLogProp(normWAPtr); getGroupAttr()->setLogExprForSynthesis(join); join->setJoinFromMJSynthLogProp(); jbbSubset_.setSubsetMJ(this); CASortedList * synthLogPropPath = new (CmpCommon::statementHeap()) CASortedList(CmpCommon::statementHeap(), jbbcs.entries()); synthLogPropPath->insert((*(left.jbbcsToJBBSubset()->getSynthLogPropPath()))); synthLogPropPath->insert(right.getFirst()); jbbSubset_.setSynthLogPropPath(synthLogPropPath); CMPASSERT ( getGroupAttr()->getNumJoinedTables() >= getArity()); }
Join* MultiJoin::createLeftLinearJoinTree (const NAList<CANodeIdSet> * const leftDeepJoinSequence, NAList<MJJoinDirective *> * joinDirectives) const { Join* result = NULL; Join* currentJoin=NULL; NABoolean reUseMultiJoins = FALSE; //Set of all JBBCs in this multi-join. //This set will be broken up to make the join tree //representing the substitue. //The loop below will construct the join tree, //starting from the top join. CANodeIdSet childSet = getJBBSubset().getJBBCs(); // variables used in loop below MultiJoin * currentMJoin = (MultiJoin *) this; // in an iteration this is the parent join // e.g. when we are create JOIN3, this will // be JOIN2 Join * parentJoin = NULL; #ifdef _DEBUG if ( CmpCommon::getDefault( NSK_DBG ) == DF_ON && CmpCommon::getDefault( NSK_DBG_MJRULES_TRACKING ) == DF_ON ) { // LCOV_EXCL_START - dpm CURRCONTEXT_OPTDEBUG->stream() << "Following is left deep join sequence: " << endl; CURRCONTEXT_OPTDEBUG->stream() << endl; // LCOV_EXCL_STOP } #endif UInt32 numJoinChildren = leftDeepJoinSequence->entries(); CANodeId currentTable = NULL_CA_ID; for (UInt32 i = 0; i < (numJoinChildren-1); i++) { //create JBBSubset representing a comprising component of the //leftDeepJoinSequence. JBBSubset * joinRightChild = ((*leftDeepJoinSequence)[i]).computeJBBSubset(); MJJoinDirective * joinDirective = (*joinDirectives)[i]; //remove all tables that will become right side of join childSet.remove((*leftDeepJoinSequence)[i]); #ifdef _DEBUG //print the right child of the current join if ( CmpCommon::getDefault( NSK_DBG ) == DF_ON && CmpCommon::getDefault( NSK_DBG_MJRULES_TRACKING ) == DF_ON ) { CURRCONTEXT_OPTDEBUG->stream() << ((*leftDeepJoinSequence)[i]).getText() << endl; // LCOV_EXCL_LINE - dpm } #endif //Get JBBSubset for left side of join JBBSubset * joinLeftChild = childSet.computeJBBSubset(); //create the join by doing a split of the multi-join currentJoin = currentMJoin->splitSubset(*joinLeftChild, *joinRightChild, reUseMultiJoins); joinDirective->setupJoin(currentJoin); if ( CmpCommon::getDefault(COMP_BOOL_120) == DF_OFF) currentJoin->updatePotential(-3); // if this is the first iteration // set the result to be the top join if (i == 0) result = currentJoin; //set the current multi-join to the left child of the //join just created //change getChild to child().getPointer currentMJoin = (MultiJoin*) currentJoin->getChild(0); //if there was a parent join, set the left child to //point to the new join we just created i.e. currentJoin. if (parentJoin) parentJoin->setChild(0,currentJoin); //set currentJoin to be the parent for the next iteration parentJoin = currentJoin; } #ifdef _DEBUG //print the left most child if ( CmpCommon::getDefault( NSK_DBG ) == DF_ON && CmpCommon::getDefault( NSK_DBG_MJRULES_TRACKING ) == DF_ON ) { // LCOV_EXCL_START - dpm CURRCONTEXT_OPTDEBUG->stream() << ((*leftDeepJoinSequence)[(numJoinChildren-1)]).getText() << endl; CURRCONTEXT_OPTDEBUG->stream() << endl; // LCOV_EXCL_STOP } #endif // end - construct the join tree // synth the join result->synthLogProp(); //if the right child of the top-most join is a multi-Join, //synthesize_it if(result->child(1)) if(result->child(1)->getOperatorType()==REL_MULTI_JOIN) result->child(1)->synthLogProp(); // synth the left child too result->child(0)->synthLogProp(); return result; } // MultiJoin::createLeftLinearJoinTree()
// This method forms the join expression for join on JBBC specified by jbbcId // inputEstLogProp should not be cacheable Join * AppliedStatMan::formJoinExprForJoinOnJBBC( CANodeIdSet jbbSubset, CANodeId jbbcId, const ValueIdSet * jbbcLocalPreds, const ValueIdSet * joinPreds, const EstLogPropSharedPtr& inputEstLogProp, const NABoolean cacheable) { NABoolean origInputIsCacheable = inputEstLogProp->isCacheable(); if(origInputIsCacheable) { inputEstLogProp->setCacheableFlag(FALSE); CCMPASSERT("Expecting Non Cacheable Input"); } RelExpr * jbbcExpr = getExprForCANodeId(jbbcId, inputEstLogProp, jbbcLocalPreds); jbbcExpr->getGroupAttr()->outputLogProp(inputEstLogProp); RelExpr * jbbSubsetExpr = jbbSubset.jbbcsToJBBSubset()->getPreferredJoin(); if(!jbbSubsetExpr) if(jbbSubset.entries()==1) if(!inputEstLogProp->isCacheable()) { inputEstLogProp->setCacheableFlag(TRUE); jbbSubsetExpr = getExprForCANodeId(jbbSubset.getFirst(), inputEstLogProp); inputEstLogProp->setCacheableFlag(FALSE); } else jbbSubsetExpr = getExprForCANodeId(jbbSubset.getFirst(), inputEstLogProp); else { CCMPASSERT("No Subset expression, need at least one entry in set"); } RelExpr * leftChildExpr = jbbSubsetExpr; RelExpr * rightChildExpr = jbbcExpr; GroupAttributes * galeft = jbbSubsetExpr->getGroupAttr(); GroupAttributes * garight = jbbcExpr->getGroupAttr(); // xxx JBBC * jbbc = jbbcId.getNodeAnalysis()->getJBBC(); Join * jbbcParentJoin = jbbc->getOriginalParentJoin(); ValueIdSet leftOuterJoinFilterPreds; Join * joinExpr = NULL; if(jbbcParentJoin) { if(jbbcParentJoin->isSemiJoin()) joinExpr = new STMTHEAP Join(leftChildExpr, rightChildExpr, REL_SEMIJOIN, NULL); if(jbbcParentJoin->isAntiSemiJoin()) joinExpr = new STMTHEAP Join(leftChildExpr, rightChildExpr, REL_ANTI_SEMIJOIN, NULL); if(jbbcParentJoin->isLeftJoin()) { joinExpr = new STMTHEAP Join(leftChildExpr, rightChildExpr, REL_LEFT_JOIN, NULL); leftOuterJoinFilterPreds += jbbc->getLeftJoinFilterPreds(); } if(joinExpr) { joinExpr->setJoinPred(jbbc->getPredsWithPredecessors()); joinExpr->nullInstantiatedOutput().insert(jbbc->nullInstantiatedOutput()); } } if(!joinExpr) { // now form a JoinExpr with these left and right children. joinExpr = new STMTHEAP Join(leftChildExpr, rightChildExpr, REL_JOIN, NULL); } ValueIdSet selPredsAndLOJFilter = leftOuterJoinFilterPreds; selPredsAndLOJFilter += (*joinPreds); joinExpr->setSelectionPredicates(selPredsAndLOJFilter); // set groupAttr of this Join expression GroupAttributes * gaJoin = new STMTHEAP GroupAttributes(); // set required outputs of Join as sum of characteristic // outputs of the left and the right children ValueIdSet requiredOutputs; requiredOutputs.addSet(getPotentialOutputs(jbbSubset)); requiredOutputs.addSet(getPotentialOutputs(jbbcId)); gaJoin->setCharacteristicOutputs(requiredOutputs); // set JBBSubset for this group, if all estLogProps are cacheable. // Else JBBSubset is NULL CANodeIdSet combinedSet = jbbSubset; combinedSet += jbbcId; if (cacheable) gaJoin->getGroupAnalysis()->setLocalJBBView(combinedSet.jbbcsToJBBSubset()); gaJoin->setMinChildEstRowCount(MINOF(garight->getMinChildEstRowCount(), galeft->getMinChildEstRowCount() ) ); // if there are some probes coming into the join // then join type = tsj. if ((inputEstLogProp->getResultCardinality() > 1) || (inputEstLogProp->getColStats().entries() > 1)) { if (cacheable) { CANodeIdSet inputNodeSet = *(inputEstLogProp->getNodeSet()); gaJoin->setCharacteristicInputs(getPotentialOutputs(inputNodeSet)); } } joinExpr->setGroupAttr(gaJoin); gaJoin->setLogExprForSynthesis(joinExpr); joinExpr->synthLogProp(); inputEstLogProp->setCacheableFlag(origInputIsCacheable); return joinExpr; } // AppliedStatMan::formJoinExprForJoinOnJBBC