summaryrefslogtreecommitdiff
path: root/src/mongo/db/matcher/expression_leaf.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/matcher/expression_leaf.cpp')
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp822
1 files changed, 416 insertions, 406 deletions
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp
index f0a91cffbbf..619fc64133d 100644
--- a/src/mongo/db/matcher/expression_leaf.cpp
+++ b/src/mongo/db/matcher/expression_leaf.cpp
@@ -41,52 +41,50 @@
namespace mongo {
- Status LeafMatchExpression::initPath( StringData path ) {
- _path = path;
- return _elementPath.init( _path );
- }
+Status LeafMatchExpression::initPath(StringData path) {
+ _path = path;
+ return _elementPath.init(_path);
+}
- bool LeafMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const {
- MatchableDocument::IteratorHolder cursor( doc, &_elementPath );
- while ( cursor->more() ) {
- ElementIterator::Context e = cursor->next();
- if ( !matchesSingleElement( e.element() ) )
- continue;
- if ( details && details->needRecord() && !e.arrayOffset().eoo() ) {
- details->setElemMatchKey( e.arrayOffset().fieldName() );
- }
- return true;
+bool LeafMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const {
+ MatchableDocument::IteratorHolder cursor(doc, &_elementPath);
+ while (cursor->more()) {
+ ElementIterator::Context e = cursor->next();
+ if (!matchesSingleElement(e.element()))
+ continue;
+ if (details && details->needRecord() && !e.arrayOffset().eoo()) {
+ details->setElemMatchKey(e.arrayOffset().fieldName());
}
- return false;
+ return true;
}
+ return false;
+}
- // -------------
+// -------------
- bool ComparisonMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( other->matchType() != matchType() )
- return false;
- const ComparisonMatchExpression* realOther =
- static_cast<const ComparisonMatchExpression*>( other );
+bool ComparisonMatchExpression::equivalent(const MatchExpression* other) const {
+ if (other->matchType() != matchType())
+ return false;
+ const ComparisonMatchExpression* realOther =
+ static_cast<const ComparisonMatchExpression*>(other);
- return
- path() == realOther->path() &&
- _rhs.valuesEqual( realOther->_rhs );
- }
+ return path() == realOther->path() && _rhs.valuesEqual(realOther->_rhs);
+}
- Status ComparisonMatchExpression::init( StringData path, const BSONElement& rhs ) {
- _rhs = rhs;
+Status ComparisonMatchExpression::init(StringData path, const BSONElement& rhs) {
+ _rhs = rhs;
- if ( rhs.eoo() ) {
- return Status( ErrorCodes::BadValue, "need a real operand" );
- }
+ if (rhs.eoo()) {
+ return Status(ErrorCodes::BadValue, "need a real operand");
+ }
- if ( rhs.type() == Undefined ) {
- return Status( ErrorCodes::BadValue, "cannot compare to undefined" );
- }
+ if (rhs.type() == Undefined) {
+ return Status(ErrorCodes::BadValue, "cannot compare to undefined");
+ }
- switch ( matchType() ) {
+ switch (matchType()) {
case LT:
case LTE:
case EQ:
@@ -94,36 +92,36 @@ namespace mongo {
case GTE:
break;
default:
- return Status( ErrorCodes::BadValue, "bad match type for ComparisonMatchExpression" );
- }
-
- return initPath( path );
+ return Status(ErrorCodes::BadValue, "bad match type for ComparisonMatchExpression");
}
+ return initPath(path);
+}
- bool ComparisonMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- //log() << "\t ComparisonMatchExpression e: " << e << " _rhs: " << _rhs << "\n"
- //<< toString() << std::endl;
- if ( e.canonicalType() != _rhs.canonicalType() ) {
- // some special cases
- // jstNULL and undefined are treated the same
- if ( e.canonicalType() + _rhs.canonicalType() == 5 ) {
- return matchType() == EQ || matchType() == LTE || matchType() == GTE;
- }
+bool ComparisonMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ // log() << "\t ComparisonMatchExpression e: " << e << " _rhs: " << _rhs << "\n"
+ //<< toString() << std::endl;
- if ( _rhs.type() == MaxKey || _rhs.type() == MinKey ) {
- return matchType() != EQ;
- }
+ if (e.canonicalType() != _rhs.canonicalType()) {
+ // some special cases
+ // jstNULL and undefined are treated the same
+ if (e.canonicalType() + _rhs.canonicalType() == 5) {
+ return matchType() == EQ || matchType() == LTE || matchType() == GTE;
+ }
- return false;
+ if (_rhs.type() == MaxKey || _rhs.type() == MinKey) {
+ return matchType() != EQ;
}
- // Special case handling for NaN. NaN is equal to NaN but
- // otherwise always compares to false.
- if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) {
- bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble());
- switch ( matchType() ) {
+ return false;
+ }
+
+ // Special case handling for NaN. NaN is equal to NaN but
+ // otherwise always compares to false.
+ if (std::isnan(e.numberDouble()) || std::isnan(_rhs.numberDouble())) {
+ bool bothNaN = std::isnan(e.numberDouble()) && std::isnan(_rhs.numberDouble());
+ switch (matchType()) {
case LT:
return false;
case LTE:
@@ -137,15 +135,15 @@ namespace mongo {
default:
// This is a comparison match expression, so it must be either
// a $lt, $lte, $gt, $gte, or equality expression.
- fassertFailed( 17448 );
- }
+ fassertFailed(17448);
}
+ }
- int x = compareElementValues( e, _rhs );
+ int x = compareElementValues(e, _rhs);
- //log() << "\t\t" << x << endl;
+ // log() << "\t\t" << x << endl;
- switch ( matchType() ) {
+ switch (matchType()) {
case LT:
return x < 0;
case LTE:
@@ -159,450 +157,462 @@ namespace mongo {
default:
// This is a comparison match expression, so it must be either
// a $lt, $lte, $gt, $gte, or equality expression.
- fassertFailed( 16828 );
- }
+ fassertFailed(16828);
}
+}
- void ComparisonMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << path() << " ";
- switch ( matchType() ) {
- case LT: debug << "$lt"; break;
- case LTE: debug << "$lte"; break;
- case EQ: debug << "=="; break;
- case GT: debug << "$gt"; break;
- case GTE: debug << "$gte"; break;
- default: debug << " UNKNOWN - should be impossible"; break;
- }
- debug << " " << _rhs.toString( false );
-
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
- }
-
- debug << "\n";
+void ComparisonMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << path() << " ";
+ switch (matchType()) {
+ case LT:
+ debug << "$lt";
+ break;
+ case LTE:
+ debug << "$lte";
+ break;
+ case EQ:
+ debug << "==";
+ break;
+ case GT:
+ debug << "$gt";
+ break;
+ case GTE:
+ debug << "$gte";
+ break;
+ default:
+ debug << " UNKNOWN - should be impossible";
+ break;
}
+ debug << " " << _rhs.toString(false);
- void ComparisonMatchExpression::toBSON(BSONObjBuilder* out) const {
- string opString = "";
- switch ( matchType() ) {
- case LT: opString = "$lt"; break;
- case LTE: opString = "$lte"; break;
- case EQ: opString = "$eq"; break;
- case GT: opString = "$gt"; break;
- case GTE: opString = "$gte"; break;
- default: opString = " UNKNOWN - should be impossible"; break;
- }
-
- out->append(path(), BSON(opString << _rhs));
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
- // ---------------
-
- // TODO: move
- inline pcrecpp::RE_Options flags2options(const char* flags) {
- pcrecpp::RE_Options options;
- options.set_utf8(true);
- while ( flags && *flags ) {
- if ( *flags == 'i' )
- options.set_caseless(true);
- else if ( *flags == 'm' )
- options.set_multiline(true);
- else if ( *flags == 'x' )
- options.set_extended(true);
- else if ( *flags == 's' )
- options.set_dotall(true);
- flags++;
- }
- return options;
+ debug << "\n";
+}
+
+void ComparisonMatchExpression::toBSON(BSONObjBuilder* out) const {
+ string opString = "";
+ switch (matchType()) {
+ case LT:
+ opString = "$lt";
+ break;
+ case LTE:
+ opString = "$lte";
+ break;
+ case EQ:
+ opString = "$eq";
+ break;
+ case GT:
+ opString = "$gt";
+ break;
+ case GTE:
+ opString = "$gte";
+ break;
+ default:
+ opString = " UNKNOWN - should be impossible";
+ break;
}
- RegexMatchExpression::RegexMatchExpression()
- : LeafMatchExpression( REGEX ) {}
+ out->append(path(), BSON(opString << _rhs));
+}
- RegexMatchExpression::~RegexMatchExpression() {}
+// ---------------
+
+// TODO: move
+inline pcrecpp::RE_Options flags2options(const char* flags) {
+ pcrecpp::RE_Options options;
+ options.set_utf8(true);
+ while (flags && *flags) {
+ if (*flags == 'i')
+ options.set_caseless(true);
+ else if (*flags == 'm')
+ options.set_multiline(true);
+ else if (*flags == 'x')
+ options.set_extended(true);
+ else if (*flags == 's')
+ options.set_dotall(true);
+ flags++;
+ }
+ return options;
+}
- bool RegexMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( matchType() != other->matchType() )
- return false;
+RegexMatchExpression::RegexMatchExpression() : LeafMatchExpression(REGEX) {}
- const RegexMatchExpression* realOther = static_cast<const RegexMatchExpression*>( other );
- return
- path() == realOther->path() &&
- _regex == realOther->_regex
- && _flags == realOther->_flags;
- }
+RegexMatchExpression::~RegexMatchExpression() {}
+bool RegexMatchExpression::equivalent(const MatchExpression* other) const {
+ if (matchType() != other->matchType())
+ return false;
- Status RegexMatchExpression::init( StringData path, const BSONElement& e ) {
- if ( e.type() != RegEx )
- return Status( ErrorCodes::BadValue, "regex not a regex" );
- return init( path, e.regex(), e.regexFlags() );
- }
+ const RegexMatchExpression* realOther = static_cast<const RegexMatchExpression*>(other);
+ return path() == realOther->path() && _regex == realOther->_regex &&
+ _flags == realOther->_flags;
+}
- Status RegexMatchExpression::init( StringData path, StringData regex, StringData options ) {
- if ( regex.size() > MaxPatternSize ) {
- return Status( ErrorCodes::BadValue, "Regular expression is too long" );
- }
+Status RegexMatchExpression::init(StringData path, const BSONElement& e) {
+ if (e.type() != RegEx)
+ return Status(ErrorCodes::BadValue, "regex not a regex");
+ return init(path, e.regex(), e.regexFlags());
+}
- _regex = regex.toString();
- _flags = options.toString();
- _re.reset( new pcrecpp::RE( _regex.c_str(), flags2options( _flags.c_str() ) ) );
- return initPath( path );
+Status RegexMatchExpression::init(StringData path, StringData regex, StringData options) {
+ if (regex.size() > MaxPatternSize) {
+ return Status(ErrorCodes::BadValue, "Regular expression is too long");
}
- bool RegexMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- //log() << "RegexMatchExpression::matchesSingleElement _regex: " << _regex << " e: " << e << std::endl;
- switch (e.type()) {
+ _regex = regex.toString();
+ _flags = options.toString();
+ _re.reset(new pcrecpp::RE(_regex.c_str(), flags2options(_flags.c_str())));
+
+ return initPath(path);
+}
+
+bool RegexMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ // log() << "RegexMatchExpression::matchesSingleElement _regex: " << _regex << " e: " << e << std::endl;
+ switch (e.type()) {
case String:
case Symbol:
// TODO
- //if (rm._prefix.empty())
- return _re->PartialMatch(e.valuestr());
- //else
- //return !strncmp(e.valuestr(), rm._prefix.c_str(), rm._prefix.size());
+ // if (rm._prefix.empty())
+ return _re->PartialMatch(e.valuestr());
+ // else
+ // return !strncmp(e.valuestr(), rm._prefix.c_str(), rm._prefix.size());
case RegEx:
return _regex == e.regex() && _flags == e.regexFlags();
default:
return false;
- }
}
+}
- void RegexMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << path() << " regex /" << _regex << "/" << _flags;
+void RegexMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << path() << " regex /" << _regex << "/" << _flags;
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
- }
- debug << "\n";
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
+ debug << "\n";
+}
- void RegexMatchExpression::toBSON(BSONObjBuilder* out) const {
- out->appendRegex(path(), _regex, _flags);
- }
+void RegexMatchExpression::toBSON(BSONObjBuilder* out) const {
+ out->appendRegex(path(), _regex, _flags);
+}
- void RegexMatchExpression::shortDebugString( StringBuilder& debug ) const {
- debug << "/" << _regex << "/" << _flags;
- }
+void RegexMatchExpression::shortDebugString(StringBuilder& debug) const {
+ debug << "/" << _regex << "/" << _flags;
+}
- // ---------
+// ---------
- Status ModMatchExpression::init( StringData path, int divisor, int remainder ) {
- if ( divisor == 0 )
- return Status( ErrorCodes::BadValue, "divisor cannot be 0" );
- _divisor = divisor;
- _remainder = remainder;
- return initPath( path );
- }
+Status ModMatchExpression::init(StringData path, int divisor, int remainder) {
+ if (divisor == 0)
+ return Status(ErrorCodes::BadValue, "divisor cannot be 0");
+ _divisor = divisor;
+ _remainder = remainder;
+ return initPath(path);
+}
- bool ModMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- if ( !e.isNumber() )
- return false;
- return e.numberLong() % _divisor == _remainder;
- }
+bool ModMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ if (!e.isNumber())
+ return false;
+ return e.numberLong() % _divisor == _remainder;
+}
- void ModMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << path() << " mod " << _divisor << " % x == " << _remainder;
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
- }
- debug << "\n";
+void ModMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << path() << " mod " << _divisor << " % x == " << _remainder;
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
+ debug << "\n";
+}
- void ModMatchExpression::toBSON(BSONObjBuilder* out) const {
- out->append(path(), BSON("$mod" << BSON_ARRAY(_divisor << _remainder)));
- }
+void ModMatchExpression::toBSON(BSONObjBuilder* out) const {
+ out->append(path(), BSON("$mod" << BSON_ARRAY(_divisor << _remainder)));
+}
- bool ModMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( matchType() != other->matchType() )
- return false;
+bool ModMatchExpression::equivalent(const MatchExpression* other) const {
+ if (matchType() != other->matchType())
+ return false;
- const ModMatchExpression* realOther = static_cast<const ModMatchExpression*>( other );
- return
- path() == realOther->path() &&
- _divisor == realOther->_divisor &&
- _remainder == realOther->_remainder;
- }
+ const ModMatchExpression* realOther = static_cast<const ModMatchExpression*>(other);
+ return path() == realOther->path() && _divisor == realOther->_divisor &&
+ _remainder == realOther->_remainder;
+}
- // ------------------
+// ------------------
- Status ExistsMatchExpression::init( StringData path ) {
- return initPath( path );
- }
+Status ExistsMatchExpression::init(StringData path) {
+ return initPath(path);
+}
- bool ExistsMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- return !e.eoo();
- }
+bool ExistsMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ return !e.eoo();
+}
- void ExistsMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << path() << " exists";
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
- }
- debug << "\n";
+void ExistsMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << path() << " exists";
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
+ debug << "\n";
+}
- void ExistsMatchExpression::toBSON(BSONObjBuilder* out) const {
- out->append(path(), BSON("$exists" << true));
- }
+void ExistsMatchExpression::toBSON(BSONObjBuilder* out) const {
+ out->append(path(), BSON("$exists" << true));
+}
- bool ExistsMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( matchType() != other->matchType() )
- return false;
+bool ExistsMatchExpression::equivalent(const MatchExpression* other) const {
+ if (matchType() != other->matchType())
+ return false;
- const ExistsMatchExpression* realOther = static_cast<const ExistsMatchExpression*>( other );
- return path() == realOther->path();
- }
+ const ExistsMatchExpression* realOther = static_cast<const ExistsMatchExpression*>(other);
+ return path() == realOther->path();
+}
- // ----
+// ----
- Status TypeMatchExpression::init( StringData path, int type ) {
- _path = path;
- _type = type;
- return _elementPath.init( _path );
- }
+Status TypeMatchExpression::init(StringData path, int type) {
+ _path = path;
+ _type = type;
+ return _elementPath.init(_path);
+}
- bool TypeMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- return e.type() == _type;
- }
+bool TypeMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ return e.type() == _type;
+}
- bool TypeMatchExpression::matches( const MatchableDocument* doc, MatchDetails* details ) const {
- MatchableDocument::IteratorHolder cursor( doc, &_elementPath );
- while ( cursor->more() ) {
- ElementIterator::Context e = cursor->next();
-
- // In the case where _elementPath is referring to an array,
- // $type should match elements of that array only.
- // outerArray() helps to identify elements of the array
- // and the containing array itself.
- // This matters when we are looking for {$type: Array}.
- // Example (_elementPath refers to field 'a' and _type is Array):
- // a : [ // outer array. should not match
- // 123, // inner array
- // [ 456 ], // inner array. should match
- // ...
- // ]
- if ( _type == mongo::Array && e.outerArray() ) {
- continue;
- }
-
- if ( !matchesSingleElement( e.element() ) ) {
- continue;
- }
-
- if ( details && details->needRecord() && !e.arrayOffset().eoo() ) {
- details->setElemMatchKey( e.arrayOffset().fieldName() );
- }
- return true;
+bool TypeMatchExpression::matches(const MatchableDocument* doc, MatchDetails* details) const {
+ MatchableDocument::IteratorHolder cursor(doc, &_elementPath);
+ while (cursor->more()) {
+ ElementIterator::Context e = cursor->next();
+
+ // In the case where _elementPath is referring to an array,
+ // $type should match elements of that array only.
+ // outerArray() helps to identify elements of the array
+ // and the containing array itself.
+ // This matters when we are looking for {$type: Array}.
+ // Example (_elementPath refers to field 'a' and _type is Array):
+ // a : [ // outer array. should not match
+ // 123, // inner array
+ // [ 456 ], // inner array. should match
+ // ...
+ // ]
+ if (_type == mongo::Array && e.outerArray()) {
+ continue;
}
- return false;
- }
- void TypeMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << _path << " type: " << _type;
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
+ if (!matchesSingleElement(e.element())) {
+ continue;
}
- debug << "\n";
- }
- void TypeMatchExpression::toBSON(BSONObjBuilder* out) const {
- out->append(path(), BSON("$type" << _type));
+ if (details && details->needRecord() && !e.arrayOffset().eoo()) {
+ details->setElemMatchKey(e.arrayOffset().fieldName());
+ }
+ return true;
}
+ return false;
+}
- bool TypeMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( matchType() != other->matchType() )
- return false;
-
- const TypeMatchExpression* realOther = static_cast<const TypeMatchExpression*>( other );
- return _path == realOther->_path && _type == realOther->_type;
+void TypeMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << _path << " type: " << _type;
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
+ debug << "\n";
+}
+void TypeMatchExpression::toBSON(BSONObjBuilder* out) const {
+ out->append(path(), BSON("$type" << _type));
+}
- // --------
+bool TypeMatchExpression::equivalent(const MatchExpression* other) const {
+ if (matchType() != other->matchType())
+ return false;
- ArrayFilterEntries::ArrayFilterEntries(){
- _hasNull = false;
- _hasEmptyArray = false;
- }
+ const TypeMatchExpression* realOther = static_cast<const TypeMatchExpression*>(other);
+ return _path == realOther->_path && _type == realOther->_type;
+}
- ArrayFilterEntries::~ArrayFilterEntries() {
- for ( unsigned i = 0; i < _regexes.size(); i++ )
- delete _regexes[i];
- _regexes.clear();
- }
- Status ArrayFilterEntries::addEquality( const BSONElement& e ) {
- if ( e.type() == RegEx )
- return Status( ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be a regex" );
+// --------
- if ( e.type() == Undefined ) {
- return Status( ErrorCodes::BadValue,
- "ArrayFilterEntries equality cannot be undefined" );
- }
+ArrayFilterEntries::ArrayFilterEntries() {
+ _hasNull = false;
+ _hasEmptyArray = false;
+}
- if ( e.type() == jstNULL ) {
- _hasNull = true;
- }
+ArrayFilterEntries::~ArrayFilterEntries() {
+ for (unsigned i = 0; i < _regexes.size(); i++)
+ delete _regexes[i];
+ _regexes.clear();
+}
- if ( e.type() == Array && e.Obj().isEmpty() )
- _hasEmptyArray = true;
+Status ArrayFilterEntries::addEquality(const BSONElement& e) {
+ if (e.type() == RegEx)
+ return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be a regex");
- _equalities.insert( e );
- return Status::OK();
+ if (e.type() == Undefined) {
+ return Status(ErrorCodes::BadValue, "ArrayFilterEntries equality cannot be undefined");
}
- Status ArrayFilterEntries::addRegex( RegexMatchExpression* expr ) {
- _regexes.push_back( expr );
- return Status::OK();
+ if (e.type() == jstNULL) {
+ _hasNull = true;
}
- bool ArrayFilterEntries::equivalent( const ArrayFilterEntries& other ) const {
- if ( _hasNull != other._hasNull )
- return false;
+ if (e.type() == Array && e.Obj().isEmpty())
+ _hasEmptyArray = true;
- if ( _regexes.size() != other._regexes.size() )
+ _equalities.insert(e);
+ return Status::OK();
+}
+
+Status ArrayFilterEntries::addRegex(RegexMatchExpression* expr) {
+ _regexes.push_back(expr);
+ return Status::OK();
+}
+
+bool ArrayFilterEntries::equivalent(const ArrayFilterEntries& other) const {
+ if (_hasNull != other._hasNull)
+ return false;
+
+ if (_regexes.size() != other._regexes.size())
+ return false;
+ for (unsigned i = 0; i < _regexes.size(); i++)
+ if (!_regexes[i]->equivalent(other._regexes[i]))
return false;
- for ( unsigned i = 0; i < _regexes.size(); i++ )
- if ( !_regexes[i]->equivalent( other._regexes[i] ) )
- return false;
- return _equalities == other._equalities;
- }
+ return _equalities == other._equalities;
+}
- void ArrayFilterEntries::copyTo( ArrayFilterEntries& toFillIn ) const {
- toFillIn._hasNull = _hasNull;
- toFillIn._hasEmptyArray = _hasEmptyArray;
- toFillIn._equalities = _equalities;
- for ( unsigned i = 0; i < _regexes.size(); i++ )
- toFillIn._regexes.push_back( static_cast<RegexMatchExpression*>(_regexes[i]->shallowClone()) );
- }
+void ArrayFilterEntries::copyTo(ArrayFilterEntries& toFillIn) const {
+ toFillIn._hasNull = _hasNull;
+ toFillIn._hasEmptyArray = _hasEmptyArray;
+ toFillIn._equalities = _equalities;
+ for (unsigned i = 0; i < _regexes.size(); i++)
+ toFillIn._regexes.push_back(
+ static_cast<RegexMatchExpression*>(_regexes[i]->shallowClone()));
+}
- void ArrayFilterEntries::debugString( StringBuilder& debug ) const {
- debug << "[ ";
- for (BSONElementSet::const_iterator it = _equalities.begin();
- it != _equalities.end(); ++it) {
- debug << it->toString( false ) << " ";
- }
- for (size_t i = 0; i < _regexes.size(); ++i) {
- _regexes[i]->shortDebugString( debug );
- debug << " ";
- }
- debug << "]";
+void ArrayFilterEntries::debugString(StringBuilder& debug) const {
+ debug << "[ ";
+ for (BSONElementSet::const_iterator it = _equalities.begin(); it != _equalities.end(); ++it) {
+ debug << it->toString(false) << " ";
}
-
- void ArrayFilterEntries::toBSON(BSONArrayBuilder* out) const {
- for (BSONElementSet::const_iterator it = _equalities.begin();
- it != _equalities.end(); ++it) {
- out->append(*it);
- }
- for (size_t i = 0; i < _regexes.size(); ++i) {
- BSONObjBuilder regexBob;
- _regexes[i]->toBSON(&regexBob);
- out->append(regexBob.obj().firstElement());
- }
- out->doneFast();
+ for (size_t i = 0; i < _regexes.size(); ++i) {
+ _regexes[i]->shortDebugString(debug);
+ debug << " ";
}
+ debug << "]";
+}
- // -----------
-
- Status InMatchExpression::init( StringData path ) {
- return initPath( path );
+void ArrayFilterEntries::toBSON(BSONArrayBuilder* out) const {
+ for (BSONElementSet::const_iterator it = _equalities.begin(); it != _equalities.end(); ++it) {
+ out->append(*it);
}
+ for (size_t i = 0; i < _regexes.size(); ++i) {
+ BSONObjBuilder regexBob;
+ _regexes[i]->toBSON(&regexBob);
+ out->append(regexBob.obj().firstElement());
+ }
+ out->doneFast();
+}
- bool InMatchExpression::_matchesRealElement( const BSONElement& e ) const {
- if ( _arrayEntries.contains( e ) )
- return true;
+// -----------
- for ( unsigned i = 0; i < _arrayEntries.numRegexes(); i++ ) {
- if ( _arrayEntries.regex(i)->matchesSingleElement( e ) )
- return true;
- }
+Status InMatchExpression::init(StringData path) {
+ return initPath(path);
+}
- return false;
- }
+bool InMatchExpression::_matchesRealElement(const BSONElement& e) const {
+ if (_arrayEntries.contains(e))
+ return true;
- bool InMatchExpression::matchesSingleElement( const BSONElement& e ) const {
- if ( _arrayEntries.hasNull() && e.eoo() )
+ for (unsigned i = 0; i < _arrayEntries.numRegexes(); i++) {
+ if (_arrayEntries.regex(i)->matchesSingleElement(e))
return true;
+ }
- if ( _matchesRealElement( e ) )
- return true;
+ return false;
+}
- /*
- if ( e.type() == Array ) {
- BSONObjIterator i( e.Obj() );
- while ( i.more() ) {
- BSONElement sub = i.next();
- if ( _matchesRealElement( sub ) )
- return true;
- }
- }
- */
+bool InMatchExpression::matchesSingleElement(const BSONElement& e) const {
+ if (_arrayEntries.hasNull() && e.eoo())
+ return true;
- return false;
- }
+ if (_matchesRealElement(e))
+ return true;
- void InMatchExpression::debugString( StringBuilder& debug, int level ) const {
- _debugAddSpace( debug, level );
- debug << path() << " $in ";
- _arrayEntries.debugString(debug);
- MatchExpression::TagData* td = getTag();
- if (NULL != td) {
- debug << " ";
- td->debugString(&debug);
+ /*
+ if ( e.type() == Array ) {
+ BSONObjIterator i( e.Obj() );
+ while ( i.more() ) {
+ BSONElement sub = i.next();
+ if ( _matchesRealElement( sub ) )
+ return true;
}
- debug << "\n";
- }
-
- void InMatchExpression::toBSON(BSONObjBuilder* out) const {
- BSONObjBuilder inBob(out->subobjStart(path()));
- BSONArrayBuilder arrBob(inBob.subarrayStart("$in"));
- _arrayEntries.toBSON(&arrBob);
- inBob.doneFast();
}
+ */
- bool InMatchExpression::equivalent( const MatchExpression* other ) const {
- if ( matchType() != other->matchType() )
- return false;
- const InMatchExpression* realOther = static_cast<const InMatchExpression*>( other );
- return
- path() == realOther->path() &&
- _arrayEntries.equivalent( realOther->_arrayEntries );
- }
+ return false;
+}
- LeafMatchExpression* InMatchExpression::shallowClone() const {
- InMatchExpression* next = new InMatchExpression();
- copyTo( next );
- if ( getTag() ) {
- next->setTag(getTag()->clone());
- }
- return next;
+void InMatchExpression::debugString(StringBuilder& debug, int level) const {
+ _debugAddSpace(debug, level);
+ debug << path() << " $in ";
+ _arrayEntries.debugString(debug);
+ MatchExpression::TagData* td = getTag();
+ if (NULL != td) {
+ debug << " ";
+ td->debugString(&debug);
}
+ debug << "\n";
+}
- void InMatchExpression::copyTo( InMatchExpression* toFillIn ) const {
- toFillIn->init( path() );
- _arrayEntries.copyTo( toFillIn->_arrayEntries );
- }
+void InMatchExpression::toBSON(BSONObjBuilder* out) const {
+ BSONObjBuilder inBob(out->subobjStart(path()));
+ BSONArrayBuilder arrBob(inBob.subarrayStart("$in"));
+ _arrayEntries.toBSON(&arrBob);
+ inBob.doneFast();
+}
+bool InMatchExpression::equivalent(const MatchExpression* other) const {
+ if (matchType() != other->matchType())
+ return false;
+ const InMatchExpression* realOther = static_cast<const InMatchExpression*>(other);
+ return path() == realOther->path() && _arrayEntries.equivalent(realOther->_arrayEntries);
}
+LeafMatchExpression* InMatchExpression::shallowClone() const {
+ InMatchExpression* next = new InMatchExpression();
+ copyTo(next);
+ if (getTag()) {
+ next->setTag(getTag()->clone());
+ }
+ return next;
+}
+void InMatchExpression::copyTo(InMatchExpression* toFillIn) const {
+ toFillIn->init(path());
+ _arrayEntries.copyTo(toFillIn->_arrayEntries);
+}
+}