0
0
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:
Anton Korshunov 2019-10-17 13:03:40 +00:00 committed by evergreen
parent abe90fb209
commit f8ede369fb
8 changed files with 117 additions and 2 deletions

View File

@ -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");

View File

@ -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}));

View 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);
}());

View File

@ -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())

View File

@ -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));

View File

@ -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());

View File

@ -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;

View File

@ -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();