// expression_leaf.h
/**
* Copyright (C) 2013 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.
*/
#pragma once
#include
#include "mongo/bson/bsonmisc.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/db/matcher/expression.h"
#include "mongo/stdx/memory.h"
namespace pcrecpp {
class RE;
} // namespace pcrecpp;
namespace mongo {
class CollatorInterface;
/**
* This file contains leaves in the parse tree that are not array-based.
*
* LeafMatchExpression: REGEX MOD EXISTS MATCH_IN
* ComparisonMatchExpression: EQ LTE LT GT GTE
* MatchExpression: TYPE_OPERATOR
*/
/**
* Many operators subclass from this:
* REGEX, MOD, EXISTS, IN
* Everything that inherits from ComparisonMatchExpression.
*/
class LeafMatchExpression : public MatchExpression {
public:
LeafMatchExpression(MatchType matchType) : MatchExpression(matchType) {}
virtual ~LeafMatchExpression() {}
virtual bool matches(const MatchableDocument* doc, MatchDetails* details = 0) const;
virtual bool matchesSingleElement(const BSONElement& e) const = 0;
virtual const StringData path() const {
return _path;
}
Status setPath(StringData path);
private:
StringData _path;
ElementPath _elementPath;
};
/**
* EQ, LTE, LT, GT, GTE subclass from ComparisonMatchExpression.
*/
class ComparisonMatchExpression : public LeafMatchExpression {
public:
ComparisonMatchExpression(MatchType type) : LeafMatchExpression(type) {}
Status init(StringData path, const BSONElement& rhs);
virtual ~ComparisonMatchExpression() {}
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual const BSONElement& getRHS() const {
return _rhs;
}
virtual void debugString(StringBuilder& debug, int level = 0) const;
/**
* 'collator' must outlive the ComparisonMatchExpression and any clones made of it.
*/
virtual void _doSetCollator(const CollatorInterface* collator) {
_collator = collator;
}
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
const BSONElement& getData() const {
return _rhs;
}
const CollatorInterface* getCollator() const {
return _collator;
}
/**
* Returns true if the MatchExpression is a ComparisonMatchExpression.
*/
static bool isComparisonMatchExpression(const MatchExpression* expr) {
switch (expr->matchType()) {
case MatchExpression::LT:
case MatchExpression::LTE:
case MatchExpression::EQ:
case MatchExpression::GTE:
case MatchExpression::GT:
return true;
default:
return false;
}
}
protected:
BSONElement _rhs;
// Collator used to compare elements. By default, simple binary comparison will be used.
const CollatorInterface* _collator = nullptr;
};
//
// ComparisonMatchExpression inheritors
//
class EqualityMatchExpression : public ComparisonMatchExpression {
public:
EqualityMatchExpression() : ComparisonMatchExpression(EQ) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _rhs);
if (getTag()) {
e->setTag(getTag()->clone());
}
e->setCollator(_collator);
return std::move(e);
}
};
class LTEMatchExpression : public ComparisonMatchExpression {
public:
LTEMatchExpression() : ComparisonMatchExpression(LTE) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _rhs);
if (getTag()) {
e->setTag(getTag()->clone());
}
e->setCollator(_collator);
return std::move(e);
}
};
class LTMatchExpression : public ComparisonMatchExpression {
public:
LTMatchExpression() : ComparisonMatchExpression(LT) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _rhs);
if (getTag()) {
e->setTag(getTag()->clone());
}
e->setCollator(_collator);
return std::move(e);
}
};
class GTMatchExpression : public ComparisonMatchExpression {
public:
GTMatchExpression() : ComparisonMatchExpression(GT) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _rhs);
if (getTag()) {
e->setTag(getTag()->clone());
}
e->setCollator(_collator);
return std::move(e);
}
};
class GTEMatchExpression : public ComparisonMatchExpression {
public:
GTEMatchExpression() : ComparisonMatchExpression(GTE) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _rhs);
if (getTag()) {
e->setTag(getTag()->clone());
}
e->setCollator(_collator);
return std::move(e);
}
};
//
// LeafMatchExpression inheritors
//
class RegexMatchExpression : public LeafMatchExpression {
public:
/**
* Maximum pattern size which pcre v8.3 can do matches correctly with
* LINK_SIZE define macro set to 2 @ pcre's config.h (based on
* experiments)
*/
static const size_t MaxPatternSize = 32764;
RegexMatchExpression();
~RegexMatchExpression();
Status init(StringData path, StringData regex, StringData options);
Status init(StringData path, const BSONElement& e);
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path(), _regex, _flags);
if (getTag()) {
e->setTag(getTag()->clone());
}
return std::move(e);
}
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
void shortDebugString(StringBuilder& debug) const;
virtual bool equivalent(const MatchExpression* other) const;
const std::string& getString() const {
return _regex;
}
const std::string& getFlags() const {
return _flags;
}
private:
std::string _regex;
std::string _flags;
std::unique_ptr _re;
};
class ModMatchExpression : public LeafMatchExpression {
public:
ModMatchExpression() : LeafMatchExpression(MOD) {}
Status init(StringData path, int divisor, int remainder);
virtual std::unique_ptr shallowClone() const {
std::unique_ptr m = stdx::make_unique();
m->init(path(), _divisor, _remainder);
if (getTag()) {
m->setTag(getTag()->clone());
}
return std::move(m);
}
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
int getDivisor() const {
return _divisor;
}
int getRemainder() const {
return _remainder;
}
private:
int _divisor;
int _remainder;
};
class ExistsMatchExpression : public LeafMatchExpression {
public:
ExistsMatchExpression() : LeafMatchExpression(EXISTS) {}
Status init(StringData path);
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
e->init(path());
if (getTag()) {
e->setTag(getTag()->clone());
}
return std::move(e);
}
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
};
/**
* query operator: $in
*/
class InMatchExpression : public LeafMatchExpression {
public:
InMatchExpression() : LeafMatchExpression(MATCH_IN) {}
Status init(StringData path);
virtual std::unique_ptr shallowClone() const;
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
/**
* 'collator' must outlive the InMatchExpression and any clones made of it.
*/
virtual void _doSetCollator(const CollatorInterface* collator);
Status addEquality(const BSONElement& elt);
Status addRegex(std::unique_ptr expr);
const BSONElementSet& getEqualities() const {
return _equalitySet;
}
const std::vector>& getRegexes() const {
return _regexes;
}
const CollatorInterface* getCollator() const {
return _collator;
}
bool hasNull() const {
return _hasNull;
}
bool hasEmptyArray() const {
return _hasEmptyArray;
}
private:
// Whether or not '_equalities' has a jstNULL element in it.
bool _hasNull = false;
// Whether or not '_equalities' has an empty array element in it.
bool _hasEmptyArray = false;
// Collator used to compare elements. By default, simple binary comparison will be used.
const CollatorInterface* _collator = nullptr;
// Set of equality elements associated with this expression. '_collator' is used as a comparator
// for this set.
BSONElementSet _equalitySet;
// Original container of equality elements, including duplicates. Needed for re-computing
// '_equalitySet' in case '_collator' changes after elements have been added.
std::vector _originalEqualityVector;
// Container of regex elements this object owns.
std::vector> _regexes;
};
//
// The odd duck out, TYPE_OPERATOR.
//
/**
* Type has some odd semantics with arrays and as such it can't inherit from
* LeafMatchExpression.
*/
class TypeMatchExpression : public MatchExpression {
public:
static const std::string kMatchesAllNumbersAlias;
static const std::unordered_map typeAliasMap;
TypeMatchExpression() : MatchExpression(TYPE_OPERATOR) {}
/**
* Initialize as matching against a specific BSONType.
*
* Returns a non-OK status if 'type' cannot be converted to a valid BSONType.
*/
Status initWithBSONType(StringData path, int type);
/**
* Initialize as matching against all number types (NumberDouble, NumberLong, and NumberInt).
*/
Status initAsMatchingAllNumbers(StringData path);
virtual std::unique_ptr shallowClone() const {
std::unique_ptr e = stdx::make_unique();
if (_matchesAllNumbers) {
e->initAsMatchingAllNumbers(_path);
} else {
e->initWithBSONType(_path, _type);
}
if (getTag()) {
e->setTag(getTag()->clone());
}
return std::move(e);
}
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual bool matches(const MatchableDocument* doc, MatchDetails* details = 0) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
/**
* What is the type we're matching against?
*/
BSONType getType() const {
return _type;
}
/**
* Whether or not to match against all number types (NumberDouble, NumberLong, and NumberInt).
* Defaults to false. If this is true, _type is EOO.
*/
bool matchesAllNumbers() const {
return _matchesAllNumbers;
}
virtual const StringData path() const {
return _path;
}
private:
bool _matches(StringData path, const MatchableDocument* doc, MatchDetails* details = 0) const;
StringData _path;
ElementPath _elementPath;
bool _matchesAllNumbers = false;
BSONType _type = BSONType::EOO;
};
/**
* Bit test query operators include $bitsAllSet, $bitsAllClear, $bitsAnySet, and $bitsAnyClear.
*/
class BitTestMatchExpression : public LeafMatchExpression {
public:
// Constant used in matchesSingleElement() and MatchExpressionParser::_parseBitTest. Is a
// double representation of 2^63.
static const double kLongLongMaxPlusOneAsDouble;
BitTestMatchExpression(MatchType type) : LeafMatchExpression(type) {}
virtual ~BitTestMatchExpression() {}
/**
* Initialize with either bit positions, a 64-bit numeric bitmask, or a char array
* bitmask.
*/
Status init(StringData path, std::vector bitPositions);
Status init(StringData path, uint64_t bitMask);
Status init(StringData path, const char* bitMaskBinary, uint32_t bitMaskLen);
virtual bool matchesSingleElement(const BSONElement& e) const;
virtual void debugString(StringBuilder& debug, int level) const;
virtual void serialize(BSONObjBuilder* out) const;
virtual bool equivalent(const MatchExpression* other) const;
size_t numBitPositions() const {
return _bitPositions.size();
}
const std::vector& getBitPositions() const {
return _bitPositions;
}
protected:
/**
* Used to copy this match expression to another BitTestMatchExpression. Does not take
* ownership.
*/
void initClone(BitTestMatchExpression* clone) const {
clone->init(path(), _bitPositions);
if (getTag()) {
clone->setTag(getTag()->clone());
}
}
private:
/**
* Performs bit test using bit positions on 'eValue' and returns whether or not the bit test
* passes.
*/
bool performBitTest(long long eValue) const;
/**
* Performs bit test using bit positions on 'eBinary' with length (in bytes) 'eBinaryLen' and
* returns whether or not the bit test passes.
*/
bool performBitTest(const char* eBinary, uint32_t eBinaryLen) const;
/**
* Helper function for performBitTest(...).
*
* needFurtherBitTests() determines if the result of a bit-test ('isBitSet') is enough
* information to skip the rest of the bit tests.
**/
bool needFurtherBitTests(bool isBitSet) const;
// Vector of bit positions to test, with bit position 0 being the least significant bit.
// Used to perform bit tests against BinData.
std::vector _bitPositions;
// Used to perform bit tests against numbers using a single bitwise operation.
uint64_t _bitMask = 0;
};
class BitsAllSetMatchExpression : public BitTestMatchExpression {
public:
BitsAllSetMatchExpression() : BitTestMatchExpression(BITS_ALL_SET) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr bitTestMatchExpression =
stdx::make_unique();
initClone(bitTestMatchExpression.get());
return std::move(bitTestMatchExpression);
}
};
class BitsAllClearMatchExpression : public BitTestMatchExpression {
public:
BitsAllClearMatchExpression() : BitTestMatchExpression(BITS_ALL_CLEAR) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr bitTestMatchExpression =
stdx::make_unique();
initClone(bitTestMatchExpression.get());
return std::move(bitTestMatchExpression);
}
};
class BitsAnySetMatchExpression : public BitTestMatchExpression {
public:
BitsAnySetMatchExpression() : BitTestMatchExpression(BITS_ANY_SET) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr bitTestMatchExpression =
stdx::make_unique();
initClone(bitTestMatchExpression.get());
return std::move(bitTestMatchExpression);
}
};
class BitsAnyClearMatchExpression : public BitTestMatchExpression {
public:
BitsAnyClearMatchExpression() : BitTestMatchExpression(BITS_ANY_CLEAR) {}
virtual std::unique_ptr shallowClone() const {
std::unique_ptr bitTestMatchExpression =
stdx::make_unique();
initClone(bitTestMatchExpression.get());
return std::move(bitTestMatchExpression);
}
};
} // namespace mongo