mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-42462 Put new $meta arguments behind FCV check
This commit is contained in:
parent
abe90fb209
commit
f8ede369fb
@ -21,7 +21,13 @@ const dbpath = MongoRunner.dataPath + testName;
|
||||
// test ensures that a collection validator accepts the new query feature when the feature
|
||||
// compatibility version is the latest version, and rejects it when the feature compatibility
|
||||
// version is the last-stable version.
|
||||
const testCases = [];
|
||||
const testCases = [
|
||||
{validator: {$expr: {$eq: [{$meta: "indexKey"}, 'foobar']}}, nonMatchingDocument: {a: 1}},
|
||||
{validator: {$expr: {$eq: [{$meta: "sortKey"}, 'foobar']}}, nonMatchingDocument: {a: 1}},
|
||||
{validator: {$expr: {$eq: [{$meta: "recordId"}, 'foobar']}}, nonMatchingDocument: {a: 1}},
|
||||
{validator: {$expr: {$eq: [{$meta: "geoNearPoint"}, 'foobar']}}, nonMatchingDocument: {a: 1}},
|
||||
{validator: {$expr: {$eq: [{$meta: "geoNearDistance"}, 'foobar']}}, nonMatchingDocument: {a: 1}}
|
||||
];
|
||||
|
||||
let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest"});
|
||||
assert.neq(null, conn, "mongod was unable to start up");
|
||||
|
@ -17,12 +17,28 @@ const dbpath = MongoRunner.dataPath + testName;
|
||||
// definition accepts the new aggregation feature when the feature compatibility version is the
|
||||
// latest version, and rejects it when the feature compatibility version is the last-stable
|
||||
// version.
|
||||
const pipelinesWithNewFeatures = [];
|
||||
const pipelinesWithNewFeatures = [
|
||||
// TODO SERVER-43168: enable once indexKey and recordId $meta works correctly with pipelines.
|
||||
// [{$project: {x: {$meta: "indexKey"}}}],
|
||||
// [{$project: {x: {$meta: "recordId"}}}],
|
||||
[{$project: {x: {$meta: "sortKey"}}}],
|
||||
[
|
||||
{$geoNear: {near: {type: "Point", coordinates: [0, 0]}, distanceField: "loc"}},
|
||||
{$project: {m: {$meta: "geoNearPoint"}}}
|
||||
],
|
||||
[
|
||||
{$geoNear: {near: {type: "Point", coordinates: [0, 0]}, distanceField: "loc"}},
|
||||
{$project: {m: {$meta: "geoNearDistance"}}}
|
||||
]
|
||||
];
|
||||
|
||||
let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest"});
|
||||
assert.neq(null, conn, "mongod was unable to start up");
|
||||
let testDB = conn.getDB(testName);
|
||||
|
||||
// We need a GeoSpatial index to test $geoNear queries.
|
||||
assert.commandWorked(testDB.coll.createIndex({loc: "2dsphere"}));
|
||||
|
||||
// Explicitly set feature compatibility version to the latest version.
|
||||
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
|
||||
|
||||
|
57
jstests/multiVersion/sortkey_meta.js
Normal file
57
jstests/multiVersion/sortkey_meta.js
Normal file
@ -0,0 +1,57 @@
|
||||
/**
|
||||
* Test sortKey $meta projection behaviour with different feature compatibility versions.
|
||||
* - It should work in find projection with in all mongod and feature compatibility versions.
|
||||
* - In aggregate it should only work with mongod 4.4 in all mongod and feature compatibility
|
||||
* versions.
|
||||
*
|
||||
* We restart mongod during the test and expect it to have the same data after restarting.
|
||||
* @tags: [requires_persistence]
|
||||
*/
|
||||
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
load("jstests/aggregation/extras/utils.js"); // For assertErrorCode.
|
||||
|
||||
const testName = jsTest.name();
|
||||
const dbpath = MongoRunner.dataPath + testName;
|
||||
|
||||
let conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "latest"});
|
||||
assert.neq(null, conn, "mongod was unable to start up");
|
||||
let testDB = conn.getDB(testName);
|
||||
let coll = testDB.coll;
|
||||
coll.drop();
|
||||
|
||||
// Explicitly set feature compatibility version to the latest version.
|
||||
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
|
||||
|
||||
// Test that we can read sortKey $meta both in find and aggregate.
|
||||
assert.doesNotThrow(() => coll.find({}, {x: {$meta: "sortKey"}}).sort({a: 1}));
|
||||
assert.doesNotThrow(() => coll.aggregate([{$sort: {a: 1}}, {$project: {x: {$meta: "sortKey"}}}]));
|
||||
|
||||
// Set the feature compatibility version to the last-stable version.
|
||||
assert.commandWorked(testDB.adminCommand({setFeatureCompatibilityVersion: lastStableFCV}));
|
||||
|
||||
// Test that we can read sortKey $meta both in find and aggregate.
|
||||
assert.doesNotThrow(() => coll.find({}, {x: {$meta: "sortKey"}}).sort({a: 1}));
|
||||
assert.doesNotThrow(() => coll.aggregate([{$sort: {a: 1}}, {$project: {x: {$meta: "sortKey"}}}]));
|
||||
|
||||
MongoRunner.stopMongod(conn);
|
||||
|
||||
// Starting up the last-stable version of mongod.
|
||||
conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: "last-stable", noCleanData: true});
|
||||
assert.neq(null,
|
||||
conn,
|
||||
`version ${MongoRunner.getBinVersionFor("last-stable")} of mongod was` +
|
||||
" unable to start up");
|
||||
testDB = conn.getDB(testName);
|
||||
coll = testDB.coll;
|
||||
|
||||
// Test that we still can read sortKey $meta in find.
|
||||
assert.doesNotThrow(() => coll.find({}, {x: {$meta: "sortKey"}}).sort({a: 1}));
|
||||
|
||||
// In 4.2 sortKey $meta is not supported in aggregate.
|
||||
assertErrorCode(coll, [{$sort: {a: 1}}, {$project: {x: {$meta: "sortKey"}}}], 17308);
|
||||
|
||||
MongoRunner.stopMongod(conn);
|
||||
}());
|
@ -330,6 +330,10 @@ StatusWithMatchExpression CollectionImpl::parseValidator(
|
||||
// Enforce a maximum feature version if requested.
|
||||
expCtx->maxFeatureCompatibilityVersion = maxFeatureCompatibilityVersion;
|
||||
|
||||
// The match expression parser needs to know that we're parsing an expression for a
|
||||
// validator to apply some additional checks.
|
||||
expCtx->isParsingCollectionValidator = true;
|
||||
|
||||
auto statusWithMatcher =
|
||||
MatchExpressionParser::parse(validator, expCtx, ExtensionsCallbackNoop(), allowedFeatures);
|
||||
if (!statusWithMatcher.isOK())
|
||||
|
@ -830,6 +830,11 @@ Status DatabaseImpl::userCreateNS(OperationContext* opCtx,
|
||||
currentFCV != ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) {
|
||||
expCtx->maxFeatureCompatibilityVersion = currentFCV;
|
||||
}
|
||||
|
||||
// The match expression parser needs to know that we're parsing an expression for a
|
||||
// validator to apply some additional checks.
|
||||
expCtx->isParsingCollectionValidator = true;
|
||||
|
||||
auto statusWithMatcher =
|
||||
MatchExpressionParser::parse(collectionOptions.validator, std::move(expCtx));
|
||||
|
||||
|
@ -2582,6 +2582,22 @@ intrusive_ptr<Expression> ExpressionMeta::parse(
|
||||
|
||||
const auto iter = kMetaNameToMetaType.find(expr.valueStringData());
|
||||
if (iter != kMetaNameToMetaType.end()) {
|
||||
if ((expCtx->isParsingCollectionValidator || expCtx->isParsingViewDefinition) &&
|
||||
expCtx->maxFeatureCompatibilityVersion &&
|
||||
expCtx->maxFeatureCompatibilityVersion !=
|
||||
ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) {
|
||||
uassert(ErrorCodes::QueryFeatureNotAllowed,
|
||||
str::stream() << "$meta type " << iter->second << " can only be used in "
|
||||
<< (expCtx->isParsingViewDefinition ? "view definition"
|
||||
: "collection validator")
|
||||
<< " when feature compatibility version is 4.4",
|
||||
iter->second != DocumentMetadataFields::kIndexKey &&
|
||||
iter->second != DocumentMetadataFields::kSortKey &&
|
||||
iter->second != DocumentMetadataFields::kRecordId &&
|
||||
iter->second != DocumentMetadataFields::kGeoNearPoint &&
|
||||
iter->second != DocumentMetadataFields::kGeoNearDist);
|
||||
}
|
||||
|
||||
return new ExpressionMeta(expCtx, iter->second);
|
||||
} else {
|
||||
uasserted(17308, "Unsupported argument to $meta: " + expr.String());
|
||||
|
@ -281,6 +281,12 @@ public:
|
||||
// "$sortKey" using the 4.2 format.
|
||||
bool use42ChangeStreamSortKeys = false;
|
||||
|
||||
// True if this ExpressionContext is used to parse a view definition pipeline.
|
||||
bool isParsingViewDefinition = false;
|
||||
|
||||
// True if this ExpressionContext is used to parse a collection validator expression.
|
||||
bool isParsingCollectionValidator = false;
|
||||
|
||||
protected:
|
||||
static const int kInterruptCheckPeriod = 128;
|
||||
|
||||
|
@ -332,6 +332,11 @@ StatusWith<stdx::unordered_set<NamespaceString>> ViewCatalog::_validatePipeline(
|
||||
currentFCV != ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) {
|
||||
expCtx->maxFeatureCompatibilityVersion = currentFCV;
|
||||
}
|
||||
|
||||
// The pipeline parser needs to know that we're parsing a pipeline for a view definition
|
||||
// to apply some additional checks.
|
||||
expCtx->isParsingViewDefinition = true;
|
||||
|
||||
auto pipelineStatus = Pipeline::parse(viewDef.pipeline(), std::move(expCtx));
|
||||
if (!pipelineStatus.isOK()) {
|
||||
return pipelineStatus.getStatus();
|
||||
|
Loading…
Reference in New Issue
Block a user