summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db')
-rwxr-xr-xsrc/mongo/db/pipeline/document_source.h2
-rwxr-xr-xsrc/mongo/db/pipeline/document_source_unwind.cpp23
-rw-r--r--src/mongo/db/pipeline/expression.cpp2
-rw-r--r--[-rwxr-xr-x]src/mongo/db/pipeline/field_path.cpp61
-rwxr-xr-xsrc/mongo/db/pipeline/field_path.h38
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];
}