const BaseTableDetailsPtr MVCandidate::getQueryTableForMvID(const NAString& id, NABoolean assertOnFailure) { QRJoinSubGraphMapPtr mvMap = getMvSubGraphMap(); if (!mvMap->contains(id)) { if (assertOnFailure) { assertLogAndThrow(CAT_MVCAND, LL_MVQR_FAIL, FALSE, QRLogicException, "Matching Query table not found in JoinGraphMap."); } return NULL; } Int32 hashKeyIndex = mvMap->getIndexForTable(id); if (hashKeyIndex == -1) { assertLogAndThrow(CAT_MVCAND, LL_MVQR_FAIL, assertOnFailure, QRLogicException, "Matching Query table not found in JoinGraphMap."); return NULL; } const JoinGraphTablePtr queryTable = getQuerySubGraphMap()->getTableForIndex(hashKeyIndex); if (queryTable == NULL) { assertLogAndThrow(CAT_MVCAND, LL_MVQR_FAIL, assertOnFailure, QRLogicException, "Matching Query table not found in JoinGraphMap."); return NULL; } return queryTable->getBaseTable(); }
// *************************************************************************** // *************************************************************************** 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()
//***************************************************************************** // thisSubgraph and otherSubGraph are equivalent subgraphs (from the MV and // query join graphs). This method checks if they will continue to match // if an extra-hub table is added. It checks that ALL predicates connecting // this table to the subgraph match those of the other table/subgraph. // The assumption is that this is the MV table/subgraph, while the other // is the query table/subgraph, so the query can have additional join // predicates over those in the MV. Those extra predicates are returned as // rewrite instructions. //***************************************************************************** NABoolean MVCandidate::matchPredsFromTableToSubGraph(const QRJoinSubGraphPtr mvSubGraph, const QRJoinSubGraphPtr querySubGraph, const JoinGraphTablePtr mvGraphTable, const JoinGraphTablePtr queryGraphTable) { // For each join pred on this table CollIndex maxEntries = mvGraphTable->getEqualitySets().entries(); for (CollIndex i=0; i<maxEntries; i++) { // Find the column its using const JoinGraphEqualitySetPtr mvEqSet = mvGraphTable->getEqualitySets()[i]; const JoinGraphHalfPredicatePtr mvHalfPred = mvEqSet->findHalfPredTo(mvGraphTable); // Get the corresponding eqSet from the other join graph const JoinGraphEqualitySetPtr queryEqSet = queryGraphTable->getEqSetUsing(mvHalfPred); if (queryEqSet == NULL) { // Corresponding eqSet not found - match failed. return FALSE; } // Verify that the half-pred to the EQ set matches. const JoinGraphHalfPredicatePtr queryHalfPred = queryEqSet->findHalfPredTo(queryGraphTable); if (mvHalfPred->match(queryHalfPred) == FALSE) return FALSE; // Let the JoinPredMatching object continue with the matching from the EQ set to the subgraph. if (matchPredsFromEQSetToSubGraph(mvSubGraph, querySubGraph, mvEqSet, queryEqSet, mvHalfPred->getID()) == FALSE) return FALSE; } return TRUE; } // matchPredsFromTableToSubGraph()
//***************************************************************************** // Add a table to the Self-Join analysis. // This method, together with doneAddingTables(), implement a state machine // with the following states: // ST_START: The start state. No open segments. // ST_SINGLE: Got the first table of a new segment, don't know segment type yet. // ST_UNIQUE: Last two tables were different. // ST_SELFJOIN: Last two tables were the same. // ST_END: We are done. // The full state machine diagram is in the MVQR IS document. //***************************************************************************** void SelfJoinHandler::addTable(JoinGraphTablePtr table) { const NAString& newTable = table->getName(); // This is the current table index. UInt32 currentIndex = table->getTempNumber(); if (currentIndex == -1) { // This subgraph generation was not yet started, // This must be the initial self-join check. currentIndex = table->getOrdinalNumber(); } // Is this table the same as the last one? // Skip the string comparison if the table is unique in the full join graph. NABoolean isDifferent = !table->isSelfJoinTable() || newTable != *lastTable_; // Which state in the state machine are we in? switch (state_) { case ST_START: segmentStart_ = currentIndex; state_ = ST_SINGLE; break; case ST_SINGLE: if (isDifferent) state_ = ST_UNIQUE; else state_ = ST_SELFJOIN; break; case ST_SELFJOIN: if (isDifferent) { // We have an open selfjoin segment and got a different table. // The selfjoin segment ends with the previous table, and the next // segment (which can be either type) starts with this table. addSegment(SelfJoinSegment::SELF_JOIN_SEGMENT); segmentStart_ = currentIndex; state_ = ST_SINGLE; } else { // do nothing. } break; case ST_UNIQUE: if (isDifferent) { // do nothing. } else { // OK, we have an open unique segment, and the new table is the same // as the last one. So actually, the open unique segment ended with the // table before the prevous one, and the new self-join segment started // with the previous table. segmentEnd_--; addSegment(SelfJoinSegment::UNIQUE_TABLE_SEGMENT); segmentStart_ = currentIndex-1; state_ = ST_SELFJOIN; } break; case ST_END: assertLogAndThrow(CAT_MVMEMO_JOINGRAPH, LL_MVQR_FAIL, FALSE, QRLogicException, "Adding a table to SelfJoinHandler in ST_END state."); break; } lastTable_ = &table->getName(); segmentEnd_ = currentIndex; }
//***************************************************************************** //***************************************************************************** NABoolean MVCandidate::CheckAnExtraHubTable(const NAString* tableID, QRJoinSubGraphMapPtr mvSubGraphMap, QRJoinSubGraphMapPtr querySubGraphMap, NABoolean& extraHubTableWasAdded) { QRJoinSubGraphPtr mvSubGraph = mvSubGraphMap->getSubGraph(); QRJoinSubGraphPtr querySubGraph = querySubGraphMap->getSubGraph(); const QRTablePtr queryTableElement = getQueryDetails()->getElementForID(*tableID)->downCastToQRTable(); const JoinGraphTablePtr queryGraphTable = querySubGraph->getParentGraph()->getTableByID(queryTableElement->getID()); // If this extra-hub table is not directly connected to the rest of // the subgraph, skip it for now. if (queryGraphTable->isConnectedTo(querySubGraph) == FALSE) { // Add additional needed extra-hub tables here... return TRUE; } // Find the corresponding MV table const QRTablePtr mvTableElement = getMvDetails()->getTableFromName(queryTableElement->getTableName()); const JoinGraphTablePtr mvGraphTable = mvSubGraph->getParentGraph()->getTableByID(mvTableElement->getID()); if (matchPredsFromTableToSubGraph(mvSubGraph, querySubGraph, mvGraphTable, queryGraphTable) == FALSE) { // Match failed. // Release the sandbox subgraphs and disqualify the MVCandidate. deletePtr(mvSubGraphMap); deletePtr(querySubGraphMap); logMVWasDisqualified1("Extra hub table %s is needed but cannot be matched.", queryTableElement->getTableName().data()); return FALSE; } // Add the table to both MV and query subgraphs. querySubGraph->addTable(queryGraphTable); mvSubGraph->addTable(mvGraphTable); // To make sure that Pass 2 matching and result desxcriptor generation will // work correctly, add the tables to the SubGraphMaps (they will have the same index). CollIndex index = querySubGraph->entries(); querySubGraphMap->addTable(index, queryGraphTable); mvSubGraphMap->addTable(index, mvGraphTable); // We are done with this table, remove it from the list. extraHubTables_.remove(tableID); extraHubTableWasAdded = TRUE; QRLogger::log(CAT_MVCAND, LL_DEBUG, "ExtraHub table %s was matched for MV %s.", queryTableElement->getTableName().data(), mvDetails_->getMVName().data()); return TRUE; } // MVCandidate::CheckAnExtraHubTable()
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()