diff options
-rw-r--r-- | etc/backports_required_for_multiversion_tests.yml | 4 | ||||
-rw-r--r-- | jstests/sharding/shard_keys_with_dollar_sign.js | 57 | ||||
-rw-r--r-- | src/mongo/s/shard_key_pattern.cpp | 5 | ||||
-rw-r--r-- | src/mongo/s/shard_key_pattern_test.cpp | 11 |
4 files changed, 77 insertions, 0 deletions
diff --git a/etc/backports_required_for_multiversion_tests.yml b/etc/backports_required_for_multiversion_tests.yml index b936889ae67..16df2fce80a 100644 --- a/etc/backports_required_for_multiversion_tests.yml +++ b/etc/backports_required_for_multiversion_tests.yml @@ -310,6 +310,8 @@ last-continuous: ticket: SERVER-73822 - test_file: jstests/sharding/internal_txns/incomplete_transaction_history_during_migration.js ticket: SERVER-73938 + - test_file: jstests/sharding/shard_keys_with_dollar_sign.js + ticket: SERVER-74124 suites: null last-lts: all: @@ -695,4 +697,6 @@ last-lts: ticket: SERVER-73822 - test_file: jstests/sharding/internal_txns/incomplete_transaction_history_during_migration.js ticket: SERVER-73938 + - test_file: jstests/sharding/shard_keys_with_dollar_sign.js + ticket: SERVER-74124 suites: null diff --git a/jstests/sharding/shard_keys_with_dollar_sign.js b/jstests/sharding/shard_keys_with_dollar_sign.js new file mode 100644 index 00000000000..5d18d6ab7ab --- /dev/null +++ b/jstests/sharding/shard_keys_with_dollar_sign.js @@ -0,0 +1,57 @@ +/** + * Tests that the shardCollection command and reshardCollection command correctly reject a shard key + * that has a field name with parts that start with '$'. + */ +(function() { +"use strict"; + +const st = new ShardingTest({shards: 1}); + +const dbName = "testDb"; +const ns0 = dbName + ".testColl0"; +const ns1 = dbName + ".testColl1"; +const ns2 = dbName + ".testColl2"; +const db = st.s.getDB(dbName); + +function testValidation(key, {isValidIndexKey, isValidShardKey}) { + jsTest.log(`Testing ${tojson({key, isValidIndexKey, isValidShardKey})}`); + assert.commandWorked(st.s.adminCommand({enableSharding: dbName})); + st.ensurePrimaryShard(dbName, st.shard0.name); + + const createIndexRes = db.getCollection(ns0).createIndex(key); + if (isValidIndexKey) { + assert.commandWorked(createIndexRes); + } else { + assert.commandFailedWithCode(createIndexRes, ErrorCodes.CannotCreateIndex); + } + + const shardCollectionRes = st.s.adminCommand({shardCollection: ns1, key}); + if (isValidShardKey) { + assert.commandWorked(shardCollectionRes); + } else { + assert.commandFailedWithCode(shardCollectionRes, ErrorCodes.BadValue); + } + + assert.commandWorked(st.s.adminCommand({shardCollection: ns2, key: {_id: 1}})); + const reshardCollectionRes = st.s.adminCommand({reshardCollection: ns2, key}); + if (isValidShardKey) { + assert.commandWorked(reshardCollectionRes); + } else { + assert.commandFailedWithCode(reshardCollectionRes, ErrorCodes.BadValue); + } + + assert.commandWorked(db.dropDatabase()); +} + +testValidation({"$x": 1}, {isValidIndexKey: false, isValidShardKey: false}); +testValidation({"x.$y": 1}, {isValidIndexKey: false, isValidShardKey: false}); +testValidation({"$**": 1}, {isValidIndexKey: true, isValidShardKey: false}); +testValidation({"x.$**": 1}, {isValidIndexKey: true, isValidShardKey: false}); +testValidation({"$": 1}, {isValidIndexKey: false, isValidShardKey: false}); + +testValidation({"x$": 1}, {isValidIndexKey: true, isValidShardKey: true}); +testValidation({"x$.y": 1}, {isValidIndexKey: true, isValidShardKey: true}); +testValidation({"x.y$": 1}, {isValidIndexKey: true, isValidShardKey: true}); + +st.stop(); +})(); diff --git a/src/mongo/s/shard_key_pattern.cpp b/src/mongo/s/shard_key_pattern.cpp index db4dce94066..b782f426cc6 100644 --- a/src/mongo/s/shard_key_pattern.cpp +++ b/src/mongo/s/shard_key_pattern.cpp @@ -76,6 +76,11 @@ std::vector<std::unique_ptr<FieldRef>> parseShardKeyPattern(const BSONObj& keyPa str::stream() << "Field " << patternEl.fieldNameStringData() << " contains empty parts", !newFieldRef->getPart(i).empty()); + + uassert(ErrorCodes::BadValue, + str::stream() << "Field " << patternEl.fieldNameStringData() + << " contains parts that start with '$'", + newFieldRef->getPart(i).find("$") != 0); } // Numeric and ascending (1.0), or "hashed" with exactly hashed field. diff --git a/src/mongo/s/shard_key_pattern_test.cpp b/src/mongo/s/shard_key_pattern_test.cpp index a59f0494f73..bbbf6136ec7 100644 --- a/src/mongo/s/shard_key_pattern_test.cpp +++ b/src/mongo/s/shard_key_pattern_test.cpp @@ -66,6 +66,7 @@ TEST_F(ShardKeyPatternTest, SingleFieldShardKeyPatternsValidityCheck) { ShardKeyPattern s3(BSON("a" << (long long)1L)); ShardKeyPattern s4(BSON("a" << "hashed")); + ShardKeyPattern s5(BSON("a$" << 1)); ASSERT_THROWS(ShardKeyPattern(BSONObj()), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << -1)), DBException); @@ -78,6 +79,9 @@ TEST_F(ShardKeyPatternTest, SingleFieldShardKeyPatternsValidityCheck) { DBException); ASSERT_THROWS(ShardKeyPattern(BSON("" << 1)), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("." << 1)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("$" << 1)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("$a" << 1)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("$**" << 1)), DBException); } TEST_F(ShardKeyPatternTest, CompositeShardKeyPatternsValidityCheck) { @@ -91,6 +95,9 @@ TEST_F(ShardKeyPatternTest, CompositeShardKeyPatternsValidityCheck) { DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "b." << 1.0)), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "" << 1.0)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "$" << 1.0)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "$b" << 1.0)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "$**" << 1.0)), DBException); } TEST_F(ShardKeyPatternTest, NestedShardKeyPatternsValidtyCheck) { @@ -98,6 +105,7 @@ TEST_F(ShardKeyPatternTest, NestedShardKeyPatternsValidtyCheck) { ShardKeyPattern s2(BSON("a.b.c.d" << 1.0)); ShardKeyPattern s3(BSON("a" << 1 << "c.d" << 1.0 << "e.f.g" << 1.0f)); ShardKeyPattern s4(BSON("a" << 1 << "a.b" << 1.0 << "a.b.c" << 1.0f)); + ShardKeyPattern s6(BSON("a.b$" << 1)); ASSERT_THROWS(ShardKeyPattern(BSON("a.b" << -1)), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << BSON("b" << 1))), DBException); @@ -106,6 +114,9 @@ TEST_F(ShardKeyPatternTest, NestedShardKeyPatternsValidtyCheck) { ASSERT_THROWS(ShardKeyPattern(BSON("a..b" << 1)), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << 1 << "a.b." << 1.0)), DBException); ASSERT_THROWS(ShardKeyPattern(BSON("a" << BSON("b" << 1) << "c.d" << 1.0)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a.$" << 1)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a.$b" << 1)), DBException); + ASSERT_THROWS(ShardKeyPattern(BSON("a.$**" << 1)), DBException); } TEST_F(ShardKeyPatternTest, IsShardKey) { |