Example #1
0
// ------------------------------------------------------------------------
// Create a left linear subtree of joins from this MultiJoin
// ------------------------------------------------------------------------
Join* MultiJoin::leftLinearize(NABoolean fixJoinOrder, NABoolean createPriviledgedJoins) const
{
  // At this point assert that the subsets has no group by member.
  // If we want to allow GBs in this method in the future we should
  // remember to use computeJBBSubset() instead of the faster
  // jbbcsToJBBSubset() used currently in this method..
  CMPASSERT ( (jbbSubset_.getGB() == NULL_CA_ID));

  const CANodeIdSet & jbbcs = jbbSubset_.getJBBCs();
  // pick some child to make right child of join
  CANodeId jbbcRight(jbbcs.getFirst());

  CANodeIdSet right(jbbcRight);
  CANodeIdSet left(jbbcs);
  left -= jbbcRight;

  NABoolean nonExpander = (left.jbbcsToJBBSubset()->
    isGuaranteedNonExpandingJoin((*jbbcRight.getNodeAnalysis()->getJBBC())));

  Join* result = splitSubset(*(left.jbbcsToJBBSubset()),
                             *(right.jbbcsToJBBSubset()));

  if (fixJoinOrder)
  {
    // disallow left shift rule on the join
    result->contextInsensRules() += JoinLeftShiftRuleNumber;
    // disallow join commutativity on the join
    result->contextInsensRules() += JoinCommutativityRuleNumber;
  }

  if (createPriviledgedJoins)
  {
    result->setJoinFromPTRule();

    if ( CmpCommon::getDefault(COMP_BOOL_120) == DF_OFF)
    {
      result->updatePotential(-2);
    }
  }

  // If left subset is a multiJoin, then linearize it too.
  if (left.entries() > 1)
  {
    // left child must be multiJoin at this point. May be add assert.
    MultiJoin* leftChild = (MultiJoin*)(result->child(0).getPtr());
    result->child(0) = leftChild->leftLinearize(fixJoinOrder,createPriviledgedJoins);
  }

  return result;
} // MultiJoin::leftLinearize()
Example #2
0
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());
}
Example #3
0
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()
Example #4
0
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;
}