void MVCandidate::logMVWasDisqualified(const char* reason) { // Avoid duplicate messages. if (wasDisqualified_) return; wasDisqualified_ = TRUE; char buffer[1024]; const MVDetailsPtr mvDetails = getMvDetails(); sprintf(buffer, "MV %s was disqualified because %s", mvDetails->getMVName().data(), reason); QRLogger::log(CAT_MVCAND, LL_INFO, buffer); disqualifiedReason_ = new (heap_) NAString(buffer, heap_); }
MVCandidatesForJBBSubsetPtr QRGroupLattice::search(QRJBBPtr queryJbb, MVCandidatesForJBBPtr mvCandidates, QRJoinSubGraphMapPtr map, ElementPtrList* minimizedGroupingList) { QRTRACER("QRGroupLattice::search()"); DescriptorDetailsPtr queryDetails = mvCandidates->getAllCandidates()->getQueryDetails(); LatticeKeyList keyList(heap_); if (minimizedGroupingList) { if (!elementListToKeyList(*minimizedGroupingList, keyList, map, queryDetails, FALSE)) return NULL; } else { // Get the grouping columns of the passed query JBB, and create a key list // from them. Return now if there are no grouping items -- a query without a // Group By can't match an MV that has one. QRGroupByPtr groupBy = queryJbb->getGroupBy(); if (!groupBy) return NULL; // An aggregate query with no GroupBy has an empty key list. if (!getGroupingLatticeKeys(keyList, map, queryDetails, queryJbb, TRUE, FALSE)) return NULL; } // Create the search node, disallowing the addition of any new keys to the hash // table used by the lattice; if the key isn't already used, the node can have // no supersets. QRLatticeIndexSearchNode searchNode(keyList, lattice_, TRUE, heap_); if (!searchNode.isValid()) // because a key wasn't added return NULL; NAString keysText; searchNode.dumpNode(keysText, *lattice_->getKeyArr()); QRLogger::log(CAT_GRP_LATTCE_INDX, LL_DEBUG, "Searching LatticeIndex for: %s.", keysText.data()); // Find the supersets of the query's group-by list in the MV group lattice // index. For each lattice index node returned, create an MVCandidate // corresponding to each MV represented by that node, and add it to the // candidate list passed by the caller. NAPtrList<QRLatticeIndexNodePtr> nodes; lattice_->findSupersets(searchNode, nodes); if (nodes.entries() == 0) { QRLogger::log(CAT_GRP_LATTCE_INDX, LL_DEBUG, "No match found."); return NULL; } MVCandidatesForJBBSubsetPtr jbbSubset = new(heap_) MVCandidatesForJBBSubset(mvCandidates, ADD_MEMCHECK_ARGS(heap_)); jbbSubset->setSubGraphMap(map); jbbSubset->setGroupBy(TRUE); if (minimizedGroupingList != NULL) jbbSubset->setMinimizedGroupingList(minimizedGroupingList); for (CollIndex i=0; i<nodes.entries(); i++) { QRLatticeIndexNodePtr thisNode = nodes[i]; const SubGraphMapList& matchingMVs = thisNode->getMVs(); NABoolean isPreferred = (*thisNode == searchNode); // preferred if exact match GroupingList* extraGroupingColumns = new(heap_) GroupingList(heap_); if (!isPreferred) { // For preferred match modes, there are no extraGroupingColumns. LatticeKeySubArray* diff = thisNode->computeDiff(searchNode, heap_); for(CollIndex i = 0; diff->nextUsed(i); i++) { LatticeIndexablePtr key = diff->element(i); QRElementPtr elem = keyToElement(key, map); extraGroupingColumns->insert(elem); } delete diff; } for (CollIndex j=0; j<matchingMVs.entries(); j++) { MVDetailsPtr mv = matchingMVs[j]->getMVDetails(); QRLogger::log(CAT_GRP_LATTCE_INDX, LL_DEBUG, "Found MV: %s!", mv->getMVName().data() ); jbbSubset->insert(mv, queryJbb, isPreferred, extraGroupingColumns, NULL, heap_); } } return jbbSubset; } // QRGroupLattice::search()
void MVCandidatesForJBBSubset::insert(MVDetailsPtr mv, QRJBBPtr queryJbb, NABoolean isPreferredMatch, GroupingList* extraGroupingColumns, QRJoinSubGraphMapPtr mvMap, CollHeap* heap) { DescriptorDetailsPtr queryDetails = jbbCandidates_->getAllCandidates()->getQueryDetails(); NAString excuse(heap); if (mv->isInitialized() == FALSE) { // Disqualify uninitialized MVs excuse = " was skipped because it is not initialized"; } else { QRDescriptorPtr desc = queryDetails->getDescriptor(); QRQueryDescriptorPtr queryDesc = static_cast<QRQueryDescriptorPtr>(desc); QRQueryMiscPtr misc = queryDesc->getMisc(); const NAString& mvAge = misc->getMVAge(); switch (misc->getRewriteLevel()) { case MRL_FRESH: // Allow only ON STATEMENT MVs. if (mv->isImmediate() == FALSE) { // Disqualify stale MVs. excuse = " was skipped because it is not completey fresh"; } break; case MRL_STALE: if (mv->isImmediate()) { // Allow immediate MVs. No need to calculate MV_AGE. break; } if ( mv->isUMV() ) { // Disqualify UMVs. excuse = " was skipped because it is user maintained"; break; } // Allow all MVs that were refreshed at least MV_AGE ago if ( mvAge != "") { const Int32 mvAgeSeconds = parseMVAge(mvAge); const Int64 mvRefreshTS = mv->getRefreshTimestamp()/1000000; const Int64 nowTS = NA_JulianTimestamp()/1000000; Int32 refreshAge = (Int32)(nowTS - mvRefreshTS); QRLogger::log(CAT_MVCAND, LL_DEBUG, "MV_AGE is: %d seconds, RefreshAge is: %d seconds.", mvAgeSeconds, refreshAge); if (mvAgeSeconds < refreshAge) { // Disqualify stale MVs. excuse = " was skipped because it is stale."; } } break; case MRL_OLD: if ( mv->isUMV() ) { // Disqualify UMVs. excuse = " was skipped because it is user maintained"; } break; case MRL_UMVS: // All MVs are allowed here. break; case MRL_OFF: // MVQR is OFF. Not supposed to get a descriptor in this case. default: assertLogAndThrow1(CAT_MVCAND, LL_ERROR, FALSE, QRLogicException, "Invalid value for MVQR_REWRITE_LEVEL: %d", (Int32)misc->getRewriteLevel()); } } // Create a new MVCandidate object for it. MVCandidatePtr newCandidate = new(heap) MVCandidate(mv, queryDetails, queryJbb, this, ADD_MEMCHECK_ARGS(heap)); if (mvMap != NULL) newCandidate->setMvSubGraphMap(mvMap); newCandidate->init(isPreferredMatch, extraGroupingColumns); insert(newCandidate); if (excuse != "") { // The reason we insert the MVCandidate and then disqualify it is that // we want the disqualification message to be added to the result descriptor. NAString msg(heap); msg = "MV "; msg.append(mv->getMVName()); msg.append(excuse); newCandidate->logMVWasDisqualified(msg); newCandidate->disqualify(); } } // MVCandidatesForJBBSubset::insert()