diff options
author | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2016-09-01 12:15:34 -0400 |
---|---|---|
committer | Max Hirschhorn <max.hirschhorn@mongodb.com> | 2016-09-01 12:15:34 -0400 |
commit | 159d4db49c2aa2ecfc988e25999ee780f53a5efd (patch) | |
tree | 5ba91ca426ad3f6f584aa57de608f31753f62a5a /src/mongo/db/catalog/index_key_validate.cpp | |
parent | af2b6a08feb822b3ce9644ee6f45a4731d868ad5 (diff) | |
download | mongo-159d4db49c2aa2ecfc988e25999ee780f53a5efd.tar.gz |
SERVER-25156 Define a validateIndexSpec() helper function.
Consolidates and moves some of the option parsing in the "createIndexes"
command to its own library so that it can be unit tested.
Diffstat (limited to 'src/mongo/db/catalog/index_key_validate.cpp')
-rw-r--r-- | src/mongo/db/catalog/index_key_validate.cpp | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/src/mongo/db/catalog/index_key_validate.cpp b/src/mongo/db/catalog/index_key_validate.cpp index 4c692f98f37..758524007c0 100644 --- a/src/mongo/db/catalog/index_key_validate.cpp +++ b/src/mongo/db/catalog/index_key_validate.cpp @@ -33,15 +33,26 @@ #include <cmath> #include <limits> +#include "mongo/base/status.h" +#include "mongo/base/status_with.h" #include "mongo/db/field_ref.h" #include "mongo/db/index_names.h" #include "mongo/db/jsobj.h" +#include "mongo/db/namespace_string.h" #include "mongo/util/mongoutils/str.h" namespace mongo { using std::string; +namespace { +const int kIndexVersionV0 = 0; + +const StringData kKeyPatternFieldName = "key"_sd; +const StringData kNamespaceFieldName = "ns"_sd; +const StringData kVersionFieldName = "v"_sd; +} // namespace + Status validateKeyPattern(const BSONObj& key) { const ErrorCodes::Error code = ErrorCodes::CannotCreateIndex; @@ -129,4 +140,97 @@ Status validateKeyPattern(const BSONObj& key) { return Status::OK(); } + +StatusWith<BSONObj> validateIndexSpec(const BSONObj& indexSpec, + const NamespaceString& expectedNamespace) { + bool hasKeyPatternField = false; + bool hasNamespaceField = false; + + for (auto&& indexSpecElem : indexSpec) { + auto indexSpecElemFieldName = indexSpecElem.fieldNameStringData(); + if (kKeyPatternFieldName == indexSpecElemFieldName) { + if (indexSpecElem.type() != BSONType::Object) { + return {ErrorCodes::TypeMismatch, + str::stream() << "The field '" << kKeyPatternFieldName + << "' must be an object, but got " + << typeName(indexSpecElem.type())}; + } + + std::vector<StringData> keys; + for (auto&& keyElem : indexSpecElem.Obj()) { + auto keyElemFieldName = keyElem.fieldNameStringData(); + if (std::find(keys.begin(), keys.end(), keyElemFieldName) != keys.end()) { + return {ErrorCodes::BadValue, + str::stream() << "The field '" << keyElemFieldName + << "' appears multiple times in the index key pattern " + << indexSpecElem.Obj()}; + } + keys.push_back(keyElemFieldName); + } + + hasKeyPatternField = true; + } else if (kNamespaceFieldName == indexSpecElemFieldName) { + if (indexSpecElem.type() != BSONType::String) { + return {ErrorCodes::TypeMismatch, + str::stream() << "The field '" << kNamespaceFieldName + << "' must be a string, but got " + << typeName(indexSpecElem.type())}; + } + + StringData ns = indexSpecElem.valueStringData(); + if (ns.empty()) { + return {ErrorCodes::BadValue, + str::stream() << "The field '" << kNamespaceFieldName + << "' cannot be an empty string"}; + } + + if (ns != expectedNamespace.ns()) { + return {ErrorCodes::BadValue, + str::stream() << "The value of the field '" << kNamespaceFieldName << "' (" + << ns + << ") doesn't match the namespace '" + << expectedNamespace.ns() + << "'"}; + } + + hasNamespaceField = true; + } else if (kVersionFieldName == indexSpecElemFieldName) { + if (!indexSpecElem.isNumber()) { + return {ErrorCodes::TypeMismatch, + str::stream() << "The field '" << kVersionFieldName + << "' must be a number, but got " + << typeName(indexSpecElem.type())}; + } + + if (kIndexVersionV0 == indexSpecElem.numberInt()) { + return {ErrorCodes::CannotCreateIndex, + str::stream() << "Invalid index specification " << indexSpec + << "; cannot create an index with " + << kVersionFieldName + << "=" + << kIndexVersionV0}; + } + } else { + // TODO SERVER-769: Validate index options specified in the "createIndexes" command. + continue; + } + } + + if (!hasKeyPatternField) { + return {ErrorCodes::FailedToParse, + str::stream() << "The '" << kKeyPatternFieldName + << "' field is a required property of an index specification"}; + } + + if (!hasNamespaceField) { + // We create a new index specification with the 'ns' field set as 'expectedNamespace' if the + // field was omitted. + BSONObjBuilder bob; + bob.append(kNamespaceFieldName, expectedNamespace.ns()); + bob.appendElements(indexSpec); + return bob.obj(); + } + + return indexSpec; +} } // namespace mongo |