summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/collation
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-08-30 13:15:15 -0400
committerDavid Storch <david.storch@10gen.com>2016-08-30 16:29:37 -0400
commited0f26286c8a267cb4111a12fdb6d956a75ddaab (patch)
tree39993f50dacc05954af7f0cc8d507b999ab367e7 /src/mongo/db/query/collation
parent5bf5929c699af25be67db53ea6039adfeecd6f25 (diff)
downloadmongo-ed0f26286c8a267cb4111a12fdb6d956a75ddaab.tar.gz
SERVER-25683 reject invalid combinations of collation options
Diffstat (limited to 'src/mongo/db/query/collation')
-rw-r--r--src/mongo/db/query/collation/collator_factory_icu.cpp38
-rw-r--r--src/mongo/db/query/collation/collator_factory_icu_test.cpp125
2 files changed, 163 insertions, 0 deletions
diff --git a/src/mongo/db/query/collation/collator_factory_icu.cpp b/src/mongo/db/query/collation/collator_factory_icu.cpp
index a7f0ba911e0..85b51c0423b 100644
--- a/src/mongo/db/query/collation/collator_factory_icu.cpp
+++ b/src/mongo/db/query/collation/collator_factory_icu.cpp
@@ -661,6 +661,39 @@ Status validateLocaleID(const BSONObj& spec,
return Status::OK();
}
+// Returns a non-OK status if 'spec' contains any invalid combinations of options.
+Status validateCollationSpec(const CollationSpec& spec) {
+ // The backwards option specifically means backwards secondary weighting, and therefore only
+ // affects the secondary comparison level. It has no effect at strength 1.
+ if (spec.backwards && spec.strength == CollationSpec::StrengthType::kPrimary) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "'" << CollationSpec::kBackwardsField << "' is invalid with '"
+ << CollationSpec::kStrengthField
+ << "' of "
+ << static_cast<int>(CollationSpec::StrengthType::kPrimary)
+ << " in: "
+ << spec.toBSON()};
+ }
+
+ // The caseFirst option only affects tertiary level or caseLevel comparisons. It will have no
+ // affect if caseLevel is off and strength is 1 or 2.
+ if (spec.caseFirst != CollationSpec::CaseFirstType::kOff && !spec.caseLevel &&
+ (spec.strength == CollationSpec::StrengthType::kPrimary ||
+ spec.strength == CollationSpec::StrengthType::kSecondary)) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "'" << CollationSpec::kCaseFirstField << "' is invalid unless '"
+ << CollationSpec::kCaseLevelField
+ << "' is on or '"
+ << CollationSpec::kStrengthField
+ << "' is greater than "
+ << static_cast<int>(CollationSpec::StrengthType::kSecondary)
+ << " in: "
+ << spec.toBSON()};
+ }
+
+ return Status::OK();
+}
+
} // namespace
StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON(
@@ -716,6 +749,11 @@ StatusWith<std::unique_ptr<CollatorInterface>> CollatorFactoryICU::makeFromBSON(
return parsedSpec.getStatus();
}
+ auto validateSpecStatus = validateCollationSpec(parsedSpec.getValue());
+ if (!validateSpecStatus.isOK()) {
+ return validateSpecStatus;
+ }
+
auto mongoCollator = stdx::make_unique<CollatorInterfaceICU>(std::move(parsedSpec.getValue()),
std::move(icuCollator));
return {std::move(mongoCollator)};
diff --git a/src/mongo/db/query/collation/collator_factory_icu_test.cpp b/src/mongo/db/query/collation/collator_factory_icu_test.cpp
index e35512a8a79..2ce271a568f 100644
--- a/src/mongo/db/query/collation/collator_factory_icu_test.cpp
+++ b/src/mongo/db/query/collation/collator_factory_icu_test.cpp
@@ -1063,6 +1063,131 @@ TEST(CollatorFactoryICUTest, FactoryMadeCollatorComparisonKeysCorrectEnUS) {
ASSERT_LT(comparisonKeyABB.getKeyData().compare(comparisonKeyBA.getKeyData()), 0);
}
+TEST(CollatorFactoryICUTest, BackwardsTrueWithStrengthOneFails) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "backwards"
+ << true
+ << "strength"
+ << 1));
+ ASSERT_NOT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, BackwardsTrueWithStrengthTwoSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "backwards"
+ << true
+ << "strength"
+ << 2));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthThreeSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "lower"
+ << "strength"
+ << 3));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthThreeSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "upper"
+ << "strength"
+ << 3));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstLowerWithCaseLevelSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "lower"
+ << "caseLevel"
+ << true
+ << "strength"
+ << 1));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstUpperWithCaseLevelSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "upper"
+ << "caseLevel"
+ << true
+ << "strength"
+ << 1));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstOffWithStrengthOneSucceeds) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "off"
+ << "strength"
+ << 1));
+ ASSERT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthOneFails) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "lower"
+ << "strength"
+ << 1));
+ ASSERT_NOT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstLowerWithStrengthTwoFails) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "lower"
+ << "strength"
+ << 2));
+ ASSERT_NOT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthOneFails) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "upper"
+ << "strength"
+ << 1));
+ ASSERT_NOT_OK(collator.getStatus());
+}
+
+TEST(CollatorFactoryICUTest, CaseFirstUpperWithStrengthTwoFails) {
+ CollatorFactoryICU factory;
+ auto collator = factory.makeFromBSON(BSON("locale"
+ << "en_US"
+ << "caseFirst"
+ << "upper"
+ << "strength"
+ << 2));
+ ASSERT_NOT_OK(collator.getStatus());
+}
+
TEST(CollatorFactoryICUTest, FactoryInitializationSucceedsWithArabicLocale) {
CollatorFactoryICU factory;
ASSERT_OK(factory