diff options
Diffstat (limited to 'src/mongo/db')
-rwxr-xr-x | src/mongo/db/pipeline/document_source.h | 2 | ||||
-rwxr-xr-x | src/mongo/db/pipeline/document_source_unwind.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 2 | ||||
-rw-r--r--[-rwxr-xr-x] | src/mongo/db/pipeline/field_path.cpp | 61 | ||||
-rwxr-xr-x | src/mongo/db/pipeline/field_path.h | 38 |
5 files changed, 61 insertions, 65 deletions
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h index 3722d1769a5..b1475310f80 100755 --- a/src/mongo/db/pipeline/document_source.h +++ b/src/mongo/db/pipeline/document_source.h @@ -1130,7 +1130,7 @@ namespace mongo { void unwindPath(const FieldPath &fieldPath); // Configuration state. - FieldPath _unwindPath; + scoped_ptr<FieldPath> _unwindPath; // Iteration state. class Unwinder; diff --git a/src/mongo/db/pipeline/document_source_unwind.cpp b/src/mongo/db/pipeline/document_source_unwind.cpp index 00913999104..bf2986046a7 100755 --- a/src/mongo/db/pipeline/document_source_unwind.cpp +++ b/src/mongo/db/pipeline/document_source_unwind.cpp @@ -162,7 +162,6 @@ namespace mongo { intrusive_ptr<Document> current = _document; intrusive_ptr<const Value> pathValue; const size_t pathLength = _unwindPath.getPathLength(); - verify(pathLength>0); for(size_t i = 0; i < pathLength; ++i) { size_t idx = current->getFieldIndex(_unwindPath.getFieldName(i)); @@ -200,14 +199,13 @@ namespace mongo { DocumentSourceUnwind::DocumentSourceUnwind( const intrusive_ptr<ExpressionContext> &pExpCtx): - DocumentSource(pExpCtx), - _unwindPath() { + DocumentSource(pExpCtx) { } void DocumentSourceUnwind::lazyInit() { if (!_unwinder) { - verify(_unwindPath.getPathLength()); - _unwinder.reset(new Unwinder(_unwindPath)); + verify(_unwindPath); + _unwinder.reset(new Unwinder(*_unwindPath)); if (!pSource->eof()) { // Set up the first source document for unwinding. _unwinder->resetDocument(pSource->getCurrent()); @@ -257,23 +255,22 @@ namespace mongo { void DocumentSourceUnwind::sourceToBson( BSONObjBuilder *pBuilder, bool explain) const { - pBuilder->append(unwindName, _unwindPath.getPath(true)); + verify(_unwindPath); + pBuilder->append(unwindName, _unwindPath->getPath(true)); } DocumentSource::GetDepsReturn DocumentSourceUnwind::getDependencies(set<string>& deps) const { - deps.insert(_unwindPath.getPath(false)); + verify(_unwindPath); + deps.insert(_unwindPath->getPath(false)); return SEE_NEXT; } void DocumentSourceUnwind::unwindPath(const FieldPath &fieldPath) { // Can't set more than one unwind path. - uassert(15979, str::stream() << unwindName << - "can't unwind more than one path at once", - !_unwindPath.getPathLength()); - uassert(15980, "the path of the field to unwind cannot be empty", - fieldPath.getPathLength()); + uassert(15979, str::stream() << unwindName << "can't unwind more than one path", + !_unwindPath); // Record the unwind path. - _unwindPath = fieldPath; + _unwindPath.reset(new FieldPath(fieldPath)); } intrusive_ptr<DocumentSource> DocumentSourceUnwind::createFromBson( diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 2cfb42ae5c0..4ab1f22a13f 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -1326,8 +1326,6 @@ namespace mongo { void ExpressionObject::addField(const FieldPath &fieldPath, const intrusive_ptr<Expression> &pExpression) { - verify(fieldPath.getPathLength() > 0); // sanity check - const string fieldPart = fieldPath.getFieldName(0); const bool haveExpr = _expressions.count(fieldPart); diff --git a/src/mongo/db/pipeline/field_path.cpp b/src/mongo/db/pipeline/field_path.cpp index b0a2b0d364b..a21010bb95c 100755..100644 --- a/src/mongo/db/pipeline/field_path.cpp +++ b/src/mongo/db/pipeline/field_path.cpp @@ -24,19 +24,16 @@ namespace mongo { const char FieldPath::prefix[] = "$"; - FieldPath::~FieldPath() { - } - - FieldPath::FieldPath(): - vFieldName() { - } - - FieldPath::FieldPath(const vector<string>& fieldPath): - vFieldName(fieldPath) { + FieldPath::FieldPath(const vector<string>& fieldPath) { + massert(16409, "FieldPath cannot be constructed from an empty vector.", !fieldPath.empty()); + vFieldName.reserve(fieldPath.size()); + for(vector<string>::const_iterator i = fieldPath.begin(); i != fieldPath.end(); ++i) { + pushFieldName(*i); + } + verify(getPathLength() > 0); } - FieldPath::FieldPath(const string &fieldPath): - vFieldName() { + FieldPath::FieldPath(const string& fieldPath) { /* The field path could be using dot notation. Break the field path up by peeling off successive pieces. @@ -48,22 +45,20 @@ namespace mongo { /* if there are no more dots, use the remainder of the string */ if (dotpos == fieldPath.npos) { - vFieldName.push_back(fieldPath.substr(startpos, dotpos)); + string lastFieldName = fieldPath.substr(startpos, dotpos); + pushFieldName(lastFieldName); break; } /* use the string up to the dot */ const size_t length = dotpos - startpos; - uassert(15998, str::stream() << - "field names cannot be zero length (in path \"" << - fieldPath << "\")", - length > 0); - - vFieldName.push_back(fieldPath.substr(startpos, length)); + string nextFieldName = fieldPath.substr(startpos, length); + pushFieldName(nextFieldName); /* next time, search starting one spot after that */ startpos = dotpos + 1; } + verify(getPathLength() > 0); } string FieldPath::getPath(bool fieldPrefix) const { @@ -76,27 +71,31 @@ namespace mongo { if (fieldPrefix) outStream << prefix; - outStream << vFieldName[0]; const size_t n = vFieldName.size(); + + verify(n > 0); + outStream << vFieldName[0]; for(size_t i = 1; i < n; ++i) outStream << '.' << vFieldName[i]; } - FieldPath &FieldPath::operator=(const FieldPath &rRHS) { - if (this != &rRHS) { - vFieldName = rRHS.vFieldName; - } - - return *this; + FieldPath FieldPath::tail() const { + vector<string> allButFirst(vFieldName.begin()+1, vFieldName.end()); + return FieldPath(allButFirst); } - FieldPath FieldPath::tail() const { - verify(!vFieldName.empty()); + void FieldPath::uassertValidFieldName(const string& fieldName) { + uassert(15998, "FieldPath field names may not be empty strings.", fieldName.length() > 0); + uassert(16410, "FieldPath field names may not start with '$'.", fieldName[0] != '$'); + uassert(16411, "FieldPath field names may not contain '\0'.", + fieldName.find('\0') == string::npos); + uassert(16412, "FieldPath field names may not contain '.'.", + !str::contains(fieldName, '.')); + } - FieldPath out; - vector<string> allButFirst(vFieldName.begin()+1, vFieldName.end()); - out.vFieldName.swap(allButFirst); - return out; + void FieldPath::pushFieldName(const string& fieldName) { + uassertValidFieldName(fieldName); + vFieldName.push_back(fieldName); } } diff --git a/src/mongo/db/pipeline/field_path.h b/src/mongo/db/pipeline/field_path.h index 5a7c19161a0..767a106ee59 100755 --- a/src/mongo/db/pipeline/field_path.h +++ b/src/mongo/db/pipeline/field_path.h @@ -22,22 +22,18 @@ namespace mongo { class FieldPath { public: - virtual ~FieldPath(); /** - Constructor. - - @param fieldPath the dotted field path string or pre-split vector + * Constructor. + * + * @param fieldPath the dotted field path string or non empty pre-split vector. + * The constructed object will have getPathLength() > 0. + * Uassert if any component field names do not pass validation. */ FieldPath(const string& fieldPath); FieldPath(const vector<string>& fieldPath); /** - Constructor. - */ - FieldPath(); - - /** Get the number of path elements in the field path. @returns the number of path elements @@ -47,7 +43,7 @@ namespace mongo { /** Get a particular path element from the path. - @param i the index of the path element + @param i the zero based index of the path element. @returns the path element */ string getFieldName(size_t i) const; @@ -69,13 +65,6 @@ namespace mongo { void writePath(ostream &outStream, bool fieldPrefix) const; /** - Assignment operator. - - @param rRHS right hand side of the assignment - */ - FieldPath &operator=(const FieldPath &rRHS); - - /** Get the prefix string. @returns the prefix string @@ -84,10 +73,22 @@ namespace mongo { static const char prefix[]; - /** a FieldPath like this but missing the first element (useful for recursion) */ + /** + * A FieldPath like this but missing the first element (useful for recursion). + * Precondition getPathLength() > 1. + */ FieldPath tail() const; private: + /** Uassert if a field name does not pass validation. */ + static void uassertValidFieldName(const string& fieldName); + + /** + * Push a new field name to the back of the vector of names comprising the field path. + * Uassert if 'fieldName' does not pass validation. + */ + void pushFieldName(const string& fieldName); + vector<string> vFieldName; }; } @@ -102,6 +103,7 @@ namespace mongo { } inline string FieldPath::getFieldName(size_t i) const { + verify(i < getPathLength()); return vFieldName[i]; } |