summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-05-24 15:28:40 -0400
committerDavid Storch <david.storch@10gen.com>2016-05-25 14:40:31 -0400
commit59ca0648a8a7627edb12e160464cf014fd7af07e (patch)
tree84a55a6b71d6af81a1cb23f262a85a8283315651 /src/mongo
parent439df4c3bdff0194cff402a6268a9bdb9de44a7a (diff)
downloadmongo-59ca0648a8a7627edb12e160464cf014fd7af07e.tar.gz
SERVER-23945 make index builds without a collation inherit the collection default
Also ensures that the full BSON representation of the collation spec associated with an index or with a collection is materialized in the catalog.
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/catalog/collection_options.cpp4
-rw-r--r--src/mongo/db/catalog/collection_options_test.cpp5
-rw-r--r--src/mongo/db/catalog/database.cpp24
-rw-r--r--src/mongo/db/catalog/index_catalog.cpp27
-rw-r--r--src/mongo/db/catalog/index_catalog.h4
5 files changed, 55 insertions, 9 deletions
diff --git a/src/mongo/db/catalog/collection_options.cpp b/src/mongo/db/catalog/collection_options.cpp
index 1595706c0e2..b2aa3da4de4 100644
--- a/src/mongo/db/catalog/collection_options.cpp
+++ b/src/mongo/db/catalog/collection_options.cpp
@@ -215,6 +215,10 @@ Status CollectionOptions::parse(const BSONObj& options) {
return Status(ErrorCodes::BadValue, "'collation' has to be a document.");
}
+ if (e.Obj().isEmpty()) {
+ return Status(ErrorCodes::BadValue, "'collation' cannot be an empty document.");
+ }
+
collation = e.Obj().getOwned();
}
}
diff --git a/src/mongo/db/catalog/collection_options_test.cpp b/src/mongo/db/catalog/collection_options_test.cpp
index 85610c6fd02..4e773f1b027 100644
--- a/src/mongo/db/catalog/collection_options_test.cpp
+++ b/src/mongo/db/catalog/collection_options_test.cpp
@@ -193,6 +193,11 @@ TEST(CollectionOptions, FailToParseCollationThatIsNotAnObject) {
ASSERT_NOT_OK(options.parse(fromjson("{collation: 'notAnObject'}")));
}
+TEST(CollectionOptions, FailToParseCollationThatIsAnEmptyObject) {
+ CollectionOptions options;
+ ASSERT_NOT_OK(options.parse(fromjson("{collation: {}}")));
+}
+
TEST(CollectionOptions, CollationFieldParsesCorrectly) {
CollectionOptions options;
ASSERT_OK(options.parse(fromjson("{collation: {locale: 'en'}}")));
diff --git a/src/mongo/db/catalog/database.cpp b/src/mongo/db/catalog/database.cpp
index 06e9b8f3933..080d37e0eb8 100644
--- a/src/mongo/db/catalog/database.cpp
+++ b/src/mongo/db/catalog/database.cpp
@@ -40,27 +40,29 @@
#include "mongo/db/audit.h"
#include "mongo/db/auth/auth_index_d.h"
#include "mongo/db/background.h"
-#include "mongo/db/clientcursor.h"
#include "mongo/db/catalog/collection.h"
#include "mongo/db/catalog/collection_catalog_entry.h"
#include "mongo/db/catalog/collection_options.h"
#include "mongo/db/catalog/database_catalog_entry.h"
#include "mongo/db/catalog/database_holder.h"
+#include "mongo/db/clientcursor.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/dbhelpers.h"
-#include "mongo/db/service_context.h"
-#include "mongo/db/service_context_d.h"
#include "mongo/db/index/index_access_method.h"
#include "mongo/db/instance.h"
#include "mongo/db/introspect.h"
#include "mongo/db/op_observer.h"
+#include "mongo/db/query/collation/collation_serializer.h"
+#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/replication_coordinator_global.h"
#include "mongo/db/server_parameters.h"
+#include "mongo/db/service_context.h"
+#include "mongo/db/service_context_d.h"
#include "mongo/db/stats/top.h"
-#include "mongo/db/storage/storage_options.h"
-#include "mongo/db/storage/storage_engine.h"
#include "mongo/db/storage/recovery_unit.h"
+#include "mongo/db/storage/storage_engine.h"
+#include "mongo/db/storage/storage_options.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -618,6 +620,18 @@ Status userCreateNS(OperationContext* txn,
if (!status.isOK())
return status;
+ // Validate the collation, if there is one.
+ if (!collectionOptions.collation.isEmpty()) {
+ auto collator = CollatorFactoryInterface::get(txn->getServiceContext())
+ ->makeFromBSON(collectionOptions.collation);
+ if (!collator.isOK()) {
+ return collator.getStatus();
+ }
+
+ collectionOptions.collation =
+ CollationSerializer::specToBSON(collator.getValue()->getSpec());
+ }
+
status =
validateStorageOptions(collectionOptions.storageEngine,
stdx::bind(&StorageEngine::Factory::validateCollectionStorageOptions,
diff --git a/src/mongo/db/catalog/index_catalog.cpp b/src/mongo/db/catalog/index_catalog.cpp
index da3d0553d9f..7887759486b 100644
--- a/src/mongo/db/catalog/index_catalog.cpp
+++ b/src/mongo/db/catalog/index_catalog.cpp
@@ -57,6 +57,7 @@
#include "mongo/db/matcher/expression.h"
#include "mongo/db/matcher/extensions_callback_disallow_extensions.h"
#include "mongo/db/ops/delete.h"
+#include "mongo/db/query/collation/collation_serializer.h"
#include "mongo/db/query/collation/collator_factory_interface.h"
#include "mongo/db/query/internal_plans.h"
#include "mongo/db/repl/replication_coordinator_global.h"
@@ -276,7 +277,7 @@ StatusWith<BSONObj> IndexCatalog::prepareSpecForCreate(OperationContext* txn,
if (!status.isOK())
return StatusWith<BSONObj>(status);
- auto fixed = _fixIndexSpec(original);
+ auto fixed = _fixIndexSpec(txn, _collection, original);
if (!fixed.isOK()) {
return fixed;
}
@@ -1260,7 +1261,9 @@ BSONObj IndexCatalog::fixIndexKey(const BSONObj& key) {
return key;
}
-StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(const BSONObj& spec) {
+StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(OperationContext* txn,
+ Collection* collection,
+ const BSONObj& spec) {
auto statusWithSpec = IndexLegacy::adjustIndexSpecObject(spec);
if (!statusWithSpec.isOK()) {
return statusWithSpec;
@@ -1289,6 +1292,24 @@ StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(const BSONObj& spec) {
}
b.append("name", name);
+ if (auto collationElt = spec["collation"]) {
+ // This should already have been verified by _isSpecOk().
+ invariant(collationElt.type() == BSONType::Object);
+
+ auto collator = CollatorFactoryInterface::get(txn->getServiceContext())
+ ->makeFromBSON(collationElt.Obj());
+ if (!collator.isOK()) {
+ return collator.getStatus();
+ }
+
+ b.append("collation", CollationSerializer::specToBSON(collator.getValue()->getSpec()));
+ } else if (collection->getDefaultCollator()) {
+ // The user did not specify an explicit collation for this index and the collection has a
+ // default collator. In this case, the index inherits the collection default.
+ b.append("collation",
+ CollationSerializer::specToBSON(collection->getDefaultCollator()->getSpec()));
+ }
+
{
BSONObjIterator i(o);
while (i.more()) {
@@ -1299,7 +1320,7 @@ StatusWith<BSONObj> IndexCatalog::_fixIndexSpec(const BSONObj& spec) {
// skip
} else if (s == "dropDups") {
// dropDups is silently ignored and removed from the spec as of SERVER-14710.
- } else if (s == "v" || s == "unique" || s == "key" || s == "name") {
+ } else if (s == "v" || s == "unique" || s == "key" || s == "name" || s == "collation") {
// covered above
} else {
b.append(e);
diff --git a/src/mongo/db/catalog/index_catalog.h b/src/mongo/db/catalog/index_catalog.h
index dac775501a2..a982a6e976b 100644
--- a/src/mongo/db/catalog/index_catalog.h
+++ b/src/mongo/db/catalog/index_catalog.h
@@ -364,7 +364,9 @@ private:
// conform to the standard for insertion. This function adds the 'v' field if it didn't
// exist, removes the '_id' field if it exists, applies plugin-level transformations if
// appropriate, etc.
- static StatusWith<BSONObj> _fixIndexSpec(const BSONObj& spec);
+ static StatusWith<BSONObj> _fixIndexSpec(OperationContext* txn,
+ Collection* collection,
+ const BSONObj& spec);
Status _isSpecOk(OperationContext* txn, const BSONObj& spec) const;