//***************************************************************************** // 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; }
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()