/** * Copyright (c) 2011 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 "mongo/platform/basic.h" #include #include "mongo/db/pipeline/dependencies.h" #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/field_path.h" #include "mongo/db/pipeline/value.h" #include "mongo/util/intrusive_counter.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/string_map.h" namespace mongo { class BSONArrayBuilder; class BSONElement; class BSONObjBuilder; class DocumentSource; // TODO: Look into merging with ExpressionContext and possibly ObjectCtx. /// The state used as input and working space for Expressions. class Variables { MONGO_DISALLOW_COPYING(Variables); public: /** * Each unique variable is assigned a unique id of this type */ typedef size_t Id; // This is only for expressions that use no variables (even ROOT). Variables() : _numVars(0) {} explicit Variables(size_t numVars, const Document& root = Document()) : _root(root), _rest(numVars == 0 ? NULL : new Value[numVars]), _numVars(numVars) {} static void uassertValidNameForUserWrite(StringData varName); static void uassertValidNameForUserRead(StringData varName); static const Id ROOT_ID = Id(-1); /** * Use this instead of setValue for setting ROOT */ void setRoot(const Document& root) { _root = root; } void clearRoot() { _root = Document(); } const Document& getRoot() const { return _root; } void setValue(Id id, const Value& value); Value getValue(Id id) const; /** * returns Document() for non-document values. */ Document getDocument(Id id) const; private: Document _root; const std::unique_ptr _rest; const size_t _numVars; }; /** * Generates Variables::Ids and keeps track of the number of Ids handed out. */ class VariablesIdGenerator { public: VariablesIdGenerator() : _nextId(0) {} Variables::Id generateId() { return _nextId++; } /** * Returns the number of Ids handed out by this Generator. * Return value is intended to be passed to Variables constructor. */ Variables::Id getIdCount() const { return _nextId; } private: Variables::Id _nextId; }; /** * This class represents the Variables that are defined in an Expression tree. * * All copies from a given instance share enough information to ensure unique Ids are assigned * and to propagate back to the original instance enough information to correctly construct a * Variables instance. */ class VariablesParseState { public: explicit VariablesParseState(VariablesIdGenerator* idGenerator) : _idGenerator(idGenerator) {} /** * Assigns a named variable a unique Id. This differs from all other variables, even * others with the same name. * * The special variables ROOT and CURRENT are always implicitly defined with CURRENT * equivalent to ROOT. If CURRENT is explicitly defined by a call to this function, it * breaks that equivalence. * * NOTE: Name validation is responsibility of caller. */ Variables::Id defineVariable(StringData name); /** * Returns the current Id for a variable. uasserts if the variable isn't defined. */ Variables::Id getVariable(StringData name) const; private: StringMap _variables; VariablesIdGenerator* _idGenerator; }; class Expression : public IntrusiveCounterUnsigned { public: virtual ~Expression(){}; /* Optimize the Expression. This provides an opportunity to do constant folding, or to collapse nested operators that have the same precedence, such as $add, $and, or $or. The Expression should be replaced with the return value, which may or may not be the same object. In the case of constant folding, a computed expression may be replaced by a constant. @returns the optimized Expression */ virtual boost::intrusive_ptr optimize() { return this; } /** * Add this expression's field dependencies to the set * * Expressions are trees, so this is often recursive. * * @param deps Fully qualified paths to depended-on fields are added to this set. * Empty std::string means need full document. * @param path path to self if all ancestors are ExpressionObjects. * Top-level ExpressionObject gets pointer to empty vector. * If any other Expression is an ancestor, or in other cases * where {a:1} inclusion objects aren't allowed, they get * NULL. */ virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const = 0; /** simple expressions are just inclusion exclusion as supported by ExpressionObject */ virtual bool isSimple() { return false; } /** * Serialize the Expression tree recursively. * If explain is false, returns a Value parsable by parseOperand(). */ virtual Value serialize(bool explain) const = 0; /// Evaluate expression with specified inputs and return result. (only used by tests) Value evaluate(const Document& root) const { Variables vars(0, root); return evaluate(&vars); } /** * Evaluate expression with specified inputs and return result. * * While vars is non-const, if properly constructed, subexpressions modifications to it * should not effect outer expressions due to unique variable Ids. */ Value evaluate(Variables* vars) const { return evaluateInternal(vars); } /* Utility class for parseObject() below. DOCUMENT_OK indicates that it is OK to use a Document in the current context. */ class ObjectCtx { public: ObjectCtx(int options); static const int DOCUMENT_OK = 0x0001; static const int TOP_LEVEL = 0x0002; static const int INCLUSION_OK = 0x0004; bool documentOk() const; bool topLevel() const; bool inclusionOk() const; private: int options; }; // // Diagram of relationship between parse functions when parsing a $op: // // { someFieldOrArrayIndex: { $op: [ARGS] } } // ^ parseExpression on inner $op BSONElement // ^ parseObject on BSONObject // ^ parseOperand on outer BSONElement wrapping the $op Object // /** * Parses a BSON Object that could represent a functional expression or a Document * expression. */ static boost::intrusive_ptr parseObject(BSONObj obj, ObjectCtx* pCtx, const VariablesParseState& vps); /** * Parses a BSONElement which has already been determined to be functional expression. * * exprElement should be the only element inside the expression object. That is the * field name should be the $op for the expression. */ static boost::intrusive_ptr parseExpression(BSONElement exprElement, const VariablesParseState& vps); /** * Parses a BSONElement which is an operand in an Expression. * * This is the most generic parser and can parse ExpressionFieldPath, a literal, or a $op. * If it is a $op, exprElement should be the outer element whose value is an Object * containing the $op. */ static boost::intrusive_ptr parseOperand(BSONElement exprElement, const VariablesParseState& vps); /* Produce a field path std::string with the field prefix removed. Throws an error if the field prefix is not present. @param prefixedField the prefixed field @returns the field path with the prefix removed */ static std::string removeFieldPrefix(const std::string& prefixedField); /** Evaluate the subclass Expression using the given Variables as context and return result. * * Should only be called by subclasses, but can't be protected because they need to call * this function on each other. */ virtual Value evaluateInternal(Variables* vars) const = 0; protected: typedef std::vector> ExpressionVector; }; /// Inherit from ExpressionVariadic or ExpressionFixedArity instead of directly from this class. class ExpressionNary : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value serialize(bool explain) const; virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; /* Add an operand to the n-ary expression. @param pExpression the expression to add */ virtual void addOperand(const boost::intrusive_ptr& pExpression); // TODO split this into two functions virtual bool isAssociativeAndCommutative() const { return false; } /* Get the name of the operator. @returns the name of the operator; this std::string belongs to the class implementation, and should not be deleted and should not */ virtual const char* getOpName() const = 0; /// Allow subclasses the opportunity to validate arguments at parse time. virtual void validateArguments(const ExpressionVector& args) const {} static ExpressionVector parseArguments(BSONElement bsonExpr, const VariablesParseState& vps); protected: ExpressionNary() {} ExpressionVector vpOperand; }; /// Inherit from ExpressionVariadic or ExpressionFixedArity instead of directly from this class. template class ExpressionNaryBase : public ExpressionNary { public: static boost::intrusive_ptr parse(BSONElement bsonExpr, const VariablesParseState& vps) { boost::intrusive_ptr expr = new SubClass(); ExpressionVector args = parseArguments(bsonExpr, vps); expr->validateArguments(args); expr->vpOperand = args; return expr; } }; /// Inherit from this class if your expression takes a variable number of arguments. template class ExpressionVariadic : public ExpressionNaryBase {}; /// Inherit from this class if your expression takes a fixed number of arguments. template class ExpressionFixedArity : public ExpressionNaryBase { public: virtual void validateArguments(const Expression::ExpressionVector& args) const { uassert(16020, mongoutils::str::stream() << "Expression " << this->getOpName() << " takes exactly " << NArgs << " arguments. " << args.size() << " were passed in.", args.size() == NArgs); } }; class ExpressionAbs final : public ExpressionFixedArity { Value evaluateInternal(Variables* vars) const final; const char* getOpName() const final; }; class ExpressionAdd : public ExpressionVariadic { public: // virtuals from Expression virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionAllElementsTrue : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionAnd : public ExpressionVariadic { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionAnyElementTrue : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionArrayElemAt final : public ExpressionFixedArity { public: Value evaluateInternal(Variables* vars) const final; const char* getOpName() const final; }; class ExpressionCoerceToBool : public Expression { public: // virtuals from ExpressionNary virtual boost::intrusive_ptr optimize(); virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; virtual Value evaluateInternal(Variables* vars) const; virtual Value serialize(bool explain) const; static boost::intrusive_ptr create( const boost::intrusive_ptr& pExpression); private: ExpressionCoerceToBool(const boost::intrusive_ptr& pExpression); boost::intrusive_ptr pExpression; }; class ExpressionCompare : public ExpressionFixedArity { public: /** Enumeration of comparison operators. Any changes to these values require adjustment of * the lookup table in the implementation. */ enum CmpOp { EQ = 0, // return true for a == b, false otherwise NE = 1, // return true for a != b, false otherwise GT = 2, // return true for a > b, false otherwise GTE = 3, // return true for a >= b, false otherwise LT = 4, // return true for a < b, false otherwise LTE = 5, // return true for a <= b, false otherwise CMP = 6, // return -1, 0, 1 for a < b, a == b, a > b }; // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static boost::intrusive_ptr parse(BSONElement bsonExpr, const VariablesParseState& vps, CmpOp cmpOp); ExpressionCompare(CmpOp cmpOp); private: CmpOp cmpOp; }; class ExpressionConcat : public ExpressionVariadic { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionConcatArrays final : public ExpressionVariadic { public: Value evaluateInternal(Variables* vars) const final; const char* getOpName() const final; }; class ExpressionCond : public ExpressionFixedArity { typedef ExpressionFixedArity Base; public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); }; class ExpressionConstant : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual Value serialize(bool explain) const; static boost::intrusive_ptr create(const Value& pValue); static boost::intrusive_ptr parse(BSONElement bsonExpr, const VariablesParseState& vps); /* Get the constant value represented by this Expression. @returns the value */ Value getValue() const; private: ExpressionConstant(const Value& pValue); Value pValue; }; class ExpressionDateToString : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value serialize(bool explain) const; virtual Value evaluateInternal(Variables* vars) const; virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); private: ExpressionDateToString(const std::string& format, // the format string boost::intrusive_ptr date); // the date to format // Will uassert on invalid data static void validateFormat(const std::string& format); // Need raw date as tm doesn't have millisecond resolution. // Format must be valid. static std::string formatDate(const std::string& format, const tm& tm, const long long date); static void insertPadded(StringBuilder& sb, int number, int spaces); const std::string _format; boost::intrusive_ptr _date; }; class ExpressionDayOfMonth : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static inline int extract(const tm& tm) { return tm.tm_mday; } }; class ExpressionDayOfWeek : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; // MySQL uses 1-7, tm uses 0-6 static inline int extract(const tm& tm) { return tm.tm_wday + 1; } }; class ExpressionDayOfYear : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; // MySQL uses 1-366, tm uses 0-365 static inline int extract(const tm& tm) { return tm.tm_yday + 1; } }; class ExpressionDivide : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionFieldPath : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; virtual Value evaluateInternal(Variables* vars) const; virtual Value serialize(bool explain) const; /* Create a field path expression using old semantics (rooted off of CURRENT). // NOTE: this method is deprecated and only used by tests // TODO remove this method in favor of parse() Evaluation will extract the value associated with the given field path from the source document. @param fieldPath the field path string, without any leading document indicator @returns the newly created field path expression */ static boost::intrusive_ptr create(const std::string& fieldPath); /// Like create(), but works with the raw std::string from the user with the "$" prefixes. static boost::intrusive_ptr parse(const std::string& raw, const VariablesParseState& vps); const FieldPath& getFieldPath() const { return _fieldPath; } private: ExpressionFieldPath(const std::string& fieldPath, Variables::Id variable); /* Internal implementation of evaluateInternal(), used recursively. The internal implementation doesn't just use a loop because of the possibility that we need to skip over an array. If the path is "a.b.c", and a is an array, then we fan out from there, and traverse "b.c" for each element of a:[...]. This requires that a be an array of objects in order to navigate more deeply. @param index current path field index to extract @param input current document traversed to (not the top-level one) @returns the field found; could be an array */ Value evaluatePath(size_t index, const Document& input) const; // Helper for evaluatePath to handle Array case Value evaluatePathArray(size_t index, const Value& input) const; const FieldPath _fieldPath; const Variables::Id _variable; }; class ExpressionFilter final : public Expression { public: // virtuals from Expression boost::intrusive_ptr optimize() final; Value serialize(bool explain) const final; Value evaluateInternal(Variables* vars) const final; void addDependencies(DepsTracker* deps, std::vector* path = NULL) const final; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); private: ExpressionFilter(std::string varName, Variables::Id varId, boost::intrusive_ptr input, boost::intrusive_ptr filter); // The name of the variable to set to each element in the array. std::string _varName; // The id of the variable to set. Variables::Id _varId; // The array to iterate over. boost::intrusive_ptr _input; // The expression determining whether each element should be present in the result array. boost::intrusive_ptr _filter; }; class ExpressionHour : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static inline int extract(const tm& tm) { return tm.tm_hour; } }; class ExpressionIfNull : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionLet : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value serialize(bool explain) const; virtual Value evaluateInternal(Variables* vars) const; virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); struct NameAndExpression { NameAndExpression() {} NameAndExpression(std::string name, boost::intrusive_ptr expression) : name(name), expression(expression) {} std::string name; boost::intrusive_ptr expression; }; typedef std::map VariableMap; private: ExpressionLet(const VariableMap& vars, boost::intrusive_ptr subExpression); VariableMap _variables; boost::intrusive_ptr _subExpression; }; class ExpressionMap : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value serialize(bool explain) const; virtual Value evaluateInternal(Variables* vars) const; virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); private: ExpressionMap( const std::string& varName, // name of variable to set Variables::Id varId, // id of variable to set boost::intrusive_ptr input, // yields array to iterate boost::intrusive_ptr each); // yields results to be added to output array std::string _varName; Variables::Id _varId; boost::intrusive_ptr _input; boost::intrusive_ptr _each; }; class ExpressionMeta : public Expression { public: // virtuals from Expression virtual Value serialize(bool explain) const; virtual Value evaluateInternal(Variables* vars) const; virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; static boost::intrusive_ptr parse(BSONElement expr, const VariablesParseState& vps); }; class ExpressionMillisecond : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static int extract(const long long date); }; class ExpressionMinute : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static int extract(const tm& tm) { return tm.tm_min; } }; class ExpressionMod : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionMultiply : public ExpressionVariadic { public: // virtuals from Expression virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionMonth : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; // MySQL uses 1-12, tm uses 0-11 static inline int extract(const tm& tm) { return tm.tm_mon + 1; } }; class ExpressionNot : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionObject : public Expression { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual bool isSimple(); virtual void addDependencies(DepsTracker* deps, std::vector* path = NULL) const; /** Only evaluates non inclusion expressions. For inclusions, use addToDocument(). */ virtual Value evaluateInternal(Variables* vars) const; virtual Value serialize(bool explain) const; /// like evaluate(), but return a Document instead of a Value-wrapped Document. Document evaluateDocument(Variables* vars) const; /** Evaluates with inclusions and adds results to passed in Mutable document * * @param output the MutableDocument to add the evaluated expressions to * @param currentDoc the input Document for this level (for inclusions) * @param vars the variables for use in subexpressions */ void addToDocument(MutableDocument& ouput, const Document& currentDoc, Variables* vars) const; // estimated number of fields that will be output size_t getSizeHint() const; /** Create an empty expression. * Until fields are added, this will evaluate to an empty document. */ static boost::intrusive_ptr create(); /// Like create but uses special handling of _id for root object of $project. static boost::intrusive_ptr createRoot(); /* Add a field to the document expression. @param fieldPath the path the evaluated expression will have in the result Document @param pExpression the expression to evaluate obtain this field's Value in the result Document */ void addField(const FieldPath& fieldPath, const boost::intrusive_ptr& pExpression); /* Add a field path to the set of those to be included. Note that including a nested field implies including everything on the path leading down to it. @param fieldPath the name of the field to be included */ void includePath(const std::string& fieldPath); /* Get a count of the added fields. @returns how many fields have been added */ size_t getFieldCount() const; /* Specialized BSON conversion that allows for writing out a $project specification. This creates a standalone object, which must be added to a containing object with a name @param pBuilder where to write the object to @param requireExpression see Expression::addToBsonObj */ void documentToBson(BSONObjBuilder* pBuilder, bool requireExpression) const; /* Visitor abstraction used by emitPaths(). Each path is recorded by calling path(). */ class PathSink { public: virtual ~PathSink(){}; /** Record a path. @param path the dotted path string @param include if true, the path is included; if false, the path is excluded */ virtual void path(const std::string& path, bool include) = 0; }; void excludeId(bool b) { _excludeId = b; } private: ExpressionObject(bool atRoot); // Mapping from fieldname to the Expression that generates its value. // NULL expression means inclusion from source document. typedef std::map> FieldMap; FieldMap _expressions; // this is used to maintain order for generated fields not in the source document std::vector _order; bool _excludeId; bool _atRoot; }; class ExpressionOr : public ExpressionVariadic { public: // virtuals from Expression virtual boost::intrusive_ptr optimize(); virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionSecond : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static inline int extract(const tm& tm) { return tm.tm_sec; } }; class ExpressionSetDifference : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionSetEquals : public ExpressionVariadic { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual void validateArguments(const ExpressionVector& args) const; }; class ExpressionSetIntersection : public ExpressionVariadic { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionSetIsSubset : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual boost::intrusive_ptr optimize(); virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; private: class Optimized; }; class ExpressionSetUnion : public ExpressionVariadic { public: // virtuals from ExpressionNary // virtual intrusive_ptr optimize(); virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; virtual bool isAssociativeAndCommutative() const { return true; } }; class ExpressionIsArray : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionSize : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionStrcasecmp : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionSubstr : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionSubtract : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionToLower : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionToUpper : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; }; class ExpressionWeek : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; static int extract(const tm& tm); }; class ExpressionYear : public ExpressionFixedArity { public: // virtuals from ExpressionNary virtual Value evaluateInternal(Variables* vars) const; virtual const char* getOpName() const; // tm_year is years since 1990 static int extract(const tm& tm) { return tm.tm_year + 1900; } }; } /* ======================= INLINED IMPLEMENTATIONS ========================== */ namespace mongo { inline Value ExpressionConstant::getValue() const { return pValue; } inline size_t ExpressionObject::getFieldCount() const { return _expressions.size(); } }