0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 01:21:03 +01:00
mongodb/db/matcher.h

182 lines
5.3 KiB
C
Raw Normal View History

2008-11-30 02:01:58 +01:00
// matcher.h
2008-11-18 21:47:37 +01:00
/* JSMatcher is our boolean expression evaluator for "where" clauses */
/**
* 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
#include "jsobj.h"
2008-12-29 02:28:49 +01:00
#include <pcrecpp.h>
2009-01-14 23:09:51 +01:00
namespace mongo {
class KeyValJSMatcher;
2009-07-07 23:38:47 +02:00
class RegexMatcher {
public:
const char *fieldName;
pcrecpp::RE *re;
RegexMatcher() {
re = 0;
}
~RegexMatcher() {
delete re;
}
};
2009-07-07 23:38:47 +02:00
struct element_lt
{
bool operator()(const BSONElement& l, const BSONElement& r) const
{
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-07-07 23:38:47 +02:00
class BasicMatcher {
public:
2009-07-07 23:38:47 +02:00
BasicMatcher(){
}
BasicMatcher( BSONElement _e , int _op ) : toMatch( _e ) , compareOp( _op ){
2009-08-20 22:50:58 +02:00
if ( _op == BSONObj::opMOD ){
BSONObj o = _e.embeddedObject().firstElement().embeddedObject();
mod = o["0"].numberInt();
modm = o["1"].numberInt();
uassert( "mod can't be 0" , mod );
}
2009-10-12 17:58:14 +02:00
else if ( _op == BSONObj::opTYPE ){
type = (BSONType)(_e.embeddedObject().firstElement().numberInt());
}
2009-07-07 23:38:47 +02:00
}
2009-10-12 18:58:43 +02:00
2009-08-20 22:50:58 +02:00
2009-07-07 23:38:47 +02:00
BasicMatcher( BSONElement _e , int _op , const BSONObj& array ) : toMatch( _e ) , compareOp( _op ){
myset.reset( new set<BSONElement,element_lt>() );
BSONObjIterator i( array );
while ( i.more() ) {
BSONElement ie = i.next();
myset->insert(ie);
}
}
BSONElement toMatch;
int compareOp;
2009-07-07 23:38:47 +02:00
shared_ptr< set<BSONElement,element_lt> > myset;
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;
};
2008-11-18 21:47:37 +01:00
// SQL where clause equivalent
class Where;
class DiskLoc;
2008-11-18 21:47:37 +01:00
/* Match BSON objects against a query pattern.
2008-11-18 21:47:37 +01:00
e.g.
db.foo.find( { a : 3 } );
2008-11-18 21:47:37 +01:00
{ a : 3 } is the pattern object.
2008-11-18 21:47:37 +01:00
GT/LT:
{ a : { $gt : 3 } }
2008-11-18 21:47:37 +01:00
Not equal:
{ a : { $ne : 3 } }
2008-11-18 21:47:37 +01:00
TODO: we should rewrite the matcher to be more an AST style.
*/
class JSMatcher : boost::noncopyable {
int matchesDotted(
const char *fieldName,
const BSONElement& toMatch, const BSONObj& obj,
2009-11-02 16:51:42 +01:00
int compareOp, const BasicMatcher& bm, bool isArr = false);
int matchesNe(
const char *fieldName,
const BSONElement &toMatch, const BSONObj &obj,
2009-11-02 16:51:42 +01:00
const BasicMatcher&bm);
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
// Only specify constrainIndexKey if matches() will be called with
// index keys having empty string field names.
JSMatcher(const BSONObj &pattern, const BSONObj &constrainIndexKey = BSONObj());
2008-11-18 21:47:37 +01:00
~JSMatcher();
2008-11-18 21:47:37 +01:00
2009-11-02 16:51:42 +01:00
bool matches(const BSONObj& j);
bool keyMatch() const { return !all && !haveSize && !hasArray; }
private:
2009-03-20 21:20:46 +01:00
void addBasic(const BSONElement &e, int c) {
// 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;
2009-07-07 23:38:47 +02:00
basics.push_back( BasicMatcher( e , c ) );
}
2008-11-18 21:47:37 +01:00
2009-11-02 16:51:42 +01:00
int valuesMatch(const BSONElement& l, const BSONElement& r, int op, const BasicMatcher& bm);
2008-11-18 21:47:37 +01:00
Where *where; // set if query uses $where
BSONObj jsobj; // the query pattern. e.g., { name: "joe" }
BSONObj constrainIndexKey_;
vector<BasicMatcher> basics;
// int n; // # of basicmatcher items
2009-04-06 17:27:43 +02:00
bool haveSize;
2009-07-07 23:38:47 +02:00
bool all;
bool hasArray;
2008-11-18 21:47:37 +01:00
RegexMatcher regexs[4];
int nRegex;
2008-11-18 21:47:37 +01:00
// so we delete the mem when we're done:
2009-04-14 00:45:58 +02:00
vector< shared_ptr< BSONObjBuilder > > builders_;
friend class KeyValJSMatcher;
2009-03-02 17:31:13 +01:00
};
2009-04-07 16:40:10 +02:00
// If match succeeds on index key, then attempt to match full record.
class KeyValJSMatcher : boost::noncopyable {
public:
KeyValJSMatcher(const BSONObj &pattern, const BSONObj &indexKeyPattern);
2009-11-02 16:51:42 +01:00
bool matches(const BSONObj &j);
bool matches(const BSONObj &key, const DiskLoc &recLoc);
2009-10-23 03:38:02 +02:00
bool needRecord(){ return _needRecord; }
2009-04-07 16:40:10 +02:00
private:
2009-10-23 03:38:02 +02:00
JSMatcher _keyMatcher;
JSMatcher _recordMatcher;
bool _needRecord;
2009-04-07 16:40:10 +02:00
};
2009-01-14 23:09:51 +01:00
} // namespace mongo