2008-11-30 02:01:58 +01:00
|
|
|
// matcher.h
|
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
/* Matcher is our boolean expression evaluator for "where" clauses */
|
2008-11-18 21:47:37 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-11-18 21:47:37 +01:00
|
|
|
* 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.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-11-18 21:47:37 +01:00
|
|
|
* 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.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-11-18 21:47:37 +01:00
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2009-01-20 21:44:40 +01:00
|
|
|
#include "jsobj.h"
|
2008-12-29 02:28:49 +01:00
|
|
|
#include <pcrecpp.h>
|
2008-12-02 18:50:19 +01:00
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
2010-03-29 18:55:44 +02:00
|
|
|
|
|
|
|
class Cursor;
|
2009-12-21 23:43:06 +01:00
|
|
|
class CoveredIndexMatcher;
|
2010-01-19 17:04:52 +01:00
|
|
|
class Matcher;
|
2009-12-31 20:04:44 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
class RegexMatcher {
|
|
|
|
public:
|
|
|
|
const char *fieldName;
|
2010-03-01 23:59:20 +01:00
|
|
|
const char *regex;
|
|
|
|
const char *flags;
|
2010-03-01 23:57:27 +01:00
|
|
|
string prefix;
|
2010-03-09 01:53:45 +01:00
|
|
|
shared_ptr< pcrecpp::RE > re;
|
2010-02-22 23:33:24 +01:00
|
|
|
bool isNot;
|
2010-03-09 01:53:45 +01:00
|
|
|
RegexMatcher() : isNot() {}
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
2009-07-07 23:38:47 +02:00
|
|
|
|
|
|
|
struct element_lt
|
|
|
|
{
|
|
|
|
bool operator()(const BSONElement& l, const BSONElement& r) const
|
|
|
|
{
|
2009-08-27 16:19:58 +02:00
|
|
|
int x = (int) l.canonicalType() - (int) r.canonicalType();
|
|
|
|
if ( x < 0 ) return true;
|
2009-07-07 23:38:47 +02:00
|
|
|
else if ( x > 0 ) return false;
|
|
|
|
return compareElementValues(l,r) < 0;
|
|
|
|
}
|
|
|
|
};
|
2009-01-15 16:17:11 +01:00
|
|
|
|
2009-07-07 23:38:47 +02:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
class ElementMatcher {
|
2009-01-15 16:17:11 +01:00
|
|
|
public:
|
2009-07-07 23:38:47 +02:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
ElementMatcher() {
|
2009-07-07 23:38:47 +02:00
|
|
|
}
|
2009-10-12 18:58:43 +02:00
|
|
|
|
2010-02-22 23:33:24 +01:00
|
|
|
ElementMatcher( BSONElement _e , int _op, bool _isNot );
|
2009-08-20 22:50:58 +02:00
|
|
|
|
2010-02-22 23:33:24 +01:00
|
|
|
ElementMatcher( BSONElement _e , int _op , const BSONObj& array, bool _isNot );
|
2009-07-07 23:38:47 +02:00
|
|
|
|
2010-01-20 19:57:20 +01:00
|
|
|
~ElementMatcher() { }
|
2009-12-31 20:04:44 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
BSONElement toMatch;
|
|
|
|
int compareOp;
|
2010-02-22 23:33:24 +01:00
|
|
|
bool isNot;
|
2009-07-07 23:38:47 +02:00
|
|
|
shared_ptr< set<BSONElement,element_lt> > myset;
|
2010-03-09 01:53:45 +01:00
|
|
|
shared_ptr< vector<RegexMatcher> > myregex;
|
2009-10-12 18:58:43 +02:00
|
|
|
|
|
|
|
// these are for specific operators
|
2009-08-20 22:50:58 +02:00
|
|
|
int mod;
|
|
|
|
int modm;
|
2009-10-12 17:58:14 +02:00
|
|
|
BSONType type;
|
2009-12-31 20:04:44 +01:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
shared_ptr<Matcher> subMatcher;
|
2010-02-19 22:11:55 +01:00
|
|
|
|
|
|
|
vector< shared_ptr<Matcher> > allMatchers;
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-01-20 19:57:20 +01:00
|
|
|
class Where; // used for $where javascript eval
|
2009-03-02 16:41:36 +01:00
|
|
|
class DiskLoc;
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-03-03 21:18:09 +01:00
|
|
|
struct MatchDetails {
|
|
|
|
MatchDetails(){
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
void reset(){
|
|
|
|
loadedObject = false;
|
2010-03-07 04:12:58 +01:00
|
|
|
elemMatchKey = 0;
|
2010-03-03 21:18:09 +01:00
|
|
|
}
|
|
|
|
|
2010-03-07 04:12:58 +01:00
|
|
|
string toString() const {
|
|
|
|
stringstream ss;
|
|
|
|
ss << "loadedObject: " << loadedObject << " ";
|
|
|
|
ss << "elemMatchKey: " << ( elemMatchKey ? elemMatchKey : "NULL" ) << " ";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
2010-03-03 21:18:09 +01:00
|
|
|
bool loadedObject;
|
2010-03-07 04:12:58 +01:00
|
|
|
const char * elemMatchKey; // warning, this may go out of scope if matched object does
|
2010-03-03 21:18:09 +01:00
|
|
|
};
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
/* Match BSON objects against a query pattern.
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
e.g.
|
|
|
|
db.foo.find( { a : 3 } );
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-12-21 23:43:06 +01:00
|
|
|
{ a : 3 } is the pattern object. See wiki documentation for full info.
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
GT/LT:
|
2009-12-21 23:43:06 +01:00
|
|
|
{ a : { $gt : 3 } }
|
2009-01-15 16:17:11 +01:00
|
|
|
Not equal:
|
2009-12-21 23:43:06 +01:00
|
|
|
{ a : { $ne : 3 } }
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
TODO: we should rewrite the matcher to be more an AST style.
|
|
|
|
*/
|
2010-01-19 17:04:52 +01:00
|
|
|
class Matcher : boost::noncopyable {
|
2009-01-15 16:17:11 +01:00
|
|
|
int matchesDotted(
|
|
|
|
const char *fieldName,
|
2009-01-20 21:44:40 +01:00
|
|
|
const BSONElement& toMatch, const BSONObj& obj,
|
2010-03-07 04:12:58 +01:00
|
|
|
int compareOp, const ElementMatcher& bm, bool isArr , MatchDetails * details );
|
2009-01-15 16:17:11 +01:00
|
|
|
|
2009-04-13 22:40:30 +02:00
|
|
|
int matchesNe(
|
|
|
|
const char *fieldName,
|
|
|
|
const BSONElement &toMatch, const BSONObj &obj,
|
2010-03-07 04:12:58 +01:00
|
|
|
const ElementMatcher&bm, MatchDetails * details );
|
2009-04-13 22:40:30 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
public:
|
|
|
|
static int opDirection(int op) {
|
2009-05-11 21:09:30 +02:00
|
|
|
return op <= BSONObj::LTE ? -1 : 1;
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-03-02 19:42:31 +01:00
|
|
|
// Only specify constrainIndexKey if matches() will be called with
|
|
|
|
// index keys having empty string field names.
|
2010-04-14 00:17:34 +02:00
|
|
|
Matcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj(), bool subMatcher = false);
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
~Matcher();
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-03-07 04:12:58 +01:00
|
|
|
bool matches(const BSONObj& j, MatchDetails * details = 0 );
|
2009-03-02 16:41:36 +01:00
|
|
|
|
2010-04-14 00:17:34 +02:00
|
|
|
// until SERVER-109 $or is opaque to indexes
|
|
|
|
bool keyMatch() const { return !all && !haveSize && !hasArray && !haveNeg && _orMatchers.size() == 0; }
|
2009-12-21 23:43:06 +01:00
|
|
|
|
|
|
|
bool atomic() const { return _atomic; }
|
2010-04-14 19:46:54 +02:00
|
|
|
|
2010-03-06 23:53:50 +01:00
|
|
|
bool hasType( BSONObj::MatchType type ) const;
|
2010-04-14 19:46:54 +02:00
|
|
|
|
|
|
|
string toString() const {
|
|
|
|
return jsobj.toString();
|
|
|
|
}
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
private:
|
2010-02-22 23:33:24 +01:00
|
|
|
void addBasic(const BSONElement &e, int c, bool isNot) {
|
2009-03-02 19:42:31 +01:00
|
|
|
// TODO May want to selectively ignore these element types based on op type.
|
2009-02-27 20:04:19 +01:00
|
|
|
if ( e.type() == MinKey || e.type() == MaxKey )
|
|
|
|
return;
|
2010-02-22 23:33:24 +01:00
|
|
|
basics.push_back( ElementMatcher( e , c, isNot ) );
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-03-02 01:53:22 +01:00
|
|
|
void addRegex(const char *fieldName, const char *regex, const char *flags, bool isNot = false);
|
2010-02-23 19:29:10 +01:00
|
|
|
bool addOp( const BSONElement &e, const BSONElement &fe, bool isNot, const char *& regex, const char *&flags );
|
2010-02-22 23:33:24 +01:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const ElementMatcher& bm);
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2010-04-27 02:22:33 +02:00
|
|
|
bool parseOrNor( const BSONElement &e, bool subMatcher );
|
|
|
|
void parseOr( const BSONElement &e, bool subMatcher, vector< shared_ptr< Matcher > > &matchers );
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
Where *where; // set if query uses $where
|
2009-03-02 19:42:31 +01:00
|
|
|
BSONObj jsobj; // the query pattern. e.g., { name: "joe" }
|
|
|
|
BSONObj constrainIndexKey_;
|
2010-01-19 17:04:52 +01:00
|
|
|
vector<ElementMatcher> basics;
|
2009-04-06 17:27:43 +02:00
|
|
|
bool haveSize;
|
2009-07-07 23:38:47 +02:00
|
|
|
bool all;
|
2009-10-09 16:12:19 +02:00
|
|
|
bool hasArray;
|
2010-03-03 01:53:07 +01:00
|
|
|
bool haveNeg;
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-12-21 23:43:06 +01:00
|
|
|
/* $atomic - if true, a multi document operation (some removes, updates)
|
|
|
|
should be done atomically. in that case, we do not yield -
|
|
|
|
i.e. we stay locked the whole time.
|
2010-01-19 17:04:52 +01:00
|
|
|
http://www.mongodb.org/display/DOCS/Removing[
|
2009-12-21 23:43:06 +01:00
|
|
|
*/
|
|
|
|
bool _atomic;
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
RegexMatcher regexs[4];
|
|
|
|
int nRegex;
|
2008-11-18 21:47:37 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
// so we delete the mem when we're done:
|
2009-12-21 23:43:06 +01:00
|
|
|
vector< shared_ptr< BSONObjBuilder > > _builders;
|
2010-04-13 02:48:55 +02:00
|
|
|
vector< shared_ptr< Matcher > > _orMatchers;
|
2010-04-27 02:22:33 +02:00
|
|
|
vector< shared_ptr< Matcher > > _norMatchers;
|
2009-09-15 17:35:14 +02:00
|
|
|
|
2009-12-21 23:43:06 +01:00
|
|
|
friend class CoveredIndexMatcher;
|
2009-03-02 17:31:13 +01:00
|
|
|
};
|
|
|
|
|
2009-12-21 23:43:06 +01:00
|
|
|
// If match succeeds on index key, then attempt to match full document.
|
|
|
|
class CoveredIndexMatcher : boost::noncopyable {
|
2009-04-07 16:40:10 +02:00
|
|
|
public:
|
2009-12-21 23:43:06 +01:00
|
|
|
CoveredIndexMatcher(const BSONObj &pattern, const BSONObj &indexKeyPattern);
|
|
|
|
bool matches(const BSONObj &o){ return _docMatcher.matches( o ); }
|
2010-03-03 21:18:09 +01:00
|
|
|
bool matches(const BSONObj &key, const DiskLoc &recLoc , MatchDetails * details = 0 );
|
2010-03-29 18:55:44 +02:00
|
|
|
bool matchesCurrent( Cursor * cursor , MatchDetails * details = 0 );
|
2009-10-23 03:38:02 +02:00
|
|
|
bool needRecord(){ return _needRecord; }
|
2009-12-21 23:43:06 +01:00
|
|
|
|
2010-01-19 17:04:52 +01:00
|
|
|
Matcher& docMatcher() { return _docMatcher; }
|
2009-04-07 16:40:10 +02:00
|
|
|
private:
|
2010-01-19 17:04:52 +01:00
|
|
|
Matcher _keyMatcher;
|
|
|
|
Matcher _docMatcher;
|
2009-10-23 03:38:02 +02:00
|
|
|
bool _needRecord;
|
2009-04-07 16:40:10 +02:00
|
|
|
};
|
2009-09-15 17:35:14 +02:00
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
} // namespace mongo
|