// ***************************************************************************
// ***************************************************************************
NABoolean MVCandidate::matchPredsFromEQSetToSubGraph(const QRJoinSubGraphPtr	    mvSubGraph, 
						     const QRJoinSubGraphPtr	    querySubGraph, 
						     const JoinGraphEqualitySetPtr  mvEqSet,
						     const JoinGraphEqualitySetPtr  queryEqSet,
						     const NAString&		    mvHalfPredID) 
{
  NABoolean extraHubColumnChecked = FALSE;
  const HalfPredicateList& queryHalfPreds = queryEqSet->getHalfPredicates();
  CollIndex maxEntries = queryHalfPreds.entries();
  for (CollIndex i=0; i<maxEntries; i++)
  {
    const JoinGraphHalfPredicatePtr queryHalfPred = queryHalfPreds[i];
    const JoinGraphTablePtr	    queryTable = queryHalfPred->getTable();
    if (querySubGraph->contains(queryTable))
    {
      // We found a join pred that's connected to the subgraph - match it.
      // Find the corresponding table in the MV join graph. 
      // ??? Don't assert if a match is not found, because maybe the join pred
      // ??? does not exist in the MV.
      const BaseTableDetailsPtr mvBaseTable = getMvTableForQueryID(queryTable->getID(), FALSE);
      if (mvBaseTable == NULL)
      {
	// Do we ever get here???
	assertLogAndThrow(CAT_MVCAND, LL_MVQR_FAIL,
                          FALSE, QRLogicException, 
			  "MV hub table corresponding to query hub not found.");
      }
      else
      {
	// We have the MV hub table corresponding to the query hub table.
	// Now find its halfPred.
	const NAString& mvID = mvBaseTable->getID();
	const JoinGraphTablePtr mvTable = mvSubGraph->getParentGraph()->getTableByID(mvID);
	const JoinGraphHalfPredicatePtr mvHalfPred = mvEqSet->findHalfPredTo(mvTable);

	if (mvHalfPred == NULL)
	{
	  // This query pred has no corresponding mv pred.
	  // Handle rewrite instructions here (Not implemented yet).
	  //if (addJoinPredForExtraHubTable(mvHalfPredID, queryHalfPred) == FALSE)
	  return FALSE;
	}
	else
	{
	  // Finally we have both the MV halfPred and its corresponding query halfPred.
	  // Match them.
	  if (mvHalfPred->match(queryHalfPred) == FALSE)
	    return FALSE;
	}

	// Continue matching with the next halfPred.
	continue;
      }

    }
  }

  return TRUE;
}  // MVCandidate::matchPredsFromEQSetToSubGraph()
QRJbbSubsetPtr MVCandidatesForJBBSubset::generateDescriptor(CollHeap* heap)
{
  // No candidates - no work.
  if (candidateList_.entries() == 0)
    return NULL;

  // Construct the new QRJbbSubset object.
  QRJbbSubsetPtr resultDesc = new(heap) QRJbbSubset(ADD_MEMCHECK_ARGS(heap));
  resultDesc->setGroupBy(hasGroupBy_);
  if (hasGroupBy_)
  {
    // Add a reference to the query NodeID of the GroupBy node.
    const NAString& groupbyID = 
      getJbbCandidates()->getQueryJbb()->getGroupBy()->getID();
    resultDesc->setRef(groupbyID);
  }

  // For each table included in the subgraph
  QRJoinSubGraphPtr   subGraph = querySubGraphMap_->getSubGraph();
  for(subGraph->reset(); subGraph->hasNext(); subGraph->advance())
  {
    JoinGraphTablePtr table = subGraph->getCurrent();

    // Add it to the JBBSubset descriptor.
    QRTablePtr tableDesc = new(heap) QRTable(heap);
    tableDesc->setTableName(table->getName());
    tableDesc->setRef(table->getID());
    resultDesc->addTable(tableDesc);
  }

  // If candidates are disqualified during the loop itself,
  // Don't remove them from the list.
  isLoopingOnCandidates_ = TRUE;

  // Now add the MVCandidates.
  CollIndex maxEntries = candidateList_.entries();
  for (CollIndex i=0; i<maxEntries; i++)
  {
    MVCandidatePtr candidate = candidateList_[i];
    if (candidate == NULL)
    {
      // The candidate was disqualified.
      continue;
    }

    QRCandidatePtr candidateXml;
    try
      {
        candidateXml = candidate->generateDescriptor();
      }
    catch (...)
      {
        candidate->logMVWasDisqualified("an exception was thrown.");
        candidate->disqualify();  // Propagate the Info element to the result descriptor.

        candidateXml = NULL;
      }

    if (candidateXml == NULL)
    {
      // The candidate was disqualified when generating the descriptor.
      continue;
    }
    resultDesc->addCandidate(candidateXml);
  }

  if (resultDesc->getCandidateList()->entries() == 0)
  {
    // None of the candidates survived the result descriptor generation.
    deletePtr(resultDesc);
    return NULL;
  }

  return resultDesc;
}  // MVCandidatesForJBBSubset::generateDescriptor()