// matcher_covered.cpp
/* Matcher is our boolean expression evaluator for "where" clauses */
/**
* Copyright (C) 2008 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#include "mongo/pch.h"
#include "mongo/db/cursor.h"
#include "mongo/db/matcher.h"
#include "mongo/db/matcher_covered.h"
#include "mongo/db/pdfile.h"
#include "mongo/db/queryutil.h"
namespace mongo {
CoveredIndexMatcher::CoveredIndexMatcher( const BSONObj &jsobj,
const BSONObj &indexKeyPattern ) :
_docMatcher( new Matcher( jsobj ) ),
_keyMatcher( *_docMatcher, indexKeyPattern ) {
init();
}
CoveredIndexMatcher::CoveredIndexMatcher( const CoveredIndexMatcher &prevClauseMatcher,
const shared_ptr &prevClauseFrv,
const BSONObj &nextClauseIndexKeyPattern ) :
_docMatcher( prevClauseMatcher._docMatcher ),
_keyMatcher( *_docMatcher, nextClauseIndexKeyPattern ),
_orDedupConstraints( prevClauseMatcher._orDedupConstraints ) {
if ( prevClauseFrv ) {
_orDedupConstraints.push_back( prevClauseFrv );
}
init();
}
void CoveredIndexMatcher::init() {
_needRecord =
!_keyMatcher.keyMatch( *_docMatcher ) ||
!_orDedupConstraints.empty();
}
bool CoveredIndexMatcher::matchesCurrent( Cursor * cursor , MatchDetails * details ) const {
// bool keyUsable = ! cursor->isMultiKey() && check for $orish like conditions in matcher SERVER-1264
bool keyUsable = true;
if ( cursor->indexKeyPattern().isEmpty() ) { // unindexed cursor
keyUsable = false;
}
else if ( cursor->isMultiKey() ) {
keyUsable =
_keyMatcher.singleSimpleCriterion() &&
( ! _docMatcher || _docMatcher->singleSimpleCriterion() );
}
return matches( cursor->currKey(),
cursor->currLoc(),
details,
keyUsable );
}
bool CoveredIndexMatcher::matches( const BSONObj& key, const DiskLoc& recLoc,
MatchDetails* details, bool keyUsable ) const {
LOG(5) << "CoveredIndexMatcher::matches() " << key.toString() << ' ' << recLoc.toString() << ' ' << keyUsable << endl;
dassert( key.isValid() );
if ( details )
details->resetOutput();
if ( keyUsable ) {
if ( !_keyMatcher.matches(key, details ) ) {
return false;
}
bool needRecordForDetails = details && details->needRecord();
if ( !_needRecord && !needRecordForDetails ) {
return true;
}
}
BSONObj obj = recLoc.obj();
bool res =
_docMatcher->matches( obj, details ) &&
!isOrClauseDup( obj );
if ( details )
details->setLoadedRecord( true );
LOG(5) << "CoveredIndexMatcher _docMatcher->matches() returns " << res << endl;
return res;
}
bool CoveredIndexMatcher::isOrClauseDup( const BSONObj &obj ) const {
for( vector >::const_iterator i = _orDedupConstraints.begin();
i != _orDedupConstraints.end(); ++i ) {
if ( (*i)->matches( obj ) ) {
// If a document matches a prior $or clause index range, generally it would have
// been returned while scanning that range and so is reported as a dup.
return true;
}
}
return false;
}
string CoveredIndexMatcher::toString() const {
StringBuilder buf;
buf << "(CoveredIndexMatcher ";
if ( _needRecord )
buf << "needRecord ";
buf << "keyMatcher: " << _keyMatcher.toString() << " ";
if ( _docMatcher )
buf << "docMatcher: " << _docMatcher->toString() << " ";
buf << ")";
return buf.str();
}
}